Skip to content

fix: let offline backups copy without live-work pacing - #1261

Open
frahlg wants to merge 1 commit into
masterfrom
fix/offline-backup-pacing-20260914
Open

frahlg wants to merge 1 commit into
masterfrom
fix/offline-backup-pacing-20260914

Conversation

@frahlg

@frahlg frahlg commented Sep 14, 2026

Copy link
Copy Markdown
Member

Problem and result

#1259 shows that a large converted history cannot finish a portable backup through ftw-backup. exportHistoryToSQLite always paused 100 ms after at most 1,024 rows, including when the store came from read-only OpenBackupSource. For ~175 million sample rows those pauses alone take about 4 h 44 m, so the live two-hour export deadline always fires.

The offline helper now copies without that live yield and without the two-hour deadline. Live Core backups still pause between copy batches so charging-goal saves keep their latency protection. Create refuses to start when the destination cannot hold the raw export, compressed archive and verification extract. Verify extracts beside the archive instead of into process temp, which is too small for these files.

Scope and safety

  • Touches go/internal/state backup copy/export and go/internal/backup create/verify. No UI.
  • Open PRs do not overlap these files. origin/fix/converter-throughput-20260914 is conversion batching, not backup pacing.
  • Live path keeps 100 ms yield, 256 KiB dirty batches, 2 h deadline and FULL goal sync.
  • Offline path keeps bounded commits, full readback, archive hashes, SQLite quick_check and restore checks.
  • Does not fix #1246 (live backup vs goal-save latency on Pi). That remains a release-blocker.
  • Does not run the 175 million-row household export; that evidence is still required on the real dataset.

Verification

cd go && go test ./internal/state ./internal/backup ./cmd/ftw-backup ./internal/api -run 'Backup|backup'

Ran:

  • go test ./internal/state (pass, 16.7 s)
  • go test ./internal/backup (pass)
  • go test ./cmd/ftw-backup (pass)
  • go test ./internal/api -run Backup (pass)

New coverage: live vs offline yield, no offline deadline, scratch-space preflight, offline create/verify/restore with process temp blocked.

Not run: FTW_STORAGE_ADMISSION=1 on a Raspberry Pi; 175 million-row offline export/verify/restore.

Checklist

  • The change follows VISION.md and one selected scope.
  • I checked overlapping PRs and coordinated shared files/contracts.
  • Relevant checks cover the changed behaviour and failure paths.
  • A human reviewed changed UI in a browser, or no UI changed.
  • A Changeset is included, or the change is exempt.
  • Every commit has a DCO sign-off.

OpenBackupSource no longer inherits the live 100ms yield that made a
two-hour export deadline unreachable for large converted histories.
Live Core backups still pause between copy batches. Verification
extracts beside the archive, and create refuses to start without
room for the raw export, compressed file and extract.

Addresses #1259

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 14, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-14T09:18:09.319011Z cee71ea PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cee71eaf82

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

}
seen := make(map[string]bool, len(want))
tmpDir, err := os.MkdirTemp("", ".ftw-backup-verify-")
tmpDir, err := os.MkdirTemp(filepath.Dir(archivePath), ".ftw-backup-verify-")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve verification for read-only archive locations

When an archive is stored on a read-only USB mount or in a directory the invoking user cannot modify, creating this temporary directory fails even though the archive is readable and the restore destination is writable. Because both Inspect and RestoreContents call Verify, this also prevents inspecting or restoring such backups; use a caller-writable workspace or restrict same-filesystem staging to the creation path.

AGENTS.md reference: AGENTS.md:L24-L25

Useful? React with 👍 / 👎.

if err := os.MkdirAll(outputDir, 0o700); err != nil {
return Info{}, fmt.Errorf("backup: create output dir: %w", err)
}
if err := state.EnsureDiskSpace(outputDir, state.BackupArchiveScratch(opts.State.BackupSourceBytes(), 0)); err != nil {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include non-database files in the space reservation

When dataDir contains substantial cold Parquet history or other persistent files, this preflight counts only the SQLite state/history files because extraBytes is always zero, while collectSources later adds those files to the archive. A target with room for three copies of a small database but not the cold archive therefore passes the promised refusal check and fills during creation; inventory and include the non-database source sizes before checking free space.

AGENTS.md reference: AGENTS.md:L24-L25

Useful? React with 👍 / 👎.

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.

Backup IO delays durable charging-goal saves on Raspberry Pi

1 participant