38
38
#include " mongo/db/catalog/index_catalog.h"
39
39
#include " mongo/db/catalog/index_consistency.h"
40
40
#include " mongo/db/catalog/throttle_cursor.h"
41
+ #include " mongo/db/curop.h"
41
42
#include " mongo/db/index/index_access_method.h"
42
43
#include " mongo/db/index/index_descriptor.h"
43
44
#include " mongo/db/index/wildcard_access_method.h"
@@ -126,6 +127,7 @@ Status ValidateAdaptor::validateRecord(OperationContext* opCtx,
126
127
127
128
for (const auto & keyString : documentKeySet) {
128
129
try {
130
+ _totalIndexKeys++;
129
131
_indexConsistency->addDocKey (opCtx, keyString, &indexInfo, recordId);
130
132
} catch (...) {
131
133
return exceptionToStatus ();
@@ -146,6 +148,14 @@ void ValidateAdaptor::traverseIndex(OperationContext* opCtx,
146
148
147
149
bool isFirstEntry = true ;
148
150
151
+ // The progress meter will be inactive after traversing the record store to allow the message
152
+ // and the total to be set to different values.
153
+ if (!_progress->isActive ()) {
154
+ const char * curopMessage = " Validate: scanning index entries" ;
155
+ stdx::unique_lock<Client> lk (*opCtx->getClient ());
156
+ _progress.set (CurOp::get (opCtx)->setProgress_inlock (curopMessage, _totalIndexKeys));
157
+ }
158
+
149
159
const KeyString::Version version =
150
160
index->accessMethod ()->getSortedDataInterface ()->getKeyStringVersion ();
151
161
KeyString::Builder firstKeyString (
@@ -187,11 +197,13 @@ void ValidateAdaptor::traverseIndex(OperationContext* opCtx,
187
197
if (descriptor->getIndexType () == IndexType::INDEX_WILDCARD &&
188
198
indexEntry->loc == kWildcardMultikeyMetadataRecordId ) {
189
199
_indexConsistency->removeMultikeyMetadataPath (indexEntry->keyString , &indexInfo);
200
+ _progress->hit ();
190
201
numKeys++;
191
202
continue ;
192
203
}
193
204
194
205
_indexConsistency->addIndexKey (indexEntry->keyString , &indexInfo, indexEntry->loc );
206
+ _progress->hit ();
195
207
numKeys++;
196
208
isFirstEntry = false ;
197
209
prevIndexKeyStringValue = indexEntry->keyString ;
@@ -220,12 +232,27 @@ void ValidateAdaptor::traverseRecordStore(OperationContext* opCtx,
220
232
results->valid = true ;
221
233
RecordId prevRecordId;
222
234
235
+ // In case validation occurs twice and the progress meter persists after index traversal
236
+ if (_progress.get () && _progress->isActive ()) {
237
+ _progress->finished ();
238
+ }
239
+
240
+ // Because the progress meter is intended as an approximation, it's sufficient to get the number
241
+ // of records when we begin traversing, even if this number may deviate from the final number.
242
+ const char * curopMessage = " Validate: scanning documents" ;
243
+ const auto totalRecords = _validateState->getCollection ()->getRecordStore ()->numRecords (opCtx);
244
+ {
245
+ stdx::unique_lock<Client> lk (*opCtx->getClient ());
246
+ _progress.set (CurOp::get (opCtx)->setProgress_inlock (curopMessage, totalRecords));
247
+ }
248
+
223
249
const std::unique_ptr<SeekableRecordThrottleCursor>& traverseRecordStoreCursor =
224
250
_validateState->getTraverseRecordStoreCursor ();
225
251
for (auto record =
226
252
traverseRecordStoreCursor->seekExact (opCtx, _validateState->getFirstRecordId ());
227
253
record;
228
254
record = traverseRecordStoreCursor->next (opCtx)) {
255
+ _progress->hit ();
229
256
++_numRecords;
230
257
interruptIntervalNumBytes += record->data .size ();
231
258
if (_numRecords % kInterruptIntervalNumRecords == 0 ||
@@ -286,6 +313,8 @@ void ValidateAdaptor::traverseRecordStore(OperationContext* opCtx,
286
313
opCtx, _numRecords, dataSizeTotal);
287
314
}
288
315
316
+ _progress->finished ();
317
+
289
318
output->appendNumber (" nInvalidDocuments" , nInvalid);
290
319
output->appendNumber (" nrecords" , _numRecords);
291
320
}
0 commit comments