Status ViewCatalog::_upsertIntoGraph(OperationContext* opCtx, const ViewDefinition& viewDef) { // Performs the insert into the graph. auto doInsert = [this, &opCtx](const ViewDefinition& viewDef, bool needsValidation) -> Status { // Validate that the pipeline is eligible to serve as a view definition. If it is, this // will also return the set of involved namespaces. auto pipelineStatus = _validatePipeline_inlock(opCtx, viewDef); if (!pipelineStatus.isOK()) { if (needsValidation) { uassertStatusOKWithContext(pipelineStatus.getStatus(), str::stream() << "Invalid pipeline for view " << viewDef.name().ns()); } return pipelineStatus.getStatus(); } auto involvedNamespaces = pipelineStatus.getValue(); std::vector<NamespaceString> refs(involvedNamespaces.begin(), involvedNamespaces.end()); refs.push_back(viewDef.viewOn()); int pipelineSize = 0; for (auto obj : viewDef.pipeline()) { pipelineSize += obj.objsize(); } if (needsValidation) { // Check the collation of all the dependent namespaces before updating the graph. auto collationStatus = _validateCollation_inlock(opCtx, viewDef, refs); if (!collationStatus.isOK()) { return collationStatus; } return _viewGraph.insertAndValidate(viewDef, refs, pipelineSize); } else { _viewGraph.insertWithoutValidating(viewDef, refs, pipelineSize); return Status::OK(); } }; if (_viewGraphNeedsRefresh) { _viewGraph.clear(); for (auto&& iter : _viewMap) { auto status = doInsert(*(iter.second.get()), false); // If we cannot fully refresh the graph, we will keep '_viewGraphNeedsRefresh' true. if (!status.isOK()) { return status; } } // Only if the inserts completed without error will we no longer need a refresh. opCtx->recoveryUnit()->onRollback([this]() { this->_viewGraphNeedsRefresh = true; }); _viewGraphNeedsRefresh = false; } // Remove the view definition first in case this is an update. If it is not in the graph, it // is simply a no-op. _viewGraph.remove(viewDef.name()); return doInsert(viewDef, true); }
void ShardingInitializationMongoD::initializeFromShardIdentity( OperationContext* opCtx, const ShardIdentityType& shardIdentity) { invariant(serverGlobalParams.clusterRole == ClusterRole::ShardServer); invariant(opCtx->lockState()->isLocked()); uassertStatusOKWithContext( shardIdentity.validate(), "Invalid shard identity document found when initializing sharding state"); log() << "initializing sharding state with: " << shardIdentity; const auto& configSvrConnStr = shardIdentity.getConfigsvrConnectionString(); auto const shardingState = ShardingState::get(opCtx); auto const shardRegistry = Grid::get(opCtx)->shardRegistry(); stdx::unique_lock<stdx::mutex> ul(_initSynchronizationMutex); if (shardingState->enabled()) { uassert(40371, "", shardingState->shardId() == shardIdentity.getShardName()); uassert(40372, "", shardingState->clusterId() == shardIdentity.getClusterId()); auto prevConfigsvrConnStr = shardRegistry->getConfigServerConnectionString(); uassert(40373, "", prevConfigsvrConnStr.type() == ConnectionString::SET); uassert(40374, "", prevConfigsvrConnStr.getSetName() == configSvrConnStr.getSetName()); return; } auto initializationStatus = shardingState->initializationStatus(); uassert(ErrorCodes::ManualInterventionRequired, str::stream() << "Server's sharding metadata manager failed to initialize and will " "remain in this state until the instance is manually reset" << causedBy(*initializationStatus), !initializationStatus); try { _initFunc(opCtx, shardIdentity, generateDistLockProcessId(opCtx)); shardingState->setInitialized(shardIdentity.getShardName().toString(), shardIdentity.getClusterId()); } catch (const DBException& ex) { shardingState->setInitialized(ex.toStatus()); } }
void TransactionRouter::_assertAbortStatusIsOkOrNoSuchTransaction( const AsyncRequestsSender::Response& response) const { auto shardResponse = uassertStatusOKWithContext( std::move(response.swResponse), str::stream() << "Failed to send abort to shard " << response.shardId << " between retries of statement " << _latestStmtId); auto status = getStatusFromCommandResult(shardResponse.data); uassert(ErrorCodes::NoSuchTransaction, str::stream() << _txnIdToString() << "Transaction aborted between retries of statement " << _latestStmtId << " due to error: " << status << " from shard: " << response.shardId, status.isOK() || status.code() == ErrorCodes::NoSuchTransaction); // abortTransaction is sent with no write concern, so there's no need to check for a write // concern error. }
void MongoDSessionCatalog::onStepUp(OperationContext* opCtx) { // Invalidate sessions that could have a retryable write on it, so that we can refresh from disk // in case the in-memory state was out of sync. const auto catalog = SessionCatalog::get(opCtx); // The use of shared_ptr here is in order to work around the limitation of stdx::function that // the functor must be copyable. auto sessionKillTokens = std::make_shared<std::vector<SessionCatalog::KillToken>>(); // Scan all sessions and reacquire locks for prepared transactions. // There may be sessions that are checked out during this scan, but none of them // can be prepared transactions, since only oplog application can make transactions // prepared on secondaries and oplog application has been stopped at this moment. std::vector<LogicalSessionId> sessionIdToReacquireLocks; SessionKiller::Matcher matcher( KillAllSessionsByPatternSet{makeKillAllSessionsByPattern(opCtx)}); catalog->scanSessions(matcher, [&](const ObservableSession& session) { const auto txnParticipant = TransactionParticipant::get(session.get()); if (!txnParticipant->inMultiDocumentTransaction()) { sessionKillTokens->emplace_back(session.kill()); } if (txnParticipant->transactionIsPrepared()) { sessionIdToReacquireLocks.emplace_back(session.getSessionId()); } }); killSessionTokensFunction(opCtx, sessionKillTokens); { // Create a new opCtx because we need an empty locker to refresh the locks. auto newClient = opCtx->getServiceContext()->makeClient("restore-prepared-txn"); AlternativeClientRegion acr(newClient); for (const auto& sessionId : sessionIdToReacquireLocks) { auto newOpCtx = cc().makeOperationContext(); newOpCtx->setLogicalSessionId(sessionId); MongoDOperationContextSession ocs(newOpCtx.get()); auto txnParticipant = TransactionParticipant::get(OperationContextSession::get(newOpCtx.get())); txnParticipant->refreshLocksForPreparedTransaction(newOpCtx.get(), false); } } const size_t initialExtentSize = 0; const bool capped = false; const bool maxSize = 0; BSONObj result; DBDirectClient client(opCtx); if (client.createCollection(NamespaceString::kSessionTransactionsTableNamespace.ns(), initialExtentSize, capped, maxSize, &result)) { return; } const auto status = getStatusFromCommandResult(result); if (status == ErrorCodes::NamespaceExists) { return; } uassertStatusOKWithContext(status, str::stream() << "Failed to create the " << NamespaceString::kSessionTransactionsTableNamespace.ns() << " collection"); }