Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 134 additions & 0 deletions apps/evm/cmd/cleanup_goheader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
package cmd

import (
"context"
"fmt"

ds "github.com/ipfs/go-datastore"
dsq "github.com/ipfs/go-datastore/query"
"github.com/spf13/cobra"

rollcmd "github.com/evstack/ev-node/pkg/cmd"
"github.com/evstack/ev-node/pkg/store"
)

const (
// go-header store prefixes used prior to the unified store migration
headerSyncPrefix = "/headerSync"
dataSyncPrefix = "/dataSync"
)

// NewCleanupGoHeaderCmd creates a command to delete the legacy go-header store data.
// This data is no longer needed after the migration to the unified store approach
// where HeaderStoreAdapter and DataStoreAdapter read directly from the ev-node store.
func NewCleanupGoHeaderCmd() *cobra.Command {
var dryRun bool

cmd := &cobra.Command{
Use: "cleanup-goheader",
Short: "Delete legacy go-header store data from disk",
Long: `Delete the legacy go-header store data (headerSync and dataSync prefixes) from the database.

This command removes data that was previously duplicated by the go-header library
for P2P sync operations. After the migration to the unified store approach,
this data is no longer needed as the HeaderStoreAdapter and DataStoreAdapter
now read directly from the ev-node store.

WARNING: Make sure the node is stopped before running this command.
This operation is irreversible.`,
RunE: func(cmd *cobra.Command, args []string) error {
nodeConfig, err := rollcmd.ParseConfig(cmd)
if err != nil {
return err
}

goCtx := cmd.Context()
if goCtx == nil {
goCtx = context.Background()
}

// Open the database
rawDB, err := store.NewDefaultKVStore(nodeConfig.RootDir, nodeConfig.DBPath, evmDbName)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

The variable evmDbName is not defined in this file or package, which will cause a compilation error. It should be defined, likely as a constant, representing the name of the EVM database.

if err != nil {
return fmt.Errorf("failed to open database: %w", err)
}
defer func() {
if closeErr := rawDB.Close(); closeErr != nil {
cmd.Printf("Warning: failed to close database: %v\n", closeErr)
}
}()

// Delete headerSync prefix
headerCount, err := deletePrefix(goCtx, rawDB, headerSyncPrefix, dryRun)
if err != nil {
return fmt.Errorf("failed to delete headerSync data: %w", err)
}

// Delete dataSync prefix
dataCount, err := deletePrefix(goCtx, rawDB, dataSyncPrefix, dryRun)
if err != nil {
return fmt.Errorf("failed to delete dataSync data: %w", err)
}

totalCount := headerCount + dataCount

if dryRun {
cmd.Printf("Dry run: would delete %d keys (%d headerSync, %d dataSync)\n",
totalCount, headerCount, dataCount)
} else {
if totalCount == 0 {
cmd.Println("No legacy go-header store data found to delete.")
} else {
cmd.Printf("Successfully deleted %d keys (%d headerSync, %d dataSync)\n",
totalCount, headerCount, dataCount)
}
}

return nil
},
}

cmd.Flags().BoolVar(&dryRun, "dry-run", false, "show what would be deleted without actually deleting")

return cmd
}

// deletePrefix deletes all keys with the given prefix from the datastore.
// Returns the number of keys deleted.
func deletePrefix(ctx context.Context, db ds.Batching, prefix string, dryRun bool) (int, error) {
results, err := db.Query(ctx, dsq.Query{
Prefix: prefix,
KeysOnly: true,
})
if err != nil {
return 0, fmt.Errorf("failed to query keys with prefix %s: %w", prefix, err)
}
defer results.Close()

count := 0
batch, err := db.Batch(ctx)
if err != nil {
return 0, fmt.Errorf("failed to create batch: %w", err)
}

for result := range results.Next() {
if result.Error != nil {
return count, fmt.Errorf("error iterating results: %w", result.Error)
}

if !dryRun {
if err := batch.Delete(ctx, ds.NewKey(result.Key)); err != nil {
return count, fmt.Errorf("failed to delete key %s: %w", result.Key, err)
}
}
count++
}

if !dryRun && count > 0 {
if err := batch.Commit(ctx); err != nil {
return count, fmt.Errorf("failed to commit batch delete: %w", err)
}
}

return count, nil
}
Comment on lines +98 to +134
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This function loads all delete operations for a given prefix into a single batch. If there are a very large number of keys to delete, this could lead to high memory consumption. Consider processing the deletions in smaller batches (e.g., committing every 1000 keys) to limit memory usage and make the operation more robust against large datasets.

1 change: 1 addition & 0 deletions apps/evm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func main() {
cmd.InitCmd(),
cmd.RunCmd,
cmd.NewRollbackCmd(),
cmd.NewCleanupGoHeaderCmd(),
rollcmd.VersionCmd,
rollcmd.NetInfoCmd,
rollcmd.StoreUnsafeCleanCmd,
Expand Down
Loading