From 2782b7815e1aa74db8f4be80dea8965525722d89 Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Tue, 15 Oct 2013 16:55:28 -0400 Subject: [PATCH] Sync wallet files to disk as needed, instead of waiting for a timer. While fixing this code, the dirty flag was also cleared so that unneeded syncs wouldn't be needed later. The dirty flag set and sync was also added for the 'getnewaddress' handler, as it was previously missing. --- cmd.go | 23 ++++++++++++----------- cmdmgr.go | 16 +++++++++++++--- disksync.go | 54 ++++++++++++++--------------------------------------- 3 files changed, 39 insertions(+), 54 deletions(-) diff --git a/cmd.go b/cmd.go index 4a16488..5e21c85 100644 --- a/cmd.go +++ b/cmd.go @@ -107,17 +107,15 @@ func (s *BtcWalletStore) Rollback(height int64, hash *btcwire.ShaHash) { func (w *BtcWallet) Rollback(height int64, hash *btcwire.ShaHash) { w.UtxoStore.Lock() w.UtxoStore.dirty = w.UtxoStore.dirty || w.UtxoStore.s.Rollback(height, hash) - if w.UtxoStore.dirty { - AddDirtyAccount(w) - } w.UtxoStore.Unlock() w.TxStore.Lock() w.TxStore.dirty = w.TxStore.dirty || w.TxStore.s.Rollback(height, hash) - if w.TxStore.dirty { - AddDirtyAccount(w) - } w.TxStore.Unlock() + + if err := w.writeDirtyToDisk(); err != nil { + log.Errorf("cannot sync dirty wallet: %v", err) + } } // walletdir returns the directory path which holds the wallet, utxo, @@ -455,8 +453,11 @@ func (w *BtcWallet) newBlockTxHandler(result interface{}, e *btcjson.Error) bool txs := w.TxStore.s w.TxStore.s = append(txs, t) w.TxStore.dirty = true - AddDirtyAccount(w) w.TxStore.Unlock() + + if err = w.writeDirtyToDisk(); err != nil { + log.Errorf("cannot sync dirty wallet: %v", err) + } }() // Do not add output to utxo store if spent. @@ -476,8 +477,11 @@ func (w *BtcWallet) newBlockTxHandler(result interface{}, e *btcjson.Error) bool w.UtxoStore.Lock() w.UtxoStore.s = append(w.UtxoStore.s, u) w.UtxoStore.dirty = true - AddDirtyAccount(w) w.UtxoStore.Unlock() + if err = w.writeDirtyToDisk(); err != nil { + log.Errorf("cannot sync dirty wallet: %v", err) + } + confirmed := w.CalculateBalance(6) unconfirmed := w.CalculateBalance(0) - confirmed NotifyWalletBalance(frontendNotificationMaster, w.name, confirmed) @@ -538,9 +542,6 @@ func main() { // Begin generating new IDs for JSON calls. go JSONIDGenerator(NewJSONID) - // Begin wallet to disk syncer. - go DirtyAccountUpdater() - for { replies := make(chan error) done := make(chan int) diff --git a/cmdmgr.go b/cmdmgr.go index 82f4cea..e0671db 100644 --- a/cmdmgr.go +++ b/cmdmgr.go @@ -334,6 +334,10 @@ func GetNewAddress(reply chan []byte, msg *btcjson.Message) { ReplyError(reply, msg.Id, &e) return } + w.dirty = true + if err = w.writeDirtyToDisk(); err != nil { + log.Errorf("cannot sync dirty wallet: %v", err) + } w.ReqNewTxsForAddress(addr) ReplySuccess(reply, msg.Id, addr) } else { @@ -493,8 +497,10 @@ func SendFrom(reply chan []byte, msg *btcjson.Message) { modified := w.UtxoStore.s.Remove(inputs) if modified { w.UtxoStore.dirty = true - AddDirtyAccount(w) w.UtxoStore.Unlock() + if err := w.writeDirtyToDisk(); err != nil { + log.Errorf("cannot sync dirty wallet: %v", err) + } // Notify all frontends of new account balances. confirmed := w.CalculateBalance(6) @@ -638,8 +644,10 @@ func SendMany(reply chan []byte, msg *btcjson.Message) { modified := w.UtxoStore.s.Remove(inputs) if modified { w.UtxoStore.dirty = true - AddDirtyAccount(w) w.UtxoStore.Unlock() + if err := w.writeDirtyToDisk(); err != nil { + log.Errorf("cannot sync dirty wallet: %v", err) + } // Notify all frontends of new account balances. confirmed := w.CalculateBalance(6) @@ -778,7 +786,9 @@ func CreateEncryptedWallet(reply chan []byte, msg *btcjson.Message) { bw.Track() wallets.m[wname] = bw - AddDirtyAccount(bw) + if err := bw.writeDirtyToDisk(); err != nil { + log.Errorf("cannot sync dirty wallet: %v", err) + } ReplySuccess(reply, msg.Id, nil) } diff --git a/disksync.go b/disksync.go index 798dc4b..5980ed3 100644 --- a/disksync.go +++ b/disksync.go @@ -23,43 +23,11 @@ import ( "time" ) -var dirtyAccountSet = make(map[*BtcWallet]bool) -var addDirtyAccount = make(chan *BtcWallet) - -// DirtyAccountUpdater is responsible for listening for listens for new -// dirty wallets (changed in memory with updaets not yet saved to disk) -// to add to dirtyAccountSet. This is designed to run as a single goroutine. -func DirtyAccountUpdater() { - timer := time.Tick(time.Minute) - for { - select { - case w := <-addDirtyAccount: - dirtyAccountSet[w] = true - - case <-timer: - for w := range dirtyAccountSet { - if err := w.writeDirtyToDisk(); err != nil { - log.Errorf("cannot sync dirty wallet '%v': %v", w.name, err) - } else { - delete(dirtyAccountSet, w) - log.Infof("removed dirty wallet '%v'", w.name) - } - } - } - } -} - -// AddDirtyAccount adds w to a set of items to be synced to disk. The -// dirty flag must still be set on the various dirty elements of the -// account (wallet, transactions, and/or utxos) or nothing will be -// written to disk during the next scheduled sync. -func AddDirtyAccount(w *BtcWallet) { - addDirtyAccount <- w -} - // writeDirtyToDisk checks for the dirty flag on an account's wallet, // txstore, and utxostore, writing them to disk if any are dirty. func (w *BtcWallet) writeDirtyToDisk() error { + fmt.Println("entered") + // Temporary files append the current time to the normal file name. // In caes of failure, the most recent temporary file can be inspected // for validity, and moved to replace the main file. @@ -72,8 +40,8 @@ func (w *BtcWallet) writeDirtyToDisk() error { // Wallet if w.dirty { - w.mtx.RLock() - defer w.mtx.RUnlock() + w.mtx.Lock() + defer w.mtx.Unlock() tmpfilepath := wfilepath + "-" + timeStr tmpfile, err := os.Create(tmpfilepath) if err != nil { @@ -88,12 +56,14 @@ func (w *BtcWallet) writeDirtyToDisk() error { if err = os.Rename(tmpfilepath, wfilepath); err != nil { return err } + + w.dirty = false } // Transactions if w.TxStore.dirty { - w.TxStore.RLock() - defer w.TxStore.RUnlock() + w.TxStore.Lock() + defer w.TxStore.Unlock() tmpfilepath := txfilepath + "-" + timeStr tmpfile, err := os.Create(tmpfilepath) if err != nil { @@ -108,12 +78,14 @@ func (w *BtcWallet) writeDirtyToDisk() error { if err = os.Rename(tmpfilepath, txfilepath); err != nil { return err } + + w.TxStore.dirty = false } // UTXOs if w.UtxoStore.dirty { - w.UtxoStore.RLock() - defer w.UtxoStore.RUnlock() + w.UtxoStore.Lock() + defer w.UtxoStore.Unlock() tmpfilepath := utxofilepath + "-" + timeStr tmpfile, err := os.Create(tmpfilepath) if err != nil { @@ -128,6 +100,8 @@ func (w *BtcWallet) writeDirtyToDisk() error { if err = os.Rename(tmpfilepath, utxofilepath); err != nil { return err } + + w.UtxoStore.dirty = false } return nil