Skip to content

Commit 51b11b0

Browse files
authored
[4.0.3 backport] CBG-5142: Only fetch backup revision for fromRev for delta sync (#8048)
1 parent 9fd7622 commit 51b11b0

15 files changed

+422
-127
lines changed

db/attachment_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ func TestGetBackupRevisionWhenCurrentRevisionHasAttachments(t *testing.T) {
134134
// can remove in CBG-4542
135135
db.FlushRevisionCacheForTest()
136136

137-
docRev, err := collection.GetRev(ctx, "doc1", doc1.HLV.GetCurrentVersionString(), false, nil)
137+
docRev, err := collection.revisionCache.GetWithCV(ctx, "doc1", doc1.HLV.ExtractCurrentVersionFromHLV(), false, true)
138138
require.NoError(t, err)
139139

140140
// assert version is fetched and attachments is empty

db/crud.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ func (db *DatabaseCollectionWithUser) getRev(ctx context.Context, docid, revOrCV
357357
revision, getErr = db.revisionCache.GetWithRev(ctx, docid, *revID, RevCacheOmitDelta)
358358
} else {
359359
cv = &currentVersion
360-
revision, getErr = db.revisionCache.GetWithCV(ctx, docid, cv, RevCacheOmitDelta)
360+
revision, getErr = db.revisionCache.GetWithCV(ctx, docid, cv, RevCacheOmitDelta, false)
361361
}
362362
} else {
363363
// No rev given, so load active revision
@@ -432,7 +432,7 @@ func (db *DatabaseCollectionWithUser) documentRevisionForRequest(ctx context.Con
432432

433433
func (db *DatabaseCollectionWithUser) GetCV(ctx context.Context, docid string, cv *Version, revTreeHistory bool) (revision DocumentRevision, err error) {
434434
if cv != nil {
435-
revision, err = db.revisionCache.GetWithCV(ctx, docid, cv, RevCacheOmitDelta)
435+
revision, err = db.revisionCache.GetWithCV(ctx, docid, cv, RevCacheOmitDelta, false)
436436
} else {
437437
revision, err = db.revisionCache.GetActive(ctx, docid)
438438
}
@@ -462,7 +462,8 @@ func (db *DatabaseCollectionWithUser) GetDelta(ctx context.Context, docID, fromR
462462
if err != nil {
463463
return nil, nil, err
464464
}
465-
initialFromRevision, err = db.revisionCache.GetWithCV(ctx, docID, &fromRevVrs, RevCacheIncludeDelta)
465+
// It is possible delta source will not be resident in the cache and we may want to lookup to the bucket for a backup revision
466+
initialFromRevision, err = db.revisionCache.GetWithCV(ctx, docID, &fromRevVrs, RevCacheIncludeDelta, true)
466467
if err != nil {
467468
return nil, nil, err
468469
}
@@ -503,7 +504,7 @@ func (db *DatabaseCollectionWithUser) GetDelta(ctx context.Context, docID, fromR
503504
// fromRevisionForDiff is a version of the fromRevision that is guarded by the delta lock that we will use to generate the delta (or check again for a newly cached delta)
504505
var fromRevisionForDiff DocumentRevision
505506
if fromRevIsCV {
506-
fromRevisionForDiff, err = db.revisionCache.GetWithCV(ctx, docID, &fromRevVrs, RevCacheIncludeDelta)
507+
fromRevisionForDiff, err = db.revisionCache.GetWithCV(ctx, docID, &fromRevVrs, RevCacheIncludeDelta, true)
507508
if err != nil {
508509
return nil, nil, err
509510
}
@@ -537,7 +538,7 @@ func (db *DatabaseCollectionWithUser) GetDelta(ctx context.Context, docID, fromR
537538
if err != nil {
538539
return nil, nil, err
539540
}
540-
toRevision, err = db.revisionCache.GetWithCV(ctx, docID, &cv, RevCacheIncludeDelta)
541+
toRevision, err = db.revisionCache.GetWithCV(ctx, docID, &cv, RevCacheIncludeDelta, false)
541542
if err != nil {
542543
return nil, nil, err
543544
}

db/database_test.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1090,14 +1090,14 @@ func TestFetchCurrentRevAfterFetchBackupRevByCV(t *testing.T) {
10901090
"k1": "v2",
10911091
BodyRev: rev1ID,
10921092
}
1093-
rev2ID, _, err := collection.Put(ctx, "doc1", rev2Body)
1093+
rev2ID, doc2, err := collection.Put(ctx, "doc1", rev2Body)
10941094
require.NoError(t, err, "Error creating doc")
10951095

10961096
// Flush the revision cache, this can be removed pending CBG-4542
10971097
db.FlushRevisionCacheForTest()
10981098

10991099
// fetch backup rev by cv and ensure we have no revID populated (no way to get revID from backup rev in CV)
1100-
docRev, err := collection.GetRev(ctx, "doc1", doc.CV(), true, nil)
1100+
docRev, err := collection.revisionCache.GetWithCV(ctx, "doc1", doc.HLV.ExtractCurrentVersionFromHLV(), false, true)
11011101
require.NoError(t, err, "Error fetching backup revision CV")
11021102
assert.Equal(t, "", docRev.RevID)
11031103
assert.Equal(t, `{"k1":"v1"}`, string(docRev.BodyBytes))
@@ -1107,6 +1107,7 @@ func TestFetchCurrentRevAfterFetchBackupRevByCV(t *testing.T) {
11071107
require.NoError(t, err, "error fetching current revision")
11081108
assert.Equal(t, rev2ID, docRev.RevID)
11091109
assert.Equal(t, `{"k1":"v2"}`, string(docRev.BodyBytes))
1110+
assert.Equal(t, doc2.HLV.GetCurrentVersionString(), docRev.CV.String())
11101111
}
11111112

11121113
func TestFetchCurrentRevAfterFetchBackupRevByRevID(t *testing.T) {

db/hybrid_logical_vector_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ func TestHLVImport(t *testing.T) {
335335
name: "HLV write from without mou",
336336
preFunc: func(t *testing.T, collection *DatabaseCollectionWithUser, docID string) {
337337
hlvHelper := NewHLVAgent(t, collection.dataStore, otherSource, "_vv")
338-
_ = hlvHelper.InsertWithHLV(ctx, docID)
338+
_ = hlvHelper.InsertWithHLV(ctx, docID, nil)
339339
},
340340
expectedMou: func(output *outputData) *MetadataOnlyUpdate {
341341
return &MetadataOnlyUpdate{
@@ -356,7 +356,7 @@ func TestHLVImport(t *testing.T) {
356356
name: "XDCR stamped with _mou",
357357
preFunc: func(t *testing.T, collection *DatabaseCollectionWithUser, docID string) {
358358
hlvHelper := NewHLVAgent(t, collection.dataStore, otherSource, "_vv")
359-
cas := hlvHelper.InsertWithHLV(ctx, docID)
359+
cas := hlvHelper.InsertWithHLV(ctx, docID, nil)
360360

361361
_, xattrs, _, err := collection.dataStore.GetWithXattrs(ctx, docID, []string{base.VirtualXattrRevSeqNo})
362362
require.NoError(t, err)
@@ -387,7 +387,7 @@ func TestHLVImport(t *testing.T) {
387387
name: "invalid _mou, but valid hlv",
388388
preFunc: func(t *testing.T, collection *DatabaseCollectionWithUser, docID string) {
389389
hlvHelper := NewHLVAgent(t, collection.dataStore, otherSource, "_vv")
390-
cas := hlvHelper.InsertWithHLV(ctx, docID)
390+
cas := hlvHelper.InsertWithHLV(ctx, docID, nil)
391391

392392
_, xattrs, _, err := collection.dataStore.GetWithXattrs(ctx, docID, []string{base.VirtualXattrRevSeqNo})
393393
require.NoError(t, err)

db/revision_cache_bypass.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (rc *BypassRevisionCache) GetWithRev(ctx context.Context, docID, revID stri
5858
}
5959

6060
// GetWithCV fetches the Current Version for the given docID and CV immediately from the bucket.
61-
func (rc *BypassRevisionCache) GetWithCV(ctx context.Context, docID string, cv *Version, collectionID uint32, includeDelta bool) (docRev DocumentRevision, err error) {
61+
func (rc *BypassRevisionCache) GetWithCV(ctx context.Context, docID string, cv *Version, collectionID uint32, includeDelta bool, loadBackup bool) (docRev DocumentRevision, err error) {
6262

6363
docRev = DocumentRevision{
6464
CV: cv,
@@ -71,12 +71,11 @@ func (rc *BypassRevisionCache) GetWithCV(ctx context.Context, docID string, cv *
7171
}
7272

7373
var hlv *HybridLogicalVector
74-
docRev.BodyBytes, docRev.History, docRev.Channels, docRev.Removed, docRev.Attachments, docRev.Deleted, docRev.Expiry, docRev.RevID, hlv, err = revCacheLoaderForDocumentCV(ctx, rc.backingStores[collectionID], doc, *cv)
74+
docRev.BodyBytes, docRev.History, docRev.Channels, docRev.Removed, docRev.Attachments, docRev.Deleted, docRev.Expiry, docRev.RevID, hlv, err = revCacheLoaderForDocumentCV(ctx, rc.backingStores[collectionID], doc, *cv, loadBackup)
7575
if err != nil {
7676
return DocumentRevision{}, err
7777
}
7878
if hlv != nil {
79-
docRev.CV = hlv.ExtractCurrentVersionFromHLV()
8079
docRev.HlvHistory = hlv.ToHistoryForHLV()
8180
}
8281

db/revision_cache_interface.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ type RevisionCache interface {
3434
GetWithRev(ctx context.Context, docID, revID string, collectionID uint32, includeDelta bool) (DocumentRevision, error)
3535

3636
// GetWithCV returns the given revision by CV, and stores if not already cached.
37-
// When includeBody=true, the returned DocumentRevision will include a mutable shallow copy of the marshaled body.
3837
// When includeDelta=true, the returned DocumentRevision will include delta - requires additional locking during retrieval.
39-
GetWithCV(ctx context.Context, docID string, cv *Version, collectionID uint32, includeDelta bool) (DocumentRevision, error)
38+
// When loadBackup=true, will load from backup revisions if requested version is not active document
39+
GetWithCV(ctx context.Context, docID string, cv *Version, collectionID uint32, includeDelta bool, loadBackup bool) (DocumentRevision, error)
4040

4141
// GetActive returns the current revision for the given doc ID, and stores if not already cached.
4242
GetActive(ctx context.Context, docID string, collectionID uint32) (docRev DocumentRevision, err error)
@@ -127,7 +127,7 @@ func DefaultRevisionCacheOptions() *RevisionCacheOptions {
127127
type RevisionCacheBackingStore interface {
128128
GetDocument(ctx context.Context, docid string, unmarshalLevel DocumentUnmarshalLevel) (doc *Document, err error)
129129
getRevision(ctx context.Context, doc *Document, revid string) ([]byte, AttachmentsMeta, base.Set, error)
130-
getCurrentVersion(ctx context.Context, doc *Document, cv Version) ([]byte, AttachmentsMeta, base.Set, bool, error)
130+
getCurrentVersion(ctx context.Context, doc *Document, cv Version, loadBackup bool) ([]byte, AttachmentsMeta, base.Set, bool, error)
131131
}
132132

133133
// collectionRevisionCache is a view of a revision cache for a collection.
@@ -150,8 +150,8 @@ func (c *collectionRevisionCache) GetWithRev(ctx context.Context, docID, revID s
150150
}
151151

152152
// Get is for per collection access to Get method
153-
func (c *collectionRevisionCache) GetWithCV(ctx context.Context, docID string, cv *Version, includeDelta bool) (DocumentRevision, error) {
154-
return (*c.revCache).GetWithCV(ctx, docID, cv, c.collectionID, includeDelta)
153+
func (c *collectionRevisionCache) GetWithCV(ctx context.Context, docID string, cv *Version, includeDelta bool, loadBackup bool) (DocumentRevision, error) {
154+
return (*c.revCache).GetWithCV(ctx, docID, cv, c.collectionID, includeDelta, loadBackup)
155155
}
156156

157157
// GetActive is for per collection access to GetActive method
@@ -421,7 +421,7 @@ func revCacheLoader(ctx context.Context, backingStore RevisionCacheBackingStore,
421421

422422
// revCacheLoaderForCv will load a document from the bucket using the CV, compare the fetched doc and the CV specified in the function,
423423
// and will still return revid for purpose of populating the Rev ID lookup map on the cache
424-
func revCacheLoaderForCv(ctx context.Context, backingStore RevisionCacheBackingStore, id IDandCV) (bodyBytes []byte, history Revisions, channels base.Set, removed bool, attachments AttachmentsMeta, deleted bool, expiry *time.Time, revid string, hlv *HybridLogicalVector, err error) {
424+
func revCacheLoaderForCv(ctx context.Context, backingStore RevisionCacheBackingStore, id IDandCV, loadBackup bool) (bodyBytes []byte, history Revisions, channels base.Set, removed bool, attachments AttachmentsMeta, deleted bool, expiry *time.Time, revid string, hlv *HybridLogicalVector, err error) {
425425
cv := Version{
426426
Value: id.Version,
427427
SourceID: id.Source,
@@ -431,7 +431,7 @@ func revCacheLoaderForCv(ctx context.Context, backingStore RevisionCacheBackingS
431431
return bodyBytes, history, channels, removed, attachments, deleted, expiry, revid, hlv, err
432432
}
433433

434-
return revCacheLoaderForDocumentCV(ctx, backingStore, doc, cv)
434+
return revCacheLoaderForDocumentCV(ctx, backingStore, doc, cv, loadBackup)
435435
}
436436

437437
// Common revCacheLoader functionality used either during a cache miss (from revCacheLoader), or directly when retrieving current rev from cache
@@ -471,8 +471,8 @@ func revCacheLoaderForDocument(ctx context.Context, backingStore RevisionCacheBa
471471

472472
// revCacheLoaderForDocumentCV used either during cache miss (from revCacheLoaderForCv), or used directly when getting current active CV from cache
473473
// nolint:staticcheck
474-
func revCacheLoaderForDocumentCV(ctx context.Context, backingStore RevisionCacheBackingStore, doc *Document, cv Version) (bodyBytes []byte, history Revisions, channels base.Set, removed bool, attachments AttachmentsMeta, deleted bool, expiry *time.Time, revid string, hlv *HybridLogicalVector, err error) {
475-
if bodyBytes, attachments, channels, deleted, err = backingStore.getCurrentVersion(ctx, doc, cv); err != nil {
474+
func revCacheLoaderForDocumentCV(ctx context.Context, backingStore RevisionCacheBackingStore, doc *Document, cv Version, loadBackup bool) (bodyBytes []byte, history Revisions, channels base.Set, removed bool, attachments AttachmentsMeta, deleted bool, expiry *time.Time, revid string, hlv *HybridLogicalVector, err error) {
475+
if bodyBytes, attachments, channels, deleted, err = backingStore.getCurrentVersion(ctx, doc, cv, loadBackup); err != nil {
476476
return nil, nil, nil, false, nil, false, nil, "", nil, err
477477
}
478478

@@ -481,9 +481,9 @@ func revCacheLoaderForDocumentCV(ctx context.Context, backingStore RevisionCache
481481
if doc.HLV.ExtractCurrentVersionFromHLV().Equal(cv) {
482482
revid = doc.GetRevTreeID()
483483
deleted = doc.Deleted
484+
hlv = doc.HLV
484485
}
485486

486-
hlv = doc.HLV
487487
validatedHistory, getHistoryErr := doc.History.getHistory(revid)
488488
if getHistoryErr != nil {
489489
return bodyBytes, history, channels, removed, attachments, deleted, doc.Expiry, revid, hlv, err
@@ -493,8 +493,12 @@ func revCacheLoaderForDocumentCV(ctx context.Context, backingStore RevisionCache
493493
return bodyBytes, history, channels, removed, attachments, deleted, doc.Expiry, revid, hlv, err
494494
}
495495

496-
func (c *DatabaseCollection) getCurrentVersion(ctx context.Context, doc *Document, cv Version) (bodyBytes []byte, attachments AttachmentsMeta, channels base.Set, deleted bool, err error) {
496+
func (c *DatabaseCollection) getCurrentVersion(ctx context.Context, doc *Document, cv Version, loadBackup bool) (bodyBytes []byte, attachments AttachmentsMeta, channels base.Set, deleted bool, err error) {
497497
if err = doc.HasCurrentVersion(ctx, cv); err != nil {
498+
if !loadBackup {
499+
// do not attempt to fetch backup revision by CV unless specified
500+
return nil, nil, nil, false, ErrMissing
501+
}
498502
bodyBytes, channels, deleted, err = c.getOldRevisionJSON(ctx, doc.ID, base.Crc32cHashString([]byte(cv.String())))
499503
if err != nil || bodyBytes == nil {
500504
return nil, nil, nil, false, err

0 commit comments

Comments
 (0)