Skip to content

Commit

Permalink
CBG-3392 perform a cas check in WriteCasWithXattr on tombstone
Browse files Browse the repository at this point in the history
  • Loading branch information
torcolvin committed Nov 28, 2023
1 parent 2368b8c commit 64f460d
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 12 deletions.
23 changes: 11 additions & 12 deletions collection+xattrs.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,20 +391,19 @@ type writeXattrOptions struct {
deleteBody bool // Delete the body along with updating tombstone
}

// checkCasXattr checks the cas supplied against the current cas of the document. e respresents the document in the bucket, and expectedCas is the expected value. Returns CasMismatchErr on an unsuccesful CAS check.
func checkCasXattr(hasPreviousDocBody bool, existingCas, expectedCas *CAS, isTombstone bool, opts writeXattrOptions) error {
// no cas supplied, nothing to check
// checkCasXattr checks the cas supplied against the current cas of the document. hasPreviousDocBody represents whether the existing document has a body. existingCas is the current Cas of the document (will be 0 if no document) and expectedCas is the expected value. Returns CasMismatchErr on an unsuccesful CAS check.
func checkCasXattr(hasPreviousDocBody bool, existingCas, expectedCas *CAS, opts writeXattrOptions) error {
// no cas supplied, nothing to check, this is different than zero when used with SetXattr
if expectedCas == nil {
return nil
}
if !hasPreviousDocBody {
if opts.isDelete {
if opts.deleteBody {
return nil
}
} else if isTombstone {
return nil
}

// avoid a cas check if there is:
// 1. no previous body (could be xattrs)
// 2. we are writing a tombstone
// 3. we are not planning on writing a new body
if !hasPreviousDocBody && opts.isDelete && opts.deleteBody {
return nil
}
if *existingCas == *expectedCas {
return nil
Expand Down Expand Up @@ -454,7 +453,7 @@ func (c *Collection) writeWithXattr(
return nil, remapKeyError(err, key)
}

err := checkCasXattr(e.value != nil, &prevCas, ifCas, wasTombstone == 1, opts)
err := checkCasXattr(e.value != nil, &prevCas, ifCas, opts)
if err != nil {
return nil, err
}
Expand Down
24 changes: 24 additions & 0 deletions collection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,30 @@ func TestWriteCasWithXattrXattrExistsNoDoc(t *testing.T) {
verifyEmptyBodyAndSyncXattr(t, col, docID)
}

func TestWriteCasWithXattrOnTombstone(t *testing.T) {
col := makeTestBucket(t).DefaultDataStore()
const docID = "XattrExistsNoDoc"

val := make(map[string]interface{})
val["type"] = docID

xattrVal := make(map[string]interface{})
xattrVal["seq"] = 456
xattrVal["rev"] = "1-1234"

ctx := testCtx(t)
cas, err := col.WriteCasWithXattr(ctx, docID, syncXattrName, 0, 0, val, xattrVal, nil)
require.NoError(t, err)

deleteCas, err := col.Remove(docID, cas)
require.NoError(t, err)
require.NotEqual(t, cas, deleteCas)

postDeleteCas, err := col.WriteCasWithXattr(ctx, docID, syncXattrName, 0, 0, val, xattrVal, nil)
require.ErrorAs(t, err, &sgbucket.CasMismatchErr{})
require.NotEqual(t, cas, postDeleteCas)
}

func verifyEmptyBodyAndSyncXattr(t *testing.T, store sgbucket.XattrStore, key string) {
var retrievedVal map[string]interface{}
var retrievedXattr map[string]interface{}
Expand Down

0 comments on commit 64f460d

Please sign in to comment.