summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBilly Donahue <billy.donahue@mongodb.com>2021-04-13 20:52:44 -0400
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-04-22 00:00:27 +0000
commit8f4dbd6889eb9534da7af27729aa0c2edea532f0 (patch)
tree9849d0d59ba36bb78f8bed91d9ee23512ea116a7
parentccca20406141099cf6f778cd01e633ecd1fd8f11 (diff)
downloadmongo-8f4dbd6889eb9534da7af27729aa0c2edea532f0.tar.gz
SERVER-43964 UUID etc need not befriend IDL types
-rw-r--r--buildscripts/idl/idl/cpp_types.py18
-rw-r--r--buildscripts/idl/idl/generator.py24
-rw-r--r--src/mongo/db/s/migration_destination_manager.cpp32
-rw-r--r--src/mongo/db/s/migration_destination_manager.h2
-rw-r--r--src/mongo/idl/idl_parser.h64
-rw-r--r--src/mongo/s/catalog/type_chunk.h12
-rw-r--r--src/mongo/util/uuid.h84
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());
}