Repository navigation
Stop expiring tombstones and make delete paths consistent - #99
Merged
Merged
Conversation
Broken: - The expirer selected every row with an expired exp, including tombstones. A tombstone that kept an expiry was deleted again, which made a second deletion event with a new CAS and a higher revSeqNo. Couchbase Server does not expire tombstones. - DeleteWithXattrs did not set tombstone=1 or isJSON=0, and kept the old expiry. Couchbase Server sets the expiry of the tombstone to 0. - WriteCas with a nil value did not set tombstone=1 and kept user xattrs. Delete removes user xattrs. Fixed: - expireDocuments and nextExpiration skip rows with tombstone=1. - DeleteWithXattrs sets exp=0, isJSON=0 and tombstone=1, the same values that remove() writes. - WriteCas with a nil value sets tombstone=1 and removes user xattrs. - remove() uses processXattrs with removeUserXattrs in place of its own loop. - TestExpirationSkipsTombstones covers each delete path. It checks the tombstone flag and exp, and that the expirer does not change the tombstone. TestTombstoneRemovesUserXattrs checks that Delete and WriteCas with a nil value keep system xattrs and remove user xattrs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved issues remain in WriteCas nil-value handling across write branches and tombstone xattr preservation.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (2)
What changed in this PR
This pull request prevents tombstones from being re-expired and aligns delete metadata and xattr handling with Couchbase behavior.
Changes:
- Excludes tombstones from expiration scans and scheduling.
- Normalizes tombstone metadata for delete paths.
- Adds regression coverage for expiration and xattr cleanup.
| File | Summary |
|---|---|
collection+xattrs.go |
Updates DeleteWithXattrs tombstone metadata. |
collection.go |
Adjusts nil writes, xattr cleanup, and expiration filtering. Review findings identify moderate and critical issues in nil-write branches and tombstone xattr preservation. |
collection_test.go |
Tests user and system xattr behavior. |
bucket_test.go |
Tests expiration behavior across delete paths. |
bucket_api.go |
Excludes tombstones from next-expiration calculation. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…ranch - The insert, upsert and append branches of WriteCas did not set tombstone=1 for a nil value, so the row had no body but counted as live. - A nil WriteCas over an existing tombstone cleared all xattrs, because the xattr reset checked the old tombstone flag. Xattrs are now cleared only when a non-nil value brings a tombstone back. - TestWriteCasNilSetsTombstone and TestWriteCasNilOnTombstoneKeepsSystemXattrs cover these cases. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Add and Set brought a tombstone back but left tombstone=1. Add also did not increment revSeqNo and always reported revSeqNo 1 in the event. - SetXattrs, UpdateXattrs and WriteWithXattrs with a nil body on a tombstone set tombstone=0 on a row with no body. - Add no longer emits a DCP event when the key exists and nothing is written. - TestTombstoneFlagMatchesBody covers each of these writes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Merged
5 tasks done
bbrks
requested changes
Oct 6, 2026
Set, SetRaw, Add and AddRaw always write a live document, and an xattr-only write keeps the document's existing tombstone state. _set reads the tombstone column instead of inferring it from a nil value.
Couchbase Server never creates a tombstone for a nil WriteCas value. An untyped nil writes null and a nil []byte writes an empty body. WriteCas also reads revSeqNo for a CAS of 0, so a write over a tombstone increases it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
bbrks
approved these changes
Oct 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Broken:
Fixed:
This doesn't fail any tests currently in Sync Gateway but it can fail some tests in the future. I didn't want to do a test in Sync Gateway because I can't use
synctest- gocb is not compatible.