/** * Perform a remove operation, which might remove multiple documents. Dispatches to remove code * currently to do most of this. * * Might fault or error, otherwise populates the result. */ static void multiRemove( const BatchItemRef& removeItem, WriteOpResult* result ) { const NamespaceString nss( removeItem.getRequest()->getNS() ); DeleteRequest request( nss ); request.setQuery( removeItem.getDelete()->getQuery() ); request.setMulti( removeItem.getDelete()->getLimit() != 1 ); request.setUpdateOpLog(true); request.setGod( false ); DeleteExecutor executor( &request ); Status status = executor.prepare(); if ( !status.isOK() ) { result->error = toWriteError( status ); return; } // NOTE: Deletes will not fault outside the lock once any data has been written PageFaultRetryableSection pFaultSection; /////////////////////////////////////////// Lock::DBWrite writeLock( nss.ns() ); /////////////////////////////////////////// // Check version once we're locked if ( !checkShardVersion( &shardingState, *removeItem.getRequest(), &result->error ) ) { // Version error return; } // Context once we're locked, to set more details in currentOp() // TODO: better constructor? Client::Context writeContext( nss.ns(), storageGlobalParams.dbpath, false /* don't check version */); try { result->stats.n = executor.execute(); } catch ( const PageFaultException& ex ) { // TODO: An actual data structure that's not an exception for this result->fault = new PageFaultException( ex ); } catch ( const DBException& ex ) { status = ex.toStatus(); if (ErrorCodes::isInterruption(status.code())) { throw; } result->error = toWriteError(status); } }
/** * Perform a remove operation, which might remove multiple documents. Dispatches to remove code * currently to do most of this. * * Might fault or error, otherwise populates the result. */ static void multiRemove( OperationContext* txn, const BatchItemRef& removeItem, WriteOpResult* result ) { const NamespaceString nss( removeItem.getRequest()->getNS() ); DeleteRequest request( nss ); request.setQuery( removeItem.getDelete()->getQuery() ); request.setMulti( removeItem.getDelete()->getLimit() != 1 ); request.setUpdateOpLog(true); request.setGod( false ); DeleteExecutor executor( &request ); Status status = executor.prepare(); if ( !status.isOK() ) { result->setError(toWriteError(status)); return; } /////////////////////////////////////////// Lock::DBWrite writeLock(txn->lockState(), nss.ns()); /////////////////////////////////////////// // Check version once we're locked if (!checkShardVersion(txn, &shardingState, *removeItem.getRequest(), result)) { // Version error return; } // Context once we're locked, to set more details in currentOp() // TODO: better constructor? Client::Context writeContext( nss.ns(), storageGlobalParams.dbpath, false /* don't check version */); try { result->getStats().n = executor.execute(txn, writeContext.db()); } catch ( const DBException& ex ) { status = ex.toStatus(); if (ErrorCodes::isInterruption(status.code())) { throw; } result->setError(toWriteError(status)); } }
/** * Perform a remove operation, which might remove multiple documents. Dispatches to remove code * currently to do most of this. * * Might fault or error, otherwise populates the result. */ static void multiRemove( const BatchItemRef& removeItem, WriteOpResult* result ) { Lock::assertWriteLocked( removeItem.getRequest()->getNS() ); try { long long n = deleteObjects( removeItem.getRequest()->getNS(), removeItem.getDelete()->getQuery(), removeItem.getDelete()->getLimit() == 1, // justOne true, // logOp false // god ); result->stats.n = n; } catch ( const PageFaultException& ex ) { // TODO: An actual data structure that's not an exception for this result->fault = new PageFaultException( ex ); } catch ( const DBException& ex ) { result->error = toWriteError( ex.toStatus() ); } }
Status Strategy::commandOpWrite(const std::string& dbName, const BSONObj& command, BatchItemRef targetingBatchItem, std::vector<CommandResult>* results) { // Note that this implementation will not handle targeting retries and does not completely // emulate write behavior ChunkManagerTargeter targeter(NamespaceString( targetingBatchItem.getRequest()->getTargetingNS())); Status status = targeter.init(); if (!status.isOK()) return status; OwnedPointerVector<ShardEndpoint> endpointsOwned; vector<ShardEndpoint*>& endpoints = endpointsOwned.mutableVector(); if (targetingBatchItem.getOpType() == BatchedCommandRequest::BatchType_Insert) { ShardEndpoint* endpoint; Status status = targeter.targetInsert(targetingBatchItem.getDocument(), &endpoint); if (!status.isOK()) return status; endpoints.push_back(endpoint); } else if (targetingBatchItem.getOpType() == BatchedCommandRequest::BatchType_Update) { Status status = targeter.targetUpdate(*targetingBatchItem.getUpdate(), &endpoints); if (!status.isOK()) return status; } else { invariant(targetingBatchItem.getOpType() == BatchedCommandRequest::BatchType_Delete); Status status = targeter.targetDelete(*targetingBatchItem.getDelete(), &endpoints); if (!status.isOK()) return status; } DBClientShardResolver resolver; DBClientMultiCommand dispatcher; // Assemble requests for (vector<ShardEndpoint*>::const_iterator it = endpoints.begin(); it != endpoints.end(); ++it) { const ShardEndpoint* endpoint = *it; ConnectionString host; Status status = resolver.chooseWriteHost(endpoint->shardName, &host); if (!status.isOK()) return status; RawBSONSerializable request(command); dispatcher.addCommand(host, dbName, request); } // Errors reported when recv'ing responses dispatcher.sendAll(); Status dispatchStatus = Status::OK(); // Recv responses while (dispatcher.numPending() > 0) { ConnectionString host; RawBSONSerializable response; Status status = dispatcher.recvAny(&host, &response); if (!status.isOK()) { // We always need to recv() all the sent operations dispatchStatus = status; continue; } CommandResult result; result.target = host; result.shardTarget = Shard::make(host.toString()); result.result = response.toBSON(); results->push_back(result); } return dispatchStatus; }