Skip to content

Commit 94d8e90

Browse files
seg rm-state: delete .tmp files from snapshot directories (#19549)
## Summary - `DeleteStateSnapshots` now unconditionally removes `.tmp` files from all 7 snapshot directories: `Snap`, `SnapIdx`, `SnapHistory`, `SnapDomain`, `SnapAccessors`, `SnapCaplin`, `SnapForkable` - `.tmp` files are artifacts from incomplete/cancelled operations and were previously skipped because `ParseFileName()` cannot parse them - Cleanup respects `--dry-run` mode and is not subject to `--step`, `--latest`, or `--domain` filters ## Test plan - [x] `Test_DeleteStateSnaps_RemovesTmpFiles`: verifies `.tmp` files across all 7 directories are cleaned up - [x] `Test_DeleteStateSnaps_DryRunKeepsTmpFiles`: verifies dry-run mode preserves `.tmp` files Closes #18789
1 parent 13c6aef commit 94d8e90

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

cmd/utils/app/snapshots_cmd.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,33 @@ func DeleteStateSnapshots(dirs datadir.Dirs, removeLatest, promptUserBeforeDelet
866866
removed++
867867
}
868868
fmt.Printf("removed %d state snapshot segments files\n", removed)
869+
870+
// Unconditionally remove .tmp files from all snapshot directories.
871+
// These are artifacts from incomplete/cancelled operations and should always be cleaned up.
872+
var removedTmp uint64
873+
for _, dirPath := range []string{dirs.Snap, dirs.SnapIdx, dirs.SnapHistory, dirs.SnapDomain, dirs.SnapAccessors, dirs.SnapCaplin, dirs.SnapForkable} {
874+
tmpFiles, err := snaptype.TmpFiles(dirPath)
875+
if err != nil {
876+
return err
877+
}
878+
for _, tmpFile := range tmpFiles {
879+
if dryRun {
880+
fmt.Printf("[dry-run] rm %s\n", tmpFile)
881+
removedTmp++
882+
continue
883+
}
884+
if err := dir2.RemoveFile(tmpFile); err != nil {
885+
if !errors.Is(err, fs.ErrNotExist) {
886+
return err
887+
}
888+
}
889+
removedTmp++
890+
}
891+
}
892+
if removedTmp > 0 {
893+
fmt.Printf("removed %d .tmp files\n", removedTmp)
894+
}
895+
869896
fmt.Printf("\n\nBefore restarting Erigon, run one of:\n - `integration stage_custom_trace --reset` if deleted domains are handled by stage_custom_trace\n - `integration stage_exec --reset` otherwise\nThis prunes DB remnants to avoid gaps between snapshots and DB.\n")
870897
return nil
871898
}

cmd/utils/app/snapshots_cmd_test.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package app
1818

1919
import (
2020
"os"
21+
"path/filepath"
2122
"testing"
2223

2324
"github.com/erigontech/erigon/db/datadir"
@@ -177,3 +178,84 @@ func createFiles(t *testing.T, dirs datadir.Dirs, from, to int, b *bundle) {
177178
genFile(b.history)
178179
genFile(b.ii)
179180
}
181+
182+
func Test_DeleteStateSnaps_RemovesTmpFiles(t *testing.T) {
183+
dirs := datadir.New(t.TempDir())
184+
185+
// Create some normal state snapshot files so DeleteStateSnapshots has something to process
186+
b := bundle{}
187+
dc := statecfg.Schema.ReceiptDomain
188+
b.domain, b.history, b.ii = state.SnapSchemaFromDomainCfg(dc, dirs, 10)
189+
for i := 0; i < 3; i++ {
190+
createFiles(t, dirs, i*10, (i+1)*10, &b)
191+
}
192+
193+
touchFile := func(path string) {
194+
f, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0644)
195+
require.NoError(t, err)
196+
f.Close()
197+
}
198+
199+
// SnapForkable is not auto-created by datadir.New, so create it manually
200+
require.NoError(t, os.MkdirAll(dirs.SnapForkable, 0755))
201+
202+
// Create .tmp files in all snapshot directories (matching patterns from issue #18789)
203+
tmpFiles := []string{
204+
filepath.Join(dirs.Snap, "v1.1-headers.0-500.seg.123456.tmp"),
205+
filepath.Join(dirs.SnapDomain, "v1.1-commitment.8272-8280.kv.252752124.tmp"),
206+
filepath.Join(dirs.SnapHistory, "v2.0-commitment.8256-8272.kvi.857462302.tmp"),
207+
filepath.Join(dirs.SnapIdx, "v1.1-storage.8256-8288.bt.209594880.tmp"),
208+
filepath.Join(dirs.SnapAccessors, "v2.0-commitment.8256-8272.kvi.3646922560.existence.tmp"),
209+
filepath.Join(dirs.SnapCaplin, "v1.0-beaconblocks.0-100.seg.999999.tmp"),
210+
filepath.Join(dirs.SnapForkable, "v1.0-forkable.0-100.kv.111111.tmp"),
211+
}
212+
for _, tf := range tmpFiles {
213+
touchFile(tf)
214+
confirmExist(t, tf)
215+
}
216+
217+
// Run DeleteStateSnapshots (non-dry-run)
218+
err := DeleteStateSnapshots(dirs, true, false, false, "")
219+
require.NoError(t, err)
220+
221+
// All .tmp files should be removed
222+
for _, tf := range tmpFiles {
223+
confirmDoesntExist(t, tf)
224+
}
225+
}
226+
227+
func Test_DeleteStateSnaps_DryRunKeepsTmpFiles(t *testing.T) {
228+
dirs := datadir.New(t.TempDir())
229+
230+
// Create some normal state snapshot files
231+
b := bundle{}
232+
dc := statecfg.Schema.ReceiptDomain
233+
b.domain, b.history, b.ii = state.SnapSchemaFromDomainCfg(dc, dirs, 10)
234+
for i := 0; i < 3; i++ {
235+
createFiles(t, dirs, i*10, (i+1)*10, &b)
236+
}
237+
238+
touchFile := func(path string) {
239+
f, err := os.OpenFile(path, os.O_RDONLY|os.O_CREATE, 0644)
240+
require.NoError(t, err)
241+
f.Close()
242+
}
243+
244+
// Create .tmp files
245+
tmpFiles := []string{
246+
filepath.Join(dirs.SnapDomain, "v1.1-commitment.8272-8280.kv.252752124.tmp"),
247+
filepath.Join(dirs.SnapHistory, "v2.0-commitment.8256-8272.kvi.857462302.tmp"),
248+
}
249+
for _, tf := range tmpFiles {
250+
touchFile(tf)
251+
}
252+
253+
// Run DeleteStateSnapshots with dry-run=true
254+
err := DeleteStateSnapshots(dirs, true, false, true, "")
255+
require.NoError(t, err)
256+
257+
// .tmp files should still exist (dry-run does not delete)
258+
for _, tf := range tmpFiles {
259+
confirmExist(t, tf)
260+
}
261+
}

0 commit comments

Comments
 (0)