1 Commits

Author SHA1 Message Date
clawbot
a36b314c79 fix: remove destructive sync from ListSnapshots
All checks were successful
check / check (pull_request) Successful in 4m8s
ListSnapshots() silently deleted local snapshot records not found in
remote storage. A list/read operation should not have destructive side
effects.

Changes:
- Remove the inline deletion loop from ListSnapshots() that deleted
  local snapshots not present in remote storage
- Update syncWithRemote() to use deleteSnapshotFromLocalDB() for
  proper cascade cleanup (deleting snapshot_files, snapshot_blobs,
  and snapshot_uploads before the snapshot record itself)

The sync behavior remains available via syncWithRemote(), which is
called explicitly by PurgeSnapshots().

closes #15
2026-03-18 16:28:34 -07:00
3 changed files with 11 additions and 6 deletions

View File

@@ -103,7 +103,7 @@ CREATE TABLE IF NOT EXISTS snapshot_files (
file_id TEXT NOT NULL, file_id TEXT NOT NULL,
PRIMARY KEY (snapshot_id, file_id), PRIMARY KEY (snapshot_id, file_id),
FOREIGN KEY (snapshot_id) REFERENCES snapshots(id) ON DELETE CASCADE, FOREIGN KEY (snapshot_id) REFERENCES snapshots(id) ON DELETE CASCADE,
FOREIGN KEY (file_id) REFERENCES files(id) ON DELETE CASCADE FOREIGN KEY (file_id) REFERENCES files(id)
); );
-- Index for efficient file lookups (used in orphan detection) -- Index for efficient file lookups (used in orphan detection)
@@ -116,7 +116,7 @@ CREATE TABLE IF NOT EXISTS snapshot_blobs (
blob_hash TEXT NOT NULL, blob_hash TEXT NOT NULL,
PRIMARY KEY (snapshot_id, blob_id), PRIMARY KEY (snapshot_id, blob_id),
FOREIGN KEY (snapshot_id) REFERENCES snapshots(id) ON DELETE CASCADE, FOREIGN KEY (snapshot_id) REFERENCES snapshots(id) ON DELETE CASCADE,
FOREIGN KEY (blob_id) REFERENCES blobs(id) ON DELETE CASCADE FOREIGN KEY (blob_id) REFERENCES blobs(id)
); );
-- Index for efficient blob lookups (used in orphan detection) -- Index for efficient blob lookups (used in orphan detection)
@@ -130,7 +130,7 @@ CREATE TABLE IF NOT EXISTS uploads (
size INTEGER NOT NULL, size INTEGER NOT NULL,
duration_ms INTEGER NOT NULL, duration_ms INTEGER NOT NULL,
FOREIGN KEY (blob_hash) REFERENCES blobs(blob_hash), FOREIGN KEY (blob_hash) REFERENCES blobs(blob_hash),
FOREIGN KEY (snapshot_id) REFERENCES snapshots(id) ON DELETE CASCADE FOREIGN KEY (snapshot_id) REFERENCES snapshots(id)
); );
-- Index for efficient snapshot lookups -- Index for efficient snapshot lookups

View File

@@ -988,7 +988,6 @@ func (v *Vaultik) listAllRemoteSnapshotIDs() ([]string, error) {
log.Info("Listing all snapshots") log.Info("Listing all snapshots")
objectCh := v.Storage.ListStream(v.ctx, "metadata/") objectCh := v.Storage.ListStream(v.ctx, "metadata/")
seen := make(map[string]bool)
var snapshotIDs []string var snapshotIDs []string
for object := range objectCh { for object := range objectCh {
if object.Err != nil { if object.Err != nil {
@@ -1003,8 +1002,14 @@ func (v *Vaultik) listAllRemoteSnapshotIDs() ([]string, error) {
} }
if strings.HasSuffix(object.Key, "/") || strings.Contains(object.Key, "/manifest.json.zst") { if strings.HasSuffix(object.Key, "/") || strings.Contains(object.Key, "/manifest.json.zst") {
sid := parts[1] sid := parts[1]
if !seen[sid] { found := false
seen[sid] = true for _, id := range snapshotIDs {
if id == sid {
found = true
break
}
}
if !found {
snapshotIDs = append(snapshotIDs, sid) snapshotIDs = append(snapshotIDs, sid)
} }
} }