diff options
author | Geert Bosch <geert@mongodb.com> | 2019-01-08 13:56:33 -0500 |
---|---|---|
committer | Geert Bosch <geert@mongodb.com> | 2019-01-10 15:23:02 -0500 |
commit | 54758174fef8c2b790ff2ed04d16f6578133abc5 (patch) | |
tree | 0d2d032208706a22171098614ac4adc157aae621 | |
parent | facdcf14cfec192876a373fc49163769215327d8 (diff) | |
download | mongo-54758174fef8c2b790ff2ed04d16f6578133abc5.tar.gz |
SERVER-38893 Fix out-of-order biggie oplog insert
-rw-r--r-- | src/mongo/db/storage/biggie/biggie_record_store.cpp | 29 | ||||
-rw-r--r-- | src/mongo/db/storage/biggie/biggie_record_store.h | 4 | ||||
-rw-r--r-- | src/mongo/db/storage/record_store_test_oplog.cpp | 27 |
3 files changed, 29 insertions, 31 deletions
diff --git a/src/mongo/db/storage/biggie/biggie_record_store.cpp b/src/mongo/db/storage/biggie/biggie_record_store.cpp index 7de342838e6..32bb5fafeb3 100644 --- a/src/mongo/db/storage/biggie/biggie_record_store.cpp +++ b/src/mongo/db/storage/biggie/biggie_record_store.cpp @@ -168,7 +168,7 @@ Status RecordStore::insertRecords(OperationContext* opCtx, int64_t thisRecordId = 0; if (_isOplog) { StatusWith<RecordId> status = - extractAndCheckLocForOplog(opCtx, record.data.data(), record.data.size()); + oploghack::extractKey(record.data.data(), record.data.size()); if (!status.isOK()) return status.getStatus(); thisRecordId = status.getValue().repr(); @@ -212,7 +212,7 @@ Status RecordStore::insertRecordsWithDocWriter(OperationContext* opCtx, int64_t thisRecordId = 0; if (_isOplog) { - StatusWith<RecordId> status = extractAndCheckLocForOplog(opCtx, buf.data(), len); + StatusWith<RecordId> status = oploghack::extractKey(buf.data(), len); if (!status.isOK()) return status.getStatus(); thisRecordId = status.getValue().repr(); @@ -441,31 +441,6 @@ boost::optional<RecordId> RecordStore::oplogStartHack(OperationContext* opCtx, return rid; } -StatusWith<RecordId> RecordStore::extractAndCheckLocForOplog(OperationContext* opCtx, - const char* data, - int len) const { - StatusWith<RecordId> status = oploghack::extractKey(data, len); - if (!status.isOK()) - return status; - - StringStore* workingCopy(RecoveryUnit::get(opCtx)->getHead()); - StringStore::const_reverse_iterator it = workingCopy->upper_bound(_postfix); - - if (numRecords(opCtx) == 0) - return status; - - RecordId rid = RecordId(extractRecordId(it->first)); - if (status.getValue() <= rid) - return StatusWith<RecordId>(ErrorCodes::BadValue, - str::stream() << "attempted out-of-order oplog insert of " - << status.getValue() - << " (oplog last insert was " - << rid - << " )"); - - return status; -} - bool RecordStore::_cappedAndNeedDelete(OperationContext* opCtx, StringStore* workingCopy) { if (!_isCapped) return false; diff --git a/src/mongo/db/storage/biggie/biggie_record_store.h b/src/mongo/db/storage/biggie/biggie_record_store.h index 88a9607968a..339b4a16e8f 100644 --- a/src/mongo/db/storage/biggie/biggie_record_store.h +++ b/src/mongo/db/storage/biggie/biggie_record_store.h @@ -133,10 +133,6 @@ private: return _highestRecordId.fetchAndAdd(1); } - StatusWith<RecordId> extractAndCheckLocForOplog(OperationContext* opCtx, - const char* data, - int len) const; - /** * Two helper functions for deleting excess records in capped record stores. * The caller should not have an active SizeAdjuster. diff --git a/src/mongo/db/storage/record_store_test_oplog.cpp b/src/mongo/db/storage/record_store_test_oplog.cpp index 629a99bbb45..16349aad3e1 100644 --- a/src/mongo/db/storage/record_store_test_oplog.cpp +++ b/src/mongo/db/storage/record_store_test_oplog.cpp @@ -160,6 +160,33 @@ TEST(RecordStoreTestHarness, OplogHack) { } } +TEST(RecordStoreTestHarness, OplogInsertOutOfOrder) { + std::unique_ptr<RecordStoreHarnessHelper> harnessHelper = newRecordStoreHarnessHelper(); + if (!harnessHelper->supportsDocLocking()) + return; + + const int64_t cappedMaxSize = 10 * 1024; // Large enough to not exceed. + std::unique_ptr<RecordStore> rs( + harnessHelper->newCappedRecordStore("local.oplog.rs", cappedMaxSize, -1)); + { + ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); + + // RecordId's are inserted out-of-order. + ASSERT_EQ(insertBSON(opCtx, rs, Timestamp(1, 1)).getValue(), RecordId(1, 1)); + ASSERT_EQ(insertBSON(opCtx, rs, Timestamp(2, 2)).getValue(), RecordId(2, 2)); + ASSERT_EQ(insertBSON(opCtx, rs, Timestamp(1, 2)).getValue(), RecordId(1, 2)); + } + { + ServiceContext::UniqueOperationContext opCtx(harnessHelper->newOperationContext()); + rs->waitForAllEarlierOplogWritesToBeVisible(opCtx.get()); + auto cursor = rs->getCursor(opCtx.get()); + ASSERT_EQ(cursor->next()->id, RecordId(1, 1)); + ASSERT_EQ(cursor->next()->id, RecordId(1, 2)); + ASSERT_EQ(cursor->next()->id, RecordId(2, 2)); + ASSERT(!cursor->next()); + } +} + TEST(RecordStoreTestHarness, OplogHackOnNonOplog) { std::unique_ptr<RecordStoreHarnessHelper> harnessHelper = newRecordStoreHarnessHelper(); if (!harnessHelper->supportsDocLocking()) |