StatusWith<std::string> KVCatalog::newOrphanedIdent(OperationContext* opCtx, std::string ident) { // The collection will be named local.orphan.xxxxx. std::string identNs = ident; std::replace(identNs.begin(), identNs.end(), '-', '_'); std::string ns = NamespaceString(NamespaceString::kOrphanCollectionDb, NamespaceString::kOrphanCollectionPrefix + identNs) .ns(); stdx::lock_guard<stdx::mutex> lk(_identsLock); Entry& old = _idents[ns]; if (!old.ident.empty()) { return Status(ErrorCodes::NamespaceExists, str::stream() << ns << " already exists in the catalog"); } opCtx->recoveryUnit()->registerChange(new AddIdentChange(this, ns)); // Generate a new UUID for the orphaned collection. CollectionOptions optionsWithUUID; optionsWithUUID.uuid.emplace(CollectionUUID::gen()); BSONObj obj; { BSONObjBuilder b; b.append("ns", ns); b.append("ident", ident); BSONCollectionCatalogEntry::MetaData md; md.ns = ns; // Default options with newly generated UUID. md.options = optionsWithUUID; // Not Prefixed. md.prefix = KVPrefix::kNotPrefixed; b.append("md", md.toBSON()); obj = b.obj(); } StatusWith<RecordId> res = _rs->insertRecord(opCtx, obj.objdata(), obj.objsize(), Timestamp()); if (!res.isOK()) return res.getStatus(); old = Entry(ident, res.getValue()); LOG(1) << "stored meta data for orphaned collection " << ns << " @ " << res.getValue(); return StatusWith<std::string>(std::move(ns)); }
Status KVCatalog::newCollection(OperationContext* opCtx, StringData ns, const CollectionOptions& options) { invariant(opCtx->lockState() == NULL || opCtx->lockState()->isDbLockedForMode(nsToDatabaseSubstring(ns), MODE_X)); std::unique_ptr<Lock::ResourceLock> rLk; if (!_isRsThreadSafe && opCtx->lockState()) { rLk.reset(new Lock::ResourceLock(opCtx->lockState(), resourceIdCatalogMetadata, MODE_X)); } const string ident = _newUniqueIdent(ns, "collection"); stdx::lock_guard<stdx::mutex> lk(_identsLock); Entry& old = _idents[ns.toString()]; if (!old.ident.empty()) { return Status(ErrorCodes::NamespaceExists, "collection already exists"); } opCtx->recoveryUnit()->registerChange(new AddIdentChange(this, ns)); BSONObj obj; { BSONObjBuilder b; b.append("ns", ns); b.append("ident", ident); BSONCollectionCatalogEntry::MetaData md; md.ns = ns.toString(); md.options = options; b.append("md", md.toBSON()); obj = b.obj(); } StatusWith<RecordId> res = _rs->insertRecord(opCtx, obj.objdata(), obj.objsize(), false); if (!res.isOK()) return res.getStatus(); old = Entry(ident, res.getValue()); LOG(1) << "stored meta data for " << ns << " @ " << res.getValue(); return Status::OK(); }
void ReplicationCoordinatorImpl::_handleHeartbeatResponseAction( const HeartbeatResponseAction& action, const StatusWith<ReplSetHeartbeatResponse>& responseStatus) { switch (action.getAction()) { case HeartbeatResponseAction::NoAction: // Update the cached member state if different than the current topology member state if (_memberState != _topCoord->getMemberState()) { stdx::unique_lock<stdx::mutex> lk(_mutex); const PostMemberStateUpdateAction postUpdateAction = _updateMemberStateFromTopologyCoordinator_inlock(); lk.unlock(); _performPostMemberStateUpdateAction(postUpdateAction); } break; case HeartbeatResponseAction::Reconfig: invariant(responseStatus.isOK()); _scheduleHeartbeatReconfig(responseStatus.getValue().getConfig()); break; case HeartbeatResponseAction::StartElection: if (isV1ElectionProtocol()) { _startElectSelfV1(); } else { _startElectSelf(); } break; case HeartbeatResponseAction::StepDownSelf: invariant(action.getPrimaryConfigIndex() == _selfIndex); log() << "Stepping down from primary in response to heartbeat"; _stepDownStart(); break; case HeartbeatResponseAction::StepDownRemotePrimary: { invariant(action.getPrimaryConfigIndex() != _selfIndex); _requestRemotePrimaryStepdown( _rsConfig.getMemberAt(action.getPrimaryConfigIndex()).getHostAndPort()); break; } default: severe() << "Illegal heartbeat response action code " << int(action.getAction()); invariant(false); } }
TEST_F(WiredTigerRecoveryUnitTestFixture, CreateAndCheckForCachePressure) { int time = 1; // Reconfigure the size of the cache to be very small so that building cache pressure is fast. WiredTigerKVEngine* engine = harnessHelper->getEngine(); std::string cacheSizeReconfig = "cache_size=1MB"; ASSERT_EQ(engine->reconfigure(cacheSizeReconfig.c_str()), 0); OperationContext* opCtx = clientAndCtx1.second.get(); std::unique_ptr<RecordStore> rs(harnessHelper->createRecordStore(opCtx, "a.b")); // Insert one document so that we can then update it in a loop to create cache pressure. // Note: inserts will not create cache pressure. WriteUnitOfWork wu(opCtx); ASSERT_OK(ru1->setTimestamp(Timestamp(time++))); std::string str = str::stream() << "foobarbaz"; StatusWith<RecordId> ress = rs->insertRecord(opCtx, str.c_str(), str.size() + 1, Timestamp()); ASSERT_OK(ress.getStatus()); auto recordId = ress.getValue(); wu.commit(); for (int j = 0; j < 1000; ++j) { // Once we hit the cache pressure threshold, i.e. have successfully created cache pressure // that is detectable, we are done. if (engine->isCacheUnderPressure(opCtx)) { invariant(j != 0); break; } try { WriteUnitOfWork wuow(opCtx); ASSERT_OK(ru1->setTimestamp(Timestamp(time++))); std::string s = str::stream() << "abcbcdcdedefefgfghghihijijkjklklmlmnmnomopopqpqrqrsrststutuv" << j; ASSERT_OK(rs->updateRecord(opCtx, recordId, s.c_str(), s.size() + 1)); wuow.commit(); } catch (const DBException& ex) { invariant(ex.toStatus().code() == ErrorCodes::WriteConflict); } } }
Status MultiIndexBlock::init(std::vector<BSONObj>& indexSpecs) { for ( size_t i = 0; i < indexSpecs.size(); i++ ) { BSONObj info = indexSpecs[i]; string pluginName = IndexNames::findPluginName( info["key"].Obj() ); if ( pluginName.size() ) { Status s = _collection->getIndexCatalog()->_upgradeDatabaseMinorVersionIfNeeded(_txn, pluginName); if ( !s.isOK() ) return s; } } for ( size_t i = 0; i < indexSpecs.size(); i++ ) { BSONObj info = indexSpecs[i]; StatusWith<BSONObj> statusWithInfo = _collection->getIndexCatalog()->prepareSpecForCreate( info ); Status status = statusWithInfo.getStatus(); if ( !status.isOK() ) return status; info = statusWithInfo.getValue(); IndexState state; state.block = new IndexCatalog::IndexBuildBlock(_txn, _collection, info); status = state.block->init(); if ( !status.isOK() ) return status; state.real = state.block->getEntry()->accessMethod(); status = state.real->initializeAsEmpty(_txn); if ( !status.isOK() ) return status; state.bulk = state.real->initiateBulk(_txn); _states.push_back( state ); } return Status::OK(); }
StatusWith<DiskLoc> RecordStoreV1Base::updateRecord( OperationContext* txn, const DiskLoc& oldLocation, const char* data, int dataSize, bool enforceQuota, UpdateMoveNotifier* notifier ) { Record* oldRecord = recordFor( oldLocation ); if ( oldRecord->netLength() >= dataSize ) { // we fit _paddingFits( txn ); memcpy( txn->recoveryUnit()->writingPtr( oldRecord->data(), dataSize ), data, dataSize ); return StatusWith<DiskLoc>( oldLocation ); } if ( isCapped() ) return StatusWith<DiskLoc>( ErrorCodes::InternalError, "failing update: objects in a capped ns cannot grow", 10003 ); // we have to move _paddingTooSmall( txn ); StatusWith<DiskLoc> newLocation = _insertRecord( txn, data, dataSize, enforceQuota ); if ( !newLocation.isOK() ) return newLocation; // insert worked, so we delete old record if ( notifier ) { Status moveStatus = notifier->recordStoreGoingToMove( txn, oldLocation, oldRecord->data(), oldRecord->netLength() ); if ( !moveStatus.isOK() ) return StatusWith<DiskLoc>( moveStatus ); } deleteRecord( txn, oldLocation ); return newLocation; }
std::unique_ptr<SortedDataInterface> newSortedDataInterface(bool unique) final { std::string ns = "test.wt"; OperationContextNoop txn(newRecoveryUnit().release()); BSONObj spec = BSON("key" << BSON("a" << 1) << "name" << "testIndex" << "ns" << ns); IndexDescriptor desc(NULL, "", spec); StatusWith<std::string> result = TerichDbIndex::generateCreateString(kTerichDbEngineName, "", "", desc); ASSERT_OK(result.getStatus()); string uri = "table:" + ns; invariantTerichDbOK(TerichDbIndex::Create(&txn, uri, result.getValue())); if (unique) return stdx::make_unique<TerichDbIndexUnique>(&txn, uri, &desc); return stdx::make_unique<TerichDbIndexStandard>(&txn, uri, &desc); }
/** * Perform a single insert into a collection. Requires the insert be preprocessed and the * collection already has been created. * * Might fault or error, otherwise populates the result. */ static void singleInsert( OperationContext* txn, const BSONObj& docToInsert, Collection* collection, WriteOpResult* result ) { const string& insertNS = collection->ns().ns(); txn->lockState()->assertWriteLocked( insertNS ); WriteUnitOfWork wunit(txn); StatusWith<DiskLoc> status = collection->insertDocument( txn, docToInsert, true ); if ( !status.isOK() ) { result->setError(toWriteError(status.getStatus())); } else { repl::logOp( txn, "i", insertNS.c_str(), docToInsert ); result->getStats().n = 1; wunit.commit(); } }
virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { string coll = cmdObj[ "godinsert" ].valuestrsafe(); log() << "test only command godinsert invoked coll:" << coll << endl; uassert( 13049, "godinsert must specify a collection", !coll.empty() ); string ns = dbname + "." + coll; BSONObj obj = cmdObj[ "obj" ].embeddedObjectUserCheck(); Lock::DBWrite lk(ns); Client::Context ctx( ns ); Database* db = ctx.db(); Collection* collection = db->getCollection( ns ); if ( !collection ) { collection = db->createCollection( ns ); if ( !collection ) { errmsg = "could not create collection"; return false; } } StatusWith<DiskLoc> res = collection->insertDocument( obj, false ); return appendCommandStatus( result, res.getStatus() ); }
BtreeLogicTestHelper<OnDiskFormat>::BtreeLogicTestHelper(const BSONObj& order) : recordStore("TestRecordStore"), btree(&headManager, &recordStore, &cursorRegistry, Ordering::make(order), "TestIndex", /*isUnique*/ false) { static const string randomData("RandomStuff"); // Generate a valid record location for a "fake" record, which we will repeatedly use // thoughout the tests. OperationContextNoop opCtx; StatusWith<RecordId> s = recordStore.insertRecord(&opCtx, randomData.c_str(), randomData.length(), false); ASSERT_TRUE(s.isOK()); ASSERT_EQUALS(1, recordStore.numRecords(NULL)); dummyDiskLoc = DiskLoc::fromRecordId(s.getValue()); }
TEST( RecordStoreTestHarness, Simple1InsertDocWroter ) { scoped_ptr<HarnessHelper> harnessHelper( newHarnessHelper() ); scoped_ptr<RecordStore> rs( harnessHelper->newNonCappedRecordStore() ); DiskLoc loc1; { scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); { WriteUnitOfWork uow( opCtx.get() ); DummyDocWriter dw; StatusWith<DiskLoc> res = rs->insertRecord( opCtx.get(), &dw, false ); ASSERT_OK( res.getStatus() ); loc1 = res.getValue(); uow.commit(); } ASSERT_EQUALS( string("eliot"), rs->dataFor( opCtx.get(), loc1 ).data() ); } }
void ReplicationCoordinatorImpl::_startVoteRequester(long long newTerm) { invariant(_voteRequester); invariant(!_electionWinnerDeclarer); LoseElectionGuardV1 lossGuard(this); _voteRequester.reset(new VoteRequester); StatusWith<ReplicationExecutor::EventHandle> nextPhaseEvh = _voteRequester->start( &_replExecutor, _rsConfig, _rsConfig.getMemberAt(_selfIndex).getId(), _topCoord->getTerm(), false, getMyLastOptime(), stdx::bind(&ReplicationCoordinatorImpl::_onVoteRequestComplete, this, newTerm)); if (nextPhaseEvh.getStatus() == ErrorCodes::ShutdownInProgress) { return; } fassert(28643, nextPhaseEvh.getStatus()); lossGuard.dismiss(); }
// Goes over the request and preprocesses normalized versions of all the inserts in the request static void normalizeInserts( const BatchedCommandRequest& request, vector<StatusWith<BSONObj> >* normalizedInserts, vector<PregeneratedKeys>* pregen ) { normalizedInserts->reserve(request.sizeWriteOps()); for ( size_t i = 0; i < request.sizeWriteOps(); ++i ) { BSONObj insertDoc = request.getInsertRequest()->getDocumentsAt( i ); StatusWith<BSONObj> normalInsert = fixDocumentForInsert( insertDoc ); normalizedInserts->push_back( normalInsert ); if ( request.getOrdered() && !normalInsert.isOK() ) break; if ( !normalInsert.getValue().isEmpty() ) insertDoc = normalInsert.getValue(); pregen->push_back( PregeneratedKeys() ); GeneratorHolder::getInstance()->prepare( request.getTargetingNS(), insertDoc, &pregen->back() ); } }
StatusWith<DiskLoc> Collection::insertDocument( OperationContext* txn, const BSONObj& doc, MultiIndexBlock& indexBlock ) { StatusWith<DiskLoc> loc = _recordStore->insertRecord( txn, doc.objdata(), doc.objsize(), 0 ); if ( !loc.isOK() ) return loc; InsertDeleteOptions indexOptions; indexOptions.logIfError = false; indexOptions.dupsAllowed = true; // in repair we should be doing no checking Status status = indexBlock.insert( doc, loc.getValue(), indexOptions ); if ( !status.isOK() ) return StatusWith<DiskLoc>( status ); return loc; }
StatusWith<ReplicationExecutor::CallbackHandle> ReplicationExecutor::scheduleWorkWithGlobalExclusiveLock( const CallbackFn& work) { boost::lock_guard<boost::mutex> lk(_mutex); StatusWith<CallbackHandle> handle = enqueueWork_inlock(&_exclusiveLockInProgressQueue, work); if (handle.isOK()) { const stdx::function<void (OperationContext*)> doOp = stdx::bind( &ReplicationExecutor::doOperationWithGlobalExclusiveLock, this, stdx::placeholders::_1, handle.getValue()); _dblockWorkers.schedule( makeNoExcept(stdx::bind( &NetworkInterface::runCallbackWithGlobalExclusiveLock, _networkInterface.get(), doOp))); } return handle; }
StatusWith<RecordId> RecordStoreV1Base::insertRecord(OperationContext* txn, const DocWriter* doc, bool enforceQuota) { int docSize = doc->documentSize(); if (docSize < 4) { return StatusWith<RecordId>(ErrorCodes::InvalidLength, "record has to be >= 4 bytes"); } const int lenWHdr = docSize + MmapV1RecordHeader::HeaderSize; if (lenWHdr > MaxAllowedAllocation) { return StatusWith<RecordId>(ErrorCodes::InvalidLength, "record has to be <= 16.5MB"); } const int lenToAlloc = (doc->addPadding() && shouldPadInserts()) ? quantizeAllocationSpace(lenWHdr) : lenWHdr; StatusWith<DiskLoc> loc = allocRecord(txn, lenToAlloc, enforceQuota); if (!loc.isOK()) return StatusWith<RecordId>(loc.getStatus()); MmapV1RecordHeader* r = recordFor(loc.getValue()); fassert(17319, r->lengthWithHeaders() >= lenWHdr); r = reinterpret_cast<MmapV1RecordHeader*>(txn->recoveryUnit()->writingPtr(r, lenWHdr)); doc->writeDocument(r->data()); _addRecordToRecListInExtent(txn, r, loc.getValue()); _details->incrementStats(txn, r->netLength(), 1); return StatusWith<RecordId>(loc.getValue().toRecordId()); }
StatusWith<SettingsType> CatalogManagerReplicaSet::getGlobalSettings(OperationContext* txn, const string& key) { const auto configShard = grid.shardRegistry()->getShard(txn, "config"); const auto readHost = configShard->getTargeter()->findHost(kConfigReadSelector); if (!readHost.isOK()) { return readHost.getStatus(); } auto findStatus = _exhaustiveFindOnConfig(readHost.getValue(), NamespaceString(SettingsType::ConfigNS), BSON(SettingsType::key(key)), BSONObj(), 1); if (!findStatus.isOK()) { return findStatus.getStatus(); } const auto& docs = findStatus.getValue().value; if (docs.empty()) { return {ErrorCodes::NoMatchingDocument, str::stream() << "can't find settings document with key: " << key}; } BSONObj settingsDoc = docs.front(); StatusWith<SettingsType> settingsResult = SettingsType::fromBSON(settingsDoc); if (!settingsResult.isOK()) { return {ErrorCodes::FailedToParse, str::stream() << "error while parsing settings document: " << settingsDoc << " : " << settingsResult.getStatus().toString()}; } const SettingsType& settings = settingsResult.getValue(); Status validationStatus = settings.validate(); if (!validationStatus.isOK()) { return validationStatus; } return settingsResult; }
Status EphemeralForTestRecordStore::insertRecordsWithDocWriter(OperationContext* opCtx, const DocWriter* const* docs, const Timestamp*, size_t nDocs, RecordId* idsOut) { stdx::lock_guard<stdx::recursive_mutex> lock(_data->recordsMutex); for (size_t i = 0; i < nDocs; i++) { const int len = docs[i]->documentSize(); if (_isCapped && len > _cappedMaxSize) { // We use dataSize for capped rollover and we don't want to delete everything if we // know this won't fit. return Status(ErrorCodes::BadValue, "object to insert exceeds cappedMaxSize"); } EphemeralForTestRecord rec(len); docs[i]->writeDocument(rec.data.get()); RecordId loc; if (_data->isOplog) { StatusWith<RecordId> status = extractAndCheckLocForOplog(rec.data.get(), len); if (!status.isOK()) return status.getStatus(); loc = status.getValue(); } else { loc = allocateLoc(); } opCtx->recoveryUnit()->registerChange(new InsertChange(opCtx, _data, loc)); _data->dataSize += len; _data->records[loc] = rec; cappedDeleteAsNeeded_inlock(opCtx); if (idsOut) idsOut[i] = loc; } return Status::OK(); }
void ReplicationCoordinatorImpl::_heartbeatReconfigFinish( const ReplicationExecutor::CallbackData& cbData, const ReplicaSetConfig& newConfig, StatusWith<int> myIndex) { boost::lock_guard<boost::mutex> lk(_mutex); invariant(_rsConfigState == kConfigHBReconfiguring); invariant(!_rsConfig.isInitialized() || _rsConfig.getConfigVersion() < newConfig.getConfigVersion()); if (!myIndex.isOK()) { switch (myIndex.getStatus().code()) { case ErrorCodes::NoSuchKey: log() << "Cannot find self in new replica set configuration; I must be removed; " << myIndex.getStatus(); break; case ErrorCodes::DuplicateKey: error() << "Several entries in new config represent this node; " "Removing self until an acceptable configuration arrives; " << myIndex.getStatus(); break; default: error() << "Could not validate configuration received from remote node; " "Removing self until an acceptable configuration arrives; " << myIndex.getStatus(); break; } myIndex = StatusWith<int>(-1); } _setCurrentRSConfig_inlock(newConfig, myIndex.getValue()); }
StatusWith<RecordId> RecordStoreV1Base::_insertRecord(OperationContext* txn, const char* data, int len, bool enforceQuota) { const int lenWHdr = len + MmapV1RecordHeader::HeaderSize; const int lenToAlloc = shouldPadInserts() ? quantizeAllocationSpace(lenWHdr) : lenWHdr; fassert(17208, lenToAlloc >= lenWHdr); StatusWith<DiskLoc> loc = allocRecord(txn, lenToAlloc, enforceQuota); if (!loc.isOK()) return StatusWith<RecordId>(loc.getStatus()); MmapV1RecordHeader* r = recordFor(loc.getValue()); fassert(17210, r->lengthWithHeaders() >= lenWHdr); // copy the data r = reinterpret_cast<MmapV1RecordHeader*>(txn->recoveryUnit()->writingPtr(r, lenWHdr)); memcpy(r->data(), data, len); _addRecordToRecListInExtent(txn, r, loc.getValue()); _details->incrementStats(txn, r->netLength(), 1); return StatusWith<RecordId>(loc.getValue().toRecordId()); }
// Insert multiple records, and verify that calling touch() on a nonempty collection // returns an OK status, even when NULL is passed in for the stats output. TEST( RecordStoreTestHarness, TouchNonEmptyWithNullStats ) { scoped_ptr<HarnessHelper> harnessHelper( newHarnessHelper() ); scoped_ptr<RecordStore> rs( harnessHelper->newNonCappedRecordStore() ); { scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); ASSERT_EQUALS( 0, rs->numRecords( opCtx.get() ) ); } int nToInsert = 10; for ( int i = 0; i < nToInsert; i++ ) { scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); { stringstream ss; ss << "record " << i; string data = ss.str(); WriteUnitOfWork uow( opCtx.get() ); StatusWith<DiskLoc> res = rs->insertRecord( opCtx.get(), data.c_str(), data.size() + 1, false ); ASSERT_OK( res.getStatus() ); uow.commit(); } } { scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); ASSERT_EQUALS( nToInsert, rs->numRecords( opCtx.get() ) ); } { scoped_ptr<OperationContext> opCtx( harnessHelper->newOperationContext() ); // XXX does not verify the collection was loaded into cache // (even if supported by storage engine) Status status = rs->touch( opCtx.get(), NULL /* stats output */ ); ASSERT( status.isOK() || status.code() == ErrorCodes::CommandNotSupported ); } }
Status CollectionCloner::_parseCursorResponse(BSONObj response, std::vector<CursorResponse>* cursors, EstablishCursorsCommand cursorCommand) { switch (cursorCommand) { case Find: { StatusWith<CursorResponse> findResponse = CursorResponse::parseFromBSON(response); if (!findResponse.isOK()) { return findResponse.getStatus().withContext( str::stream() << "Error parsing the 'find' query against collection '" << _sourceNss.ns() << "'"); } cursors->push_back(std::move(findResponse.getValue())); break; } case ParallelCollScan: { auto cursorElements = _parseParallelCollectionScanResponse(response); if (!cursorElements.isOK()) { return cursorElements.getStatus(); } std::vector<BSONElement> cursorsArray; cursorsArray = cursorElements.getValue(); // Parse each BSONElement into a 'CursorResponse' object. for (BSONElement cursor : cursorsArray) { if (!cursor.isABSONObj()) { Status errorStatus( ErrorCodes::FailedToParse, "The 'cursor' field in the list of cursor responses is not a " "valid BSON Object"); return errorStatus; } const BSONObj cursorObj = cursor.Obj().getOwned(); StatusWith<CursorResponse> parallelCollScanResponse = CursorResponse::parseFromBSON(cursorObj); if (!parallelCollScanResponse.isOK()) { return parallelCollScanResponse.getStatus(); } cursors->push_back(std::move(parallelCollScanResponse.getValue())); } break; } default: { Status errorStatus( ErrorCodes::FailedToParse, "The command used to establish the collection cloner cursors is not valid."); return errorStatus; } } return Status::OK(); }
TEST( RocksRecordStoreTest, Delete1 ) { unittest::TempDir td( _rocksRecordStoreTestDir ); scoped_ptr<rocksdb::DB> db( getDB( td.path() ) ); { RocksRecordStore rs( "foo.bar", db.get(), db->DefaultColumnFamily(), db->DefaultColumnFamily() ); string s = "eliot was here"; DiskLoc loc; { MyOperationContext opCtx( db.get() ); { WriteUnitOfWork uow( opCtx.recoveryUnit() ); StatusWith<DiskLoc> res = rs.insertRecord(&opCtx, s.c_str(), s.size() + 1, -1 ); ASSERT_OK( res.getStatus() ); loc = res.getValue(); } ASSERT_EQUALS( s, rs.dataFor( loc ).data() ); ASSERT_EQUALS( 1, rs.numRecords() ); ASSERT_EQUALS( static_cast<long long> ( s.length() + 1 ), rs.dataSize() ); } ASSERT( rs.dataFor( loc ).data() != NULL ); { MyOperationContext opCtx( db.get() ); WriteUnitOfWork uow( opCtx.recoveryUnit() ); rs.deleteRecord( &opCtx, loc ); ASSERT_EQUALS( 0, rs.numRecords() ); ASSERT_EQUALS( 0, rs.dataSize() ); } } }
StatusWith<ReplicationExecutor::CallbackHandle> ReplicationExecutor::scheduleRemoteCommand( const RemoteCommandRequest& request, const RemoteCommandCallbackFn& cb) { RemoteCommandRequest scheduledRequest = request; if (request.timeout == kNoTimeout) { scheduledRequest.expirationDate = kNoExpirationDate; } else { scheduledRequest.expirationDate = _networkInterface->now() + scheduledRequest.timeout.total_milliseconds(); } boost::lock_guard<boost::mutex> lk(_mutex); StatusWith<CallbackHandle> handle = enqueueWork_inlock( &_networkInProgressQueue, stdx::bind(remoteCommandFailedEarly, stdx::placeholders::_1, cb, scheduledRequest)); if (handle.isOK()) { handle.getValue()._iter->isNetworkOperation = true; _networkInterface->startCommand( handle.getValue(), scheduledRequest, stdx::bind(&ReplicationExecutor::_finishRemoteCommand, this, scheduledRequest, stdx::placeholders::_1, handle.getValue(), handle.getValue()._iter->generation, cb)); } return handle; }
Status ReplicationCoordinatorExternalStateImpl::storeLocalLastVoteDocument( OperationContext* opCtx, const LastVote& lastVote) { BSONObj lastVoteObj = lastVote.toBSON(); try { Status status = writeConflictRetry(opCtx, "save replica set lastVote", lastVoteCollectionName, [&] { Lock::DBLock dbWriteLock(opCtx, lastVoteDatabaseName, MODE_X); // If there is no last vote document, we want to store one. Otherwise, we only want // to replace it if the new last vote document would have a higher term. We both // check the term of the current last vote document and insert the new document // under the DBLock to synchronize the two operations. BSONObj result; bool exists = Helpers::getSingleton(opCtx, lastVoteCollectionName, result); if (!exists) { Helpers::putSingleton(opCtx, lastVoteCollectionName, lastVoteObj); } else { StatusWith<LastVote> oldLastVoteDoc = LastVote::readFromLastVote(result); if (!oldLastVoteDoc.isOK()) { return oldLastVoteDoc.getStatus(); } if (lastVote.getTerm() > oldLastVoteDoc.getValue().getTerm()) { Helpers::putSingleton(opCtx, lastVoteCollectionName, lastVoteObj); } } return Status::OK(); }); if (!status.isOK()) { return status; } opCtx->recoveryUnit()->waitUntilDurable(); return Status::OK(); } catch (const DBException& ex) { return ex.toStatus(); } }
void ReplicationCoordinatorImpl::_startVoteRequester(long long newTerm) { invariant(_voteRequester); LoseElectionGuardV1 lossGuard(this); LockGuard lk(_topoMutex); const auto lastOpTime = _isDurableStorageEngine() ? getMyLastDurableOpTime() : getMyLastAppliedOpTime(); _voteRequester.reset(new VoteRequester); StatusWith<ReplicationExecutor::EventHandle> nextPhaseEvh = _voteRequester->start( &_replExecutor, _rsConfig, _selfIndex, _topCoord->getTerm(), false, lastOpTime); if (nextPhaseEvh.getStatus() == ErrorCodes::ShutdownInProgress) { return; } fassert(28643, nextPhaseEvh.getStatus()); _replExecutor.onEvent( nextPhaseEvh.getValue(), stdx::bind(&ReplicationCoordinatorImpl::_onVoteRequestComplete, this, newTerm)); lossGuard.dismiss(); }
bool WriteCmd::run(OperationContext* txn, const string& dbName, BSONObj& cmdObj, int options, string& errMsg, BSONObjBuilder& result) { // Can't be run on secondaries. dassert(txn->writesAreReplicated()); BatchedCommandRequest request( _writeType ); BatchedCommandResponse response; if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { return appendCommandStatus( result, Status( ErrorCodes::FailedToParse, errMsg ) ); } // Note that this is a runCommmand, and therefore, the database and the collection name // are in different parts of the grammar for the command. But it's more convenient to // work with a NamespaceString. We built it here and replace it in the parsed command. // Internally, everything work with the namespace string as opposed to just the // collection name. NamespaceString nss(dbName, request.getNS()); request.setNSS(nss); StatusWith<WriteConcernOptions> wcStatus = extractWriteConcern(cmdObj); if (!wcStatus.isOK()) { return appendCommandStatus(result, wcStatus.getStatus()); } txn->setWriteConcern(wcStatus.getValue()); WriteBatchExecutor writeBatchExecutor(txn, &globalOpCounters, &LastError::get(txn->getClient())); writeBatchExecutor.executeBatch( request, &response ); result.appendElements( response.toBSON() ); return response.getOk(); }
StatusWith<RecordId> Collection::insertDocument(OperationContext* txn, const BSONObj& docToInsert, bool enforceQuota, bool fromMigrate) { { auto status = checkValidation(txn, docToInsert); if (!status.isOK()) return status; } const SnapshotId sid = txn->recoveryUnit()->getSnapshotId(); if (_indexCatalog.findIdIndex(txn)) { if (docToInsert["_id"].eoo()) { return StatusWith<RecordId>(ErrorCodes::InternalError, str::stream() << "Collection::insertDocument got " "document without _id for ns:" << _ns.ns()); } } if (_mustTakeCappedLockOnInsert) synchronizeOnCappedInFlightResource(txn->lockState()); StatusWith<RecordId> res = _insertDocument(txn, docToInsert, enforceQuota); invariant(sid == txn->recoveryUnit()->getSnapshotId()); if (res.isOK()) { getGlobalServiceContext()->getOpObserver()->onInsert(txn, ns(), docToInsert, fromMigrate); // If there is a notifier object and another thread is waiting on it, then we notify // waiters of this document insert. Waiters keep a shared_ptr to '_cappedNotifier', so // there are waiters if this Collection's shared_ptr is not unique. if (_cappedNotifier && !_cappedNotifier.unique()) { _cappedNotifier->notifyOfInsert(); } } return res; }
Status KVCatalog::newCollection(OperationContext* opCtx, StringData ns, const CollectionOptions& options, KVPrefix prefix) { invariant(opCtx->lockState()->isDbLockedForMode(nsToDatabaseSubstring(ns), MODE_X)); const string ident = _newUniqueIdent(ns, "collection"); stdx::lock_guard<stdx::mutex> lk(_identsLock); Entry& old = _idents[ns.toString()]; if (!old.ident.empty()) { return Status(ErrorCodes::NamespaceExists, "collection already exists"); } opCtx->recoveryUnit()->registerChange(new AddIdentChange(this, ns)); BSONObj obj; { BSONObjBuilder b; b.append("ns", ns); b.append("ident", ident); BSONCollectionCatalogEntry::MetaData md; md.ns = ns.toString(); md.options = options; md.prefix = prefix; b.append("md", md.toBSON()); obj = b.obj(); } const bool enforceQuota = false; // TODO SERVER-30638: using timestamp 0 for these inserts. StatusWith<RecordId> res = _rs->insertRecord(opCtx, obj.objdata(), obj.objsize(), Timestamp(), enforceQuota); if (!res.isOK()) return res.getStatus(); old = Entry(ident, res.getValue()); LOG(1) << "stored meta data for " << ns << " @ " << res.getValue(); return Status::OK(); }
void WiredTigerUtil::fetchTypeAndSourceURI(OperationContext* opCtx, const std::string& tableUri, std::string* type, std::string* source) { std::string colgroupUri = "colgroup"; const size_t colon = tableUri.find(':'); invariant(colon != string::npos); colgroupUri += tableUri.substr(colon); StatusWith<std::string> colgroupResult = getMetadata(opCtx, colgroupUri); invariant(colgroupResult.isOK()); WiredTigerConfigParser parser(colgroupResult.getValue()); WT_CONFIG_ITEM typeItem; invariant(parser.get("type", &typeItem) == 0); invariant(typeItem.type == WT_CONFIG_ITEM::WT_CONFIG_ITEM_ID); *type = std::string(typeItem.str, typeItem.len); WT_CONFIG_ITEM sourceItem; invariant(parser.get("source", &sourceItem) == 0); invariant(sourceItem.type == WT_CONFIG_ITEM::WT_CONFIG_ITEM_STRING); *source = std::string(sourceItem.str, sourceItem.len); }