diff --git a/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/PandoFormatDriver.java b/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/PandoFormatDriver.java index 9da0e67f..fe9c1cb9 100644 --- a/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/PandoFormatDriver.java +++ b/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/PandoFormatDriver.java @@ -781,8 +781,16 @@ private boolean doUpdate(BsonDocument updateDoc, BsonDocument filter) { UpdateResult result = collection.updateOne(filter, updateDoc); LOGGER.debug("| Update result: {}", result); if (result.wasAcknowledged()) { - assert result.getMatchedCount() <= 1; - return result.getMatchedCount() >= 1; + long matchedCount = result.getMatchedCount(); + if (matchedCount == 0) { + LOGGER.debug("| -> No documents were updated; double-checking that the root document still exists"); + try (var cursor = collection.find(documentFilter(rootRef)).limit(1).cursor()) { + if (!cursor.hasNext()) { + throw new IllegalStateException("Root document disappeared"); + } + } + } + return matchedCount >= 1; } else { LOGGER.error("MongoDB write was not acknowledged"); LOGGER.trace("Details of MongoDB write not acknowledged:\n\tFilter: {}\n\tUpdate: {}\n\tResult: {}", filter, updateDoc, result); diff --git a/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/SequoiaFormatDriver.java b/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/SequoiaFormatDriver.java index f67775bb..e3c006d9 100644 --- a/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/SequoiaFormatDriver.java +++ b/bosk-mongo/src/main/java/io/vena/bosk/drivers/mongo/SequoiaFormatDriver.java @@ -386,6 +386,24 @@ private boolean doUpdate(BsonDocument updateDoc, BsonDocument filter) { UpdateResult result = collection.updateOne(filter, updateDoc); LOGGER.debug("| Update result: {}", result); if (result.wasAcknowledged()) { + // NOTE: This case can occur in a few situations: + // 1. A conditional update whose precondition failed + // 2. An update inside a nonexistent node + // 3. The bosk document has disappeared + // + // Differentiating these cases without transactions is complex, + // and the only benefit of the Sequoia format is its simplicity, + // so for now, we're opting not to handle this case. + // + // This means valid updates can be silently ignored during the window + // between when a refurbish operation deletes the bosk document and + // when the corresponding change event arrives. We are going to accept + // and document this risk for the time being, unless we can determine + // a sufficiently straightforward way to detect this situation. + // + // Therefore, when refurbishing from Sequoia to another format, + // the system should be quiescent or else updates may be lost. + assert result.getMatchedCount() <= 1; return result.getMatchedCount() >= 1; } else {