diff --git a/LiteCore/Database/VectorDocument.cc b/LiteCore/Database/VectorDocument.cc index 0da683b4f..736606525 100644 --- a/LiteCore/Database/VectorDocument.cc +++ b/LiteCore/Database/VectorDocument.cc @@ -674,9 +674,8 @@ namespace litecore { // Check whether the doc's current rev is this version, or a newer, or a conflict: versionOrder cmp; - bool recUsesVVs = revid(rec.version).isVersion(); - cmp = compareLocalRev(revid(rec.version)); - auto status = C4FindDocAncestorsResultFlags(cmp); + cmp = compareLocalRev(revid(rec.version)); + auto status = C4FindDocAncestorsResultFlags(cmp); // Check whether this revID matches any of the doc's remote revisions: if ( remoteDBID != 0 ) { @@ -694,7 +693,7 @@ namespace litecore { return {&statusChar, 1}; } - // I don't have the requested rev, so find revs that could be ancestors of it, + // I don't have the requested rev, so find all my current revs // and append them as a JSON array: result.str(""); result << statusChar << '['; @@ -704,8 +703,8 @@ namespace litecore { VectorRecord::forAllRevIDs(rec, [&](RemoteID, revid aRev, bool hasBody) { if ( delim.count() < maxAncestors && hasBody >= mustHaveBodies ) { alloc_slice vector; - if ( recUsesVVs ) { - if ( !(compareLocalRev(aRev) & kNewer) ) vector = localVec.asASCII(mySourceID); + if ( aRev.isVersion() ) { + vector = aRev.asVersion().asASCII(mySourceID); } else { vector = aRev.expanded(); } diff --git a/LiteCore/RevTrees/VectorRecord.cc b/LiteCore/RevTrees/VectorRecord.cc index f547a399d..9bba00974 100644 --- a/LiteCore/RevTrees/VectorRecord.cc +++ b/LiteCore/RevTrees/VectorRecord.cc @@ -754,4 +754,21 @@ namespace litecore { } } + optional VectorRecord::findLatestWithAuthor(SourceID author) { + RemoteID remote = RemoteID::Local; + + optional latest = nullopt; + + while ( auto rev = loadRemoteRevision(remote) ) { + VersionVector vv = rev->versionVector(); + for ( auto ver : vv.versions() ) { + if ( ver.author() == author && (!latest || ver.time() > latest->time()) ) { latest = ver; } + } + remote = loadNextRemoteID(remote); + } + + return latest; + } + + } // namespace litecore diff --git a/LiteCore/RevTrees/VectorRecord.hh b/LiteCore/RevTrees/VectorRecord.hh index a48288541..8a0264232 100644 --- a/LiteCore/RevTrees/VectorRecord.hh +++ b/LiteCore/RevTrees/VectorRecord.hh @@ -15,6 +15,8 @@ #include "RevID.hh" #include "fleece/Fleece.hh" #include "fleece/Mutable.hh" + +#include "SourceID.hh" #include #include @@ -221,6 +223,8 @@ namespace litecore { /// Given only a record, find all the revision IDs and pass them to the callback. static void forAllRevIDs(const RecordUpdate&, const ForAllRevIDsCallback&); + std::optional findLatestWithAuthor(SourceID author); + //---- For testing: /// Generates a version-vector revision ID given parent vector. diff --git a/LiteCore/tests/c4DocumentTest_Internal.cc b/LiteCore/tests/c4DocumentTest_Internal.cc index 2e174dce5..7c2238d47 100644 --- a/LiteCore/tests/c4DocumentTest_Internal.cc +++ b/LiteCore/tests/c4DocumentTest_Internal.cc @@ -119,21 +119,24 @@ N_WAY_TEST_CASE_METHOD(C4Test, "Document FindDocAncestors", "[Document][C]") { // Newer revision: CHECK(findDocAncestor(doc1, "11@BobBobBobBobBobBobBobA; 3@AliceAliceAliceAliceAA"_sl) - == R"(1["3@AliceAliceAliceAliceAA; 10@BobBobBobBobBobBobBobA"])"); + == R"(1["3@AliceAliceAliceAliceAA"])"); // Conflict: - CHECK(findDocAncestor(doc1, "11@BobBobBobBobBobBobBobA; 2@AliceAliceAliceAliceAA"_sl) == R"(3[])"); + CHECK(findDocAncestor(doc1, "11@BobBobBobBobBobBobBobA; 2@AliceAliceAliceAliceAA"_sl) + == R"(3["3@AliceAliceAliceAliceAA"])"); // Single version: CHECK(findDocAncestor(doc1, "10@BobBobBobBobBobBobBobA"_sl) == "2"); - CHECK(findDocAncestor(doc1, "11@BobBobBobBobBobBobBobA"_sl) == "3[]"); - CHECK(findDocAncestor(doc1, "1@DaveDaveDaveDaveDaveDA"_sl) == "3[]"); + CHECK(findDocAncestor(doc1, "11@BobBobBobBobBobBobBobA"_sl) == R"(3["3@AliceAliceAliceAliceAA"])"); + + // Single version with a unknown author + CHECK(findDocAncestor(doc1, "1@DaveDaveDaveDaveDaveDA"_sl) == R"(3["3@AliceAliceAliceAliceAA"])"); // Limit number of results: C4Slice newRevID = "11@BobBobBobBobBobBobBobA; 3@AliceAliceAliceAliceAA"_sl; REQUIRE(c4coll_findDocAncestors(defaultColl, 1, 1, kNoBodies, kRemoteID, &doc1, &newRevID, ancestors, WITH_ERROR())); - CHECK(toString(ancestors[0]) == R"(1["3@AliceAliceAliceAliceAA; 10@BobBobBobBobBobBobBobA"])"); + CHECK(toString(ancestors[0]) == R"(1["3@AliceAliceAliceAliceAA"])"); freeAncestors(); // Multiple docs: @@ -143,10 +146,10 @@ N_WAY_TEST_CASE_METHOD(C4Test, "Document FindDocAncestors", "[Document][C]") { "1@DaveDaveDaveDaveDaveDA; 3@CarolCarolCarolCarolCA, 30@BobBobBobBobBobBobBobA"_sl}; REQUIRE(c4coll_findDocAncestors(defaultColl, 4, kMaxAncestors, kNoBodies, kRemoteID, docIDs, revIDs, ancestors, WITH_ERROR())); - CHECK(toString(ancestors[0]) == R"(1["3@AliceAliceAliceAliceAA; 10@BobBobBobBobBobBobBobA"])"); + CHECK(toString(ancestors[0]) == R"(1["3@AliceAliceAliceAliceAA"])"); CHECK(toString(ancestors[1]) == "0"); CHECK(!slice(ancestors[2])); - CHECK(toString(ancestors[3]) == R"(1["3@CarolCarolCarolCarolCA; 30@BobBobBobBobBobBobBobA"])"); + CHECK(toString(ancestors[3]) == R"(1["3@CarolCarolCarolCarolCA"])"); freeAncestors(); } } @@ -225,6 +228,7 @@ N_WAY_TEST_CASE_METHOD(C4Test, "Random RevID", "[Document][C]") { kNotEncryptable = R"({"foo":1234,"nested":[0,1,{"SSN":{"type":"encryptable","value":"123-45-6789"}},3,4]})"; slice json; + SECTION("verify sha1 digest") { json = kNotEncryptable; } SECTION("verify encryptable") { json = kEncryptable; } if ( !json ) { return; } diff --git a/Replicator/tests/ReplicatorCollectionSGTest.cc b/Replicator/tests/ReplicatorCollectionSGTest.cc index ab82c6427..706bcd0c3 100644 --- a/Replicator/tests/ReplicatorCollectionSGTest.cc +++ b/Replicator/tests/ReplicatorCollectionSGTest.cc @@ -1948,8 +1948,6 @@ TEST_CASE_METHOD(ReplicatorCollectionSGTest, "Pull iTunes deltas from Collection timeWithoutDelta / timeWithDelta); } -// Disabled, to be re-enabled with CBL-5621 -#if 0 // cbl-4499 TEST_CASE_METHOD(ReplicatorCollectionSGTest, "Pull invalid deltas with filter from SG", "[.SyncServerCollection][Delta]") { @@ -1958,14 +1956,13 @@ TEST_CASE_METHOD(ReplicatorCollectionSGTest, "Pull invalid deltas with filter fr initTest({Tulips}, {channelID}, "test_user"); static constexpr int kNumDocs = 10, kNumProps = 100; - static constexpr int kDocBufSize = 80; - static constexpr const char* cblTicket = "cbl-4499"; + static constexpr const char* cblTicket = "cbl-4499"; const string docPrefix = idPrefix + cblTicket + "_"; vector docIDs(kNumDocs); - for (int docNo = 0; docNo < kNumDocs; ++docNo) { + for ( int docNo = 0; docNo < kNumDocs; ++docNo ) { docIDs[docNo] = stringprintf("%sdoc-%03d", docPrefix.c_str(), docNo); } @@ -1973,7 +1970,7 @@ TEST_CASE_METHOD(ReplicatorCollectionSGTest, "Pull invalid deltas with filter fr auto populateDB = [&]() { TransactionHelper t(db); std::srand(123456); // start random() sequence at a known place - for (const string& docID : docIDs) { + for ( const string& docID : docIDs ) { Encoder enc(c4db_createFleeceEncoder(db)); enc.beginDict(); for ( int p = 0; p < kNumProps; ++p ) { @@ -1997,7 +1994,7 @@ TEST_CASE_METHOD(ReplicatorCollectionSGTest, "Pull invalid deltas with filter fr replicate(replParams); // -------- Updating docs on SG -------- - for (const string& docID : docIDs) { + for ( const string& docID : docIDs ) { C4Error error; c4::ref doc = c4coll_getDoc(_collections[0], slice(docID), true, kDocGetAll, ERROR_INFO(error)); REQUIRE(doc); @@ -2024,9 +2021,9 @@ TEST_CASE_METHOD(ReplicatorCollectionSGTest, "Pull invalid deltas with filter fr FLDict flbody, void* context) { return true; }; // -------- Pulling changes from SG -------- -# ifdef LITECORE_CPPTEST +#ifdef LITECORE_CPPTEST _expectedDocPullErrors = {docPrefix + "doc-001"}; -# endif +#endif replParams.setPushPull(kC4Disabled, kC4OneShot); replParams.setPullFilter(_pullFilter).setCallbackContext(this); { @@ -2051,7 +2048,6 @@ TEST_CASE_METHOD(ReplicatorCollectionSGTest, "Pull invalid deltas with filter fr } CHECK(n == kNumDocs); } -#endif // cbl-4499 TEST_CASE_METHOD(ReplicatorCollectionSGTest, "Push invalid deltas to SG", "[.SyncServerCollection][Delta]") { diff --git a/Replicator/tests/ReplicatorCollectionTest.cc b/Replicator/tests/ReplicatorCollectionTest.cc index e688b1030..128536073 100644 --- a/Replicator/tests/ReplicatorCollectionTest.cc +++ b/Replicator/tests/ReplicatorCollectionTest.cc @@ -594,7 +594,7 @@ N_WAY_TEST_CASE_METHOD(ReplicatorCollectionTest, "Multiple Collections Increment addRevs(tulips, 500ms, alloc_slice("tulips-docko"), 1, 3, true, "db-tulips"); addRevs(roses2, 500ms, alloc_slice("roses2-docko"), 1, 3, true, "db2-roses"); addRevs(tulips2, 500ms, alloc_slice("tulips2-docko"), 1, 3, true, "db2-tulips"); - sleepFor(5s); + sleepFor(10s); stopWhenIdle(); }}); _callbackWhenIdle = nullptr;