void WireProtocolWriter::write( const StringData& ns, const std::vector<WriteOperation*>& write_operations, bool ordered, const WriteConcern* wc, std::vector<BSONObj>* results ) { bool inRequest = false; int opsInRequest = 0; Operations requestType; BufBuilder builder; std::vector<WriteOperation*>::const_iterator iter = write_operations.begin(); while (iter != write_operations.end()) { // We don't have a pending request yet if (!inRequest) { (*iter)->startRequest(ns.toString(), ordered, &builder); inRequest = true; requestType = (*iter)->operationType(); } // now we have a pending request, can we add to it? if (requestType == (*iter)->operationType() && opsInRequest < _client->getMaxWriteBatchSize()) { // We can add to the request, lets see if it will fit and we can batch if(_fits(&builder, *iter)) { (*iter)->appendSelfToRequest(&builder); ++opsInRequest; ++iter; if (_batchableRequest(requestType)) continue; } } // Send the current request to the server, record the response, start a new request results->push_back(_send(requestType, builder, wc, ns)); inRequest = false; opsInRequest = 0; builder.reset(); } // Last batch if (opsInRequest != 0) results->push_back(_send(requestType, builder, wc, ns)); }
void WireProtocolWriter::write(const StringData& ns, const std::vector<WriteOperation*>& write_operations, bool ordered, bool bypassDocumentValidation, const WriteConcern* writeConcern, WriteResult* writeResult) { if (_client->getMaxWireVersion() >= 4) { // Per DRIVERS-250: // If your driver sends unacknowledged writes using op codes (OP_INSERT, OP_UPDATE, // OP_DELETE), you MUST raise an error when bypassDocumentValidation is explicitly set by a // user on >= 3.2 servers. // uassert(0, "bypassDocumentValidation is not supported for unacknowledged writes with MongoDB " "3.2 and later.", !bypassDocumentValidation); } // Effectively a map of batch relative indexes to WriteOperations std::vector<WriteOperation*> batchOps; BufBuilder builder; std::vector<WriteOperation*>::const_iterator batch_begin = write_operations.begin(); const std::vector<WriteOperation*>::const_iterator end = write_operations.end(); while (batch_begin != end) { std::vector<WriteOperation*>::const_iterator batch_iter = batch_begin; // We must be able to fit the first item of the batch. Otherwise, the calling code // passed an over size write operation in violation of our contract. invariant(_fits(&builder, *batch_iter)); // Set the current operation type for this batch const WriteOpType batchOpType = (*batch_iter)->operationType(); // Begin the command for this batch. (*batch_iter)->startRequest(ns.toString(), ordered, &builder); while (true) { // Always safe to append here: either we just entered the loop, or all the // below checks passed. (*batch_iter)->appendSelfToRequest(&builder); // Associate batch index with WriteOperation batchOps.push_back(*batch_iter); // If the operation we just queued isn't batchable, issue what we have. if (!_batchableRequest(batchOpType, writeResult)) break; // Peek at the next operation. const std::vector<WriteOperation*>::const_iterator next = boost::next(batch_iter); // If we are out of operations, issue what we have. if (next == end) break; // If the next operation is of a different type, issue what we have. if ((*next)->operationType() != batchOpType) break; // If adding the next op would put us over the limit of ops in a batch, issue // what we have. if (std::distance(batch_begin, next) >= _client->getMaxWriteBatchSize()) break; // If we can't put the next item into the current batch, issue what we have. if (!_fits(&builder, *next)) break; // OK to proceed to next op batch_iter = next; } // Issue the complete command. BSONObj batchResult = _send(batchOpType, builder, writeConcern, ns); // Merge this batch's result into the result for all batches written. writeResult->_mergeGleResult(batchOps, batchResult); batchOps.clear(); // Check write result for errors if we are doing ordered processing or last op bool lastOp = *batch_iter == write_operations.back(); if (ordered || lastOp) writeResult->_check(lastOp); // Reset the builder so we can build the next request. builder.reset(); // The next batch begins with the op after the last one in the just issued batch. batch_begin = ++batch_iter; } }
void CommandWriter::write( const StringData& ns, const std::vector<WriteOperation*>& write_operations, bool ordered, const WriteConcern* writeConcern, WriteResult* writeResult ) { // Effectively a map of batch relative indexes to WriteOperations std::vector<WriteOperation*> batchOps; std::vector<WriteOperation*>::const_iterator batch_begin = write_operations.begin(); const std::vector<WriteOperation*>::const_iterator end = write_operations.end(); while (batch_begin != end) { boost::scoped_ptr<BSONObjBuilder> command(new BSONObjBuilder); boost::scoped_ptr<BSONArrayBuilder> batch(new BSONArrayBuilder); std::vector<WriteOperation*>::const_iterator batch_iter = batch_begin; // We must be able to fit the first item of the batch. Otherwise, the calling code // passed an over size write operation in violation of our contract. invariant(_fits(batch.get(), *batch_iter)); // Set the current operation type const WriteOpType batchOpType = (*batch_iter)->operationType(); // Begin the command for this batch. (*batch_iter)->startCommand(ns.toString(), command.get()); while (true) { // Always safe to append here: either we just entered the loop, or all the // checks below passed. (*batch_iter)->appendSelfToCommand(batch.get()); // Associate batch index with WriteOperation batchOps.push_back(*batch_iter); // Peek at the next operation. const std::vector<WriteOperation*>::const_iterator next = boost::next(batch_iter); // If we are out of operations, issue what we have. if (next == end) break; // If the next operation is of a different type, issue what we have. if ((*next)->operationType() != batchOpType) break; // If adding the next op would put us over the limit of ops in a batch, issue // what we have. if (std::distance(batch_begin, next) >= _client->getMaxWriteBatchSize()) break; // If we can't put the next item into the current batch, issue what we have. if (!_fits(batch.get(), *next)) break; // OK to proceed to next op. batch_iter = next; } // End the command for this batch. _endCommand(batch.get(), *batch_iter, ordered, command.get()); // Issue the complete command. BSONObj batchResult = _send(command.get(), writeConcern, ns); // Merge this batch's result into the result for all batches written. writeResult->_mergeCommandResult(batchOps, batchResult); batchOps.clear(); // Check write result for errors if we are doing ordered processing or last op bool lastOp = *batch_iter == write_operations.back(); if (ordered || lastOp) writeResult->_check(lastOp); // The next batch begins with the op after the last one in the just issued batch. batch_begin = ++batch_iter; } }