diff options
author | Gregory Noma <gregory.noma@gmail.com> | 2021-03-25 12:46:26 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-03-25 17:26:18 +0000 |
commit | 75d3a439ea77e6f8bd9bed2b4f397803b66c2949 (patch) | |
tree | 799eaf1cdeaec65618435981ae41e95ef69e6af7 | |
parent | 1a2e420059f71f3b486f389fdb1463d927ffac58 (diff) | |
download | mongo-75d3a439ea77e6f8bd9bed2b4f397803b66c2949.tar.gz |
SERVER-55136 Clean up invalid state on failed time-series insert
-rw-r--r-- | jstests/noPassthrough/timeseries_insert_after_failed_insert.js | 51 | ||||
-rw-r--r-- | src/mongo/db/commands/write_commands.cpp | 15 |
2 files changed, 60 insertions, 6 deletions
diff --git a/jstests/noPassthrough/timeseries_insert_after_failed_insert.js b/jstests/noPassthrough/timeseries_insert_after_failed_insert.js new file mode 100644 index 00000000000..bc95cc35a8b --- /dev/null +++ b/jstests/noPassthrough/timeseries_insert_after_failed_insert.js @@ -0,0 +1,51 @@ +/** + * Tests that a failed time-series insert does not leave behind any invalid state. + */ +(function() { +'use strict'; + +load('jstests/core/timeseries/libs/timeseries.js'); +load('jstests/libs/fail_point_util.js'); + +const conn = MongoRunner.runMongod(); + +if (!TimeseriesTest.timeseriesCollectionsEnabled(conn)) { + jsTestLog('Skipping test because the time-series collection feature flag is disabled'); + MongoRunner.stopMongod(conn); + return; +} + +const testDB = conn.getDB(jsTestName()); + +const coll = testDB.getCollection('t'); +const bucketsColl = testDB.getCollection('system.buckets.' + coll.getName()); + +const timeFieldName = 'time'; +const metaFieldName = 'meta'; + +coll.drop(); +assert.commandWorked(testDB.createCollection( + coll.getName(), {timeseries: {timeField: timeFieldName, metaField: metaFieldName}})); +assert.contains(bucketsColl.getName(), testDB.getCollectionNames()); + +const docs = [ + {_id: 0, meta: 'fail', [timeFieldName]: ISODate()}, + {_id: 1, meta: 'fail', [timeFieldName]: ISODate()}, +]; + +const fp = configureFailPoint(conn, 'failTimeseriesInsert', {metadata: 'fail'}); +assert.commandFailed(coll.insert(docs[0], {ordered: false})); +fp.off(); + +// Insert a document that belongs in the same bucket that the failed insert woulld have gone into. +assert.commandWorked(coll.insert(docs[1], {ordered: false})); + +// There should not be any leftover state from the failed insert. +assert.docEq(coll.find().toArray(), [docs[1]]); +const buckets = bucketsColl.find().sort({['control.min.' + timeFieldName]: 1}).toArray(); +jsTestLog('Checking buckets: ' + tojson(buckets)); +assert.eq(buckets.length, 1); +assert.eq(buckets[0].control.min._id, docs[1]._id); + +MongoRunner.stopMongod(conn); +})();
\ No newline at end of file diff --git a/src/mongo/db/commands/write_commands.cpp b/src/mongo/db/commands/write_commands.cpp index d2a9c2fa518..ae0f2d0298a 100644 --- a/src/mongo/db/commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands.cpp @@ -612,16 +612,19 @@ public: ? _performTimeseriesInsert(opCtx, batch, metadata, stmtIds) : _performTimeseriesUpdate(opCtx, batch, metadata, stmtIds); - if (batch->numPreviouslyCommittedMeasurements() != 0 && result.isOK() && - result.getValue().getNModified() == 0) { - // No bucket was found to update, meaning that it was manually removed. + if (auto error = generateError(opCtx, result, start + index, errors->size())) { + errors->push_back(*error); bucketCatalog.abort(batch); - updatesToRetry->push_back(index); return; } - if (auto error = generateError(opCtx, result, start + index, errors->size())) { - errors->push_back(*error); + if (batch->numPreviouslyCommittedMeasurements() != 0 && + result.getValue().getNModified() == 0) { + // No document in the buckets collection was found to update, meaning that it was + // removed. + bucketCatalog.abort(batch); + updatesToRetry->push_back(index); + return; } auto* replCoord = repl::ReplicationCoordinator::get(opCtx->getServiceContext()); |