diff options
Diffstat (limited to 'src/mongo/db')
26 files changed, 157 insertions, 81 deletions
diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 4f444b9f755..c76f86163b3 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -58,6 +58,7 @@ #include "mongo/db/op_observer.h" #include "mongo/db/ops/insert.h" #include "mongo/db/repl/isself.h" +#include "mongo/db/repl/read_concern_args.h" #include "mongo/db/repl/replication_coordinator.h" #include "mongo/db/service_context.h" #include "mongo/db/storage/durable_catalog.h" @@ -311,7 +312,9 @@ void Cloner::copy(OperationContext* opCtx, from_collection, query, nullptr, - options); + options, + 0 /* batchSize */, + repl::ReadConcernArgs::kImplicitDefault); } uassert(ErrorCodes::PrimarySteppedDown, diff --git a/src/mongo/db/dbdirectclient.cpp b/src/mongo/db/dbdirectclient.cpp index 84818dcf8c4..6c8a8d3d43e 100644 --- a/src/mongo/db/dbdirectclient.cpp +++ b/src/mongo/db/dbdirectclient.cpp @@ -166,15 +166,22 @@ unique_ptr<DBClientCursor> DBDirectClient::query(const NamespaceStringOrUUID& ns int nToSkip, const BSONObj* fieldsToReturn, int queryOptions, - int batchSize) { + int batchSize, + boost::optional<BSONObj> readConcernObj) { + invariant(!readConcernObj, "passing readConcern to DBDirectClient functions is not supported"); return DBClientBase::query( nsOrUuid, query, nToReturn, nToSkip, fieldsToReturn, queryOptions, batchSize); } -long long DBDirectClient::count( - const NamespaceStringOrUUID nsOrUuid, const BSONObj& query, int options, int limit, int skip) { +long long DBDirectClient::count(const NamespaceStringOrUUID nsOrUuid, + const BSONObj& query, + int options, + int limit, + int skip, + boost::optional<BSONObj> readConcernObj) { + invariant(!readConcernObj, "passing readConcern to DBDirectClient functions is not supported"); DirectClientScope directClientScope(_opCtx); - BSONObj cmdObj = _countCmd(nsOrUuid, query, options, limit, skip); + BSONObj cmdObj = _countCmd(nsOrUuid, query, options, limit, skip, boost::none); auto dbName = (nsOrUuid.uuid() ? nsOrUuid.dbname() : (*nsOrUuid.nss()).db().toString()); diff --git a/src/mongo/db/dbdirectclient.h b/src/mongo/db/dbdirectclient.h index 9ff0dc9cd80..0554334d6fd 100644 --- a/src/mongo/db/dbdirectclient.h +++ b/src/mongo/db/dbdirectclient.h @@ -58,13 +58,15 @@ public: // XXX: is this valid or useful? void setOpCtx(OperationContext* opCtx); - virtual std::unique_ptr<DBClientCursor> query(const NamespaceStringOrUUID& nsOrUuid, - Query query, - int nToReturn = 0, - int nToSkip = 0, - const BSONObj* fieldsToReturn = nullptr, - int queryOptions = 0, - int batchSize = 0); + virtual std::unique_ptr<DBClientCursor> query( + const NamespaceStringOrUUID& nsOrUuid, + Query query, + int nToReturn = 0, + int nToSkip = 0, + const BSONObj* fieldsToReturn = nullptr, + int queryOptions = 0, + int batchSize = 0, + boost::optional<BSONObj> readConcernObj = boost::none); virtual bool isFailed() const; @@ -85,7 +87,8 @@ public: const BSONObj& query = BSONObj(), int options = 0, int limit = 0, - int skip = 0); + int skip = 0, + boost::optional<BSONObj> readConcernObj = boost::none); virtual ConnectionString::ConnectionType type() const; diff --git a/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp b/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp index 009168fd88d..70720b4442b 100644 --- a/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp +++ b/src/mongo/db/pipeline/process_interface/replica_set_node_process_interface.cpp @@ -210,10 +210,7 @@ StatusWith<BSONObj> ReplicaSetNodeProcessInterface::_executeCommandOnPrimary( void ReplicaSetNodeProcessInterface::_attachGenericCommandArgs(OperationContext* opCtx, BSONObjBuilder* cmd) const { - auto writeConcern = opCtx->getWriteConcern(); - if (!writeConcern.usedDefault) { - cmd->append(WriteConcernOptions::kWriteConcernField, writeConcern.toBSON()); - } + cmd->append(WriteConcernOptions::kWriteConcernField, opCtx->getWriteConcern().toBSON()); logical_session_id_helpers::serializeLsidAndTxnNumber(opCtx, cmd); } diff --git a/src/mongo/db/pipeline/process_interface/shardsvr_process_interface.cpp b/src/mongo/db/pipeline/process_interface/shardsvr_process_interface.cpp index 9fa7b4fc59d..dcca4ab8dd6 100644 --- a/src/mongo/db/pipeline/process_interface/shardsvr_process_interface.cpp +++ b/src/mongo/db/pipeline/process_interface/shardsvr_process_interface.cpp @@ -59,18 +59,6 @@ using write_ops::Insert; using write_ops::Update; using write_ops::UpdateOpEntry; -namespace { - -// Attaches the write concern to the given batch request. If it looks like 'writeConcern' has -// been default initialized to {w: 0, wtimeout: 0} then we do not bother attaching it. -void attachWriteConcern(const WriteConcernOptions& writeConcern, BatchedCommandRequest* request) { - if (!writeConcern.wMode.empty() || writeConcern.wNumNodes > 0) { - request->setWriteConcern(writeConcern.toBSON()); - } -} - -} // namespace - bool ShardServerProcessInterface::isSharded(OperationContext* opCtx, const NamespaceString& nss) { Lock::DBLock dbLock(opCtx, nss.db(), MODE_IS); Lock::CollectionLock collLock(opCtx, nss, MODE_IS); @@ -123,8 +111,7 @@ Status ShardServerProcessInterface::insert(const boost::intrusive_ptr<Expression BatchedCommandRequest insertCommand( buildInsertOp(ns, std::move(objs), expCtx->bypassDocumentValidation)); - // If applicable, attach a write concern to the batched command request. - attachWriteConcern(wc, &insertCommand); + insertCommand.setWriteConcern(wc.toBSON()); ClusterWriter::write(expCtx->opCtx, insertCommand, &stats, &response, targetEpoch); @@ -144,8 +131,7 @@ StatusWith<MongoProcessInterface::UpdateResult> ShardServerProcessInterface::upd BatchedCommandRequest updateCommand(buildUpdateOp(expCtx, ns, std::move(batch), upsert, multi)); - // If applicable, attach a write concern to the batched command request. - attachWriteConcern(wc, &updateCommand); + updateCommand.setWriteConcern(wc.toBSON()); ClusterWriter::write(expCtx->opCtx, updateCommand, &stats, &response, targetEpoch); @@ -176,10 +162,8 @@ void ShardServerProcessInterface::renameIfOptionsAndIndexesHaveNotChanged( auto newCmdObj = CommonMongodProcessInterface::_convertRenameToInternalRename( opCtx, renameCommandObj, originalCollectionOptions, originalIndexes); BSONObjBuilder newCmdWithWriteConcernBuilder(std::move(newCmdObj)); - if (!opCtx->getWriteConcern().usedDefault) { - newCmdWithWriteConcernBuilder.append(WriteConcernOptions::kWriteConcernField, - opCtx->getWriteConcern().toBSON()); - } + newCmdWithWriteConcernBuilder.append(WriteConcernOptions::kWriteConcernField, + opCtx->getWriteConcern().toBSON()); newCmdObj = newCmdWithWriteConcernBuilder.done(); auto cachedDbInfo = uassertStatusOK(Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, destinationNs.db())); @@ -226,12 +210,10 @@ void ShardServerProcessInterface::createCollection(OperationContext* opCtx, const BSONObj& cmdObj) { auto cachedDbInfo = uassertStatusOK(Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, dbName)); - BSONObj finalCmdObj = cmdObj; - if (!opCtx->getWriteConcern().usedDefault) { - auto writeObj = - BSON(WriteConcernOptions::kWriteConcernField << opCtx->getWriteConcern().toBSON()); - finalCmdObj = cmdObj.addField(writeObj.getField(WriteConcernOptions::kWriteConcernField)); - } + BSONObjBuilder finalCmdBuilder(cmdObj); + finalCmdBuilder.append(WriteConcernOptions::kWriteConcernField, + opCtx->getWriteConcern().toBSON()); + BSONObj finalCmdObj = finalCmdBuilder.obj(); auto response = executeCommandAgainstDatabasePrimary(opCtx, dbName, @@ -256,10 +238,8 @@ void ShardServerProcessInterface::createIndexesOnEmptyCollection( BSONObjBuilder newCmdBuilder; newCmdBuilder.append("createIndexes", ns.coll()); newCmdBuilder.append("indexes", indexSpecs); - if (!opCtx->getWriteConcern().usedDefault) { - newCmdBuilder.append(WriteConcernOptions::kWriteConcernField, - opCtx->getWriteConcern().toBSON()); - } + newCmdBuilder.append(WriteConcernOptions::kWriteConcernField, + opCtx->getWriteConcern().toBSON()); auto cmdObj = newCmdBuilder.done(); auto response = executeCommandAgainstDatabasePrimary(opCtx, @@ -285,10 +265,8 @@ void ShardServerProcessInterface::dropCollection(OperationContext* opCtx, uassertStatusOK(Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, ns.db())); BSONObjBuilder newCmdBuilder; newCmdBuilder.append("drop", ns.coll()); - if (!opCtx->getWriteConcern().usedDefault) { - newCmdBuilder.append(WriteConcernOptions::kWriteConcernField, - opCtx->getWriteConcern().toBSON()); - } + newCmdBuilder.append(WriteConcernOptions::kWriteConcernField, + opCtx->getWriteConcern().toBSON()); auto cmdObj = newCmdBuilder.done(); auto response = executeCommandAgainstDatabasePrimary(opCtx, diff --git a/src/mongo/db/pipeline/sharded_agg_helpers.cpp b/src/mongo/db/pipeline/sharded_agg_helpers.cpp index 5b3556b6089..eeb614813ef 100644 --- a/src/mongo/db/pipeline/sharded_agg_helpers.cpp +++ b/src/mongo/db/pipeline/sharded_agg_helpers.cpp @@ -108,13 +108,16 @@ RemoteCursor openChangeStreamNewShardMonitor(const boost::intrusive_ptr<Expressi aggReq.setFromMongos(true); aggReq.setNeedsMerge(true); aggReq.setBatchSize(0); - auto configCursor = - establishCursors(expCtx->opCtx, - expCtx->mongoProcessInterface->taskExecutor, - aggReq.getNamespaceString(), - ReadPreferenceSetting{ReadPreference::PrimaryPreferred}, - {{configShard->getId(), aggReq.serializeToCommandObj().toBson()}}, - false); + auto cmdObjWithRWC = applyReadWriteConcern(expCtx->opCtx, + true, /* appendRC */ + !expCtx->explain, /* appendWC */ + aggReq.serializeToCommandObj().toBson()); + auto configCursor = establishCursors(expCtx->opCtx, + expCtx->mongoProcessInterface->taskExecutor, + aggReq.getNamespaceString(), + ReadPreferenceSetting{ReadPreference::PrimaryPreferred}, + {{configShard->getId(), cmdObjWithRWC}}, + false); invariant(configCursor.size() == 1); return std::move(*configCursor.begin()); } diff --git a/src/mongo/db/query/query_request.cpp b/src/mongo/db/query/query_request.cpp index cd308aae77a..dd80516535c 100644 --- a/src/mongo/db/query/query_request.cpp +++ b/src/mongo/db/query/query_request.cpp @@ -835,6 +835,10 @@ Status QueryRequest::init(int ntoskip, } else { _filter = queryObj.getOwned(); } + // It's not possible to specify readConcern in a legacy query message, so initialize it to + // an empty readConcern object, ie. equivalent to `readConcern: {}`. This ensures that + // mongos passes this empty readConcern to shards. + _readConcern = BSONObj(); } else { // This is the debugging code path. _filter = queryObj.getOwned(); diff --git a/src/mongo/db/read_concern_mongod.cpp b/src/mongo/db/read_concern_mongod.cpp index 54588856e58..dbe4ba193cf 100644 --- a/src/mongo/db/read_concern_mongod.cpp +++ b/src/mongo/db/read_concern_mongod.cpp @@ -180,7 +180,9 @@ Status makeNoopWriteIfNeeded(OperationContext* opCtx, LogicalTime clusterTime) { "admin", BSON("appendOplogNote" << 1 << "maxClusterTime" << clusterTime.asTimestamp() << "data" - << BSON("noop write for afterClusterTime read concern" << 1)), + << BSON("noop write for afterClusterTime read concern" << 1) + << WriteConcernOptions::kWriteConcernField + << WriteConcernOptions::kImplicitDefault), Shard::RetryPolicy::kIdempotent); status = swRes.getStatus(); std::get<1>(myWriteRequest)->set(status); diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index e983f6acbd4..4425209c8db 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -895,6 +895,7 @@ env.Library( LIBDEPS=[ 'oplog_entry', 'optime', + 'read_concern_args', '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/client/fetcher', '$BUILD_DIR/mongo/db/namespace_string', diff --git a/src/mongo/db/repl/collection_cloner.cpp b/src/mongo/db/repl/collection_cloner.cpp index b4c54057e31..c98cb47d034 100644 --- a/src/mongo/db/repl/collection_cloner.cpp +++ b/src/mongo/db/repl/collection_cloner.cpp @@ -132,7 +132,12 @@ BaseCloner::AfterStageBehavior CollectionCloner::CollectionClonerStage::run() { } BaseCloner::AfterStageBehavior CollectionCloner::countStage() { - auto count = getClient()->count(_sourceDbAndUuid, {} /* Query */, QueryOption_SlaveOk); + auto count = getClient()->count(_sourceDbAndUuid, + {} /* Query */, + QueryOption_SlaveOk, + 0 /* limit */, + 0 /* skip */, + ReadConcernArgs::kImplicitDefault); // The count command may return a negative value after an unclean shutdown, // so we set it to zero here to avoid aborting the collection clone. @@ -231,7 +236,8 @@ void CollectionCloner::runQuery() { nullptr /* fieldsToReturn */, QueryOption_NoCursorTimeout | QueryOption_SlaveOk | (collectionClonerUsesExhaust ? QueryOption_Exhaust : 0), - _collectionClonerBatchSize); + _collectionClonerBatchSize, + ReadConcernArgs::kImplicitDefault); } catch (...) { auto status = exceptionToStatus(); diff --git a/src/mongo/db/repl/initial_syncer.cpp b/src/mongo/db/repl/initial_syncer.cpp index 6bc07e723b7..39ad438a288 100644 --- a/src/mongo/db/repl/initial_syncer.cpp +++ b/src/mongo/db/repl/initial_syncer.cpp @@ -1736,7 +1736,8 @@ void InitialSyncer::_finishCallback(StatusWith<OpTimeAndWallTime> lastApplied) { Status InitialSyncer::_scheduleLastOplogEntryFetcher_inlock( Fetcher::CallbackFn callback, LastOplogEntryFetcherRetryStrategy retryStrategy) { BSONObj query = BSON("find" << _opts.remoteOplogNS.coll() << "sort" << BSON("$natural" << -1) - << "limit" << 1); + << "limit" << 1 << ReadConcernArgs::kReadConcernFieldName + << ReadConcernArgs::kImplicitDefault); _lastOplogEntryFetcher = std::make_unique<Fetcher>( _exec, diff --git a/src/mongo/db/repl/oplog_interface_remote.cpp b/src/mongo/db/repl/oplog_interface_remote.cpp index a71aae7cb15..883596318b9 100644 --- a/src/mongo/db/repl/oplog_interface_remote.cpp +++ b/src/mongo/db/repl/oplog_interface_remote.cpp @@ -34,6 +34,7 @@ #include "mongo/client/dbclient_base.h" #include "mongo/client/dbclient_cursor.h" #include "mongo/db/jsobj.h" +#include "mongo/db/repl/read_concern_args.h" #include "mongo/util/str.h" namespace mongo { @@ -83,8 +84,14 @@ std::unique_ptr<OplogInterface::Iterator> OplogInterfaceRemote::makeIterator() c const Query query = Query().sort(BSON("$natural" << -1)); const BSONObj fields = BSON("ts" << 1 << "t" << 1); return std::unique_ptr<OplogInterface::Iterator>( - new OplogIteratorRemote(_getConnection()->query( - NamespaceString(_collectionName), query, 0, 0, &fields, 0, _batchSize))); + new OplogIteratorRemote(_getConnection()->query(NamespaceString(_collectionName), + query, + 0, + 0, + &fields, + 0, + _batchSize, + ReadConcernArgs::kImplicitDefault))); } std::unique_ptr<TransactionHistoryIteratorBase> diff --git a/src/mongo/db/repl/read_concern_args.cpp b/src/mongo/db/repl/read_concern_args.cpp index 2ef071a38cc..0c446ce4780 100644 --- a/src/mongo/db/repl/read_concern_args.cpp +++ b/src/mongo/db/repl/read_concern_args.cpp @@ -57,6 +57,11 @@ const ReadConcernArgs& ReadConcernArgs::get(const OperationContext* opCtx) { } +// The "kImplicitDefault" read concern, used by internal operations, is deliberately empty (no +// 'level' specified). This allows internal operations to specify a read concern, while still +// allowing it to be either local or available on sharded secondaries. +const BSONObj ReadConcernArgs::kImplicitDefault; + ReadConcernArgs::ReadConcernArgs() : _specified(false) {} ReadConcernArgs::ReadConcernArgs(boost::optional<ReadConcernLevel> level) diff --git a/src/mongo/db/repl/read_concern_args.h b/src/mongo/db/repl/read_concern_args.h index 1adba9777fc..46353040528 100644 --- a/src/mongo/db/repl/read_concern_args.h +++ b/src/mongo/db/repl/read_concern_args.h @@ -55,6 +55,8 @@ public: static constexpr StringData kAtClusterTimeFieldName = "atClusterTime"_sd; static constexpr StringData kLevelFieldName = "level"_sd; + static const BSONObj kImplicitDefault; + /** * Represents the internal mechanism an operation uses to satisfy 'majority' read concern. */ diff --git a/src/mongo/db/repl/replication_info.cpp b/src/mongo/db/repl/replication_info.cpp index fd8ce22e8d0..bf33e4334d7 100644 --- a/src/mongo/db/repl/replication_info.cpp +++ b/src/mongo/db/repl/replication_info.cpp @@ -185,9 +185,15 @@ TopologyVersion appendReplicationInfo(OperationContext* opCtx, DBClientConnection* cliConn = dynamic_cast<DBClientConnection*>(&conn.conn()); if (cliConn && replAuthenticate(cliConn).isOK()) { BSONObj first = conn->findOne((string) "local.oplog.$" + sourcename, - Query().sort(BSON("$natural" << 1))); + Query().sort(BSON("$natural" << 1)), + nullptr /* fieldsToReturn */, + 0 /* queryOptions */, + ReadConcernArgs::kImplicitDefault); BSONObj last = conn->findOne((string) "local.oplog.$" + sourcename, - Query().sort(BSON("$natural" << -1))); + Query().sort(BSON("$natural" << -1)), + nullptr /* fieldsToReturn */, + 0 /* queryOptions */, + ReadConcernArgs::kImplicitDefault); bb.appendDate("masterFirst", first["ts"].timestampTime()); bb.appendDate("masterLast", last["ts"].timestampTime()); const auto lag = (last["ts"].timestampTime() - s["syncedTo"].timestampTime()); diff --git a/src/mongo/db/repl/roll_back_local_operations_test.cpp b/src/mongo/db/repl/roll_back_local_operations_test.cpp index f51e5404d4b..6862dbf20bb 100644 --- a/src/mongo/db/repl/roll_back_local_operations_test.cpp +++ b/src/mongo/db/repl/roll_back_local_operations_test.cpp @@ -326,7 +326,8 @@ public: int nToSkip, const BSONObj* fieldsToReturn, int queryOptions, - int batchSize) override { + int batchSize, + boost::optional<BSONObj> readConcernObj) override { if (_initFailuresLeft > 0) { _initFailuresLeft--; LOGV2(21657, diff --git a/src/mongo/db/repl/rollback_source_impl.cpp b/src/mongo/db/repl/rollback_source_impl.cpp index 8d06503b597..bc111c75397 100644 --- a/src/mongo/db/repl/rollback_source_impl.cpp +++ b/src/mongo/db/repl/rollback_source_impl.cpp @@ -35,6 +35,7 @@ #include "mongo/db/cloner.h" #include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/repl/read_concern_args.h" #include "mongo/db/repl/replication_auth.h" #include "mongo/util/assert_util.h" #include "mongo/util/str.h" @@ -68,19 +69,21 @@ int RollbackSourceImpl::getRollbackId() const { BSONObj RollbackSourceImpl::getLastOperation() const { const Query query = Query().sort(BSON("$natural" << -1)); - return _getConnection()->findOne(_collectionName, query, nullptr, QueryOption_SlaveOk); + return _getConnection()->findOne( + _collectionName, query, nullptr, QueryOption_SlaveOk, ReadConcernArgs::kImplicitDefault); } BSONObj RollbackSourceImpl::findOne(const NamespaceString& nss, const BSONObj& filter) const { return _getConnection() - ->findOne(nss.toString(), filter, nullptr, QueryOption_SlaveOk) + ->findOne( + nss.toString(), filter, nullptr, QueryOption_SlaveOk, ReadConcernArgs::kImplicitDefault) .getOwned(); } std::pair<BSONObj, NamespaceString> RollbackSourceImpl::findOneByUUID(const std::string& db, UUID uuid, const BSONObj& filter) const { - return _getConnection()->findOneByUUID(db, uuid, filter); + return _getConnection()->findOneByUUID(db, uuid, filter, ReadConcernArgs::kImplicitDefault); } void RollbackSourceImpl::copyCollectionFromRemote(OperationContext* opCtx, diff --git a/src/mongo/db/repl/sync_source_resolver.cpp b/src/mongo/db/repl/sync_source_resolver.cpp index a7e289e3996..e75c1782192 100644 --- a/src/mongo/db/repl/sync_source_resolver.cpp +++ b/src/mongo/db/repl/sync_source_resolver.cpp @@ -173,9 +173,7 @@ std::unique_ptr<Fetcher> SyncSourceResolver::_makeFirstOplogEntryFetcher( << "projection" << BSON(OplogEntryBase::kTimestampFieldName << 1 << OplogEntryBase::kTermFieldName << 1) - << "readConcern" - << BSON("level" - << "local")), + << ReadConcernArgs::kReadConcernFieldName << ReadConcernArgs::kImplicitDefault), [=](const StatusWith<Fetcher::QueryResponse>& response, Fetcher::NextAction*, BSONObjBuilder*) { @@ -198,9 +196,7 @@ std::unique_ptr<Fetcher> SyncSourceResolver::_makeRequiredOpTimeFetcher(HostAndP BSON("find" << kLocalOplogNss.coll() << "oplogReplay" << true << "filter" << BSON("ts" << BSON("$gte" << _requiredOpTime.getTimestamp() << "$lte" << _requiredOpTime.getTimestamp())) - << "readConcern" - << BSON("level" - << "local")), + << ReadConcernArgs::kReadConcernFieldName << ReadConcernArgs::kImplicitDefault), [=](const StatusWith<Fetcher::QueryResponse>& response, Fetcher::NextAction*, BSONObjBuilder*) { diff --git a/src/mongo/db/s/add_shard_cmd.cpp b/src/mongo/db/s/add_shard_cmd.cpp index c2e8e3684a2..aab1f4d7b79 100644 --- a/src/mongo/db/s/add_shard_cmd.cpp +++ b/src/mongo/db/s/add_shard_cmd.cpp @@ -79,7 +79,7 @@ public: private: bool supportsWriteConcern() const override { - return true; + return false; } // The command parameter happens to be string so it's historically been interpreted diff --git a/src/mongo/db/s/balancer/migration_manager.cpp b/src/mongo/db/s/balancer/migration_manager.cpp index 4a1d614d34d..100855905b7 100644 --- a/src/mongo/db/s/balancer/migration_manager.cpp +++ b/src/mongo/db/s/balancer/migration_manager.cpp @@ -469,6 +469,17 @@ shared_ptr<Notification<RemoteCommandResponse>> MigrationManager::_schedule( waitForDelete, migrateInfo.forceJumbo); + // In 4.4, commands sent to shards that accept writeConcern, must always have writeConcern. + // So if the MoveChunkRequest didn't add writeConcern (from secondaryThrottle), then we add + // the implicit server default writeConcern. + if (!builder.hasField(WriteConcernOptions::kWriteConcernField) && + serverGlobalParams.featureCompatibility.isVersionInitialized() && + serverGlobalParams.featureCompatibility.getVersion() == + ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44) { + builder.append(WriteConcernOptions::kWriteConcernField, + WriteConcernOptions::kImplicitDefault); + } + stdx::lock_guard<Latch> lock(_mutex); if (_state != State::kEnabled && _state != State::kRecovering) { diff --git a/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp b/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp index a3941cfde46..98766413fac 100644 --- a/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp +++ b/src/mongo/db/s/migration_chunk_cloner_source_legacy.cpp @@ -296,6 +296,17 @@ Status MigrationChunkClonerSourceLegacy::startClone(OperationContext* opCtx, _shardKeyPattern.toBSON(), _args.getSecondaryThrottle()); + if (serverGlobalParams.featureCompatibility.isVersion( + ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44)) { + // In 4.4, commands sent to shards that accept writeConcern, must always have writeConcern. + // So if the StartChunkCloneRequest didn't add writeConcern (from secondaryThrottle), then + // we add the implicit server default writeConcern. + if (!cmdBuilder.hasField(WriteConcernOptions::kWriteConcernField)) { + cmdBuilder.append(WriteConcernOptions::kWriteConcernField, + WriteConcernOptions::kImplicitDefault); + } + } + auto startChunkCloneResponseStatus = _callRecipient(cmdBuilder.obj()); if (!startChunkCloneResponseStatus.isOK()) { return startChunkCloneResponseStatus.getStatus(); @@ -367,6 +378,17 @@ Status MigrationChunkClonerSourceLegacy::startClone(OperationContext* opCtx) { _shardKeyPattern.toBSON(), _args.getSecondaryThrottle()); + if (serverGlobalParams.featureCompatibility.isVersion( + ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo44)) { + // In 4.4, commands sent to shards that accept writeConcern, must always have writeConcern. + // So if the StartChunkCloneRequest didn't add writeConcern (from secondaryThrottle), then + // we add the implicit server default writeConcern. + if (!cmdBuilder.hasField(WriteConcernOptions::kWriteConcernField)) { + cmdBuilder.append(WriteConcernOptions::kWriteConcernField, + WriteConcernOptions::kImplicitDefault); + } + } + auto startChunkCloneResponseStatus = _callRecipient(cmdBuilder.obj()); if (!startChunkCloneResponseStatus.isOK()) { return startChunkCloneResponseStatus.getStatus(); diff --git a/src/mongo/db/s/migration_util.cpp b/src/mongo/db/s/migration_util.cpp index ead3d722055..02d7e5bcc31 100644 --- a/src/mongo/db/s/migration_util.cpp +++ b/src/mongo/db/s/migration_util.cpp @@ -41,6 +41,7 @@ #include "mongo/client/query.h" #include "mongo/db/catalog/collection_catalog_helper.h" #include "mongo/db/catalog_raii.h" +#include "mongo/db/commands.h" #include "mongo/db/dbdirectclient.h" #include "mongo/db/logical_session_cache.h" #include "mongo/db/namespace_string.h" @@ -693,7 +694,8 @@ void ensureChunkVersionIsGreaterThan(OperationContext* opCtx, newOpCtx, ReadPreferenceSetting{ReadPreference::PrimaryOnly}, "admin", - ensureChunkVersionIsGreaterThanRequestBSON, + CommandHelpers::appendMajorityWriteConcern( + ensureChunkVersionIsGreaterThanRequestBSON), Shard::RetryPolicy::kIdempotent); const auto ensureChunkVersionIsGreaterThanStatus = Shard::CommandResponse::getEffectiveStatus(ensureChunkVersionIsGreaterThanResponse); diff --git a/src/mongo/db/s/shard_key_util.cpp b/src/mongo/db/s/shard_key_util.cpp index 906757d353c..62c67614e2e 100644 --- a/src/mongo/db/s/shard_key_util.cpp +++ b/src/mongo/db/s/shard_key_util.cpp @@ -167,7 +167,8 @@ void validateShardKeyAgainstExistingIndexes(OperationContext* opCtx, } } - auto countCmd = BSON("count" << nss.coll()); + auto countCmd = BSON("count" << nss.coll() << repl::ReadConcernArgs::kReadConcernFieldName + << repl::ReadConcernArgs::kImplicitDefault); auto countRes = uassertStatusOK(primaryShard->runCommand(opCtx, ReadPreferenceSetting(ReadPreference::PrimaryOnly), diff --git a/src/mongo/db/sessions_collection.cpp b/src/mongo/db/sessions_collection.cpp index 4e0e121abaf..b883bebf76c 100644 --- a/src/mongo/db/sessions_collection.cpp +++ b/src/mongo/db/sessions_collection.cpp @@ -40,6 +40,7 @@ #include "mongo/db/create_indexes_gen.h" #include "mongo/db/logical_session_id.h" #include "mongo/db/ops/write_ops.h" +#include "mongo/db/repl/read_concern_args.h" #include "mongo/rpc/get_status_from_command_result.h" #include "mongo/s/write_ops/batched_command_response.h" @@ -234,7 +235,10 @@ LogicalSessionIdSet SessionsCollection::_doFindRemoved( LogicalSessionIdSet removed{sessions.begin(), sessions.end()}; auto wrappedSend = [&](BSONObj batch) { - auto swBatchResult = send(batch); + BSONObjBuilder batchWithReadConcernLocal(batch); + batchWithReadConcernLocal.append(repl::ReadConcernArgs::kReadConcernFieldName, + repl::ReadConcernArgs::kImplicitDefault); + auto swBatchResult = send(batchWithReadConcernLocal.obj()); auto result = SessionsCollectionFetchResult::parse("SessionsCollectionFetchResult"_sd, swBatchResult); @@ -279,7 +283,9 @@ BSONObj SessionsCollection::generateCreateIndexesCmd() { createIndexes.setCreateIndexes(NamespaceString::kLogicalSessionsNamespace.coll()); createIndexes.setIndexes(std::move(indexes)); - return createIndexes.toBSON(); + return BSONObjBuilder(createIndexes.toBSON()) + .append(WriteConcernOptions::kWriteConcernField, WriteConcernOptions::kImplicitDefault) + .obj(); } BSONObj SessionsCollection::generateCollModCmd() { @@ -292,6 +298,8 @@ BSONObj SessionsCollection::generateCollModCmd() { indexBuilder << "expireAfterSeconds" << localLogicalSessionTimeoutMinutes * 60; indexBuilder.done(); + collModCmdBuilder.append(WriteConcernOptions::kWriteConcernField, + WriteConcernOptions::kImplicitDefault); collModCmdBuilder.done(); return collModCmdBuilder.obj(); diff --git a/src/mongo/db/write_concern_options.cpp b/src/mongo/db/write_concern_options.cpp index 298941fbdef..7ff06c9d224 100644 --- a/src/mongo/db/write_concern_options.cpp +++ b/src/mongo/db/write_concern_options.cpp @@ -72,6 +72,12 @@ const BSONObj WriteConcernOptions::Default = BSONObj(); const BSONObj WriteConcernOptions::Acknowledged(BSON("w" << W_NORMAL)); const BSONObj WriteConcernOptions::Unacknowledged(BSON("w" << W_NONE)); const BSONObj WriteConcernOptions::Majority(BSON("w" << WriteConcernOptions::kMajority)); + +// The "kImplicitDefault" write concern, used by internal operations, is deliberately empty (no +// 'w' or 'wtimeout' specified). This allows internal operations to specify a write concern, while +// still allowing it to be either w:1 or automatically upconverted to w:majority on configsvrs. +const BSONObj WriteConcernOptions::kImplicitDefault; + constexpr Seconds WriteConcernOptions::kWriteConcernTimeoutSystem; constexpr Seconds WriteConcernOptions::kWriteConcernTimeoutMigration; constexpr Seconds WriteConcernOptions::kWriteConcernTimeoutSharding; diff --git a/src/mongo/db/write_concern_options.h b/src/mongo/db/write_concern_options.h index 07cd6a6e1d7..0d9cca66889 100644 --- a/src/mongo/db/write_concern_options.h +++ b/src/mongo/db/write_concern_options.h @@ -54,6 +54,7 @@ public: static const BSONObj Unacknowledged; static const BSONObj Majority; static const BSONObj ConfigMajority; + static const BSONObj kImplicitDefault; static constexpr StringData kWriteConcernField = "writeConcern"_sd; static const char kMajority[]; // = "majority" |