diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp index c8d9f70..7206902 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store.cpp @@ -184,20 +184,32 @@ void WiredTigerRecordStore::OplogStones::awaitHasExcessStonesOrDead() { } } -boost::optional -WiredTigerRecordStore::OplogStones::peekOldestStoneIfNeeded() const { +boost::optional> +WiredTigerRecordStore::OplogStones::peekOldestStonesIfNeeded() const { stdx::lock_guard lk(_mutex); if (!hasExcessStones()) { return {}; } - return _stones.front(); + size_t numExcessStones = _stones.size() - _numStonesToKeep; + int64_t totalRecords = 0; + int64_t totalBytes = 0; + RecordId lastRecord; + + for (auto it = _stones.begin(); it < _stones.begin() + numExcessStones; ++it) { + totalRecords += it->records; + totalBytes += it->bytes; + lastRecord = it->lastRecord; + } + + WiredTigerRecordStore::OplogStones::Stone truncateSpan = {totalRecords, totalBytes, lastRecord}; + return {std::make_tuple(truncateSpan, numExcessStones)}; } -void WiredTigerRecordStore::OplogStones::popOldestStone() { +void WiredTigerRecordStore::OplogStones::popOldestStones(size_t numStones) { stdx::lock_guard lk(_mutex); - _stones.pop_front(); + _stones.erase(_stones.begin(), _stones.begin() + numStones); } void WiredTigerRecordStore::OplogStones::createNewStoneIfNeeded(RecordId lastRecord) { @@ -1155,12 +1167,16 @@ bool WiredTigerRecordStore::yieldAndAwaitOplogDeletionRequest(OperationContext* } void WiredTigerRecordStore::reclaimOplog(OperationContext* txn) { - while (auto stone = _oplogStones->peekOldestStoneIfNeeded()) { - invariant(stone->lastRecord.isNormal()); + while (auto excess = _oplogStones->peekOldestStonesIfNeeded()) { + auto truncateSpan = std::get<0>(*excess); + size_t numStonesToRemove = std::get<1>(*excess); + + invariant(truncateSpan.lastRecord.isNormal()); + invariant(numStonesToRemove > 0); LOG(1) << "Truncating the oplog between " << _oplogStones->firstRecord << " and " - << stone->lastRecord << " to remove approximately " << stone->records - << " records totaling to " << stone->bytes << " bytes"; + << truncateSpan.lastRecord << " to remove approximately " << truncateSpan.records + << " records totaling to " << truncateSpan.bytes << " bytes"; WiredTigerRecoveryUnit* ru = WiredTigerRecoveryUnit::get(txn); ru->markNoTicketRequired(); // No ticket is needed for internal operations. @@ -1175,19 +1191,19 @@ void WiredTigerRecordStore::reclaimOplog(OperationContext* txn) { WiredTigerCursor endwrap(_uri, _tableId, true, txn); WT_CURSOR* end = endwrap.get(); - end->set_key(end, _makeKey(stone->lastRecord)); + end->set_key(end, _makeKey(truncateSpan.lastRecord)); invariantWTOK(session->truncate(session, nullptr, start, end, nullptr)); - _changeNumRecords(txn, -stone->records); - _increaseDataSize(txn, -stone->bytes); + _changeNumRecords(txn, -truncateSpan.records); + _increaseDataSize(txn, -truncateSpan.bytes); wuow.commit(); - // Remove the stone after a successful truncation. - _oplogStones->popOldestStone(); + // Remove the stone(s) after a successful truncation. + _oplogStones->popOldestStones(numStonesToRemove); // Stash the truncate point for next time to cleanly skip over tombstones, etc. - _oplogStones->firstRecord = stone->lastRecord; + _oplogStones->firstRecord = truncateSpan.lastRecord; } catch (const WriteConflictException& wce) { LOG(1) << "Caught WriteConflictException while truncating oplog entries, retrying"; } diff --git a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_oplog_stones.h b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_oplog_stones.h index daa8998..66a3114 100644 --- a/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_oplog_stones.h +++ b/src/mongo/db/storage/wiredtiger/wiredtiger_record_store_oplog_stones.h @@ -30,6 +30,7 @@ #pragma once #include +#include #include "mongo/db/storage/wiredtiger/wiredtiger_record_store.h" #include "mongo/platform/atomic_word.h" @@ -63,9 +64,9 @@ public: void awaitHasExcessStonesOrDead(); - boost::optional peekOldestStoneIfNeeded() const; + boost::optional> peekOldestStonesIfNeeded() const; - void popOldestStone(); + void popOldestStones(size_t numStones); void createNewStoneIfNeeded(RecordId lastRecord);