Status MultiIndexBlock::insertAllDocumentsInCollection(std::set<DiskLoc>* dupsOut) { const char* curopMessage = _buildInBackground ? "Index Build (background)" : "Index Build"; ProgressMeter* progress = _txn->setMessage(curopMessage, curopMessage, _collection->numRecords(_txn)); Timer t; unsigned long long n = 0; scoped_ptr<PlanExecutor> exec(InternalPlanner::collectionScan(_txn, _collection->ns().ns(), _collection)); BSONObj objToIndex; DiskLoc loc; while (PlanExecutor::ADVANCED == exec->getNext(&objToIndex, &loc)) { { bool shouldCommitWUnit = true; WriteUnitOfWork wunit(_txn); Status ret = insert(objToIndex, loc); if (!ret.isOK()) { if (dupsOut && ret.code() == ErrorCodes::DuplicateKey) { // If dupsOut is non-null, we should only fail the specific insert that // led to a DuplicateKey rather than the whole index build. dupsOut->insert(loc); shouldCommitWUnit = false; } else { return ret; } } if (shouldCommitWUnit) wunit.commit(); } n++; progress->hit(); if (_allowInterruption) _txn->checkForInterrupt(); progress->setTotalWhileRunning( _collection->numRecords(_txn) ); } progress->finished(); Status ret = doneInserting(dupsOut); if (!ret.isOK()) return ret; log() << "build index done. scanned " << n << " total records. " << t.seconds() << " secs" << endl; return Status::OK(); }
unsigned long long addExistingToIndex( OperationContext* txn, Collection* collection, const IndexDescriptor* descriptor, IndexAccessMethod* accessMethod, bool canBeKilled ) { string ns = collection->ns().ns(); // our copy for sanity bool dupsAllowed = !descriptor->unique(); bool dropDups = descriptor->dropDups(); string curopMessage; { stringstream ss; ss << "Index Build"; if ( canBeKilled ) ss << "(background)"; curopMessage = ss.str(); } ProgressMeter* progress = txn->setMessage(curopMessage.c_str(), curopMessage, collection->numRecords()); unsigned long long n = 0; unsigned long long numDropped = 0; auto_ptr<Runner> runner(InternalPlanner::collectionScan(ns,collection)); std::string idxName = descriptor->indexName(); // After this yields in the loop, idx may point at a different index (if indexes get // flipped, see insert_makeIndex) or even an empty IndexDetails, so nothing below should // depend on idx. idxNo should be recalculated after each yield. BSONObj js; DiskLoc loc; while (Runner::RUNNER_ADVANCED == runner->getNext(&js, &loc)) { try { if ( !dupsAllowed && dropDups ) { LastError::Disabled led( lastError.get() ); addKeysToIndex(txn, collection, descriptor, accessMethod, js, loc); } else { addKeysToIndex(txn, collection, descriptor, accessMethod, js, loc); } } catch( AssertionException& e ) { if (ErrorCodes::isInterruption(DBException::convertExceptionCode(e.getCode()))) { txn->checkForInterrupt(); } // TODO: Does exception really imply dropDups exception? if (dropDups) { bool runnerEOF = runner->isEOF(); runner->saveState(); BSONObj toDelete; collection->deleteDocument( txn, loc, false, true, &toDelete ); repl::logOp(txn, "d", ns.c_str(), toDelete); if (!runner->restoreState(txn)) { // Runner got killed somehow. This probably shouldn't happen. if (runnerEOF) { // Quote: "We were already at the end. Normal. // TODO: Why is this normal? } else { uasserted(ErrorCodes::CursorNotFound, "cursor gone during bg index; dropDups"); } break; } // We deleted a record, but we didn't actually yield the dblock. // TODO: Why did the old code assume we yielded the lock? numDropped++; } else { log() << "background addExistingToIndex exception " << e.what() << endl; throw; } } n++; progress->hit(); txn->recoveryUnit()->commitIfNeeded(); if (canBeKilled) { // Checking for interrupt here is necessary because the bg index // interruptors can only interrupt this index build while they hold // a write lock, and yieldAndCheckIfOK only checks for // interrupt prior to yielding our write lock. We need to check the kill flag // here before another iteration of the loop. txn->checkForInterrupt(); } progress->setTotalWhileRunning( collection->numRecords() ); } progress->finished(); if ( dropDups && numDropped ) log() << "\t index build dropped: " << numDropped << " dups"; return n; }