Skip to content

seg: add rm-blocks command to remove latest block snapshot files#20554

Draft
sudeepdino008 wants to merge 4 commits intomainfrom
rm-blocks
Draft

seg: add rm-blocks command to remove latest block snapshot files#20554
sudeepdino008 wants to merge 4 commits intomainfrom
rm-blocks

Conversation

@sudeepdino008
Copy link
Copy Markdown
Member

Summary

  • Adds seg rm-blocks (aliases: rm-block-snapshots, rm-block-segments) alongside seg rm-state.
  • Removes the latest block snapshot file set (headers/bodies/transactions .seg + .idx, including transactions-to-block.idx) from <datadir>/snapshots, plus their .torrent companions.
  • "Latest" = the file group with the highest From value — the most recent, unmerged range.
  • Interactive KEEP/REMOVE menu modeled on the improved rm-state display, 1) RemoveFile / 4) Exit prompt, and --dry-run support.

A local parser is used in place of snaptype.ParseFileName because the latter rejects composite type names like transactions-to-block, which live next to block segments and must be removed alongside them.

Test plan

  • make erigon builds clean
  • make lint clean
  • Dry-run on mirror of hoodi_arch_bak correctly identifies range 002593-002594 (3 .seg + 4 .idx = 7 files)
  • Real run removes exactly those 14 files (data + .torrent); previous range 002592-002593 untouched
  • Re-running after deletion advances to the new latest range 002592-002593

Mirrors seg rm-state but targets block/header/transaction segments and
their index files in <datadir>/snapshots. Removes the file set at the
highest From value (the most recent, smallest, unmerged range), with an
interactive KEEP/REMOVE menu and --dry-run support. Accessor index files
with composite type names like transactions-to-block.idx are included.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new seg rm-blocks subcommand to the snapshots CLI tooling to remove the most recent (highest-From) block snapshot file range from <datadir>/snapshots, including transactions-to-block accessor indexes, with interactive confirmation and --dry-run support.

Changes:

  • Register new rm-blocks (rm-block-snapshots, rm-block-segments) CLI subcommand.
  • Implement block snapshot filename parsing that accepts composite type names (e.g. transactions-to-block).
  • Implement selection/display and deletion flow for the latest block snapshot range, with optional prompting and dry-run output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1235 to +1238
}
return nil
}

Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

DeleteStateSnapshots unconditionally cleans up .tmp artifacts across snapshot directories (including dirs.Snap). rm-blocks currently leaves .tmp files in dirs.Snap untouched, even though they can be created by incomplete snapshot/torrent operations. Consider reusing the same .tmp cleanup logic (at least for dirs.Snap) to keep recovery commands consistent and avoid leaving behind confusing temp files.

Suggested change
}
return nil
}
}
tmpRemoved, err := cleanupTmpArtifactsInDir(args.Dirs.Snap, args.DryRun)
if err != nil {
return err
}
if args.DryRun {
fmt.Printf("[dry-run] would remove %d .tmp artifacts from %s\n", tmpRemoved, args.Dirs.Snap)
} else if tmpRemoved > 0 {
fmt.Printf("removed %d .tmp artifacts from %s\n", tmpRemoved, args.Dirs.Snap)
}
return nil
}
func cleanupTmpArtifactsInDir(root string, dryRun bool) (uint64, error) {
if root == "" {
return 0, nil
}
if _, err := os.Stat(root); err != nil {
if errors.Is(err, os.ErrNotExist) {
return 0, nil
}
return 0, err
}
var tmpPaths []string
if err := filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if path == root {
return nil
}
if strings.HasSuffix(d.Name(), ".tmp") {
tmpPaths = append(tmpPaths, path)
if d.IsDir() {
return filepath.SkipDir
}
}
return nil
}); err != nil {
return 0, err
}
for _, path := range tmpPaths {
if dryRun {
fmt.Printf("[dry-run] rm %s\n", path)
continue
}
if err := os.RemoveAll(path); err != nil {
return 0, err
}
}
return uint64(len(tmpPaths)), nil
}

Copilot uses AI. Check for mistakes.
Comment on lines +1112 to +1137
func DeleteBlockSnapshots(args DeleteBlockSnapshotsArgs) error {
dirs := args.Dirs

filePaths, err := dir2.ListFiles(dirs.Snap)
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
fmt.Printf("snapshot directory does not exist: %s\n", dirs.Snap)
return nil
}
return err
}

allFiles := make([]blockFileInfo, 0, len(filePaths))
var maxFrom uint64
for _, p := range filePaths {
_, name := filepath.Split(p)
bf, ok := parseBlockFileName(name)
if !ok {
continue
}
bf.Path = p
allFiles = append(allFiles, bf)
if bf.From > maxFrom {
maxFrom = bf.From
}
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

DeleteBlockSnapshots introduces new behavior (parsing/selecting latest block snapshot range and deleting associated files) but there are no unit tests alongside the existing snapshots_cmd_test.go coverage for DeleteStateSnapshots. Add tests that create a temp dirs.Snap with multiple ranges/types (including transactions-to-block.idx), verify the highest-From range is selected, and verify DryRun vs non-dry-run behavior.

Copilot uses AI. Check for mistakes.
Comment thread cmd/utils/app/snapshots_cmd.go Outdated
Comment on lines +1222 to +1228
if args.DryRun {
fmt.Printf("[dry-run] rm %s\n", f.Path)
fmt.Printf("[dry-run] rm %s\n", f.Path+".torrent")
continue
}
dir2.RemoveFile(f.Path)
dir2.RemoveFile(f.Path + ".torrent")
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

This command only deletes the exact companion file path + ".torrent". Snapshot dirs can also contain partial/temporary torrent files with extensions like .torrent<suffix> (see snaptype.IsTorrentPartial / tests). Consider also deleting any files matching path + ".torrent*" (or using existing snaptype helpers) so rm-blocks doesn't leave torrent artifacts behind for the removed snapshot range.

Suggested change
if args.DryRun {
fmt.Printf("[dry-run] rm %s\n", f.Path)
fmt.Printf("[dry-run] rm %s\n", f.Path+".torrent")
continue
}
dir2.RemoveFile(f.Path)
dir2.RemoveFile(f.Path + ".torrent")
torrentArtifacts, globErr := filepath.Glob(f.Path + ".torrent*")
if globErr != nil || len(torrentArtifacts) == 0 {
torrentArtifacts = []string{f.Path + ".torrent"}
}
if args.DryRun {
fmt.Printf("[dry-run] rm %s\n", f.Path)
for _, torrentArtifact := range torrentArtifacts {
fmt.Printf("[dry-run] rm %s\n", torrentArtifact)
}
continue
}
dir2.RemoveFile(f.Path)
for _, torrentArtifact := range torrentArtifacts {
dir2.RemoveFile(torrentArtifact)
}

Copilot uses AI. Check for mistakes.
@sudeepdino008 sudeepdino008 marked this pull request as draft April 14, 2026 11:41
sudeepdino008 and others added 3 commits April 14, 2026 14:10
…nd .tmp

Address review feedback on #20554:
- Drop the local parseBlockFileName/blockFileInfo; snaptype.ParseFileName
  already handles composite type strings like transactions-to-block, and
  returns block-scaled From/To so the "step in thousands of blocks" caveat
  goes away.
- Sweep .torrent<suffix> partials (snaptype.IsTorrentPartial) via glob,
  not just the exact .torrent companion.
- Unconditionally clean .tmp artifacts in dirs.Snap via a new
  sweepTmpFilesInSnapDir helper, mirroring DeleteStateSnapshots.
- Replace os.Exit(0) in DeleteBlockSnapshots with a normal return so the
  caller's defer l.Unlock() runs.
- Extract a shared promptRemoveFiles helper for the confirmation prompt.
- Surface os.Stat / dir2.RemoveFile errors instead of swallowing them.
- Add unit tests covering: latest-range removal (incl.
  transactions-to-block.idx), dry-run, no-files, torrent partial sweep,
  and .tmp sweep.
Merge the six block-snapshot tests down to three: a single happy-path
test that exercises latest-range removal, transactions-to-block.idx,
.torrent / partial .torrent<suffix> companions, and .tmp sweep all at
once; a dry-run test; and a no-block-files-still-sweeps-tmp test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants