// This free function is used by the initial sync writer threads to apply each op void multiInitialSyncApply(const std::vector<BSONObj>& ops, SyncTail* st) { initializeWriterThread(); for (std::vector<BSONObj>::const_iterator it = ops.begin(); it != ops.end(); ++it) { try { OperationContextImpl txn; if (!st->syncApply(&txn, *it)) { bool status; { Lock::GlobalWrite lk(txn.lockState()); status = st->shouldRetry(&txn, *it); } if (status) { // retry if (!st->syncApply(&txn, *it)) { fassertFailedNoTrace(15915); } } // If shouldRetry() returns false, fall through. // This can happen if the document that was moved and missed by Cloner // subsequently got deleted and no longer exists on the Sync Target at all } } catch (const DBException& e) { error() << "exception: " << causedBy(e) << " on: " << it->toString() << endl; fassertFailedNoTrace(16361); } } }
void ReplSetImpl::_assumePrimary() { LOG(1) << "replSet assuming primary" << endl; verify(iAmPotentiallyHot()); // Wait for replication to stop and buffer to be consumed LOG(1) << "replSet waiting for replication to finish before becoming primary" << endl; BackgroundSync::get()->stopReplicationAndFlushBuffer(); // Lock here to prevent stepping down & becoming primary from getting interleaved LOG(1) << "replSet waiting for global write lock"; OperationContextImpl txn; // XXX? Lock::GlobalWrite lk(txn.lockState()); initOpTimeFromOplog(&txn, "local.oplog.rs"); // Generate new election unique id elect.setElectionId(OID::gen()); LOG(1) << "replSet truly becoming primary"; changeState(MemberState::RS_PRIMARY); // This must be done after becoming primary but before releasing the write lock. This adds // the dropCollection entries for every temp collection to the opLog since we want it to be // replicated to secondaries. dropAllTempCollections(&txn); }
static void replMasterThread() { sleepsecs(4); Client::initThread("replmaster"); int toSleep = 10; while (1) { sleepsecs(toSleep); // Write a keep-alive like entry to the log. This will make things like // printReplicationStatus() and printSlaveReplicationStatus() stay up-to-date even // when things are idle. OperationContextImpl txn; txn.getClient()->getAuthorizationSession()->grantInternalAuthorization(); Lock::GlobalWrite globalWrite(txn.lockState(), 1); if (globalWrite.isLocked()) { toSleep = 10; try { WriteUnitOfWork wuow(&txn); logKeepalive(&txn); wuow.commit(); } catch (...) { log() << "caught exception in replMasterThread()" << endl; } } else { LOG(5) << "couldn't logKeepalive" << endl; toSleep = 1; } } }
void run() { OperationContextImpl txn; DBDirectClient client(&txn); for ( int i = 0; i < 10; ++i ) { client.insert( ns, BSON( "_id" << i ) ); } { // Remove _id range [_min, _max). Lock::DBWrite lk(txn.lockState(), ns); WriteUnitOfWork wunit(txn.recoveryUnit()); Client::Context ctx(&txn, ns ); KeyRange range( ns, BSON( "_id" << _min ), BSON( "_id" << _max ), BSON( "_id" << 1 ) ); mongo::WriteConcernOptions dummyWriteConcern; Helpers::removeRange(&txn, range, false, dummyWriteConcern); wunit.commit(); } // Check that the expected documents remain. ASSERT_EQUALS( expected(), docs(&txn) ); }
TEST(DBHelperTests, FindDiskLocsNoIndex) { OperationContextImpl txn; DBDirectClient client(&txn); client.remove( ns, BSONObj() ); client.insert( ns, BSON( "_id" << OID::gen() ) ); long long maxSizeBytes = 1024 * 1024 * 1024; set<DiskLoc> locs; long long numDocsFound; long long estSizeBytes; { Lock::DBRead lk(txn.lockState(), ns); // search invalid index range KeyRange range( ns, BSON( "badIndex" << 0 ), BSON( "badIndex" << 10 ), BSON( "badIndex" << 1 ) ); Status result = Helpers::getLocsInRange( &txn, range, maxSizeBytes, &locs, &numDocsFound, &estSizeBytes ); // Make sure we get the right error code ASSERT_EQUALS( result.code(), ErrorCodes::IndexNotFound ); ASSERT_EQUALS( static_cast<long long>( locs.size() ), 0 ); ASSERT_EQUALS( numDocsFound, 0 ); ASSERT_EQUALS( estSizeBytes, 0 ); } }
// This free function is used by the writer threads to apply each op void multiSyncApply(const std::vector<BSONObj>& ops, SyncTail* st) { initializeWriterThread(); OperationContextImpl txn; txn.setReplicatedWrites(false); DisableDocumentValidation validationDisabler(&txn); // allow us to get through the magic barrier txn.lockState()->setIsBatchWriter(true); bool convertUpdatesToUpserts = true; for (std::vector<BSONObj>::const_iterator it = ops.begin(); it != ops.end(); ++it) { try { const Status s = SyncTail::syncApply(&txn, *it, convertUpdatesToUpserts); if (!s.isOK()) { severe() << "Error applying operation (" << it->toString() << "): " << s; fassertFailedNoTrace(16359); } } catch (const DBException& e) { severe() << "writer worker caught exception: " << causedBy(e) << " on: " << it->toString(); if (inShutdown()) { return; } fassertFailedNoTrace(16360); } } }
static void logStartup() { BSONObjBuilder toLog; stringstream id; id << getHostNameCached() << "-" << jsTime(); toLog.append( "_id", id.str() ); toLog.append( "hostname", getHostNameCached() ); toLog.appendTimeT( "startTime", time(0) ); toLog.append( "startTimeLocal", dateToCtimeString(curTimeMillis64()) ); toLog.append("cmdLine", serverGlobalParams.parsedOpts); toLog.append( "pid", ProcessId::getCurrent().asLongLong() ); BSONObjBuilder buildinfo( toLog.subobjStart("buildinfo")); appendBuildInfo(buildinfo); buildinfo.doneFast(); BSONObj o = toLog.obj(); OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); DBDirectClient c(&txn); static const char* name = "local.startup_log"; c.createCollection( name, 10 * 1024 * 1024, true ); c.insert( name, o); }
OpTime ReplSetImpl::getEarliestOpTimeWritten() const { OperationContextImpl txn; // XXX? Lock::DBRead lk(txn.lockState(), rsoplog); BSONObj o; uassert(17347, "Problem reading earliest entry from oplog", Helpers::getFirst(&txn, rsoplog, o)); return o["ts"]._opTime(); }
OpTime ReplSetImpl::getMinValid() { OperationContextImpl txn; // XXX? Lock::DBRead lk(txn.lockState(), "local.replset.minvalid"); BSONObj mv; if (Helpers::getSingleton(&txn, "local.replset.minvalid", mv)) { return mv["ts"]._opTime(); } return OpTime(); }
void run() { OperationContextImpl txn; Lock::DBWrite lk(txn.lockState(), _cappedNs); BSONObj op = updateFail(); Sync s(""); verify(!s.shouldRetry(&txn, op)); }
bool ReplSetImpl::getInitialSyncFlag() { OperationContextImpl txn; // XXX? Lock::DBRead lk (txn.lockState(), "local"); BSONObj mv; if (Helpers::getSingleton(&txn, minvalidNS, mv)) { return mv[_initialSyncFlagString].trueValue(); } return false; }
~IndexIteratorTests() { OperationContextImpl txn; Lock::DBLock lk(txn.lockState(), nsToDatabaseSubstring(_ns), MODE_X); Client::Context ctx(&txn, _ns); WriteUnitOfWork wuow(&txn); _db->dropCollection(&txn, _ns); wuow.commit(); }
void ReplSetImpl::setMinValid(BSONObj obj) { BSONObjBuilder builder; BSONObjBuilder subobj(builder.subobjStart("$set")); subobj.appendTimestamp("ts", obj["ts"].date()); subobj.done(); OperationContextImpl txn; // XXX? Lock::DBWrite lk(txn.lockState(), "local"); Helpers::putSingleton(&txn, "local.replset.minvalid", builder.obj()); }
void ReplSetImpl::loadLastOpTimeWritten(bool quiet) { OperationContextImpl txn; // XXX? Lock::DBRead lk(txn.lockState(), rsoplog); BSONObj o; if (Helpers::getLast(&txn, rsoplog, o)) { lastH = o["h"].numberLong(); lastOpTimeWritten = o["ts"]._opTime(); uassert(13290, "bad replSet oplog entry?", quiet || !lastOpTimeWritten.isNull()); } }
void NetworkInterfaceImpl::runCallbackWithGlobalExclusiveLock( const stdx::function<void (OperationContext*)>& callback) { std::ostringstream sb; sb << "repl" << boost::this_thread::get_id(); Client::initThreadIfNotAlready(sb.str().c_str()); OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); callback(&txn); }
IndexIteratorTests() { OperationContextImpl txn; Lock::DBLock lk(txn.lockState(), nsToDatabaseSubstring(_ns), MODE_X); Client::Context ctx(&txn, _ns); WriteUnitOfWork wuow(&txn); _db = ctx.db(); _coll = _db->createCollection(&txn, _ns); _catalog = _coll->getIndexCatalog(); wuow.commit(); }
void run() { OperationContextImpl txn; Lock::GlobalWrite lk(txn.lockState()); Database db( &txn, "dbtests_basictests_ownsns", NULL ); ASSERT( db.ownsNS( "dbtests_basictests_ownsns.x" ) ); ASSERT( db.ownsNS( "dbtests_basictests_ownsns.x.y" ) ); ASSERT( !db.ownsNS( "dbtests_basictests_ownsn.x.y" ) ); ASSERT( !db.ownsNS( "dbtests_basictests_ownsnsa.x.y" ) ); }
/** * Checks if this server was started without --replset but has a config in local.system.replset * (meaning that this is probably a replica set member started in stand-alone mode). * * @returns the number of documents in local.system.replset or 0 if this was started with * --replset. */ static unsigned long long checkIfReplMissingFromCommandLine() { OperationContextImpl txn; // This is helpful for the query below to work as you can't open files when readlocked Lock::GlobalWrite lk(txn.lockState()); if (!repl::replSettings.usingReplSets()) { DBDirectClient c(&txn); return c.count("local.system.replset"); } return 0; }
TEST(DBHelperTests, FindDiskLocs) { DBDirectClient client; OperationContextImpl txn; // Some unique tag we can use to make sure we're pulling back the right data OID tag = OID::gen(); client.remove( ns, BSONObj() ); int numDocsInserted = 10; for ( int i = 0; i < numDocsInserted; ++i ) { client.insert( ns, BSON( "_id" << i << "tag" << tag ) ); } long long maxSizeBytes = 1024 * 1024 * 1024; set<DiskLoc> locs; long long numDocsFound; long long estSizeBytes; { // search _id range (0, 10) Lock::DBRead lk(txn.lockState(), ns); KeyRange range( ns, BSON( "_id" << 0 ), BSON( "_id" << numDocsInserted ), BSON( "_id" << 1 ) ); Status result = Helpers::getLocsInRange( &txn, range, maxSizeBytes, &locs, &numDocsFound, &estSizeBytes ); ASSERT_EQUALS( result, Status::OK() ); ASSERT_EQUALS( numDocsFound, numDocsInserted ); ASSERT_NOT_EQUALS( estSizeBytes, 0 ); ASSERT_LESS_THAN( estSizeBytes, maxSizeBytes ); Database* db = dbHolder().get( &txn, nsToDatabase(range.ns), storageGlobalParams.dbpath); const Collection* collection = db->getCollection(&txn, ns); // Make sure all the disklocs actually correspond to the right info for ( set<DiskLoc>::const_iterator it = locs.begin(); it != locs.end(); ++it ) { const BSONObj obj = collection->docFor(*it); ASSERT_EQUALS(obj["tag"].OID(), tag); } } }
bool getInitialSyncFlag() { OperationContextImpl txn; MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock lk(txn.lockState(), "local", MODE_X); BSONObj mv; bool found = Helpers::getSingleton(&txn, minvalidNS, mv); if (found) { return mv[initialSyncFlagString].trueValue(); } return false; } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(&txn, "getInitialSyncFlags", minvalidNS); }
void FSyncLockThread::doRealWork() { SimpleMutex::scoped_lock lkf(filesLockedFsync); OperationContextImpl txn; // XXX? Lock::GlobalWrite global(txn.lockState()); // No WriteUnitOfWork needed SimpleMutex::scoped_lock lk(fsyncCmd.m); verify( ! fsyncCmd.locked ); // impossible to get here if locked is true try { getDur().syncDataAndTruncateJournal(&txn); } catch( std::exception& e ) { error() << "error doing syncDataAndTruncateJournal: " << e.what() << endl; fsyncCmd.err = e.what(); fsyncCmd._threadSync.notify_one(); fsyncCmd.locked = false; return; } global.downgrade(); try { StorageEngine* storageEngine = getGlobalEnvironment()->getGlobalStorageEngine(); storageEngine->flushAllFiles(true); } catch( std::exception& e ) { error() << "error doing flushAll: " << e.what() << endl; fsyncCmd.err = e.what(); fsyncCmd._threadSync.notify_one(); fsyncCmd.locked = false; return; } verify( ! fsyncCmd.locked ); fsyncCmd.locked = true; fsyncCmd._threadSync.notify_one(); while ( ! fsyncCmd.pendingUnlock ) { fsyncCmd._unlockSync.wait(fsyncCmd.m); } fsyncCmd.pendingUnlock = false; fsyncCmd.locked = false; fsyncCmd.err = "unlocked"; fsyncCmd._unlockSync.notify_one(); }
void IndexBuilder::run() { Client::initThread(name().c_str()); LOG(2) << "IndexBuilder building index " << _index; OperationContextImpl txn; txn.lockState()->setIsBatchWriter(true); AuthorizationSession::get(txn.getClient())->grantInternalAuthorization(); txn.getCurOp()->reset(HostAndPort(), dbInsert); NamespaceString ns(_index["ns"].String()); ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock dlk(txn.lockState(), ns.db(), MODE_X); OldClientContext ctx(&txn, ns.getSystemIndexesCollection()); Database* db = dbHolder().get(&txn, ns.db().toString()); Status status = _build(&txn, db, true, &dlk); if ( !status.isOK() ) { error() << "IndexBuilder could not build index: " << status.toString(); fassert(28555, ErrorCodes::isInterruption(status.code())); } }
void ServiceContextMongoDTest::_dropAllDBs() { OperationContextImpl txn; dropAllDatabasesExceptLocal(&txn); ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite lk(txn.lockState()); AutoGetDb autoDBLocal(&txn, "local", MODE_X); const auto localDB = autoDBLocal.getDb(); if (localDB) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { // Do not wrap in a WriteUnitOfWork until SERVER-17103 is addressed. autoDBLocal.getDb()->dropDatabase(&txn, localDB); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(&txn, "_dropAllDBs", "local"); } }
/** write an op to the oplog that is already built. todo : make _logOpRS() call this so we don't repeat ourself? */ void _logOpObjRS(const BSONObj& op) { OperationContextImpl txn; Lock::DBWrite lk(txn.lockState(), "local"); const OpTime ts = op["ts"]._opTime(); long long h = op["h"].numberLong(); { if ( localOplogRSCollection == 0 ) { Client::Context ctx(rsoplog, storageGlobalParams.dbpath); localDB = ctx.db(); verify( localDB ); localOplogRSCollection = localDB->getCollection( &txn, rsoplog ); massert(13389, "local.oplog.rs missing. did you drop it? if so restart server", localOplogRSCollection); } Client::Context ctx(rsoplog, localDB); checkOplogInsert( localOplogRSCollection->insertDocument( &txn, op, false ) ); /* todo: now() has code to handle clock skew. but if the skew server to server is large it will get unhappy. this code (or code in now() maybe) should be improved. */ if( theReplSet ) { if( !(theReplSet->lastOpTimeWritten<ts) ) { log() << "replication oplog stream went back in time. previous timestamp: " << theReplSet->lastOpTimeWritten << " newest timestamp: " << ts << ". attempting to sync directly from primary." << endl; std::string errmsg; BSONObjBuilder result; if (!theReplSet->forceSyncFrom(theReplSet->box.getPrimary()->fullName(), errmsg, result)) { log() << "Can't sync from primary: " << errmsg << endl; } } theReplSet->lastOpTimeWritten = ts; theReplSet->lastH = h; ctx.getClient()->setLastOp( ts ); BackgroundSync::notify(); } } setNewOptime(ts); }
void run() { const string dbName = "rollback_drop_collection"; const string droppedName = dbName + ".dropped"; const string rolledBackName = dbName + ".rolled_back"; OperationContextImpl txn; ScopedTransaction transaction(&txn, MODE_IX); Lock::DBLock lk(txn.lockState(), dbName, MODE_X); bool justCreated; Database* db = dbHolder().openDb(&txn, dbName, &justCreated); ASSERT(justCreated); { WriteUnitOfWork wunit(&txn); ASSERT_FALSE(db->getCollection(droppedName)); Collection* droppedColl; droppedColl = db->createCollection(&txn, droppedName); ASSERT_EQUALS(db->getCollection(droppedName), droppedColl); db->dropCollection(&txn, droppedName); wunit.commit(); } // Should have been really dropped ASSERT_FALSE(db->getCollection(droppedName)); { WriteUnitOfWork wunit(&txn); ASSERT_FALSE(db->getCollection(rolledBackName)); Collection* rolledBackColl = db->createCollection(&txn, rolledBackName); wunit.commit(); ASSERT_EQUALS(db->getCollection(rolledBackName), rolledBackColl); db->dropCollection(&txn, rolledBackName); // not committing so dropping should be rolled back } // The rolledBackCollection dropping should have been rolled back. // Original Collection pointers are no longer valid. ASSERT(db->getCollection(rolledBackName)); // The droppedCollection should not have been restored by the rollback. ASSERT_FALSE(db->getCollection(droppedName)); }
static void logStartup() { BSONObjBuilder toLog; stringstream id; id << getHostNameCached() << "-" << jsTime().asInt64(); toLog.append("_id", id.str()); toLog.append("hostname", getHostNameCached()); toLog.appendTimeT("startTime", time(0)); toLog.append("startTimeLocal", dateToCtimeString(Date_t::now())); toLog.append("cmdLine", serverGlobalParams.parsedOpts); toLog.append("pid", ProcessId::getCurrent().asLongLong()); BSONObjBuilder buildinfo(toLog.subobjStart("buildinfo")); appendBuildInfo(buildinfo); appendStorageEngineList(&buildinfo); buildinfo.doneFast(); BSONObj o = toLog.obj(); OperationContextImpl txn; ScopedTransaction transaction(&txn, MODE_X); Lock::GlobalWrite lk(txn.lockState()); AutoGetOrCreateDb autoDb(&txn, "local", mongo::MODE_X); Database* db = autoDb.getDb(); const std::string ns = "local.startup_log"; Collection* collection = db->getCollection(ns); WriteUnitOfWork wunit(&txn); if (!collection) { BSONObj options = BSON("capped" << true << "size" << 10 * 1024 * 1024); bool shouldReplicateWrites = txn.writesAreReplicated(); txn.setReplicatedWrites(false); ON_BLOCK_EXIT(&OperationContext::setReplicatedWrites, &txn, shouldReplicateWrites); uassertStatusOK(userCreateNS(&txn, db, ns, options)); collection = db->getCollection(ns); } invariant(collection); uassertStatusOK(collection->insertDocument(&txn, o, false).getStatus()); wunit.commit(); }
void SyncTail::applyOpsToOplog(std::deque<BSONObj>* ops) { { OperationContextImpl txn; // XXX? Lock::DBWrite lk(txn.lockState(), "local"); while (!ops->empty()) { const BSONObj& op = ops->front(); // this updates theReplSet->lastOpTimeWritten _logOpObjRS(op); ops->pop_front(); } } if (BackgroundSync::get()->isAssumingPrimary()) { LOG(1) << "notifying BackgroundSync"; } // Update write concern on primary BackgroundSync::notify(); }
OpTime SyncTail::applyOpsToOplog(std::deque<BSONObj>* ops) { OpTime lastOpTime; { OperationContextImpl txn; // XXX? Lock::DBLock lk(txn.lockState(), "local", MODE_X); WriteUnitOfWork wunit(&txn); while (!ops->empty()) { const BSONObj& op = ops->front(); // this updates lastOpTimeApplied lastOpTime = _logOpObjRS(&txn, op); ops->pop_front(); } wunit.commit(); } // Update write concern on primary BackgroundSync::get()->notify(); return lastOpTime; }
void pretouchN(vector<BSONObj>& v, unsigned a, unsigned b) { Client* c = currentClient.get(); if (c == 0) { Client::initThread("pretouchN"); c = &cc(); } OperationContextImpl txn; // XXX ScopedTransaction transaction(&txn, MODE_S); Lock::GlobalRead lk(txn.lockState()); for (unsigned i = a; i <= b; i++) { const BSONObj& op = v[i]; const char* which = "o"; const char* opType = op.getStringField("op"); if (*opType == 'i') ; else if (*opType == 'u') which = "o2"; else continue; /* todo : other operations */ try { BSONObj o = op.getObjectField(which); BSONElement _id; if (o.getObjectID(_id)) { const char* ns = op.getStringField("ns"); BSONObjBuilder b; b.append(_id); BSONObj result; Client::Context ctx(&txn, ns); if (Helpers::findById(&txn, ctx.db(), ns, b.done(), result)) _dummy_z += result.objsize(); // touch } } catch (DBException& e) { log() << "ignoring assertion in pretouchN() " << a << ' ' << b << ' ' << i << ' ' << e.toString() << endl; } } }
void run() { for ( int i = 0; i < 10; ++i ) { client.insert( ns, BSON( "_id" << i ) ); } { // Remove _id range [_min, _max). OperationContextImpl txn; Lock::DBWrite lk(txn.lockState(), ns); Client::Context ctx( ns ); KeyRange range( ns, BSON( "_id" << _min ), BSON( "_id" << _max ), BSON( "_id" << 1 ) ); Helpers::removeRange( &txn, range ); } // Check that the expected documents remain. ASSERT_EQUALS( expected(), docs() ); }