summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2017-06-09 19:20:07 -0400
committerMathias Stearn <mathias@10gen.com>2017-06-19 17:08:35 -0400
commit1babec6a705c242628a765935ac9d98b56a41218 (patch)
tree1b917e39f921cce0a2cd41db170ea6c22e6348bc /src/mongo
parenta9a849b21ced693f2345d4507ee14541818244d9 (diff)
downloadmongo-1babec6a705c242628a765935ac9d98b56a41218.tar.gz
SERVER-29564 BSONObjBuilder can now be seeded with a BSONObj prefix
This will avoid copying whenever it is safe.
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/bson/bsonobj.h8
-rw-r--r--src/mongo/bson/bsonobjbuilder.cpp4
-rw-r--r--src/mongo/bson/bsonobjbuilder.h36
-rw-r--r--src/mongo/bson/bsonobjbuilder_test.cpp80
-rw-r--r--src/mongo/bson/util/builder.h15
-rw-r--r--src/mongo/client/dbclient.cpp5
-rw-r--r--src/mongo/client/dbclientcursor.cpp5
-rw-r--r--src/mongo/client/query.cpp3
-rw-r--r--src/mongo/client/query.h3
-rw-r--r--src/mongo/client/scoped_db_conn_test.cpp2
-rw-r--r--src/mongo/db/commands.cpp2
-rw-r--r--src/mongo/db/repl/repl_set_commands.cpp3
-rw-r--r--src/mongo/db/repl/storage_interface_impl_test.cpp3
-rw-r--r--src/mongo/executor/network_interface_asio.cpp3
-rw-r--r--src/mongo/executor/network_test_env.cpp12
-rw-r--r--src/mongo/rpc/command_request.cpp3
-rw-r--r--src/mongo/rpc/legacy_reply_builder.cpp4
-rw-r--r--src/mongo/rpc/legacy_reply_builder.h2
-rw-r--r--src/mongo/rpc/legacy_request.cpp2
-rw-r--r--src/mongo/rpc/metadata.cpp3
-rw-r--r--src/mongo/rpc/reply_builder_interface.cpp15
-rw-r--r--src/mongo/rpc/reply_builder_interface.h3
-rw-r--r--src/mongo/s/commands/cluster_aggregate.cpp3
-rw-r--r--src/mongo/s/commands/cluster_commands_helpers.cpp5
-rw-r--r--src/mongo/s/commands/cluster_commands_helpers.h2
-rw-r--r--src/mongo/s/commands/commands_public.cpp3
-rw-r--r--src/mongo/s/commands/strategy.cpp7
-rw-r--r--src/mongo/s/write_ops/batched_command_request.cpp27
-rw-r--r--src/mongo/scripting/mozjs/mongo.cpp4
-rw-r--r--src/mongo/tools/bridge.cpp5
-rw-r--r--src/mongo/util/net/op_msg.h5
-rw-r--r--src/mongo/util/shared_buffer.h44
32 files changed, 229 insertions, 92 deletions
diff --git a/src/mongo/bson/bsonobj.h b/src/mongo/bson/bsonobj.h
index b1b3473c7d2..8d62bc8fd3d 100644
--- a/src/mongo/bson/bsonobj.h
+++ b/src/mongo/bson/bsonobj.h
@@ -204,11 +204,17 @@ public:
shareOwnershipWith(other.sharedBuffer());
}
- ConstSharedBuffer sharedBuffer() const {
+ const ConstSharedBuffer& sharedBuffer() const {
invariant(isOwned());
return _ownedBuffer;
}
+ ConstSharedBuffer releaseSharedBuffer() {
+ invariant(isOwned());
+ BSONObj sink = std::move(*this); // Leave *this in a valid moved-from state.
+ return std::move(sink._ownedBuffer);
+ }
+
/** If the data buffer is under the control of this BSONObj, return it.
Else return an owned copy.
*/
diff --git a/src/mongo/bson/bsonobjbuilder.cpp b/src/mongo/bson/bsonobjbuilder.cpp
index 32c46b30a00..ae60c65b5ee 100644
--- a/src/mongo/bson/bsonobjbuilder.cpp
+++ b/src/mongo/bson/bsonobjbuilder.cpp
@@ -188,7 +188,7 @@ BSONObjBuilder& BSONObjBuilder::appendDate(StringData fieldName, Date_t dt) {
}
/* add all the fields from the object specified to this object */
-BSONObjBuilder& BSONObjBuilder::appendElements(BSONObj x) {
+BSONObjBuilder& BSONObjBuilder::appendElements(const BSONObj& x) {
if (!x.isEmpty())
_b.appendBuf(x.objdata() + 4, // skip over leading length
x.objsize() - 5); // ignore leading length and trailing \0
@@ -196,7 +196,7 @@ BSONObjBuilder& BSONObjBuilder::appendElements(BSONObj x) {
}
/* add all the fields from the object specified to this object if they don't exist */
-BSONObjBuilder& BSONObjBuilder::appendElementsUnique(BSONObj x) {
+BSONObjBuilder& BSONObjBuilder::appendElementsUnique(const BSONObj& x) {
std::set<std::string> have;
{
BSONObjIterator i = iterator();
diff --git a/src/mongo/bson/bsonobjbuilder.h b/src/mongo/bson/bsonobjbuilder.h
index bd10a7b3d16..b5207af742e 100644
--- a/src/mongo/bson/bsonobjbuilder.h
+++ b/src/mongo/bson/bsonobjbuilder.h
@@ -124,6 +124,33 @@ public:
_b.reserveBytes(1);
}
+ /**
+ * Creates a new BSONObjBuilder prefixed with the fields in 'prefix'.
+ *
+ * If prefix is an rvalue referring to the only view of the underlying BSON buffer, it will be
+ * able to avoid copying and will just reuse the buffer. Therefore, you should try to std::move
+ * into this constructor where possible.
+ */
+ BSONObjBuilder(BSONObj prefix)
+ : _b(_buf), _buf(0), _offset(0), _s(this), _tracker(0), _doneCalled(false) {
+ // If prefix wasn't owned or we don't have exclusive access to it, we must copy.
+ if (!prefix.isOwned() || prefix.sharedBuffer().isShared()) {
+ _b.grow(prefix.objsize()); // Make sure we won't need to realloc().
+ _b.setlen(sizeof(int)); // Skip over size bytes (see first constructor).
+ _b.reserveBytes(1); // Reserve room for our EOO byte.
+ appendElements(prefix);
+ return;
+ }
+
+ const auto size = prefix.objsize();
+ const char* const firstByte = prefix.objdata();
+ auto buf = prefix.releaseSharedBuffer().constCast();
+ _offset = firstByte - buf.get();
+ _b.useSharedBuffer(std::move(buf));
+ _b.setlen(_offset + size - 1); // Position right before prefix's EOO byte.
+ _b.reserveBytes(1); // Reserve room for our EOO byte.
+ }
+
// Move constructible, but not assignable due to reference member.
BSONObjBuilder(BSONObjBuilder&& other)
: _b(&other._b == &other._buf ? _buf : other._b),
@@ -146,10 +173,10 @@ public:
}
/** add all the fields from the object specified to this object */
- BSONObjBuilder& appendElements(BSONObj x);
+ BSONObjBuilder& appendElements(const BSONObj& x);
/** add all the fields from the object specified to this object if they don't exist already */
- BSONObjBuilder& appendElementsUnique(BSONObj x);
+ BSONObjBuilder& appendElementsUnique(const BSONObj& x);
/** append element to the object we are building */
BSONObjBuilder& append(const BSONElement& e) {
@@ -637,8 +664,9 @@ public:
*/
BSONObj obj() {
massert(10335, "builder does not own memory", owned());
- doneFast();
- return BSONObj(_b.release());
+ auto out = done();
+ out.shareOwnershipWith(_b.release());
+ return out;
}
/** Fetch the object we have built.
diff --git a/src/mongo/bson/bsonobjbuilder_test.cpp b/src/mongo/bson/bsonobjbuilder_test.cpp
index 901b2d14965..6debaa2fa3a 100644
--- a/src/mongo/bson/bsonobjbuilder_test.cpp
+++ b/src/mongo/bson/bsonobjbuilder_test.cpp
@@ -366,5 +366,85 @@ TEST(BSONArrayBuilderTest, MovingABSONArrayBuilderWorks) {
ASSERT_BSONOBJ_EQ(bob.obj(), BSON("a" << 1 << "array" << BSON_ARRAY(1 << "2" << 3 << "4")));
}
+TEST(BSONObjBuilderTest, SeedingBSONObjBuilderWithRootedUnsharedOwnedBsonWorks) {
+ auto origObj = BSON("a" << 1);
+ auto origObjPtr = origObj.objdata();
+
+ BSONObjBuilder bob(std::move(origObj)); // moving.
+ bob.append("b", 1);
+ const auto obj = bob.obj();
+ ASSERT_BSONOBJ_EQ(origObj, BSONObj());
+ ASSERT_BSONOBJ_EQ(obj, BSON("a" << 1 << "b" << 1));
+ ASSERT_EQ(static_cast<const void*>(obj.objdata()), static_cast<const void*>(origObjPtr));
+}
+
+TEST(BSONObjBuilderTest, SeedingBSONObjBuilderWithRootedSharedOwnedBsonWorks) {
+ const auto origObj = BSON("a" << 1);
+ auto origObjPtr = origObj.objdata();
+
+ BSONObjBuilder bob(origObj); // not moving.
+ bob.append("b", 1);
+ const auto obj = bob.obj();
+ ASSERT_BSONOBJ_EQ(origObj, BSON("a" << 1));
+ ASSERT_BSONOBJ_EQ(obj, BSON("a" << 1 << "b" << 1));
+ ASSERT_NE(static_cast<const void*>(obj.objdata()), static_cast<const void*>(origObjPtr));
+}
+
+TEST(BSONObjBuilderTest, SeedingBSONObjBuilderWithRootedUnownedBsonWorks) {
+ const auto origObjHolder = BSON("a" << 1);
+ auto origObjPtr = origObjHolder.objdata();
+ const auto origObj = BSONObj(origObjPtr);
+ invariant(!origObj.isOwned());
+
+ BSONObjBuilder bob(origObj); // not moving.
+ bob.append("b", 1);
+ const auto obj = bob.obj();
+ ASSERT_BSONOBJ_EQ(origObj, BSON("a" << 1));
+ ASSERT_BSONOBJ_EQ(obj, BSON("a" << 1 << "b" << 1));
+ ASSERT_NE(static_cast<const void*>(obj.objdata()), static_cast<const void*>(origObjPtr));
+}
+
+TEST(BSONObjBuilderTest, SeedingBSONObjBuilderWithNonrootedUnsharedOwnedBsonWorks) {
+ auto origObjHolder = BSON("" << BSON("a" << 1));
+ auto origObj = origObjHolder.firstElement().Obj();
+ auto origObjPtr = origObj.objdata();
+ origObj.shareOwnershipWith(origObjHolder.releaseSharedBuffer());
+
+ BSONObjBuilder bob(std::move(origObj)); // moving.
+ bob.append("b", 1);
+ const auto obj = bob.obj();
+ ASSERT_BSONOBJ_EQ(origObj, BSONObj());
+ ASSERT_BSONOBJ_EQ(obj, BSON("a" << 1 << "b" << 1));
+ ASSERT_EQ(static_cast<const void*>(obj.objdata()), static_cast<const void*>(origObjPtr));
+}
+
+TEST(BSONObjBuilderTest, SeedingBSONObjBuilderWithNonrootedSharedOwnedBsonWorks) {
+ auto origObjHolder = BSON("" << BSON("a" << 1));
+ auto origObj = origObjHolder.firstElement().Obj();
+ auto origObjPtr = origObj.objdata();
+ origObj.shareOwnershipWith(origObjHolder.releaseSharedBuffer());
+
+ BSONObjBuilder bob(origObj); // not moving.
+ bob.append("b", 1);
+ const auto obj = bob.obj();
+ ASSERT_BSONOBJ_EQ(origObj, BSON("a" << 1));
+ ASSERT_BSONOBJ_EQ(obj, BSON("a" << 1 << "b" << 1));
+ ASSERT_NE(static_cast<const void*>(obj.objdata()), static_cast<const void*>(origObjPtr));
+}
+
+TEST(BSONObjBuilderTest, SeedingBSONObjBuilderWithNonrootedUnownedBsonWorks) {
+ auto origObjHolder = BSON("" << BSON("a" << 1));
+ auto origObj = origObjHolder.firstElement().Obj();
+ auto origObjPtr = origObj.objdata();
+ invariant(!origObj.isOwned());
+
+ BSONObjBuilder bob(origObj); // not moving.
+ bob.append("b", 1);
+ const auto obj = bob.obj();
+ ASSERT_BSONOBJ_EQ(origObj, BSON("a" << 1));
+ ASSERT_BSONOBJ_EQ(obj, BSON("a" << 1 << "b" << 1));
+ ASSERT_NE(static_cast<const void*>(obj.objdata()), static_cast<const void*>(origObjPtr));
+}
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/bson/util/builder.h b/src/mongo/bson/util/builder.h
index fbb470fd6fd..abd4dd95f90 100644
--- a/src/mongo/bson/util/builder.h
+++ b/src/mongo/bson/util/builder.h
@@ -80,6 +80,9 @@ class SharedBufferAllocator {
public:
SharedBufferAllocator() = default;
+ SharedBufferAllocator(SharedBuffer buf) : _buf(std::move(buf)) {
+ invariant(!_buf.isShared());
+ }
// Allow moving but not copying. It would be an error for two SharedBufferAllocators to use the
// same underlying buffer.
@@ -314,6 +317,18 @@ public:
reservedBytes -= bytes;
}
+ /**
+ * Replaces the buffer backing this BufBuilder with the passed in SharedBuffer.
+ * Only legal to call when this builder is empty and when the SharedBuffer isn't shared.
+ */
+ void useSharedBuffer(SharedBuffer buf) {
+ MONGO_STATIC_ASSERT(std::is_same<BufferAllocator, SharedBufferAllocator>());
+ invariant(l == 0); // Can only do this while empty.
+ invariant(reservedBytes == 0);
+ size = buf.capacity();
+ _buf = SharedBufferAllocator(std::move(buf));
+ }
+
private:
template <typename T>
void appendNumImpl(T t) {
diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp
index 21b88587ad1..36821188887 100644
--- a/src/mongo/client/dbclient.cpp
+++ b/src/mongo/client/dbclient.cpp
@@ -185,8 +185,7 @@ rpc::UniqueReply DBClientWithCommands::runCommandWithMetadata(StringData databas
// call() oddly takes this by pointer, so we need to put it on the stack.
auto host = getServerAddress();
- BSONObjBuilder metadataBob;
- metadataBob.appendElements(metadata);
+ BSONObjBuilder metadataBob(std::move(metadata));
if (_metadataWriter) {
uassertStatusOK(
@@ -198,7 +197,7 @@ rpc::UniqueReply DBClientWithCommands::runCommandWithMetadata(StringData databas
requestBuilder->setDatabase(database);
requestBuilder->setCommandName(command);
requestBuilder->setCommandArgs(commandArgs);
- requestBuilder->setMetadata(metadataBob.done());
+ requestBuilder->setMetadata(metadataBob.obj());
auto requestMsg = requestBuilder->done();
Message replyMsg;
diff --git a/src/mongo/client/dbclientcursor.cpp b/src/mongo/client/dbclientcursor.cpp
index a9a1f854006..e7675630ab6 100644
--- a/src/mongo/client/dbclientcursor.cpp
+++ b/src/mongo/client/dbclientcursor.cpp
@@ -72,8 +72,7 @@ Message assembleCommandRequest(DBClientWithCommands* cli,
std::tie(upconvertedCommand, upconvertedMetadata) =
rpc::upconvertRequestMetadata(std::move(legacyQuery), legacyQueryOptions);
- BSONObjBuilder metadataBob;
- metadataBob.appendElements(upconvertedMetadata);
+ BSONObjBuilder metadataBob(std::move(upconvertedMetadata));
if (cli->getRequestMetadataWriter()) {
uassertStatusOK(cli->getRequestMetadataWriter()(
(haveClient() ? cc().getOperationContext() : nullptr), &metadataBob));
@@ -84,7 +83,7 @@ Message assembleCommandRequest(DBClientWithCommands* cli,
// been wrapped.
requestBuilder->setCommandName(upconvertedCommand.firstElementFieldName());
requestBuilder->setCommandArgs(std::move(upconvertedCommand));
- requestBuilder->setMetadata(metadataBob.done());
+ requestBuilder->setMetadata(metadataBob.obj());
return requestBuilder->done();
}
diff --git a/src/mongo/client/query.cpp b/src/mongo/client/query.cpp
index 349ed5ff96d..6d3e22d4c78 100644
--- a/src/mongo/client/query.cpp
+++ b/src/mongo/client/query.cpp
@@ -53,8 +53,7 @@ Query& Query::hint(const string& jsonKeyPatt) {
Query& Query::where(const string& jscode, BSONObj scope) {
/* use where() before sort() and hint() and explain(), else this will assert. */
verify(!isComplex());
- BSONObjBuilder b;
- b.appendElements(obj);
+ BSONObjBuilder b(std::move(obj));
b.appendWhere(jscode, scope);
obj = b.obj();
return *this;
diff --git a/src/mongo/client/query.h b/src/mongo/client/query.h
index 4a4a97bd9b8..3ced9c591f4 100644
--- a/src/mongo/client/query.h
+++ b/src/mongo/client/query.h
@@ -164,8 +164,7 @@ private:
template <class T>
void appendComplex(const char* fieldName, const T& val) {
makeComplex();
- BSONObjBuilder b;
- b.appendElements(obj);
+ BSONObjBuilder b(std::move(obj));
b.append(fieldName, val);
obj = b.obj();
}
diff --git a/src/mongo/client/scoped_db_conn_test.cpp b/src/mongo/client/scoped_db_conn_test.cpp
index bda09d75263..1a9d7581424 100644
--- a/src/mongo/client/scoped_db_conn_test.cpp
+++ b/src/mongo/client/scoped_db_conn_test.cpp
@@ -118,7 +118,7 @@ private:
commandResponse.append("minWireVersion", WireVersion::RELEASE_2_4_AND_BEFORE);
}
- auto response = reply->setCommandReply(commandResponse.done())
+ auto response = reply->setCommandReply(commandResponse.obj())
.setMetadata(rpc::makeEmptyMetadata())
.done();
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp
index 045a4c3715c..dd75b69c6be 100644
--- a/src/mongo/db/commands.cpp
+++ b/src/mongo/db/commands.cpp
@@ -303,7 +303,7 @@ void Command::generateHelpResponse(OperationContext* opCtx,
command.help(ss);
helpBuilder.append("help", ss.str());
- replyBuilder->setCommandReply(helpBuilder.done());
+ replyBuilder->setCommandReply(helpBuilder.obj());
replyBuilder->setMetadata(rpc::makeEmptyMetadata());
}
diff --git a/src/mongo/db/repl/repl_set_commands.cpp b/src/mongo/db/repl/repl_set_commands.cpp
index f34b91f4af2..2c35b250c9a 100644
--- a/src/mongo/db/repl/repl_set_commands.cpp
+++ b/src/mongo/db/repl/repl_set_commands.cpp
@@ -381,8 +381,7 @@ public:
if (configObj.getField("version").eoo()) {
// Missing version field defaults to version 1.
- BSONObjBuilder builder;
- builder.appendElements(configObj);
+ BSONObjBuilder builder(std::move(configObj));
builder.append("version", 1);
configObj = builder.obj();
}
diff --git a/src/mongo/db/repl/storage_interface_impl_test.cpp b/src/mongo/db/repl/storage_interface_impl_test.cpp
index 1ad0829b08b..7df2de5e2f8 100644
--- a/src/mongo/db/repl/storage_interface_impl_test.cpp
+++ b/src/mongo/db/repl/storage_interface_impl_test.cpp
@@ -118,8 +118,7 @@ void createCollection(OperationContext* opCtx,
* Creates an oplog entry with given optime.
*/
BSONObj makeOplogEntry(OpTime opTime) {
- BSONObjBuilder bob;
- bob.appendElements(opTime.toBSON());
+ BSONObjBuilder bob(opTime.toBSON());
bob.append("h", 1LL);
bob.append("op", "c");
bob.append("ns", "test.t");
diff --git a/src/mongo/executor/network_interface_asio.cpp b/src/mongo/executor/network_interface_asio.cpp
index 22666b05672..f2d5fa97c3b 100644
--- a/src/mongo/executor/network_interface_asio.cpp
+++ b/src/mongo/executor/network_interface_asio.cpp
@@ -230,8 +230,7 @@ Status attachMetadataIfNeeded(RemoteCommandRequest& request,
// Append the metadata of the request with metadata from the metadata hook
// if a hook is installed
if (metadataHook) {
- BSONObjBuilder augmentedBob;
- augmentedBob.appendElements(request.metadata);
+ BSONObjBuilder augmentedBob(std::move(request.metadata));
auto writeStatus = callNoexcept(*metadataHook,
&rpc::EgressMetadataHook::writeRequestMetadata,
diff --git a/src/mongo/executor/network_test_env.cpp b/src/mongo/executor/network_test_env.cpp
index 2d5ec28ebc3..79dbd27a992 100644
--- a/src/mongo/executor/network_test_env.cpp
+++ b/src/mongo/executor/network_test_env.cpp
@@ -47,12 +47,10 @@ void NetworkTestEnv::onCommand(OnCommandFunction func) {
const NetworkInterfaceMock::NetworkOperationIterator noi = _mockNetwork->getNextReadyRequest();
const RemoteCommandRequest& request = noi->getRequest();
- const auto& resultStatus = func(request);
-
- BSONObjBuilder result;
+ auto resultStatus = func(request);
if (resultStatus.isOK()) {
- result.appendElements(resultStatus.getValue());
+ BSONObjBuilder result(std::move(resultStatus.getValue()));
Command::appendCommandStatus(result, resultStatus.getStatus());
const RemoteCommandResponse response(result.obj(), BSONObj(), Milliseconds(1));
@@ -72,12 +70,10 @@ void NetworkTestEnv::onCommandWithMetadata(OnCommandWithMetadataFunction func) {
const NetworkInterfaceMock::NetworkOperationIterator noi = _mockNetwork->getNextReadyRequest();
const RemoteCommandRequest& request = noi->getRequest();
- const auto cmdResponseStatus = func(request);
-
- BSONObjBuilder result;
+ auto cmdResponseStatus = func(request);
if (cmdResponseStatus.isOK()) {
- result.appendElements(cmdResponseStatus.data);
+ BSONObjBuilder result(std::move(cmdResponseStatus.data));
Command::appendCommandStatus(result, cmdResponseStatus.status);
const RemoteCommandResponse response(
result.obj(), cmdResponseStatus.metadata, Milliseconds(1));
diff --git a/src/mongo/rpc/command_request.cpp b/src/mongo/rpc/command_request.cpp
index a796f6f8a19..067abeef636 100644
--- a/src/mongo/rpc/command_request.cpp
+++ b/src/mongo/rpc/command_request.cpp
@@ -105,8 +105,7 @@ ParsedOpCommand ParsedOpCommand::parse(const Message& message) {
OpMsgRequest opMsgRequestFromCommandRequest(const Message& message) {
auto parsed = ParsedOpCommand::parse(message);
- BSONObjBuilder bodyBuilder;
- bodyBuilder.appendElements(parsed.body);
+ BSONObjBuilder bodyBuilder(std::move(parsed.body));
// OP_COMMAND is only used when communicating with 3.4 nodes and they serialize their metadata
// fields differently. We do all up-conversion here so that the rest of the code only has to
diff --git a/src/mongo/rpc/legacy_reply_builder.cpp b/src/mongo/rpc/legacy_reply_builder.cpp
index 5fb373d12c8..340d892472f 100644
--- a/src/mongo/rpc/legacy_reply_builder.cpp
+++ b/src/mongo/rpc/legacy_reply_builder.cpp
@@ -52,7 +52,7 @@ LegacyReplyBuilder::LegacyReplyBuilder(Message&& message) : _message{std::move(m
LegacyReplyBuilder::~LegacyReplyBuilder() {}
LegacyReplyBuilder& LegacyReplyBuilder::setCommandReply(Status nonOKStatus,
- const BSONObj& extraErrorInfo) {
+ BSONObj extraErrorInfo) {
invariant(_state == State::kCommandReply);
if (nonOKStatus == ErrorCodes::SendStaleConfig) {
_staleConfigError = true;
@@ -66,7 +66,7 @@ LegacyReplyBuilder& LegacyReplyBuilder::setCommandReply(Status nonOKStatus,
setRawCommandReply(err.done());
} else {
// All other errors proceed through the normal path, which also handles state transitions.
- ReplyBuilderInterface::setCommandReply(std::move(nonOKStatus), extraErrorInfo);
+ ReplyBuilderInterface::setCommandReply(std::move(nonOKStatus), std::move(extraErrorInfo));
}
return *this;
}
diff --git a/src/mongo/rpc/legacy_reply_builder.h b/src/mongo/rpc/legacy_reply_builder.h
index beb7806147c..d72fdc6b93b 100644
--- a/src/mongo/rpc/legacy_reply_builder.h
+++ b/src/mongo/rpc/legacy_reply_builder.h
@@ -49,7 +49,7 @@ public:
~LegacyReplyBuilder() final;
// Override of setCommandReply specifically used to handle SendStaleConfigException.
- LegacyReplyBuilder& setCommandReply(Status nonOKStatus, const BSONObj& extraErrorInfo) final;
+ LegacyReplyBuilder& setCommandReply(Status nonOKStatus, BSONObj extraErrorInfo) final;
LegacyReplyBuilder& setRawCommandReply(const BSONObj& commandReply) final;
BSONObjBuilder getInPlaceReplyBuilder(std::size_t) final;
diff --git a/src/mongo/rpc/legacy_request.cpp b/src/mongo/rpc/legacy_request.cpp
index 9d5beae3af2..8247c7d3923 100644
--- a/src/mongo/rpc/legacy_request.cpp
+++ b/src/mongo/rpc/legacy_request.cpp
@@ -55,7 +55,7 @@ OpMsgRequest opMsgRequestFromLegacyRequest(const Message& message) {
auto bodyAndMetadata = rpc::upconvertRequestMetadata(qm.query, qm.queryOptions);
return OpMsgRequest::fromDBAndBody(
- ns.db(), std::get<0>(bodyAndMetadata), std::get<1>(bodyAndMetadata));
+ ns.db(), std::move(std::get<0>(bodyAndMetadata)), std::get<1>(bodyAndMetadata));
}
} // namespace rpc
diff --git a/src/mongo/rpc/metadata.cpp b/src/mongo/rpc/metadata.cpp
index bf3aab6c8e4..715532f453d 100644
--- a/src/mongo/rpc/metadata.cpp
+++ b/src/mongo/rpc/metadata.cpp
@@ -164,8 +164,7 @@ CommandAndMetadata upconvertRequestMetadata(BSONObj legacyCmdObj, int queryFlags
LegacyCommandAndFlags downconvertRequestMetadata(BSONObj cmdObj, BSONObj metadata) {
int legacyQueryFlags = 0;
if (auto logicalTime = metadata[LogicalTimeMetadata::fieldName()]) {
- BSONObjBuilder logicalTimeCommandBob;
- logicalTimeCommandBob.appendElements(cmdObj);
+ BSONObjBuilder logicalTimeCommandBob(std::move(cmdObj));
logicalTimeCommandBob.append(logicalTime);
cmdObj = logicalTimeCommandBob.obj();
}
diff --git a/src/mongo/rpc/reply_builder_interface.cpp b/src/mongo/rpc/reply_builder_interface.cpp
index 34a99cd4176..99fe2edcb1e 100644
--- a/src/mongo/rpc/reply_builder_interface.cpp
+++ b/src/mongo/rpc/reply_builder_interface.cpp
@@ -48,14 +48,13 @@ const char kErrorField[] = "errmsg";
// similar to appendCommandStatus (duplicating logic here to avoid cyclic library
// dependency)
-BSONObj augmentReplyWithStatus(const Status& status, const BSONObj& reply) {
+BSONObj augmentReplyWithStatus(const Status& status, BSONObj reply) {
auto okField = reply.getField(kOKField);
if (!okField.eoo() && okField.trueValue()) {
return reply;
}
- BSONObjBuilder bob;
- bob.appendElements(reply);
+ BSONObjBuilder bob(std::move(reply));
if (okField.eoo()) {
bob.append(kOKField, status.isOK() ? 1.0 : 0.0);
}
@@ -63,11 +62,11 @@ BSONObj augmentReplyWithStatus(const Status& status, const BSONObj& reply) {
return bob.obj();
}
- if (!reply.hasField(kErrorField)) {
+ if (!bob.asTempObj().hasField(kErrorField)) {
bob.append(kErrorField, status.reason());
}
- if (!reply.hasField(kCodeField)) {
+ if (!bob.asTempObj().hasField(kCodeField)) {
bob.append(kCodeField, status.code());
bob.append(kCodeNameField, ErrorCodes::errorString(status.code()));
}
@@ -78,13 +77,13 @@ BSONObj augmentReplyWithStatus(const Status& status, const BSONObj& reply) {
ReplyBuilderInterface& ReplyBuilderInterface::setCommandReply(StatusWith<BSONObj> commandReply) {
auto reply = commandReply.isOK() ? std::move(commandReply.getValue()) : BSONObj();
- return setRawCommandReply(augmentReplyWithStatus(commandReply.getStatus(), reply));
+ return setRawCommandReply(augmentReplyWithStatus(commandReply.getStatus(), std::move(reply)));
}
ReplyBuilderInterface& ReplyBuilderInterface::setCommandReply(Status nonOKStatus,
- const BSONObj& extraErrorInfo) {
+ BSONObj extraErrorInfo) {
invariant(!nonOKStatus.isOK());
- return setRawCommandReply(augmentReplyWithStatus(nonOKStatus, extraErrorInfo));
+ return setRawCommandReply(augmentReplyWithStatus(nonOKStatus, std::move(extraErrorInfo)));
}
} // namespace rpc
diff --git a/src/mongo/rpc/reply_builder_interface.h b/src/mongo/rpc/reply_builder_interface.h
index b2631bfaf0e..a157f41167e 100644
--- a/src/mongo/rpc/reply_builder_interface.h
+++ b/src/mongo/rpc/reply_builder_interface.h
@@ -84,8 +84,7 @@ public:
* interfacing with legacy code that adds additional data to a failed command reply and
* its use is discouraged in new code.
*/
- virtual ReplyBuilderInterface& setCommandReply(Status nonOKStatus,
- const BSONObj& extraErrorInfo);
+ virtual ReplyBuilderInterface& setCommandReply(Status nonOKStatus, BSONObj extraErrorInfo);
/**
* Gets the protocol used to serialize this reply. This should be used for validity checks
diff --git a/src/mongo/s/commands/cluster_aggregate.cpp b/src/mongo/s/commands/cluster_aggregate.cpp
index 72a860f1517..0453bfa1880 100644
--- a/src/mongo/s/commands/cluster_aggregate.cpp
+++ b/src/mongo/s/commands/cluster_aggregate.cpp
@@ -468,7 +468,8 @@ Status ClusterAggregate::aggPassthrough(OperationContext* opCtx,
opCtx,
ReadPreferenceSetting::get(opCtx),
namespaces.executionNss.db().toString(),
- !shard->isConfig() ? appendShardVersion(cmdObj, ChunkVersion::UNSHARDED()) : cmdObj,
+ !shard->isConfig() ? appendShardVersion(std::move(cmdObj), ChunkVersion::UNSHARDED())
+ : std::move(cmdObj),
Shard::RetryPolicy::kNoRetry));
if (ErrorCodes::isStaleShardingError(cmdResponse.commandStatus.code())) {
diff --git a/src/mongo/s/commands/cluster_commands_helpers.cpp b/src/mongo/s/commands/cluster_commands_helpers.cpp
index b7311ac4dbe..a8d44e4017a 100644
--- a/src/mongo/s/commands/cluster_commands_helpers.cpp
+++ b/src/mongo/s/commands/cluster_commands_helpers.cpp
@@ -213,9 +213,8 @@ StatusWith<std::vector<AsyncRequestsSender::Response>> gatherResponses(
} // namespace
-BSONObj appendShardVersion(const BSONObj& cmdObj, ChunkVersion version) {
- BSONObjBuilder cmdWithVersionBob;
- cmdWithVersionBob.appendElements(cmdObj);
+BSONObj appendShardVersion(BSONObj cmdObj, ChunkVersion version) {
+ BSONObjBuilder cmdWithVersionBob(std::move(cmdObj));
version.appendForCommands(&cmdWithVersionBob);
return cmdWithVersionBob.obj();
}
diff --git a/src/mongo/s/commands/cluster_commands_helpers.h b/src/mongo/s/commands/cluster_commands_helpers.h
index 184be2d6063..9445063e7e1 100644
--- a/src/mongo/s/commands/cluster_commands_helpers.h
+++ b/src/mongo/s/commands/cluster_commands_helpers.h
@@ -62,7 +62,7 @@ void appendWriteConcernErrorToCmdResponse(const ShardId& shardID,
/**
* Returns a copy of 'cmdObj' with 'version' appended.
*/
-BSONObj appendShardVersion(const BSONObj& cmdObj, ChunkVersion version);
+BSONObj appendShardVersion(BSONObj cmdObj, ChunkVersion version);
/**
* Generic function for dispatching commands to the cluster.
diff --git a/src/mongo/s/commands/commands_public.cpp b/src/mongo/s/commands/commands_public.cpp
index a3cadb1ddb7..398aa6f3123 100644
--- a/src/mongo/s/commands/commands_public.cpp
+++ b/src/mongo/s/commands/commands_public.cpp
@@ -1296,8 +1296,7 @@ public:
// long as we keep getting more chunks. The end condition is when we go to
// look for chunk n and it doesn't exist. This means that the file's last
// chunk is n-1, so we return the computed md5 results.
- BSONObjBuilder bb;
- bb.appendElements(filterCommandRequestForPassthrough(cmdObj));
+ BSONObjBuilder bb(filterCommandRequestForPassthrough(cmdObj));
bb.appendBool("partialOk", true);
bb.append("startAt", n);
if (!lastResult.isEmpty()) {
diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp
index c6e69ee1bdd..afa4f04e55a 100644
--- a/src/mongo/s/commands/strategy.cpp
+++ b/src/mongo/s/commands/strategy.cpp
@@ -473,8 +473,7 @@ DbResponse Strategy::clientOpQueryCommand(OperationContext* opCtx,
// If the slaveOK bit is set, behave as-if read preference secondary-preferred was
// specified.
const auto readPref = ReadPreferenceSetting(ReadPreference::SecondaryPreferred);
- BSONObjBuilder finalCmdObjBuilder;
- finalCmdObjBuilder.appendElements(cmdObj);
+ BSONObjBuilder finalCmdObjBuilder(std::move(cmdObj));
readPref.toContainingBSON(&finalCmdObjBuilder);
cmdObj = finalCmdObjBuilder.obj();
}
@@ -662,11 +661,9 @@ void Strategy::writeOp(OperationContext* opCtx, DbMessage* dbm) {
// Adjust namespace for command
const NamespaceString& fullNS(commandRequest->getNS());
- BSONObj commandBSON = commandRequest->toBSON();
-
BSONObjBuilder builder;
runAgainstRegistered(
- opCtx, OpMsgRequest::fromDBAndBody(fullNS.db(), commandBSON), builder);
+ opCtx, OpMsgRequest::fromDBAndBody(fullNS.db(), commandRequest->toBSON()), builder);
bool parsed = commandResponse.parseBSON(builder.done(), nullptr);
(void)parsed; // for compile
diff --git a/src/mongo/s/write_ops/batched_command_request.cpp b/src/mongo/s/write_ops/batched_command_request.cpp
index e4811ffe763..48c77723db3 100644
--- a/src/mongo/s/write_ops/batched_command_request.cpp
+++ b/src/mongo/s/write_ops/batched_command_request.cpp
@@ -138,21 +138,18 @@ bool BatchedCommandRequest::isValid(std::string* errMsg) const {
}
BSONObj BatchedCommandRequest::toBSON() const {
- BSONObjBuilder builder;
-
- switch (getBatchType()) {
- case BatchedCommandRequest::BatchType_Insert:
- builder.appendElements(_insertReq->toBSON());
- break;
- case BatchedCommandRequest::BatchType_Update:
- builder.appendElements(_updateReq->toBSON());
- break;
- case BatchedCommandRequest::BatchType_Delete:
- builder.appendElements(_deleteReq->toBSON());
- break;
- default:
- MONGO_UNREACHABLE;
- }
+ BSONObjBuilder builder([&] {
+ switch (getBatchType()) {
+ case BatchedCommandRequest::BatchType_Insert:
+ return _insertReq->toBSON();
+ case BatchedCommandRequest::BatchType_Update:
+ return _updateReq->toBSON();
+ case BatchedCommandRequest::BatchType_Delete:
+ return _deleteReq->toBSON();
+ default:
+ MONGO_UNREACHABLE;
+ }
+ }());
// Append the shard version
if (_shardVersion) {
diff --git a/src/mongo/scripting/mozjs/mongo.cpp b/src/mongo/scripting/mozjs/mongo.cpp
index 5e2c2236fc9..e8399fd10d8 100644
--- a/src/mongo/scripting/mozjs/mongo.cpp
+++ b/src/mongo/scripting/mozjs/mongo.cpp
@@ -583,9 +583,7 @@ void MongoBase::Functions::copyDatabaseWithSCRAM::call(JSContext* cx, JS::CallAr
status = session->step(payload, &responsePayload);
uassertStatusOK(status);
- BSONObjBuilder commandBuilder;
-
- commandBuilder.appendElements(saslCommandPrefix);
+ BSONObjBuilder commandBuilder(std::move(saslCommandPrefix));
commandBuilder.appendBinData(saslCommandPayloadFieldName,
static_cast<int>(responsePayload.size()),
BinDataGeneral,
diff --git a/src/mongo/tools/bridge.cpp b/src/mongo/tools/bridge.cpp
index a6730e8a32c..0b33349a4f0 100644
--- a/src/mongo/tools/bridge.cpp
+++ b/src/mongo/tools/bridge.cpp
@@ -179,8 +179,9 @@ public:
if (!status->isOK()) {
commandReply = StatusWith<BSONObj>(*status);
}
- auto cmdResponse =
- replyBuilder->setCommandReply(commandReply).setMetadata(metadata).done();
+ auto cmdResponse = replyBuilder->setCommandReply(std::move(commandReply))
+ .setMetadata(metadata)
+ .done();
_mp->say(cmdResponse, requestId);
continue;
}
diff --git a/src/mongo/util/net/op_msg.h b/src/mongo/util/net/op_msg.h
index dc8037146be..e32b370d5d2 100644
--- a/src/mongo/util/net/op_msg.h
+++ b/src/mongo/util/net/op_msg.h
@@ -109,12 +109,11 @@ struct OpMsgRequest : public OpMsg {
}
static OpMsgRequest fromDBAndBody(StringData db,
- const BSONObj& body,
+ BSONObj body,
const BSONObj& extraFields = {}) {
OpMsgRequest request;
request.body = ([&] {
- BSONObjBuilder bodyBuilder;
- bodyBuilder.appendElements(body);
+ BSONObjBuilder bodyBuilder(std::move(body));
bodyBuilder.appendElements(extraFields);
bodyBuilder.append("$db", db);
return bodyBuilder.obj();
diff --git a/src/mongo/util/shared_buffer.h b/src/mongo/util/shared_buffer.h
index 09951dc80dc..dc8599f7e6e 100644
--- a/src/mongo/util/shared_buffer.h
+++ b/src/mongo/util/shared_buffer.h
@@ -48,7 +48,7 @@ public:
}
static SharedBuffer allocate(size_t bytes) {
- return takeOwnership(mongoMalloc(sizeof(Holder) + bytes));
+ return takeOwnership(mongoMalloc(sizeof(Holder) + bytes), bytes);
}
/**
@@ -67,7 +67,7 @@ public:
// Get newPtr into _holder with a ref-count of 1 without touching the current pointee of
// _holder which is now invalid.
- auto tmp = SharedBuffer::takeOwnership(newPtr);
+ auto tmp = SharedBuffer::takeOwnership(newPtr, size);
_holder.detach();
_holder = std::move(tmp._holder);
}
@@ -80,11 +80,29 @@ public:
return bool(_holder);
}
+ /**
+ * Returns true if this object has exclusive access to the underlying buffer.
+ * (That is, reference count == 1).
+ */
+ bool isShared() const {
+ return _holder && _holder->isShared();
+ }
+
+ /**
+ * Returns the allocation size of the underlying buffer.
+ * Users of this type must maintain the "used" size separately.
+ */
+ size_t capacity() const {
+ return _holder ? _holder->_capacity : 0;
+ }
+
private:
class Holder {
public:
- explicit Holder(AtomicUInt32::WordType initial = AtomicUInt32::WordType())
- : _refCount(initial) {}
+ explicit Holder(AtomicUInt32::WordType initial, size_t capacity)
+ : _refCount(initial), _capacity(capacity) {
+ invariant(capacity == _capacity);
+ }
// these are called automatically by boost::intrusive_ptr
friend void intrusive_ptr_add_ref(Holder* h) {
@@ -113,6 +131,7 @@ private:
}
AtomicUInt32 _refCount;
+ uint32_t _capacity;
};
explicit SharedBuffer(Holder* holder) : _holder(holder, /*add_ref=*/false) {
@@ -127,12 +146,12 @@ private:
* This class will call free(holderPrefixedData), so it must have been allocated in a way
* that makes that valid.
*/
- static SharedBuffer takeOwnership(void* holderPrefixedData) {
+ static SharedBuffer takeOwnership(void* holderPrefixedData, size_t capacity) {
// Initialize the refcount to 1 so we don't need to increment it in the constructor
// (see private Holder* constructor above).
//
// TODO: Should dassert alignment of holderPrefixedData here if possible.
- return SharedBuffer(new (holderPrefixedData) Holder(1U));
+ return SharedBuffer(new (holderPrefixedData) Holder(1U, capacity));
}
boost::intrusive_ptr<Holder> _holder;
@@ -164,6 +183,19 @@ public:
return bool(_buffer);
}
+ bool isShared() const {
+ return _buffer.isShared();
+ }
+
+ /**
+ * Converts to a mutable SharedBuffer.
+ * This is only legal to call if you have exclusive access to the underlying buffer.
+ */
+ SharedBuffer constCast() && {
+ invariant(!isShared());
+ return std::move(_buffer);
+ }
+
private:
SharedBuffer _buffer;
};