diff options
author | Billy Donahue <billy.donahue@mongodb.com> | 2021-04-13 20:52:44 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-04-22 00:00:27 +0000 |
commit | 8f4dbd6889eb9534da7af27729aa0c2edea532f0 (patch) | |
tree | 9849d0d59ba36bb78f8bed91d9ee23512ea116a7 | |
parent | ccca20406141099cf6f778cd01e633ecd1fd8f11 (diff) | |
download | mongo-8f4dbd6889eb9534da7af27729aa0c2edea532f0.tar.gz |
SERVER-43964 UUID etc need not befriend IDL types
-rw-r--r-- | buildscripts/idl/idl/cpp_types.py | 18 | ||||
-rw-r--r-- | buildscripts/idl/idl/generator.py | 24 | ||||
-rw-r--r-- | src/mongo/db/s/migration_destination_manager.cpp | 32 | ||||
-rw-r--r-- | src/mongo/db/s/migration_destination_manager.h | 2 | ||||
-rw-r--r-- | src/mongo/idl/idl_parser.h | 64 | ||||
-rw-r--r-- | src/mongo/s/catalog/type_chunk.h | 12 | ||||
-rw-r--r-- | src/mongo/util/uuid.h | 84 |
7 files changed, 108 insertions, 128 deletions
diff --git a/buildscripts/idl/idl/cpp_types.py b/buildscripts/idl/idl/cpp_types.py index d4066af197f..bb7ec7d0a22 100644 --- a/buildscripts/idl/idl/cpp_types.py +++ b/buildscripts/idl/idl/cpp_types.py @@ -56,24 +56,6 @@ def is_primitive_scalar_type(cpp_type): ] -def get_primitive_scalar_type_default_value(cpp_type): - # type: (str) -> str - """ - Return a default value for a primitive scalar type. - - Assumes the IDL generated code verifies the user sets the value before serialization. - """ - # pylint: disable=invalid-name - assert is_primitive_scalar_type(cpp_type) - if cpp_type == 'bool': - return 'false' - # TODO (SERVER-50101): Remove 'FeatureCompatibility::Version' once IDL supports a command - # cpp_type of C++ enum. - if cpp_type == 'ServerGlobalParams::FeatureCompatibility::Version': - return 'ServerGlobalParams::FeatureCompatibility::Version::kUnsetDefault44Behavior' - return '-1' - - def is_primitive_type(cpp_type): # type: (str) -> bool """Return True if a cpp_type is a primitive type and should not be returned as reference.""" diff --git a/buildscripts/idl/idl/generator.py b/buildscripts/idl/idl/generator.py index 34747fd6d24..3dc643b5075 100644 --- a/buildscripts/idl/idl/generator.py +++ b/buildscripts/idl/idl/generator.py @@ -1580,13 +1580,12 @@ class _CppSourceFileWriter(_CppFileWriterBase): if default_init: for field in struct.fields: needs_init = (field.type and field.type.cpp_type and not field.type.is_array - and cpp_types.is_primitive_scalar_type(field.type.cpp_type)) - - if _is_required_serializer_field(field) and needs_init: + and _is_required_serializer_field(field) + and field.cpp_name != 'dbName') + if needs_init: initializers.append( - '%s(%s)' % (_get_field_member_name(field), - cpp_types.get_primitive_scalar_type_default_value( - field.type.cpp_type))) + '%s(mongo::idl::preparsedValue<decltype(%s)>())' % + (_get_field_member_name(field), _get_field_member_name(field))) # Serialize the _dbName field second initializes_db_name = False @@ -1760,13 +1759,13 @@ class _CppSourceFileWriter(_CppFileWriterBase): if struct.command_field.type.cpp_type and cpp_types.is_primitive_scalar_type( struct.command_field.type.cpp_type): - self._writer.write_line('%s localCmdType(%s);' % - (cpp_type_info.get_storage_type(), - cpp_types.get_primitive_scalar_type_default_value( - struct.command_field.type.cpp_type))) + self._writer.write_line( + 'auto localCmdType = mongo::idl::preparsedValue<%s>();' % + (cpp_type_info.get_storage_type())) else: self._writer.write_line( - '%s localCmdType;' % (cpp_type_info.get_storage_type())) + 'auto localCmdType = mongo::idl::preparsedValue<%s>();' % + (cpp_type_info.get_storage_type())) self._writer.write_line( '%s object(localCmdType);' % (common.title_case(struct.cpp_name))) elif struct.namespace in (common.COMMAND_NAMESPACE_CONCATENATE_WITH_DB, @@ -1777,7 +1776,8 @@ class _CppSourceFileWriter(_CppFileWriterBase): else: assert False, "Missing case" else: - self._writer.write_line('%s object;' % common.title_case(struct.cpp_name)) + self._writer.write_line('auto object = mongo::idl::preparsedValue<%s>();' % + common.title_case(struct.cpp_name)) self._writer.write_line(method_info.get_call('object')) self._writer.write_line('return object;') diff --git a/src/mongo/db/s/migration_destination_manager.cpp b/src/mongo/db/s/migration_destination_manager.cpp index 7e5a9fbe72f..3c62eaa932d 100644 --- a/src/mongo/db/s/migration_destination_manager.cpp +++ b/src/mongo/db/s/migration_destination_manager.cpp @@ -701,7 +701,7 @@ MigrationDestinationManager::getCollectionOptions(OperationContext* opCtx, fromOptionsBob.append(info["uuid"]); fromOptions = fromOptionsBob.obj(); - return {fromOptions, fromUUID}; + return {fromOptions, UUID::fromCDR(fromUUID)}; } void MigrationDestinationManager::_dropLocalIndexesIfNecessary( @@ -918,7 +918,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* outerOpCtx) { "fromShard"_attr = _fromShard, "epoch"_attr = _epoch, "sessionId"_attr = *_sessionId, - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); MoveTimingHelper timing( outerOpCtx, "to", _nss.ns(), _min, _max, 6 /* steps */, &_errmsg, _toShard, _fromShard); @@ -928,7 +928,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* outerOpCtx) { if (initialState == ABORT) { LOGV2_ERROR(22013, "Migration abort requested before the migration started", - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); return; } @@ -965,7 +965,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* outerOpCtx) { "scheduled for deletion", "namespace"_attr = _nss.ns(), "range"_attr = redact(range.toString()), - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); auto status = CollectionShardingRuntime::waitForClean( outerOpCtx, _nss, donorCollectionOptionsAndIndexes.uuid, range); @@ -979,7 +979,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* outerOpCtx) { } // Insert a pending range deletion task for the incoming range. - RangeDeletionTask recipientDeletionTask(_migrationId, + RangeDeletionTask recipientDeletionTask(*_migrationId, _nss, donorCollectionOptionsAndIndexes.uuid, _fromShard, @@ -1099,7 +1099,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* outerOpCtx) { LOGV2_WARNING( 22011, "secondaryThrottle on, but doc insert timed out; continuing", - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); } else { uassertStatusOK(replStatus.status); } @@ -1177,7 +1177,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* outerOpCtx) { if (getState() == ABORT) { LOGV2(22002, "Migration aborted while waiting for replication at catch up stage", - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); return; } @@ -1190,7 +1190,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* outerOpCtx) { if (i > 100) { LOGV2(22003, "secondaries having hard time keeping up with migrate", - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); } sleepmillis(20); @@ -1212,12 +1212,12 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* outerOpCtx) { LOGV2(22004, "Waiting for replication to catch up before entering critical section", - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); LOGV2_DEBUG_OPTIONS(4817411, 2, {logv2::LogComponent::kShardMigrationPerf}, "Starting majority commit wait on recipient", - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); runWithoutSession(outerOpCtx, [&] { auto awaitReplicationResult = @@ -1229,12 +1229,12 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* outerOpCtx) { LOGV2(22005, "Chunk data replicated successfully.", - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); LOGV2_DEBUG_OPTIONS(4817412, 2, {logv2::LogComponent::kShardMigrationPerf}, "Finished majority commit wait on recipient", - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); } { @@ -1274,7 +1274,7 @@ void MigrationDestinationManager::_migrateDriver(OperationContext* outerOpCtx) { if (getState() == ABORT) { LOGV2(22006, "Migration aborted while transferring mods", - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); return; } @@ -1407,7 +1407,7 @@ bool MigrationDestinationManager::_applyMigrateOp(OperationContext* opCtx, "reloaded remote document", "localDoc"_attr = redact(localDoc), "remoteDoc"_attr = redact(updatedDoc), - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); } // We are in write lock here, so sure we aren't killing @@ -1438,7 +1438,7 @@ bool MigrationDestinationManager::_flushPendingWrites(OperationContext* opCtx, "chunkMin"_attr = redact(_min), "chunkMax"_attr = redact(_max), "lastOpApplied"_attr = op, - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); } return false; } @@ -1449,7 +1449,7 @@ bool MigrationDestinationManager::_flushPendingWrites(OperationContext* opCtx, "namespace"_attr = _nss.ns(), "chunkMin"_attr = redact(_min), "chunkMax"_attr = redact(_max), - "migrationId"_attr = _migrationId.toBSON()); + "migrationId"_attr = _migrationId->toBSON()); return true; } diff --git a/src/mongo/db/s/migration_destination_manager.h b/src/mongo/db/s/migration_destination_manager.h index 761f8c9c4ef..b90a56f52f1 100644 --- a/src/mongo/db/s/migration_destination_manager.h +++ b/src/mongo/db/s/migration_destination_manager.h @@ -234,7 +234,7 @@ private: stdx::thread _migrateThreadHandle; - UUID _migrationId; + boost::optional<UUID> _migrationId; LogicalSessionId _lsid; TxnNumber _txnNumber{kUninitializedTxnNumber}; NamespaceString _nss; diff --git a/src/mongo/idl/idl_parser.h b/src/mongo/idl/idl_parser.h index 316ccd06c7e..17d7c803586 100644 --- a/src/mongo/idl/idl_parser.h +++ b/src/mongo/idl/idl_parser.h @@ -37,6 +37,7 @@ #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/bsontypes.h" #include "mongo/db/namespace_string.h" +#include "mongo/stdx/type_traits.h" namespace mongo { @@ -70,6 +71,69 @@ void idlSerialize(BSONObjBuilder* builder, StringData fieldName, std::vector<T> } } +/** + * A few overloads of `idlPreparsedValue` are built into IDL. See + * `preparsedValue` below. They are placed into a tiny private + * namespace which defines no types to isolate them. + */ +namespace preparsed_value_adl_barrier { + +/** + * This is the fallback for `idlPreparsedValue`. It value-initializes a `T` + * with a forwarded argument list in the usual way. + */ +template <typename T, typename... A> +auto idlPreparsedValue(stdx::type_identity<T>, A&&... a) { + return T(std::forward<A>(a)...); +} + +/** + * The value -1 is a conspicuous "uninitialized" value for integers. + * The integral type `bool` is exempt from this convention, however. + */ +template <typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<bool, T>, int> = 0> +auto idlPreparsedValue(stdx::type_identity<T>) { + return static_cast<T>(-1); +} + +/** + * Define a default Feature Compatibility Version enum value for use in parsed + * ServerGlobalParams. + * TODO(SERVER-50101): Remove 'FeatureCompatibility::Version' once IDL supports + * a command cpp_type of C++ enum. + */ +inline auto idlPreparsedValue( + stdx::type_identity<ServerGlobalParams::FeatureCompatibility::Version>) { + return ServerGlobalParams::FeatureCompatibility::Version::kUnsetDefault44Behavior; +} + +} // namespace preparsed_value_adl_barrier + +/** + * Constructs an instance of `T(args...)` for use in idl parsing. The way the + * IDL generator currently writes C++ parse functions, it makes an instance of + * a field of type `T` and then mutates it. `preparsedValue<T>()` is used to + * construct those objects. This convention allows an extension hook whereby a + * type can select a custom initializer for such pre-parsed objects, + * particularly for types that shouldn't have a public default constructor. + * + * The extension hook is implemented via ADL on the name `idlPreparsedValue`. + * + * `idlPreparsedValue` takes a `type_identity<T>` and then some forwarded + * constructor arguments optionally (the IDL generator doesn't currently + * provide any such arguments but could conceivably do so in the future). A + * type `T` is deduced from this `type_identity<T>` argument. + * + * There are other ways to implement this extension mechanism, but this + * phrasing allows argument-dependent lookup to search the namespaces + * associated with `T`, since `T` is a template parameter of the + * `type_identity<T>` argument. + */ +template <typename T, typename... A> +T preparsedValue(A&&... args) { + using preparsed_value_adl_barrier::idlPreparsedValue; + return idlPreparsedValue(stdx::type_identity<T>{}, std::forward<A>(args)...); +} } // namespace idl diff --git a/src/mongo/s/catalog/type_chunk.h b/src/mongo/s/catalog/type_chunk.h index 425edb9c4e2..1de86691f20 100644 --- a/src/mongo/s/catalog/type_chunk.h +++ b/src/mongo/s/catalog/type_chunk.h @@ -39,6 +39,7 @@ #include "mongo/s/chunk_version.h" #include "mongo/s/shard_id.h" #include "mongo/s/shard_key_pattern.h" +#include "mongo/stdx/type_traits.h" namespace mongo { @@ -123,17 +124,14 @@ public: ChunkRange unionWith(ChunkRange const& other) const; private: - // For use with IDL parsing - limited to friend access only. - ChunkRange() = default; - - // Make the IDL generated parser a friend - friend class RangeDeletionTask; - friend class MigrationCoordinatorDocument; - BSONObj _minKey; BSONObj _maxKey; }; +inline ChunkRange idlPreparsedValue(stdx::type_identity<ChunkRange>) { + return ChunkRange{{}, {}}; +} + class ChunkHistory : public ChunkHistoryBase { public: ChunkHistory() : ChunkHistoryBase() {} diff --git a/src/mongo/util/uuid.h b/src/mongo/util/uuid.h index a5e259a3c9a..eade27480d6 100644 --- a/src/mongo/util/uuid.h +++ b/src/mongo/util/uuid.h @@ -40,83 +40,20 @@ #include "mongo/bson/bsonmisc.h" #include "mongo/bson/bsonobj.h" #include "mongo/logv2/log_attr.h" +#include "mongo/stdx/type_traits.h" namespace mongo { -namespace repl { -class CollectionInfo; -class OplogEntryBase; -class DurableReplOperation; -class InitialSyncIdDocument; -} // namespace repl - -namespace idl { -namespace import { -class One_UUID; -} // namespace import -} // namespace idl - /** * A UUID is a 128-bit unique identifier, per RFC 4122, v4, using * a secure random number generator. */ class UUID { - using UUIDStorage = std::array<unsigned char, 16>; - - // Make the IDL generated parser a friend - friend class ConfigsvrShardCollectionResponse; - friend class CommonReshardingMetadata; - friend class DonorAbortMigration; - friend class DonorStartMigration; - friend class DonorWaitForMigrationToCommit; - friend class DonorForgetMigration; - friend class DonorStateMachine; - friend class DatabaseVersion; - friend class DbCheckOplogCollection; - friend class EncryptionPlaceholder; - friend class ExternalKeysCollectionDocument; - friend class idl::import::One_UUID; - friend class IndexBuildEntry; - friend class KeyStoreRecord; - friend class ListCollectionsReplyInfo; - friend class LogicalSessionId; - friend class LogicalSessionToClient; - friend class LogicalSessionIdToClient; - friend class LogicalSessionFromClient; - friend class MigrationCoordinatorDocument; - friend class MigrationDestinationManager; - friend class MigrationRecipientCommonData; - friend class RangeDeletionTask; - friend class ResolvedKeyId; - friend class repl::CollectionInfo; - friend class repl::OplogEntryBase; - friend class repl::DurableReplOperation; - friend class repl::InitialSyncIdDocument; - friend class RecipientForgetMigration; - friend class RecipientSyncData; - friend class ReshardingDonorDocument; - friend class ReshardingSourceId; - friend class ResumeIndexInfo; - friend class ResumeTokenInternal; - friend class ShardCollectionTypeBase; - friend class ShardsvrCleanupReshardCollection; - friend class ShardsvrShardCollectionResponse; - friend class ShardsvrRenameCollection; - friend class TenantMigrationDonorDocument; - friend class TenantMigrationRecipientDocument; - friend class TestReshardCloneCollection; - friend class TypeCollectionRecipientFields; - friend class TypeCollectionReshardingFields; - friend class VoteCommitIndexBuild; - friend class ImportCollectionOplogEntry; - friend class VoteCommitImportCollection; - - public: /** * The number of bytes contained in a UUID. */ - static constexpr int kNumBytes = sizeof(UUIDStorage); + static constexpr int kNumBytes = 16; /** * Generate a new random v4 UUID per RFC 4122. @@ -143,7 +80,7 @@ public: static UUID parse(const BSONObj& obj); static UUID fromCDR(ConstDataRange cdr) { - UUID uuid; + UUID uuid{UUIDStorage{}}; invariant(cdr.length() == uuid._uuid.size()); memcpy(uuid._uuid.data(), cdr.data(), uuid._uuid.size()); return uuid; @@ -242,19 +179,18 @@ public: } private: - UUID(const UUIDStorage& uuid) : _uuid(uuid) {} + using UUIDStorage = std::array<unsigned char, kNumBytes>; - /** - * Should never be used, as the resulting UUID will not be unique. - * The exception is in code generated by the IDL compiler, which itself ensures - * such an invalid value cannot propagate. - */ - friend class LogicalSessionId; - UUID() = default; + UUID(const UUIDStorage& uuid) : _uuid(uuid) {} UUIDStorage _uuid{}; // UUID in network byte order }; +/** Allow IDL-generated parsers to define uninitialized UUID objects. */ +inline auto idlPreparsedValue(stdx::type_identity<UUID>) { + return UUID::fromCDR(std::array<unsigned char, 16>{}); +} + inline std::ostream& operator<<(std::ostream& s, const UUID& uuid) { return (s << uuid.toString()); } |