Skip to content

Commit

Permalink
CBL-6597: The proposeChange not include remote revision id for the up… (
Browse files Browse the repository at this point in the history
#2200)

* CBL-6597: The proposeChange not include remote revision id for the updated doc when using version vector

This occurs because as we produce originalRecord from VectorRecord, we overlooked the effect of kSync flag. This happens when the copy constructor of VectorRecord is called. We do the following to fix the problem.
1. As we clear flag kSynced in VectorRecord, we make a note with _wasSynced, in VectorRecord. In particular, it applies to the source VectorRecord.
2. The copy constructor will use the originalRecord produced by the source VectorRecord. As we do it, we put back (restore) kSynced in the originalRecord if _wasSynced is set.
3. As we construct VectorRecord from the originalRecord of the source VectorRecord, we (already) pass DocumentFlags from the originalRecord to the target VectorRecord, which now includes kSynced.
And, thus, it circles back to the state when the document is loaded from the KeyStore when kSynced is set.
  • Loading branch information
jianminzhao authored Jan 9, 2025
1 parent e6ca3aa commit 89151de
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 2 deletions.
10 changes: 8 additions & 2 deletions LiteCore/RevTrees/VectorRecord.cc
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ namespace litecore {
if ( _docFlags & DocumentFlags::kSynced ) {
setRemoteRevision(RemoteID(1), currentRevision());
_docFlags -= DocumentFlags::kSynced;
_changed = false;
_wasSynced = true;
_changed = false;
}
}

Expand Down Expand Up @@ -240,7 +241,12 @@ namespace litecore {
rec.updateSubsequence(_subsequence);
if ( _sequence > 0_seq ) rec.setExists();
rec.setVersion(_savedRevID);
rec.setFlags(_docFlags);
if ( _wasSynced ) {
Assert(!(_docFlags & DocumentFlags::kSynced));
rec.setFlags(_docFlags | DocumentFlags::kSynced);
} else {
rec.setFlags(_docFlags);
}
rec.setBody(_bodyDoc.allocedData());
rec.setExtra(_extraDoc.allocedData());
rec.setContentLoaded(_whichContent);
Expand Down
1 change: 1 addition & 0 deletions LiteCore/RevTrees/VectorRecord.hh
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,7 @@ namespace litecore {
int _parentOfLocal{}; // (only used in imported revtree)
bool _changed{false}; // Set to true on explicit change
bool _revIDChanged{false}; // Has setRevID() been called?
bool _wasSynced{false}; // Set when kSync is cleared.
ContentOption _whichContent; // Which parts of record are available
// (Note: _changed doesn't reflect mutations to _properties; changed() checks for those.)
};
Expand Down
38 changes: 38 additions & 0 deletions Replicator/tests/ReplicatorCollectionTest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "c4Database.hh"
#include "Defer.hh"
#include "fleece/Mutable.hh"
#include <future>

static constexpr slice GuitarsName = "guitars"_sl;
static constexpr C4CollectionSpec Guitars = {GuitarsName, kC4DefaultScopeID};
Expand Down Expand Up @@ -1055,4 +1056,41 @@ N_WAY_TEST_CASE_METHOD(ReplicatorCollectionTest, "Filters & docIDs with Multiple
}
}

N_WAY_TEST_CASE_METHOD(ReplicatorCollectionTest, "Remote RevID Continuous Push", "[Push]") {
// 1. Create 1 doc
// 2. Start a continuous push replicator
// 3. Wait until idle
// 4. Update the doc.
// 5. Wait until idle and stop
// 6. Check the log if the proposeChange contains the remoteRevID when the update is push
C4Collection* roses = getCollection(db, Roses);
{
auto body = json2fleece("{'ok':'really!'}");
TransactionHelper t(db);
C4DocPutRequest rq = {};
rq.body = body;
rq.docID = slice("doc1");
rq.revFlags = 0;
rq.save = true;
C4Error c4err;
auto doc = c4coll_putDoc(roses, &rq, nullptr, &c4err);
c4doc_release(doc);
}

std::future<void> future;
_callbackWhenIdle = [this, roses, &future]() {
c4::ref<C4Document> doc1 = c4coll_getDoc(roses, slice("doc1"), true, kDocGetAll, ERROR_INFO());
TransactionHelper t(db);
c4::ref<C4Document> doc = c4doc_update(doc1, json2fleece("{'ok':'no way!'}"), 0, nullptr);
future = std::async(std::launch::async, [this]() {
sleepFor(1s);
stopWhenIdle();
});
_callbackWhenIdle = nullptr;
};

_expectedDocumentCount = 2;
runPushReplication({Roses}, {Roses}, kC4Continuous);
}

#endif

0 comments on commit 89151de

Please sign in to comment.