Skip to content

Commit 848e05f

Browse files
snejjianminzhao
andauthored
CBL-6239: Fixed c4doc_getRevisionBody in a 2.x db (#2136)
VectorRecord didn't properly manage the `body` column of a doc from a 2.x db that doesn't have the `extra` column. In such a db the body is the encoded rev tree, not just the current rev. VectorRecord was returning that entire slice from its currentRevisionData method. I added a new member _bodyDocRange, a slice that's just the current rev within the _bodyDoc. Normally it's the same as _bodyDoc.data(), but in a 2.x doc it encompasses just the current rev body. Fixes CBL-6239 Co-authored-by: Jianmin Zhao <jianmin.zhao@couchbase.com>
1 parent 92fc5cc commit 848e05f

File tree

3 files changed

+44
-28
lines changed

3 files changed

+44
-28
lines changed

C/tests/c4DatabaseTest.cc

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,13 +1115,18 @@ static void testOpeningOlderDBFixture(const string& dbPath, C4DatabaseFlags with
11151115
for ( unsigned i = 1; i <= 100; i++ ) {
11161116
snprintf(docID, bufSize, "doc-%03u", i);
11171117
INFO("Checking docID " << docID);
1118-
auto defaultColl = c4db_getDefaultCollection(db, nullptr);
1119-
C4Document* doc = c4coll_getDoc(defaultColl, slice(docID), true, kDocGetCurrentRev, ERROR_INFO());
1118+
auto defaultColl = c4db_getDefaultCollection(db, nullptr);
1119+
c4::ref<C4Document> doc = c4coll_getDoc(defaultColl, slice(docID), true, kDocGetCurrentRev, ERROR_INFO());
11201120
REQUIRE(doc);
11211121
CHECK(((doc->flags & kDocDeleted) != 0) == (i > 50));
1122-
Dict body = c4doc_getProperties(doc);
1123-
CHECK(body["n"].asInt() == i);
1124-
c4doc_release(doc);
1122+
Dict root = c4doc_getProperties(doc);
1123+
CHECK(root["n"].asInt() == i);
1124+
// Test getting doc body from data [CBL-6239]:
1125+
slice body = c4doc_getRevisionBody(doc);
1126+
REQUIRE(body);
1127+
FLValue rootVal = FLValue_FromData(body, kFLUntrusted);
1128+
CHECK(rootVal);
1129+
CHECK(FLValue_GetType(rootVal) == kFLDict);
11251130
}
11261131

11271132
// Verify enumerating documents:

LiteCore/RevTrees/VectorRecord.cc

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,10 @@ namespace litecore {
9191
static constexpr slice kLegacyRevIDKey = "~";
9292
static constexpr slice kRevFlagsKey = "&";
9393

94-
bool Revision::hasVersionVector() const { return revID.isVersion(); }
9594

96-
Version Revision::version() const { return VersionVector::readCurrentVersionFromBinary(revID); }
95+
#pragma mark - INITIALIZATION:
9796

98-
VersionVector Revision::versionVector() const { return VersionVector::fromBinary(revID); }
97+
bool Revision::hasVersionVector() const { return revID.isVersion(); }
9998

10099
VectorRecord::VectorRecord(KeyStore& store, const Record& rec)
101100
: _store(store)
@@ -133,6 +132,7 @@ namespace litecore {
133132
} else {
134133
if ( body ) {
135134
_bodyDoc = newLinkedFleeceDoc(body, kFLTrusted);
135+
_bodyDocRange = _bodyDoc.data();
136136
_current.properties = _bodyDoc.asDict();
137137
if ( !_current.properties )
138138
error::_throw(error::CorruptRevisionData, "VectorRecord reading properties error");
@@ -180,10 +180,13 @@ namespace litecore {
180180
if ( _docFlags & DocumentFlags::kSynced ) revTree.setLatestRevisionOnRemote(1, curRev);
181181

182182
if ( !extra ) {
183-
// This is a v2.x document with body & rev-tree in `body`, and no `extra`:
183+
// This is a v2.x document with body & rev-tree in `body`, and no `extra`.
184+
// That means _bodyDoc's data is the entire rev-tree, not just the current rev data.
185+
// This is why we have _bodyDocRange! Set it to the current rev itself:
184186
Assert(!_bodyDoc);
185187
_bodyDoc = newLinkedFleeceDoc(body, kFLTrustedDontParse);
186-
FLValue bodyProps = FLValue_FromData(curRev->body(), kFLTrusted);
188+
_bodyDocRange = curRev->body();
189+
FLValue bodyProps = FLValue_FromData(_bodyDocRange, kFLTrusted);
187190
_current.properties = Value(bodyProps).asDict();
188191
if ( !_current.properties )
189192
error::_throw(error::CorruptRevisionData, "VectorRecord reading 2.x properties error");
@@ -370,9 +373,13 @@ namespace litecore {
370373

371374
#pragma mark - CURRENT REVISION:
372375

376+
Version Revision::version() const { return VersionVector::readCurrentVersionFromBinary(revID); }
377+
378+
VersionVector Revision::versionVector() const { return VersionVector::fromBinary(revID); }
379+
373380
slice VectorRecord::currentRevisionData() const {
374381
requireBody();
375-
return _bodyDoc.data();
382+
return _bodyDocRange;
376383
}
377384

378385
void VectorRecord::setCurrentRevision(const Revision& rev) {
@@ -383,7 +390,7 @@ namespace litecore {
383390

384391
Dict VectorRecord::originalProperties() const {
385392
requireBody();
386-
return _bodyDoc.asDict();
393+
return Value(FLValue_FromData(_bodyDocRange, kFLTrusted)).asDict();
387394
}
388395

389396
MutableDict VectorRecord::mutableProperties() {

LiteCore/RevTrees/VectorRecord.hh

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -255,22 +255,26 @@ namespace litecore {
255255
void clearPropertiesChanged() const;
256256
void updateDocFlags();
257257

258-
KeyStore& _store; // The database KeyStore
259-
FLEncoder _encoder{nullptr}; // Database shared Fleece Encoder
260-
alloc_slice _docID; // The docID
261-
sequence_t _sequence; // The Record's sequence
262-
uint64_t _subsequence; // The Record's subsequence
263-
DocumentFlags _docFlags; // Document-level flags
264-
alloc_slice _savedRevID; // Revision ID saved in db (may == _revID)
265-
alloc_slice _revID; // Current revision ID backing store
266-
Revision _current; // Current revision
267-
fleece::RetainedValue _currentProperties; // Retains local properties
268-
fleece::Doc _bodyDoc; // If saved, a Doc of the Fleece body
269-
fleece::Doc _extraDoc; // Fleece Doc holding record `extra`
270-
fleece::Array _revisions; // Top-level parsed body; stores revs
271-
mutable fleece::MutableArray _mutatedRevisions; // Mutable version of `_revisions`
272-
bool _changed{false}; // Set to true on explicit change
273-
ContentOption _whichContent; // Which parts of record are available
258+
KeyStore& _store; // The database KeyStore
259+
FLEncoder _encoder{nullptr}; // Database shared Fleece Encoder
260+
alloc_slice _docID; // The docID
261+
sequence_t _sequence; // The Record's sequence
262+
uint64_t _subsequence; // The Record's subsequence
263+
DocumentFlags _docFlags; // Document-level flags
264+
alloc_slice _savedRevID; // Revision ID saved in db (may == _revID)
265+
alloc_slice _revID; // Current revision ID backing store
266+
Revision _current; // Current revision
267+
fleece::RetainedValue _currentProperties; // Retains local properties
268+
fleece::Doc _bodyDoc; // If saved, a Doc of the `body` column
269+
slice _bodyDocRange; // Fleece data within _bodyDoc
270+
fleece::Doc _extraDoc; // Fleece Doc holding record `extra`
271+
fleece::Array _revisions; // Top-level parsed body; stores revs
272+
mutable fleece::MutableArray _mutatedRevisions; // Mutable version of `_revisions`
273+
Versioning _versioning; // RevIDs or VersionVectors?
274+
int _parentOfLocal{}; // (only used in imported revtree)
275+
bool _changed{false}; // Set to true on explicit change
276+
bool _revIDChanged{false}; // Has setRevID() been called?
277+
ContentOption _whichContent; // Which parts of record are available
274278
// (Note: _changed doesn't reflect mutations to _properties; changed() checks for those.)
275279
};
276280
} // namespace litecore

0 commit comments

Comments
 (0)