Skip to content

Add live point-in-time logical backup producer#1128

Open
bootjp wants to merge 6 commits into
design/live-backup-pin-substratefrom
design/live-backup-producer
Open

Add live point-in-time logical backup producer#1128
bootjp wants to merge 6 commits into
design/live-backup-pin-substratefrom
design/live-backup-producer

Conversation

@bootjp

@bootjp bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • add the live point-in-time logical backup producer and CLI over the backup control-plane RPCs
  • renew the distributed pin while streaming, stop renewal before publishing MANIFEST.json, and always end the backup session
  • encode DynamoDB, S3, Redis, and SQS scopes with checksums and expected-key validation
  • add crash, renewal-race, cross-adapter, and TTL-expiry acceptance coverage
  • add the operator backup/restore runbook and promote the Phase 1 design document to Implemented

Stack

Risk

The data path is opt-in through the new backup CLI and admin RPCs. The main correctness risks are publishing a completion marker after pin loss and reading from a changing route catalog; both are covered by pinned-route and renewal-quiescence tests.

Verification

  • go test ./internal/backup ./cmd/elastickv-backup -count=1
  • go test -race ./internal/backup -run 'Test(RunLiveBackup|ProducerCrash|CrossAdapterConsistency|ExpectedKeysBaseline)' -count=1
  • go test ./adapter -run 'Test(BeginBackup|RenewBackup|StreamBackup|ListBackup|BackupProtocol|InternalForwardAdminProposal)' -count=1
  • go test ./kv -run 'Test(Backup|BeginBackup|Pin|BackupScanner|ShardStoreScanAt_RoutesFilesystem)' -count=1
  • make -C proto gen followed by a clean generated diff
  • golangci-lint run ./... --timeout=15m --allow-parallel-runners -j 2
  • git diff --check
  • no references remain to docs/design/2026_04_29_proposed_logical_backup.md

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 41f10c30-5939-4a3c-a895-7aa8ae17f6cd

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

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.

@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Current signed HEAD is 2d468c5a169c93696b0037d66c644b5378685898.

Verification:

  • producer and CLI tests pass
  • focused producer acceptance tests pass under -race
  • control-plane adapter and backup scanner tests pass
  • proto breaking/generation checks pass with no generated diff
  • full lint reports 0 issues
  • git diff --check passes
  • the former proposed design path has no remaining references

Please review the latest head.

@codex review
@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

@bootjp: Reviewing the latest signed HEAD (2d468c5a169c93696b0037d66c644b5378685898) now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request implements Phase 1 of the logical backup feature, enabling point-in-time consistent logical backups from a running elastickv cluster. It introduces the elastickv-backup CLI tool, adds server-side configurations for active backup pins, implements the live backup producer lifecycle (including streaming and renewal), and updates design documents and runbooks. The review feedback highlights a potential nil pointer dereference on Windows when loading system certificates, portability issues with using os.Link for manifest publication on filesystems that do not support hard links, and noisy warning logs during graceful shutdown due to unsuppressed context cancellation errors.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread cmd/elastickv-backup/main.go Outdated
Comment thread internal/backup/finalize.go Outdated
Comment thread internal/backup/live_producer.go
@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Updated the latest head d5a5934945c060183a6409fd0cc81c2010a7672b for all three findings:

  • fall back to a new certificate pool when SystemCertPool returns either an error or a nil pool
  • publish the final manifest with same-directory os.Rename, while preserving the pre-existing marker guard
  • keep graceful cancellation warning-free and retain warnings for genuine renewal failures

Verification:

  • go test ./internal/backup ./cmd/elastickv-backup -count=1
  • go test -race ./internal/backup -run 'Test(RunLiveBackup|ProducerCrash|CrossAdapterConsistency|ExpectedKeysBaseline)' -count=1
  • GOOS=windows GOARCH=amd64 go test -c -o /tmp/elastickv-backup-windows.test.exe ./cmd/elastickv-backup
  • golangci-lint run ./internal/backup/... ./cmd/elastickv-backup/... --timeout=5m

Caller audit for the manifest error-semantics change found one production caller (RunLiveBackup), which propagates finalization errors, leaves no manifest, and still executes EndBackup.

@codex review

@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Current head d5a5934 is fully green and all prior inline findings are resolved. @codex review

@bootjp
bootjp force-pushed the design/live-backup-control-plane branch from 830d645 to 6a85349 Compare July 19, 2026 11:09
@bootjp
bootjp force-pushed the design/live-backup-producer branch from d5a5934 to 83f3a9f Compare July 19, 2026 11:09
@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

History-only author-compliance repair completed at 83f3a9f6aa23fd632aba203228284ddda27c4d53.

  • final tree is byte-identical to prior head d5a5934945c060183a6409fd0cc81c2010a7672b
  • the PR now exposes one linear commit authored and committed by bootjp <contact@bootjp.me>
  • GitHub reports the commit signature as verified/valid
  • parent is sanitized Add live logical backup control plane #1119 head 6a85349d2deec210799349b420d35c9563666e55

No runtime or source-tree semantics changed. CI is running on the reconstructed head.

@codex review

@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Current reconstructed head 83f3a9f6aa23fd632aba203228284ddda27c4d53 is fully green. PR-visible authorship and signature verification pass, the final tree remains identical to the pre-rewrite head, and there are no current-head root findings. Please complete the latest-head review. @codex review

@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Latest signed head 83f3a9f6aa23fd632aba203228284ddda27c4d53 remains mergeable with all required checks green and no current-head root findings. @codex review

@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: 83f3a9f6aa

ℹ️ 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".

Comment thread cmd/elastickv-backup/main.go
Comment thread cmd/elastickv-backup/main.go
Comment thread cmd/elastickv-backup/main.go Outdated
Comment thread internal/backup/live_producer.go
Comment thread internal/backup/live_producer.go
@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Current signed HEAD 56277d2cbc957487a967e03263167fb3cb5ed38f addresses all five current-head findings.

Evidence:

  • live producer modes unsupported by the shipped native restore path fail before dial and at the library entrypoint
  • TLS server-name-only and CA plus skip-verify combinations fail closed
  • non-empty one/two-record scopes require at least one returned record
  • server baseline and stream now exclude decoder-dropped S3 generation/incomplete-upload and SQS side rows; producer counts only after decoder acceptance
  • runbook and implemented design no longer recommend unrestorable modes

Verification:

  • go test ./cmd/elastickv-backup ./internal/backup ./adapter -run 'Test(ParseFlags|LoadTransportCredentials|ScopeForKey|RunLiveBackup|ExpectedKeysBaseline|ValidateLiveBackupRestoreCompatibility|Backup|StreamBackup|ListBackupScopes)' -count=1 -timeout=300s
  • focused -race tests for the backup CLI and producer
  • golangci-lint run ./cmd/elastickv-backup ./internal/backup ./adapter --timeout=5m --allow-parallel-runners reports 0 issues
  • git diff --check

Caller audit for the ScopeForKey semantic change found the baseline scan, server stream, producer stream validator, and tests; baseline and stream now share the same retained-record classification. CI is running for this head.

@codex review

@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

case bytes.HasPrefix(key, []byte(DDBTableGenPrefix)):
return ddbScopeFromDirectSegment(key, DDBTableGenPrefix)

P2 Badge Exclude DynamoDB generation counters from scopes

When a DynamoDB table has been deleted, the live adapter leaves the !ddb|meta|gen| counter behind while the table schema is gone, and the decoder's HandleTableGen is a no-op. Classifying that counter as a scoped table makes BeginBackup/ListAdaptersAndScopes select a deleted table and lets the live manifest publish dynamodb.tables for a scope that has no _schema.json; the native restore path then emits no table even though the manifest says it was dumped. Treat this like the other generation counters that are already unscoped, or only count it when the schema record is present.

ℹ️ 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".

Comment thread internal/backup/live_producer.go Outdated
Comment thread internal/backup/live_producer.go
Comment thread internal/backup/live_producer.go

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Latest signed HEAD 7d4834f1211074152a9238e98dc23d11c31ad358 addresses all current-head findings.

  • DynamoDB generation counters are now unscoped, so deleted-table counters cannot create manifest-only tables.
  • Each pin renewal is bounded by TTL/3 and the remaining expiry; deadline failure cancels the dump and blocks manifest publication.
  • Default all-scope selection includes every non-empty Begin baseline scope even when the later List response omits it.
  • S3 validation now counts only records retained after finalize: bucket metadata, active manifests, and manifest-selected chunks.

Verification:

  • go test ./internal/backup ./cmd/elastickv-backup -count=1 -timeout=300s
  • focused adapter backup tests
  • focused producer tests under -race
  • golangci-lint run ./internal/backup ./cmd/elastickv-backup ./adapter --timeout=5m --allow-parallel-runners reports 0 issues
  • git diff --check

Caller audit for ScopeForKey covers the server baseline, server stream, producer validator, and tests; all now exclude the same generation counter.

@codex review

@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: 7d4834f121

ℹ️ 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".

Comment thread internal/backup/live.go Outdated
Comment thread internal/backup/live.go Outdated
Comment thread internal/backup/live.go Outdated
@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Evidence for current HEAD ed0498de2d24eeabd7b07c25a637cfb2d8438841:

  • Finalized retained counts now cover SQS, DynamoDB, Redis, and S3.
  • Deleted SQS generation-only state, schema-less DynamoDB items, Redis orphan TTLs, and Redis stream entries without metadata cannot mask a short stream or publish a misleading manifest.
  • Redis derivable delta, claim, and score indexes are excluded consistently from Begin baseline and Stream filtering.
  • Caller audit covered all ScopeForKey, FinalizedScopeCounts, and retained-count production callers.
  • All three current review threads were replied to and resolved.

Validation:

  • go test ./internal/backup ./cmd/elastickv-backup -count=1 -timeout=300s
  • focused go test -race ./internal/backup
  • golangci-lint run ./internal/backup ./cmd/elastickv-backup --timeout=5m --allow-parallel-runners (0 issues)
  • signed author and committer: bootjp <contact@bootjp.me>

Requesting a fresh latest-head review.

@codex review

@bootjp
bootjp force-pushed the design/live-backup-producer branch from ed0498d to 53e6402 Compare July 19, 2026 13:44
@bootjp

bootjp commented Jul 19, 2026

Copy link
Copy Markdown
Owner Author

Rebase evidence for current HEAD 53e64025e8efaa147b7759cfb2d2ad434dfb9a64:

  • Rebased onto Add live logical backup control plane #1119 HEAD f30bd74b5e64064d6a846ac640cf35d639a9d03b.
  • git range-diff reports all four producer commits unchanged (=).
  • All four PR-visible commits retain author and committer bootjp <contact@bootjp.me> and GitHub signature verification is verified: true.
  • The retained-count findings remain fixed in rebased commit 53e64025.

Post-rebase validation:

  • go test ./internal/backup ./cmd/elastickv-backup ./kv . -count=1 -timeout=600s
  • go test ./adapter -run 'Backup|ForwardLeaseRead|ForwardAdminProposal' -count=1 -timeout=300s
  • focused producer race tests
  • golangci-lint run ./internal/backup ./cmd/elastickv-backup ./adapter ./kv . --timeout=5m --allow-parallel-runners (0 issues)
  • git diff --check

The broad unfiltered adapter suite reached its 600-second timeout in Raft integration cleanup; the focused backup/forwarding adapter suite passed and GitHub CI is now running on this head.

Requesting a fresh latest-head review after the dependency rebase.

@codex review

@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: 53e64025e8

ℹ️ 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".

Comment thread internal/backup/s3.go
Comment thread internal/backup/dynamodb.go Outdated
Comment thread internal/backup/sqs.go Outdated
Comment thread internal/backup/redis_string.go
@bootjp
bootjp force-pushed the design/live-backup-producer branch from 53e6402 to 7f11f84 Compare July 23, 2026 07:51
@bootjp

bootjp commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

Rebase evidence for current HEAD 7f11f84:

Validation:

  • go test ./internal/backup -run 'Test(RunLiveBackup|ExpectedKeysBaseline|ScopeForKey|LiveDecoder|Finalize|SQS|DynamoDB|Redis|S3)' -count=1\n- go test ./cmd/elastickv-backup ./adapter ./kv -run 'Test(StreamBackup|ListBackupScopes|RenewBackup|SnapshotBackupGroups|BeginBackup|FSMSnapshotRejectsActiveBackupPin|ActiveTimestampTrackerOldestBackupForGroup)' -count=1\n- golangci-lint run ./cmd/elastickv-backup ./adapter ./kv ./internal/backup ./cmd/server --timeout=5m\n- go test ./... -run '^$'\n\n@codex review

@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: 7f11f84972

ℹ️ 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".

Comment thread internal/backup/live_producer.go
Comment thread internal/backup/live_producer.go
Comment thread internal/backup/live_producer.go Outdated
Comment thread internal/backup/live_producer.go
@bootjp
bootjp force-pushed the design/live-backup-producer branch from 99b37ee to 688c1b2 Compare July 23, 2026 09:54
@bootjp

bootjp commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

Latest signed HEAD 688c1b28a4196f01908575932e9f26dfeb0fb2cf addresses the current-head findings.

  • BeginBackup/ListAdaptersAndScopes now build expected counts from retained key/value decoder state, so S3, DynamoDB, SQS, and Redis cleanup leftovers use the same denominator as final validation.
  • StreamBackup now checks the renewed server-side session deadline while streaming, so an original stream request token can continue after its embedded initial deadline once the pin has been renewed.
  • Explicit --scope requests can use non-empty baseline scopes even when ListAdaptersAndScopes omits them.
  • Scoped manifests now include only adapters selected by the requested scopes.
  • The branch was rebased onto base 6608a1cd8f4e25c10b869c6d131ac6d17bf020ce; local merge-tree against the base is clean.

Validation:

  • go test ./internal/backup ./adapter -run 'Test(LiveScopeCounterUsesRetainedCounts|RunLiveBackupAcceptsRequestedBaselineOnlyScope|RunLiveBackupScopedManifestOmitsUnselectedAdapters|BeginBackupExpectedKeysUseRetainedCounts|StreamBackupHonorsRenewedSessionDeadline|StreamBackupStopsWhenTokenExpiresMidStream|ListBackupScopesReportsScannerCloseError)' -count=1 -timeout=300s
  • go test ./cmd/elastickv-backup ./internal/backup ./adapter ./kv -run 'Test(StreamBackup|ListBackupScopes|RenewBackup|SnapshotBackupGroups|BeginBackup|RunLiveBackup|ExpectedKeysBaseline|ScopeForKey|LiveDecoder|Finalize|SQS|DynamoDB|Redis|S3)' -count=1 -timeout=600s
  • go test ./... -run '^$' -count=1 -timeout=600s
  • golangci-lint run ./cmd/elastickv-backup ./adapter ./kv ./internal/backup ./cmd/server --timeout=5m --allow-parallel-runners
  • git diff --check

All visible commits are signed by bootjp <contact@bootjp.me>. CI is running for this head.

@codex review

@bootjp
bootjp force-pushed the design/live-backup-producer branch from 688c1b2 to 7c134ba Compare July 23, 2026 10:10
@bootjp

bootjp commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

Latest signed HEAD 7c134ba4123ec8782f6d9b6b7bb6cc48fd90e29d supersedes the previous update.

The prior CI test (ubuntu-latest) failure was the token-rotation regression test still expecting StreamBackup to reject an old embedded token deadline. That expectation is now aligned with the server-side session-deadline behavior: Renew/List still reject the old token, while StreamBackup uses the renewed session deadline.

Validation after this update:

  • go test -race ./adapter -run 'TestBackupTokenDeadlineRotatesAndFailsClosed|TestStreamBackupHonorsRenewedSessionDeadline' -count=1 -timeout=300s
  • go test ./internal/backup ./adapter -run 'Test(LiveScopeCounterUsesRetainedCounts|RunLiveBackupAcceptsRequestedBaselineOnlyScope|RunLiveBackupScopedManifestOmitsUnselectedAdapters|BeginBackupExpectedKeysUseRetainedCounts|BackupTokenDeadlineRotatesAndFailsClosed|StreamBackupHonorsRenewedSessionDeadline|StreamBackupStopsWhenTokenExpiresMidStream|ListBackupScopesReportsScannerCloseError)' -count=1 -timeout=300s
  • go test ./cmd/elastickv-backup ./internal/backup ./adapter ./kv -run 'Test(StreamBackup|ListBackupScopes|RenewBackup|SnapshotBackupGroups|BeginBackup|RunLiveBackup|ExpectedKeysBaseline|ScopeForKey|LiveDecoder|Finalize|SQS|DynamoDB|Redis|S3)' -count=1 -timeout=600s
  • go test ./... -run '^$' -count=1 -timeout=600s
  • golangci-lint run ./cmd/elastickv-backup ./adapter ./kv ./internal/backup ./cmd/server --timeout=5m --allow-parallel-runners
  • git diff --check

Current-head unresolved review threads are 0. CI is running again for this head.

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Keep it up!

Reviewed commit: 7c134ba412

ℹ️ 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".

@bootjp
bootjp force-pushed the design/live-backup-producer branch from 7c134ba to 8f76d8c Compare July 23, 2026 10:26
@bootjp

bootjp commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

Latest signed HEAD 8f76d8c373b09bbdaf748103eb5548ebee6d8598 is rebased onto base b3b8ab9f7fb2d4c161d4226bcafe75e45c977b1d.

The rebase conflict was limited to adapter/admin_backup_test.go; the resolution keeps the base scope-filter recording and the retained-count key/value scanner test support together. Local merge-tree against the latest base is clean.

Validation after this rebase:

  • go test ./internal/backup ./adapter -run 'Test(LiveScopeCounterUsesRetainedCounts|RunLiveBackupAcceptsRequestedBaselineOnlyScope|RunLiveBackupScopedManifestOmitsUnselectedAdapters|BeginBackupExpectedKeysUseRetainedCounts|BackupTokenDeadlineRotatesAndFailsClosed|StreamBackupHonorsRenewedSessionDeadline|StreamBackupStopsWhenTokenExpiresMidStream|StreamBackupUsesPinTimestampAndScopeFilter|ListBackupScopesReportsScannerCloseError)' -count=1 -timeout=300s
  • go test -race ./adapter -run 'Test(BackupTokenDeadlineRotatesAndFailsClosed|StreamBackupHonorsRenewedSessionDeadline)' -count=1 -timeout=300s
  • go test ./... -run '^$' -count=1 -timeout=600s
  • golangci-lint run ./cmd/elastickv-backup ./adapter ./kv ./internal/backup ./cmd/server --timeout=5m --allow-parallel-runners
  • git diff --check

Current-head unresolved review threads are 0. CI is running for this head.

@codex review

@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: 8f76d8c373

ℹ️ 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".

Comment thread internal/backup/live_producer.go Outdated
Comment thread adapter/admin_backup.go Outdated
Comment thread adapter/admin_backup.go Outdated
@bootjp
bootjp force-pushed the design/live-backup-producer branch from d590c6a to db7ec7d Compare July 23, 2026 14:50
@bootjp

bootjp commented Jul 23, 2026

Copy link
Copy Markdown
Owner Author

Latest signed HEAD db7ec7d0ce9143ff9211e1f8e0e4a46066732324 addresses the three latest-head findings and is rebased onto base d91744b04be1ce78e16f49a0e488d31f0b340cbc.

  • Default no---scope manifests preserve enabled empty adapters while explicit scoped dumps still omit unselected adapters.
  • BeginBackup now carries adapter/scope selection into the baseline count, so unselected adapters are skipped before decoding.
  • Baseline counting uses a key-only pass plus metadata-only value reads; large blob/message payloads are not materialized for the preflight count.
  • The rebase conflict resolution preserves live-session checks during ListAdaptersAndScopes and StreamBackup.

Validation:

  • make -C proto gen
  • go test ./internal/backup ./adapter -run 'Test(LiveScopeCounterUsesRetainedCounts|RunLiveBackupAcceptsRequestedBaselineOnlyScope|RunLiveBackupScopedManifestOmitsUnselectedAdapters|RunLiveBackupDefaultManifestPreservesEnabledEmptyAdapters|BeginBackupExpectedKeysUseRetainedCounts|BeginBackupExpectedKeysAvoidMaterializingBlobValues|BeginBackupBaselineSkipsUnselectedAdapterValues|ListBackupScopesFailsWhenSessionEndsDuringScan|StreamBackupFailsClosedWithoutPinnedRouteSnapshot|BackupTokenDeadlineRotatesAndFailsClosed|StreamBackupHonorsRenewedSessionDeadline|StreamBackupStopsWhenTokenExpiresMidStream|StreamBackupUsesPinTimestampAndScopeFilter|ListBackupScopesReportsScannerCloseError)' -count=1 -timeout=300s
  • go test ./cmd/elastickv-backup ./internal/backup ./adapter ./kv -run 'Test(StreamBackup|ListBackupScopes|RenewBackup|SnapshotBackupGroups|BeginBackup|RunLiveBackup|ExpectedKeysBaseline|ScopeForKey|LiveDecoder|Finalize|SQS|DynamoDB|Redis|S3|ValidateBackupSnapshotAt|BackupScanners|FilteredBackupScanner|BackupTokenDeadline|ActiveTimestampTrackerOldestBackupForGroup)' -count=1 -timeout=600s
  • go test ./... -run '^$' -count=1 -timeout=600s
  • golangci-lint run ./cmd/elastickv-backup ./adapter ./kv ./internal/backup ./cmd/server --timeout=5m --allow-parallel-runners
  • git diff --check

Caller audit covered BeginBackupRequest, scanBackupScopeCounts, NewLiveScopeCounter, liveManifestAdapters, and requireLiveBackupSession production call sites.

Current-head unresolved review threads are 0. CI is running for this head.

@codex review

@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: db7ec7d0ce

ℹ️ 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".

Comment thread adapter/admin_backup.go
Comment on lines +745 to +748
if !logicalbackup.AdapterEnabled(selection.adapters, adapter) {
return false, nil
}
scope, scoped, err := logicalbackup.ScopeForKey(key)

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 Skip adapters excluded by explicit scopes

When a dump is narrowed only by Scopes (the CLI default still sends all adapters), this check treats every adapter as enabled and then calls ScopeForKey on keys from adapters that have no requested scope. In a Redis-only scoped dump, for example, a malformed or future-format S3/DynamoDB key can still abort BeginBackup even though that adapter will be omitted; derive/consult the adapter set present in selection.scopes before parsing the scoped key.

Useful? React with 👍 / 👎.

Comment thread internal/backup/live.go
Comment on lines +359 to +360
adapter, ok := AdapterForKey(key)
return ok && adapter == adapterRedis

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 Avoid materializing Redis payloads in baseline counts

For Redis scopes this returns true for every Redis key, so the baseline metadata pass materializes user payload values such as large strings, hash/list values, and stream entries. On Redis-heavy backups, BeginBackup can therefore load a page of large payloads just to compute expected counts, defeating the key-only/metadata-only preflight path; restrict value reads to Redis metadata/TTL records that are actually needed and count payload-bearing keys from their keys.

Useful? React with 👍 / 👎.

Comment thread adapter/admin_backup.go
Comment on lines +535 to +537
counts, _, err := s.scanBackupScopeCounts(
ctx, routes, tok.readTS, groups,
backupBaselineSelection{adapters: logicalbackup.AllAdapters()},

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 Thread adapter filters into scope listing

After BeginBackup honors an --adapter redis selection, the producer still calls ListAdaptersAndScopes, and this server path scans every adapter with AllAdapters(). That means a disabled adapter can still abort an otherwise valid filtered dump (for example a malformed DynamoDB/S3 key fails classification during this list pass), even though its values were intentionally excluded from the baseline and will not be streamed; carry the requested adapter/scope selection into the listing RPC or avoid the full-adapter scan for filtered runs.

Useful? React with 👍 / 👎.

Comment thread proto/admin.proto
Comment on lines +181 to +187
// Empty means all adapters. Non-empty lets the server build the
// expected-key baseline only for adapters the producer will emit.
repeated string adapters = 2;
// Empty means every scope in the selected adapters. Non-empty narrows the
// expected-key baseline to the exact adapter/scope pairs requested by the
// producer.
repeated BackupScope scopes = 3;

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 Gate scoped BeginBackup fields by protocol version

These new request fields are silently ignored by older live-backup servers because protobuf preserves forward compatibility, while backup_protocol_version still advertises v1. During a rolling upgrade or when the CLI contacts an old admin endpoint, an explicit scoped dump can receive an unfiltered baseline and then select extra baseline scopes (especially with the default all-adapter setting), producing a broader dump than requested; bump/gate the client-server backup protocol before relying on adapters and scopes.

Useful? React with 👍 / 👎.

Comment thread adapter/admin_backup.go
Comment on lines +1247 to +1250
if _, ok := metadataKeys[string(pair.Key)]; !ok {
continue
}
if err := counter.AddValue(pair.Key, pair.Value); 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 Fail when baseline metadata keys disappear

When a key-only baseline pass records metadata keys and one of those keys is missing from this second value pass, the loop simply finishes and finalizes a lower retained count because observed keys are never tracked as consumed. If a backup pin is lost or compaction races between the key pass and the metadata pass, this can turn a missing table/bucket/queue metadata record into an omitted baseline instead of the expected shortfall failure; remove each consumed metadata key and fail if any remain after the scan.

Useful? React with 👍 / 👎.

Base automatically changed from design/live-backup-control-plane to design/live-backup-pin-substrate July 23, 2026 15:14
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.

1 participant