Skip to content

fix(backup): skip DB backup when the index is unchanged - #10

Merged
solomonneas merged 3 commits into
mainfrom
fix/backup-skip-unchanged-db
Oct 1, 2026
Merged

solomonneas merged 3 commits into
mainfrom
fix/backup-skip-unchanged-db

Conversation

@solomonneas

Copy link
Copy Markdown
Collaborator

What

backup-db.sh makes a full copy of the index on every scheduled run. When the index has not changed, that only adds another identical copy. On one install the index had been static for months, and four identical 15G copies were sitting in backups/.

This change makes the script skip the copy when nothing changed since the last good backup:

  • After a successful backup it writes backups/.last-source-stamp with the DB's size, nanosecond mtime, and inode, plus the backup file name.
  • A later run skips only when the stamp matches, the -wal file is empty, and that backup file still exists.
  • The copy goes to *.db.tmp and is renamed on success. A killed run cannot leave a truncated file that looks like a valid backup.
  • The stamp is written only if the source did not change during the copy.
  • Default retention drops from 14 to 4 (CODE_SEARCH_MAX_BACKUPS still overrides it).

Verify

  • tests/test_backup_db.py (new, 5 tests): unchanged DB is skipped; a same-second write, pending WAL frames, a missing stamp, or a deleted newest backup each force a new backup; no .tmp file is left behind.
  • The skip test fails against main's script and passes with this change.
  • ./scripts/verify passes: mcp typecheck/test/build, 28 Python tests, serve smoke test.

Review notes

An existing stamp in the old format will not match, so the first run after upgrading takes one more backup and then starts skipping.

🤖 Generated with Claude Code

Solomon Neas and others added 3 commits October 1, 2026 11:23
Each backup is a full 15G copy of code_index.db. The index had not changed
since 2026-07-09, so the twice-daily job was keeping four identical copies
(60G). Record the source size and mtime after each backup and skip when they
match and the WAL is empty. Also lower the default retention from 14 to 4.

Co-Authored-By: Claude <noreply@anthropic.com>
Runs backup-db.sh against a throwaway SQLite file: an unchanged DB is skipped,
a changed DB or a missing stamp file produces a new backup.

Co-Authored-By: Claude <noreply@anthropic.com>
Address review findings on the skip-if-unchanged change:
- copy to a .tmp file and rename on success, so a killed run never leaves a
  truncated file that the skip check would treat as a valid backup
- record the backup file name in the stamp and skip only if it still exists
- use size, nanosecond mtime, and inode, and write the stamp only if the
  source did not change during the copy
- tests now use WAL mode and cover pending WAL frames, same-second writes,
  and a deleted newest backup

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 1, 2026 15:28
@coderabbitai

coderabbitai Bot commented Oct 1, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are limited based on label configuration.

🏷️ Required labels (at least one) (1)
  • coderabbit-review

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository: escoffier-labs/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 203de332-e492-41a5-a5c2-95bb0be71716

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@solomonneas
solomonneas merged commit 48b3c95 into main Oct 1, 2026
4 checks passed
@solomonneas
solomonneas deleted the fix/backup-skip-unchanged-db branch October 1, 2026 15:29
@solomonneas solomonneas self-assigned this Oct 1, 2026

Copilot AI 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.

Copilot review overview

🟡 Changes recommended

Concurrent writers or backup runs can bypass change detection or expose an incomplete backup.

Review effort: Balanced
Findings: 2 High severity

Open (2)
What changed in this PR

Adds change-aware SQLite backups to avoid redundant large copies.

Changes:

  • Skips unchanged databases using source metadata and WAL state.
  • Adds temporary-file backups and reduces default retention to four.
  • Adds regression tests for backup and skip scenarios.
File Description
backup-db.sh Implements change detection, atomic replacement, and retention changes.
tests/​test_backup_db.py Tests skip and forced-backup scenarios.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread backup-db.sh
Comment on lines +27 to +31
WAL_BEFORE="$(wal_size)"
if [ "$WAL_BEFORE" -eq 0 ] && [ -f "$STAMP_FILE" ]; then
IFS=$'\t' read -r LAST_STATE LAST_BACKUP < "$STAMP_FILE" || true
if [ "${LAST_STATE:-}" = "$BEFORE" ] && [ -n "${LAST_BACKUP:-}" ] \
&& [ -f "$BACKUP_DIR/$LAST_BACKUP" ]; then
Comment thread backup-db.sh
Comment on lines +40 to +43
BACKUP_NAME="code_index_$TIMESTAMP.db"
TMP_BACKUP="$BACKUP_DIR/$BACKUP_NAME.tmp"
trap 'rm -f "$TMP_BACKUP"' EXIT
rm -f "$TMP_BACKUP"
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.

2 participants