diff --git a/LiteCore/RevTrees/RevTree.cc b/LiteCore/RevTrees/RevTree.cc index 621d16fd9..8ed2ce306 100644 --- a/LiteCore/RevTrees/RevTree.cc +++ b/LiteCore/RevTrees/RevTree.cc @@ -606,6 +606,28 @@ void RevTree::resetConflictSequence(const Rev* winningRev) { return false; } + bool RevTree::ensureConflictStateConsistent() { + if (hasConflict()) { + sort(); + bool recovered = false; + // _revs[0] is current rev after sort + for (auto rev = _revs.begin() + 1; rev != _revs.end(); rev++) { + auto f = (*rev)->flags; + // a undeleted, non-closed, unconflict leaf rev + if ((f & Rev::kLeaf) && + !(f & Rev::kClosed) && + !(f & Rev::kDeleted) && + !(f & Rev::kIsConflict)) { + (*rev)->addFlag(Rev::kIsConflict); + recovered = true; + } + } + _changed |= recovered; + return recovered; + } + return false; + } + void RevTree::saved(sequence_t newSequence) { for (Rev *rev : _revs) { rev->clearFlag(Rev::kNew); diff --git a/LiteCore/RevTrees/RevTree.hh b/LiteCore/RevTrees/RevTree.hh index d3bc5b87c..b59c1404f 100644 --- a/LiteCore/RevTrees/RevTree.hh +++ b/LiteCore/RevTrees/RevTree.hh @@ -112,6 +112,15 @@ namespace litecore { bool hasConflict() const; bool hasNewRevisions() const; + /// For unknown reason, sometimes the rev tree would come into an inconsistent state, + /// in which some conflicted leaf revs are not tagged conflict. + /// The method is a workaround for the problem. It tag those unclosed, non-current + /// leaves as conflict, solving the problem regardless of its real cause. + /// + /// Return true if it was recovered from inconsistent state + /// Return false otherwise + bool ensureConflictStateConsistent(); + /// Given an array of revision IDs in consecutive descending-generation order, /// finds the first one that exists in this tree. Returns: /// * {rev, index} if a common ancestor was found; diff --git a/LiteCore/RevTrees/VersionedDocument.cc b/LiteCore/RevTrees/VersionedDocument.cc index a060eec23..459926034 100644 --- a/LiteCore/RevTrees/VersionedDocument.cc +++ b/LiteCore/RevTrees/VersionedDocument.cc @@ -164,6 +164,9 @@ namespace litecore { } VersionedDocument::SaveResult VersionedDocument::save(Transaction& transaction) { + if (_usuallyFalse(ensureConflictStateConsistent())) { + Warn("Document '%.*s' recovered from inconsistent state", SPLAT(docID())); + } if (!_changed) return kNoNewSequence; updateMeta(); diff --git a/LiteCore/RevTrees/VersionedDocument.hh b/LiteCore/RevTrees/VersionedDocument.hh index 3694408a6..4b5d28890 100644 --- a/LiteCore/RevTrees/VersionedDocument.hh +++ b/LiteCore/RevTrees/VersionedDocument.hh @@ -20,6 +20,8 @@ #include "RevTree.hh" #include "Record.hh" #include "Doc.hh" +#include "Logging.hh" +#include "StringUtil.hh" #include #include