From 44c70dfbcbf65c7afd93971bc6b19345a6cc7929 Mon Sep 17 00:00:00 2001 From: Eduard S Date: Tue, 20 Oct 2020 14:52:46 +0200 Subject: [PATCH] Replace cp -r in StateDB by checkpoints, Resolve #93 --- db/statedb/statedb.go | 67 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/db/statedb/statedb.go b/db/statedb/statedb.go index 084ca43..4a830c8 100644 --- a/db/statedb/statedb.go +++ b/db/statedb/statedb.go @@ -4,10 +4,10 @@ import ( "errors" "fmt" "os" - "os/exec" "strconv" "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/log" "github.com/iden3/go-merkletree" "github.com/iden3/go-merkletree/db" "github.com/iden3/go-merkletree/db/pebble" @@ -103,7 +103,7 @@ func NewStateDB(path string, typ TypeStateDB, nLevels int) (*StateDB, error) { } // make reset (get checkpoint) at currentBatch - err = sdb.Reset(sdb.currentBatch) + err = sdb.reset(sdb.currentBatch, false) if err != nil { return nil, err } @@ -162,6 +162,8 @@ func (s *StateDB) MakeCheckpoint() error { if err != nil { return err } + } else if err != nil && !os.IsNotExist(err) { + return err } // execute Checkpoint @@ -184,14 +186,59 @@ func (s *StateDB) DeleteCheckpoint(batchNum common.BatchNum) error { return os.RemoveAll(checkpointPath) } +func pebbleMakeCheckpoint(source, dest string) error { + // Remove dest folder (if it exists) before doing the checkpoint + if _, err := os.Stat(dest); !os.IsNotExist(err) { + err := os.RemoveAll(dest) + if err != nil { + return err + } + } else if err != nil && !os.IsNotExist(err) { + return err + } + + sto, err := pebble.NewPebbleStorage(source, false) + if err != nil { + return err + } + defer func() { + errClose := sto.Pebble().Close() + if errClose != nil { + log.Errorw("Pebble.Close", "err", errClose) + } + }() + + // execute Checkpoint + err = sto.Pebble().Checkpoint(dest) + if err != nil { + return err + } + + return nil +} + // Reset resets the StateDB to the checkpoint at the given batchNum. Reset // does not delete the checkpoints between old current and the new current, // those checkpoints will remain in the storage, and eventually will be // deleted when MakeCheckpoint overwrites them. func (s *StateDB) Reset(batchNum common.BatchNum) error { + return s.reset(batchNum, true) +} + +// reset resets the StateDB to the checkpoint at the given batchNum. Reset +// does not delete the checkpoints between old current and the new current, +// those checkpoints will remain in the storage, and eventually will be +// deleted when MakeCheckpoint overwrites them. `closeCurrent` will close the +// currently opened db before doing the reset. +func (s *StateDB) reset(batchNum common.BatchNum, closeCurrent bool) error { checkpointPath := s.path + PathBatchNum + strconv.Itoa(int(batchNum)) currentPath := s.path + PathCurrent + if closeCurrent { + if err := s.db.Pebble().Close(); err != nil { + return err + } + } // remove 'current' err := os.RemoveAll(currentPath) if err != nil { @@ -210,8 +257,7 @@ func (s *StateDB) Reset(batchNum common.BatchNum) error { } // copy 'BatchNumX' to 'current' - cmd := exec.Command("cp", "-r", checkpointPath, currentPath) //nolint:gosec - err = cmd.Run() + err = pebbleMakeCheckpoint(checkpointPath, currentPath) if err != nil { return err } @@ -431,20 +477,21 @@ func (l *LocalStateDB) Reset(batchNum common.BatchNum, fromSynchronizer bool) er return fmt.Errorf("Checkpoint not exist in Synchronizer") } + if err := l.db.Pebble().Close(); err != nil { + return err + } // remove 'current' err := os.RemoveAll(currentPath) if err != nil { return err } // copy synchronizer'BatchNumX' to 'current' - cmd := exec.Command("cp", "-r", synchronizerCheckpointPath, currentPath) //nolint:gosec - err = cmd.Run() + err = pebbleMakeCheckpoint(synchronizerCheckpointPath, currentPath) if err != nil { return err } - // copy synchronizer-'BatchNumX' to 'BatchNumX' - cmd = exec.Command("cp", "-r", synchronizerCheckpointPath, checkpointPath) //nolint:gosec - err = cmd.Run() + // copy synchronizer'BatchNumX' to 'BatchNumX' + err = pebbleMakeCheckpoint(synchronizerCheckpointPath, checkpointPath) if err != nil { return err } @@ -471,5 +518,5 @@ func (l *LocalStateDB) Reset(batchNum common.BatchNum, fromSynchronizer bool) er return nil } // use checkpoint from LocalStateDB - return l.StateDB.Reset(batchNum) + return l.StateDB.reset(batchNum, true) }