Skip to content

Commit 5e9f50e

Browse files
moustafamaherEvergreen Agent
authored andcommitted
SERVER-82164 Use throttling in extraKeys dbcheck
1 parent 1f366b9 commit 5e9f50e

File tree

6 files changed

+71
-59
lines changed

6 files changed

+71
-59
lines changed

jstests/replsets/dbcheck.js

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -302,29 +302,53 @@ function testDbCheckParameters() {
302302
}
303303
{
304304
// Validate maxDbCheckMBperSec.
305-
clearHealthLog(replSet);
306305
const coll = db.getSiblingDB("maxDbCheckMBperSec").maxDbCheckMBperSec;
306+
assert.commandWorked(db.getSiblingDB("maxDbCheckMBperSec").runCommand({
307+
createIndexes: coll.getName(),
308+
indexes: [{key: {a: 1}, name: 'a_1'}],
309+
}));
307310

308311
// Insert nDocs, each slightly larger than the maxDbCheckMBperSec value (1MB), which is the
309312
// default value, while maxBatchTimeMillis is defaulted to 1 second. Consequently, we will
310313
// have only 1MB per batch.
311314
const nDocs = 5;
312-
coll.insertMany([...Array(nDocs).keys()].map(x => ({a: 'a'.repeat(1024 * 1024 * 2)})),
315+
const chars = ['a', 'b', 'c', 'd', 'e'];
316+
coll.insertMany([...Array(nDocs).keys()].map(x => ({a: chars[x].repeat(1024 * 1024 * 2)})),
313317
{ordered: false});
318+
[{}, {validateMode: "dataConsistency"}, {
319+
validateMode: "dataConsistencyAndMissingIndexKeysCheck"
320+
}].forEach(parameters => {
321+
clearHealthLog(replSet);
322+
runDbCheck(replSet, db.getSiblingDB("maxDbCheckMBperSec"), coll.getName(), parameters);
323+
324+
// DbCheck logs (nDocs + 1) batches to account for each batch hitting the time deadline
325+
// after processing only one document. Then, DbCheck will run an additional empty batch
326+
// at the end to confirm that there are no more documents.
327+
let query = {"operation": "dbCheckBatch"};
328+
checkHealthLog(healthlog, query, nDocs + 1);
329+
330+
query = {"operation": "dbCheckBatch", "data.count": 1};
331+
checkHealthLog(healthlog, query, nDocs);
332+
333+
query = {"operation": "dbCheckBatch", "data.count": 0};
334+
checkHealthLog(healthlog, query, 1);
335+
});
314336

315-
runDbCheck(replSet, db.getSiblingDB("maxDbCheckMBperSec"), coll.getName(), {});
337+
clearHealthLog(replSet);
338+
runDbCheck(replSet, db.getSiblingDB("maxDbCheckMBperSec"), coll.getName(), {
339+
validateMode: "extraIndexKeysCheck",
340+
secondaryIndex: "a_1",
341+
});
316342

317-
// DbCheck logs (nDocs + 1) batches to account for each batch hitting the time deadline
318-
// after processing only one document. Then, DbCheck will run an additional empty batch at
319-
// the end to confirm that there are no more documents.
343+
// DbCheck logs (nDocs) batches to account for each batch hitting the time deadline after
344+
// processing only one document.
345+
// Extra index check's implementation is different from 'dataConsistency' as it doesn't need
346+
// to run an additional empty batch at the end to confirm that there are no more documents.
320347
let query = {"operation": "dbCheckBatch"};
321-
checkHealthLog(healthlog, query, nDocs + 1);
348+
checkHealthLog(healthlog, query, nDocs);
322349

323350
query = {"operation": "dbCheckBatch", "data.count": 1};
324351
checkHealthLog(healthlog, query, nDocs);
325-
326-
query = {"operation": "dbCheckBatch", "data.count": 0};
327-
checkHealthLog(healthlog, query, 1);
328352
}
329353
}
330354

src/mongo/db/catalog/throttle_cursor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ class SortedDataInterfaceThrottleCursor {
138138
return _cursor->isRecordIdAtEndOfKeyString();
139139
}
140140

141+
void setEndPosition(const BSONObj& key, bool inclusive) {
142+
_cursor->setEndPosition(key, inclusive);
143+
}
144+
141145
private:
142146
std::unique_ptr<SortedDataInterface::Cursor> _cursor;
143147
DataThrottle* _dataThrottle;

src/mongo/db/commands/dbcheck_command.cpp

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -674,20 +674,9 @@ void DbChecker::_extraIndexKeysCheck(OperationContext* opCtx) {
674674

675675
int64_t totalBytesSeen = 0;
676676
int64_t totalKeysSeen = 0;
677-
using Clock = stdx::chrono::system_clock;
678-
using TimePoint = stdx::chrono::time_point<Clock>;
679-
TimePoint lastStart = Clock::now();
680-
int64_t docsInCurrentInterval = 0;
681-
682677
do {
683-
using namespace std::literals::chrono_literals;
684-
685-
if (Clock::now() - lastStart > 1s) {
686-
lastStart = Clock::now();
687-
docsInCurrentInterval = 0;
688-
}
689-
690678
DbCheckExtraIndexKeysBatchStats batchStats = {0};
679+
batchStats.deadline = Date_t::now() + Milliseconds(_info.maxBatchTimeMillis);
691680

692681
// 1. Get batch bounds (stored in batchStats) and run reverse lookup if
693682
// skipLookupForExtraKeys is not set.
@@ -759,21 +748,11 @@ void DbChecker::_extraIndexKeysCheck(OperationContext* opCtx) {
759748
// 5. Check if we've exceeded any limits.
760749
_batchesProcessed++;
761750
totalBytesSeen += batchStats.nBytes;
762-
totalKeysSeen += batchStats.nDocs;
763-
docsInCurrentInterval += batchStats.nDocs;
751+
totalKeysSeen += batchStats.nKeys;
764752

765-
bool tooManyDocs = totalKeysSeen >= _info.maxCount;
753+
bool tooManyKeys = totalKeysSeen >= _info.maxCount;
766754
bool tooManyBytes = totalBytesSeen >= _info.maxSize;
767-
reachedEnd = batchStats.finishedIndexCheck || tooManyDocs || tooManyBytes;
768-
769-
if (docsInCurrentInterval > _info.maxRate && _info.maxRate > 0) {
770-
// If an extremely low max rate has been set (substantially smaller than the
771-
// batch size) we might want to sleep for multiple seconds between batches.
772-
int64_t timesExceeded = docsInCurrentInterval / _info.maxRate;
773-
774-
stdx::this_thread::sleep_for(timesExceeded * 1s - (Clock::now() - lastStart));
775-
}
776-
755+
reachedEnd = batchStats.finishedIndexCheck || tooManyKeys || tooManyBytes;
777756
} while (!reachedEnd);
778757

779758
// TODO SERVER-79846: Add testing for progress meter
@@ -882,9 +861,8 @@ Status DbChecker::_hashExtraIndexKeysCheck(OperationContext* opCtx,
882861
return e.toStatus();
883862
}
884863

885-
const auto batchDeadline = Date_t::now() + Milliseconds(_info.maxBatchTimeMillis);
886-
Status status = hasher->hashForExtraIndexKeysCheck(
887-
opCtx, collection.get(), batchFirst, batchLast, batchDeadline);
864+
Status status =
865+
hasher->hashForExtraIndexKeysCheck(opCtx, collection.get(), batchFirst, batchLast);
888866
if (!status.isOK()) {
889867
return status;
890868
}
@@ -1063,8 +1041,8 @@ Status DbChecker::_getCatalogSnapshotAndRunReverseLookup(
10631041
const auto ordering = iam->getSortedDataInterface()->getOrdering();
10641042

10651043

1066-
std::unique_ptr<SortedDataInterface::Cursor> indexCursor =
1067-
iam->newCursor(opCtx, true /* forward */);
1044+
auto indexCursor =
1045+
std::make_unique<SortedDataInterfaceThrottleCursor>(opCtx, iam, &_info.dataThrottle);
10681046

10691047

10701048
// Set the index cursor's end position based on the inputted end parameter for when to stop
@@ -1085,7 +1063,7 @@ Status DbChecker::_getCatalogSnapshotAndRunReverseLookup(
10851063
logAttrs(_info.nss),
10861064
"uuid"_attr = _info.uuid);
10871065

1088-
auto currIndexKey = indexCursor->seekForKeyString(lookupStart);
1066+
auto currIndexKey = indexCursor->seekForKeyString(opCtx, lookupStart);
10891067

10901068
// Note that if we can't find lookupStart (e.g. it was deleted in between snapshots),
10911069
// seekForKeyString will automatically return the next adjacent keystring in the storage
@@ -1148,9 +1126,9 @@ Status DbChecker::_getCatalogSnapshotAndRunReverseLookup(
11481126
numBytes += keyString.getSize();
11491127
numKeys++;
11501128
batchStats.nBytes += keyString.getSize();
1151-
batchStats.nDocs++;
1129+
batchStats.nKeys++;
11521130

1153-
currIndexKey = indexCursor->nextKeyString();
1131+
currIndexKey = indexCursor->nextKeyString(opCtx);
11541132

11551133
// Set nextLookupStart.
11561134
if (currIndexKey) {
@@ -1162,8 +1140,7 @@ Status DbChecker::_getCatalogSnapshotAndRunReverseLookup(
11621140
// snapshot/batch, so skip this check.
11631141
if (!(currIndexKey && (keyString == currIndexKey.get().keyString))) {
11641142
// Check if we should finish this batch.
1165-
if (batchStats.nBytes >= _info.maxBytesPerBatch ||
1166-
batchStats.nDocs >= _info.maxDocsPerBatch) {
1143+
if (batchStats.nKeys >= _info.maxDocsPerBatch) {
11671144
batchStats.finishedIndexBatch = true;
11681145
break;
11691146
}
@@ -1172,6 +1149,11 @@ Status DbChecker::_getCatalogSnapshotAndRunReverseLookup(
11721149
break;
11731150
}
11741151
}
1152+
1153+
if (Date_t::now() > batchStats.deadline) {
1154+
batchStats.finishedIndexBatch = true;
1155+
break;
1156+
}
11751157
}
11761158

11771159

@@ -1211,9 +1193,12 @@ void DbChecker::_reverseLookup(OperationContext* opCtx,
12111193
}
12121194
MONGO_UNREACHABLE;
12131195
}();
1214-
RecordData record;
1215-
bool res = collection->getRecordStore()->findRecord(opCtx, recordId, &record);
1216-
if (!res) {
1196+
1197+
auto seekRecordStoreCursor = std::make_unique<SeekableRecordThrottleCursor>(
1198+
opCtx, collection->getRecordStore(), &_info.dataThrottle);
1199+
1200+
auto record = seekRecordStoreCursor->seekExact(opCtx, recordId);
1201+
if (!record) {
12171202
LOGV2_DEBUG(7844802,
12181203
3,
12191204
"reverse lookup failed to find record data",
@@ -1247,7 +1232,7 @@ void DbChecker::_reverseLookup(OperationContext* opCtx,
12471232
}
12481233

12491234
// Found record in record store.
1250-
auto recordBson = record.toBson();
1235+
auto recordBson = record->data.toBson();
12511236

12521237
// Generate the set of keys for the record data and check that it includes the
12531238
// index key.

src/mongo/db/commands/dbcheck_command.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ struct DbCheckCollectionBatchStats {
7979
* For organizing the results of batches for extra index keys check.
8080
*/
8181
struct DbCheckExtraIndexKeysBatchStats {
82-
int64_t nDocs;
82+
int64_t nKeys;
8383
int64_t nBytes;
8484
key_string::Value firstIndexKey;
8585
key_string::Value lastIndexKey;
@@ -89,6 +89,7 @@ struct DbCheckExtraIndexKeysBatchStats {
8989
std::string md5;
9090
repl::OpTime time;
9191
boost::optional<Timestamp> readTimestamp;
92+
Date_t deadline;
9293
};
9394

9495
/**

src/mongo/db/repl/dbcheck.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,7 @@ void maybeAppend(md5_state_t* state, const boost::optional<UUID>& uuid) {
429429
Status DbCheckHasher::hashForExtraIndexKeysCheck(OperationContext* opCtx,
430430
const Collection* collection,
431431
const key_string::Value& first,
432-
const key_string::Value& last,
433-
Date_t deadline) {
432+
const key_string::Value& last) {
434433
// hashForExtraIndexKeysCheck must only be called if the hasher was created with indexName.
435434
invariant(_indexName);
436435
StringData indexName = _indexName.get();
@@ -442,17 +441,17 @@ Status DbCheckHasher::hashForExtraIndexKeysCheck(OperationContext* opCtx,
442441
auto iam = indexCatalogEntry->accessMethod()->asSortedData();
443442
const auto ordering = iam->getSortedDataInterface()->getOrdering();
444443

445-
std::unique_ptr<SortedDataInterface::Cursor> indexCursor =
446-
iam->newCursor(opCtx, true /* forward */);
444+
auto indexCursor =
445+
std::make_unique<SortedDataInterfaceThrottleCursor>(opCtx, iam, _dataThrottle);
447446
auto firstBson =
448447
key_string::toBsonSafe(first.getBuffer(), first.getSize(), ordering, first.getTypeBits());
449448
auto lastBson =
450449
key_string::toBsonSafe(last.getBuffer(), last.getSize(), ordering, last.getTypeBits());
451450
indexCursor->setEndPosition(lastBson, true /*inclusive*/);
452451

453452
// Iterate through index table.
454-
for (auto currEntry = indexCursor->seekForKeyString(first); currEntry;
455-
currEntry = indexCursor->nextKeyString()) {
453+
for (auto currEntry = indexCursor->seekForKeyString(opCtx, first); currEntry;
454+
currEntry = indexCursor->nextKeyString(opCtx)) {
456455
const auto keyString = currEntry->keyString;
457456
auto keyStringBson = key_string::toBsonSafe(
458457
keyString.getBuffer(), keyString.getSize(), ordering, keyString.getTypeBits());

src/mongo/db/repl/dbcheck.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -198,13 +198,12 @@ class DbCheckHasher {
198198
Date_t deadline = Date_t::max());
199199

200200
/**
201-
* Hash index keys up to the deadline.
201+
* Hash index keys between first and last inclusive.
202202
*/
203203
Status hashForExtraIndexKeysCheck(OperationContext* opCtx,
204204
const Collection* collection,
205205
const key_string::Value& first,
206-
const key_string::Value& last,
207-
Date_t deadline = Date_t::max());
206+
const key_string::Value& last);
208207

209208
/**
210209
* Checks if a document has missing index keys by finding the index keys that should be

0 commit comments

Comments
 (0)