Skip to content

CBG-5745: keep attachment metadata on metadata-only writes - #8690

Open
torcolvin wants to merge 1 commit into
mainfrom
CBG-5745
Open

CBG-5745: keep attachment metadata on metadata-only writes#8690
torcolvin wants to merge 1 commit into
mainfrom
CBG-5745

Conversation

@torcolvin

Copy link
Copy Markdown
Collaborator

Attachment metadata written before 4.0 lives in _sync.attachments. When a document is unmarshalled that metadata is moved onto the document's global sync data and cleared from the sync data, so a write that persists the sync xattr without the global xattr destroys it: for a document attachment migration has not reached yet, that was the only copy.

Two writes did exactly that, dropping the attachment metadata of any document still in the pre-4.0 layout:

  • ResyncDocument ignored the global xattr returned to it by MarshalWithXattrs.
  • CompactDocChannelHistory marshalled the sync data on its own and wrote only the sync and _mou xattrs. Reachable through POST /{keyspace}/_channel_history/{docid}/compact.

Both now write the global xattr alongside the sync xattr.

  • TestWritePathsPreserveUnmigratedAttachmentMetadata covers every path that rewrites a document's sync xattr to verify that none of them were missed by my code changes.

Pre-review checklist

  • Logging sensitive data? Make sure it's tagged (e.g. base.UD(docID), base.MD(dbName))
  • Updated relevant information in the API specifications (such as endpoint descriptions, schemas, ...) in docs/api

Integration Tests

Attachment metadata written before 4.0 lives in _sync.attachments. When
a document is unmarshalled that metadata is moved onto the document's
global sync data and cleared from the sync data, so a write that
persists the sync xattr without the global xattr destroys it: for a
document attachment migration has not reached yet, that was the only
copy.

Two writes did exactly that, dropping the attachment metadata of any
document still in the pre-4.0 layout:

- ResyncDocument ignored the global xattr returned to it by
  MarshalWithXattrs.
- CompactDocChannelHistory marshalled the sync data on its own and wrote
  only the sync and _mou xattrs. Reachable through
  POST /{keyspace}/_channel_history/{docid}/compact.

Both now write the global xattr alongside the sync xattr.

- TestWritePathsPreserveUnmigratedAttachmentMetadata covers every path
that rewrites a document's sync xattr
@torcolvin
torcolvin requested review from a team and a lite review from Copilot August 27, 2026 00:56
@factory-droid

factory-droid Bot commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Droid finished @torcolvin's task —— View job


Droid review (Phase 2 validation) complete.

No candidate inline comments to validate for this PR. Overall, the change looks correct: metadata-only write paths now persist _globalSync alongside _sync, and tests cover the critical unmigrated attachment-metadata rewrite scenarios.

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

Pull request overview

This PR fixes a data-loss risk for pre-4.0 attachment metadata by ensuring any code path that rewrites a document’s _sync xattr also persists the _globalSync xattr (where attachment metadata is moved during unmarshal).

Changes:

  • Ensure ResyncDocument writes _globalSync alongside _sync/_mou on metadata-only writes.
  • Ensure CompactDocChannelHistory writes _globalSync alongside _sync/_mou.
  • Add targeted tests to cover tombstone import behavior and to assert all _sync rewrite paths preserve unmigrated attachment metadata.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
db/document.go Factors global-xattr marshalling into marshalGlobalXattr and centralizes attachment-aware gating.
db/database.go Updates ResyncDocument to include _globalSync in the xattrs written.
db/crud.go Updates channel history compaction to also persist _globalSync.
db/attachment_test.go Adds coverage to assert all _sync rewrite paths preserve unmigrated attachment metadata.
db/import_test.go Adds tests pinning import behavior for SDK tombstones and legacy attachment metadata layouts.

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

Comment thread db/database.go
Comment on lines 1996 to 2000
updatedDoc := sgbucket.UpdatedDoc{
Doc: nil, // Resync does not require document body update
Xattrs: map[string][]byte{
base.SyncXattrName: rawSyncXattr,
base.MouXattrName: rawMouXattr,
},
Doc: nil, // Resync does not require document body update
Xattrs: xattrs,
Expiry: updatedExpiry,
Spec: []sgbucket.MacroExpansionSpec{
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