Skip to content

Commit 97d49c6

Browse files
committed
feat: streamline backup process for badger4 datastore and improve error handling
1 parent 097f3ce commit 97d49c6

2 files changed

Lines changed: 19 additions & 41 deletions

File tree

pkg/cmd/restore.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ func NewRestoreCmd() *cobra.Command {
4646
return fmt.Errorf("failed to access backup file: %w", err)
4747
}
4848

49-
// Check if datastore already exists
5049
force, err := cmd.Flags().GetBool("force")
5150
if err != nil {
5251
return err
5352
}
5453

54+
// Check if datastore already exists
5555
dbPath := filepath.Join(nodeConfig.RootDir, nodeConfig.DBPath)
5656
if _, err := os.Stat(dbPath); err == nil && !force {
5757
return fmt.Errorf("datastore already exists at %s (use --force to overwrite)", dbPath)

pkg/store/backup.go

Lines changed: 18 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -17,51 +17,29 @@ func (s *DefaultStore) Backup(ctx context.Context, writer io.Writer, since uint6
1717
return 0, err
1818
}
1919

20-
visited := make(map[ds.Datastore]struct{})
21-
current, ok := any(s.db).(ds.Datastore)
22-
if !ok {
23-
return 0, fmt.Errorf("backup is not supported by the configured datastore")
20+
// Try direct badger4 cast first
21+
if badgerDatastore, ok := s.db.(*badger4.Datastore); ok {
22+
return backupBadger(badgerDatastore, writer, since)
2423
}
2524

26-
for {
27-
// Try to leverage a native backup implementation if the underlying datastore exposes one.
28-
type backupable interface {
29-
Backup(io.Writer, uint64) (uint64, error)
30-
}
31-
if dsBackup, ok := current.(backupable); ok {
32-
version, err := dsBackup.Backup(writer, since)
33-
if err != nil {
34-
return 0, fmt.Errorf("datastore backup failed: %w", err)
35-
}
36-
return version, nil
37-
}
38-
39-
// Default Badger datastore used across ev-node.
40-
if badgerDatastore, ok := current.(*badger4.Datastore); ok {
41-
// `badger.DB.Backup` internally orchestrates a consistent snapshot without pausing writes.
42-
version, err := badgerDatastore.DB.Backup(writer, since)
43-
if err != nil {
44-
return 0, fmt.Errorf("badger backup failed: %w", err)
25+
// Try to unwrap one level (e.g., PrefixTransform wrapper)
26+
if shim, ok := s.db.(ds.Shim); ok {
27+
children := shim.Children()
28+
if len(children) > 0 {
29+
if badgerDatastore, ok := children[0].(*badger4.Datastore); ok {
30+
return backupBadger(badgerDatastore, writer, since)
4531
}
46-
return version, nil
4732
}
33+
}
4834

49-
// Attempt to unwrap shimmed datastores (e.g., prefix or mutex wrappers) to reach the backing store.
50-
if _, seen := visited[current]; seen {
51-
break
52-
}
53-
visited[current] = struct{}{}
35+
return 0, fmt.Errorf("backup is only supported for badger4 datastore")
36+
}
5437

55-
shim, ok := current.(ds.Shim)
56-
if !ok {
57-
break
58-
}
59-
children := shim.Children()
60-
if len(children) == 0 {
61-
break
62-
}
63-
current = children[0]
38+
func backupBadger(badgerDatastore *badger4.Datastore, writer io.Writer, since uint64) (uint64, error) {
39+
// `badger.DB.Backup` internally orchestrates a consistent snapshot without pausing writes.
40+
version, err := badgerDatastore.DB.Backup(writer, since)
41+
if err != nil {
42+
return 0, fmt.Errorf("badger backup failed: %w", err)
6443
}
65-
66-
return 0, fmt.Errorf("backup is not supported by the configured datastore")
44+
return version, nil
6745
}

0 commit comments

Comments
 (0)