diff --git a/src/mongo/db/query/query_knob.h b/src/mongo/db/query/query_knob.h index e40dd5d7c48..f0ef7dd6e71 100644 --- a/src/mongo/db/query/query_knob.h +++ b/src/mongo/db/query/query_knob.h @@ -37,6 +37,8 @@ #include "mongo/util/assert_util.h" #include +#include +#include #include #include #include @@ -91,6 +93,24 @@ QueryKnobValue readGlobalValue(StringData paramName) { } } +/** + * Strong id type to identify query knobs. Defaults to 'kUninitialized'. + */ +struct QueryKnobId { + using value_t = std::uint16_t; + constexpr static auto kUninitialized = std::numeric_limits::max(); + + friend bool operator==(const QueryKnobId& lhs, const QueryKnobId& rhs) { + return rhs.value == lhs.value; + } + + bool initialized() const { + return value != kUninitialized; + } + + value_t value = kUninitialized; +}; + /** * Type-erased descriptor for a single query knob. Each typed QueryKnob inherits from this and * self-registers into QueryKnobDescriptorSet at static init time. The index field is left as a @@ -116,8 +136,7 @@ public: return _readFn(paramName); } - // TODO SERVER-125549: refactor to use a strongly typed KnobId. - size_t index = ~size_t{0}; // Sentinel until QueryKnobRegistry assigns a dense index. + QueryKnobId id; StringData paramName; private: diff --git a/src/mongo/db/query/query_knob_registry.cpp b/src/mongo/db/query/query_knob_registry.cpp index 33c551a214a..0786eb68457 100644 --- a/src/mongo/db/query/query_knob_registry.cpp +++ b/src/mongo/db/query/query_knob_registry.cpp @@ -104,11 +104,13 @@ void QueryKnobRegistry::init(QueryKnobRegistry reg) { void QueryKnobRegistry::_writeBackDescriptorIndexes() { for (size_t i = 0; i < _entries.size(); ++i) { - _entries[i].knob.index = i; + auto&& knob = _entries[i].knob; + invariant(!knob.id.initialized()); + knob.id = QueryKnobId(i); } } -boost::optional QueryKnobRegistry::getKnobIdForName(StringData wireName) const { +boost::optional QueryKnobRegistry::getKnobIdForName(StringData wireName) const { auto it = _wireNameIndex.find(wireName); if (it == _wireNameIndex.end()) { return boost::none; @@ -116,12 +118,12 @@ boost::optional QueryKnobRegistry::getKnobIdForName(StringData wireName) return it->second; } -const QueryKnobRegistry::Entry& QueryKnobRegistry::entry(size_t id) const { +const QueryKnobRegistry::Entry& QueryKnobRegistry::entry(QueryKnobId id) const { tassert(12317800, - str::stream() << "QueryKnobRegistry::entry id " << id << " out of range (size " + str::stream() << "QueryKnobRegistry::entry id " << id.value << " out of range (size " << _entries.size() << ")", - id < _entries.size()); - return _entries[id]; + id.value < _entries.size()); + return _entries[id.value]; } size_t QueryKnobRegistry::knobCount() const { diff --git a/src/mongo/db/query/query_knob_registry.h b/src/mongo/db/query/query_knob_registry.h index 56154f6b4a4..3ccf6c36ea4 100644 --- a/src/mongo/db/query/query_knob_registry.h +++ b/src/mongo/db/query/query_knob_registry.h @@ -76,9 +76,9 @@ public: /** * PQS-settable knobs only; boost::none for non-PQS or unknown name. */ - boost::optional getKnobIdForName(StringData wireName) const; + boost::optional getKnobIdForName(StringData wireName) const; - const Entry& entry(size_t id) const; + const Entry& entry(QueryKnobId id) const; size_t knobCount() const; size_t knobsExposedToQuerySettingsCount() const; @@ -93,7 +93,7 @@ private: void _writeBackDescriptorIndexes(); std::vector _entries; - StringMap _wireNameIndex; + StringMap _wireNameIndex; size_t _knobsExposedToQuerySettingsCount = 0; bool _initialized = false; }; diff --git a/src/mongo/db/query/query_knob_registry_test.cpp b/src/mongo/db/query/query_knob_registry_test.cpp index c0ef5dc7a8f..933eb897492 100644 --- a/src/mongo/db/query/query_knob_registry_test.cpp +++ b/src/mongo/db/query/query_knob_registry_test.cpp @@ -57,14 +57,15 @@ namespace { // Linear scan for the entry whose `knob` refers to `target`. Returns knobCount() // on miss so callers can assert without risking an out-of-range `entry()` call. -size_t findEntryIndex(const QueryKnobBase& target) { +QueryKnobId findEntryIndex(const QueryKnobBase& target) { const auto& reg = QueryKnobRegistry::instance(); for (size_t i = 0; i < reg.knobCount(); ++i) { - if (®.entry(i).knob == &target) { - return i; + auto id = QueryKnobId(i); + if (®.entry(id).knob == &target) { + return id; } } - return reg.knobCount(); + return QueryKnobId(reg.knobCount()); } // The test IDL registers `synthIntPqs` as a ServerParameter, which is convenient @@ -94,7 +95,7 @@ TEST(QueryKnobRegistryTest, NonPqsKnobInvisibleToLookupButCarriesWireName) { ASSERT_FALSE(reg.getKnobIdForName("synthLongNonPqsWire"_sd).has_value()); auto idx = findEntryIndex(test_synth_knobs::synthLongNonPqsKnob); - ASSERT_LT(idx, reg.knobCount()); + ASSERT_LT(idx.value, reg.knobCount()); const auto& e = reg.entry(idx); ASSERT_EQ(e.wireName, "synthLongNonPqsWire"_sd); ASSERT_FALSE(e.pqsSettable); @@ -107,7 +108,8 @@ TEST(QueryKnobRegistryTest, PlainServerParameterNotRegistered) { auto* plain = ServerParameterSet::getNodeParameterSet()->getIfExists("synthDoublePlainParam"); ASSERT(plain); for (size_t i = 0; i < reg.knobCount(); ++i) { - ASSERT_NE(®.entry(i).param, plain); + auto id = QueryKnobId(i); + ASSERT_NE(®.entry(id).param, plain); } } @@ -123,7 +125,8 @@ TEST(QueryKnobRegistryTest, MinFcvRoundTrip) { TEST(QueryKnobRegistryTest, DenseIndicesWrittenBackToDescriptors) { const auto& reg = QueryKnobRegistry::instance(); for (size_t i = 0; i < reg.knobCount(); ++i) { - ASSERT_EQ(reg.entry(i).knob.index, i); + auto id = QueryKnobId(i); + ASSERT_EQ(reg.entry(id).knob.id, id); } } @@ -132,7 +135,8 @@ TEST(QueryKnobRegistryTest, CountsReflectPqsSplitOverSynthSubset) { size_t synthTotal = 0; size_t synthPqs = 0; for (size_t i = 0; i < reg.knobCount(); ++i) { - const auto& e = reg.entry(i); + auto id = QueryKnobId(i); + const auto& e = reg.entry(id); if (e.wireName.starts_with("synth"_sd)) { ++synthTotal; if (e.pqsSettable) { @@ -162,7 +166,8 @@ DEATH_TEST_REGEX(QueryKnobRegistryDeathTest, EntryGetterOutOfRangeTasserts, "QueryKnobRegistry::entry.*out of range") { const auto& reg = QueryKnobRegistry::instance(); - reg.entry(reg.knobCount()); + auto id = QueryKnobId(reg.knobCount()); + reg.entry(id); } DEATH_TEST_REGEX(QueryKnobRegistryDeathTest, diff --git a/src/mongo/db/query/query_knob_snapshot.h b/src/mongo/db/query/query_knob_snapshot.h index b2ab79a29b5..48c4b33b852 100644 --- a/src/mongo/db/query/query_knob_snapshot.h +++ b/src/mongo/db/query/query_knob_snapshot.h @@ -72,9 +72,9 @@ public: QueryKnobSnapshot& operator=(QueryKnobSnapshot&&) noexcept = default; template - T get(size_t index) const { - tassert(12312300, "QueryKnobSnapshot index out of bounds", index < _values.size()); - const QueryKnobValue& val = _values[index]; + T get(QueryKnobId id) const { + tassert(12312300, "QueryKnobSnapshot index out of bounds", id.value < _values.size()); + const QueryKnobValue& val = _values[id.value]; if constexpr (std::is_enum_v) { return static_cast(std::get(val)); } else { @@ -82,9 +82,9 @@ public: } } - KnobSource getSource(size_t index) const { - tassert(12312301, "QueryKnobSnapshot index out of bounds", index < _sources.size()); - return _sources[index]; + KnobSource getSource(QueryKnobId id) const { + tassert(12312301, "QueryKnobSnapshot index out of bounds", id.value < _sources.size()); + return _sources[id.value]; } size_t size() const { @@ -115,13 +115,14 @@ public: QueryKnobSnapshotBuilder(const QueryKnobSnapshotBuilder&) = delete; QueryKnobSnapshotBuilder& operator=(const QueryKnobSnapshotBuilder&) = delete; - QueryKnobSnapshotBuilder& set(size_t index, QueryKnobValue value, KnobSource source) { - tassert(12312302, "QueryKnobSnapshotBuilder index out of bounds", index < _values.size()); + QueryKnobSnapshotBuilder& set(QueryKnobId id, QueryKnobValue value, KnobSource source) { + tassert( + 12312302, "QueryKnobSnapshotBuilder index out of bounds", id.value < _values.size()); tassert(12312303, "QueryKnobSnapshotBuilder::set() value must not be DeleteQueryKnobOverride", !std::holds_alternative(value)); - _values[index] = std::move(value); - _sources[index] = source; + _values[id.value] = std::move(value); + _sources[id.value] = source; return *this; } diff --git a/src/mongo/db/query/query_knob_snapshot_test.cpp b/src/mongo/db/query/query_knob_snapshot_test.cpp index 60db81ed0a5..c4749b6e1ac 100644 --- a/src/mongo/db/query/query_knob_snapshot_test.cpp +++ b/src/mongo/db/query/query_knob_snapshot_test.cpp @@ -40,8 +40,8 @@ namespace { TEST(QueryKnobSnapshotTest, SizeMatchesConstructorArgument) { auto builder = QueryKnobSnapshotBuilder{5}; - for (int i = 0; i < 5; i++) { - builder.set(i, QueryKnobValue{i}, KnobSource::kDefault); + for (QueryKnobId::value_t i = 0; i < 5; i++) { + builder.set(QueryKnobId{i}, QueryKnobValue{static_cast(i)}, KnobSource::kDefault); } ASSERT_EQ(std::move(builder).build().size(), 5u); } @@ -56,158 +56,166 @@ TEST(QueryKnobSnapshotTest, RoundTripAllQueryKnobValueTypes) { constexpr auto kEnumVal = QueryFrameworkControlEnum::kTrySbeRestricted; auto snap = std::move(QueryKnobSnapshotBuilder{5} - .set(0, QueryKnobValue{42}, KnobSource::kDefault) - .set(1, QueryKnobValue{123456789LL}, KnobSource::kDefault) - .set(2, QueryKnobValue{2.718}, KnobSource::kDefault) - .set(3, QueryKnobValue{true}, KnobSource::kDefault) - .set(4, QueryKnobValue{static_cast(kEnumVal)}, KnobSource::kDefault)) + .set(QueryKnobId{0}, QueryKnobValue{42}, KnobSource::kDefault) + .set(QueryKnobId{1}, QueryKnobValue{123456789LL}, KnobSource::kDefault) + .set(QueryKnobId{2}, QueryKnobValue{2.718}, KnobSource::kDefault) + .set(QueryKnobId{3}, QueryKnobValue{true}, KnobSource::kDefault) + .set(QueryKnobId{4}, + QueryKnobValue{static_cast(kEnumVal)}, + KnobSource::kDefault)) .build(); - ASSERT_EQ(snap.get(0), 42); - ASSERT_EQ(snap.get(1), 123456789LL); - ASSERT_APPROX_EQUAL(snap.get(2), 2.718, 1e-9); - ASSERT_EQ(snap.get(3), true); - ASSERT_EQ(snap.get(4), kEnumVal); + ASSERT_EQ(snap.get(QueryKnobId{0}), 42); + ASSERT_EQ(snap.get(QueryKnobId{1}), 123456789LL); + ASSERT_APPROX_EQUAL(snap.get(QueryKnobId{2}), 2.718, 1e-9); + ASSERT_EQ(snap.get(QueryKnobId{3}), true); + ASSERT_EQ(snap.get(QueryKnobId{4}), kEnumVal); } TEST(QueryKnobSnapshotTest, RoundTripInt) { - auto snap = - std::move(QueryKnobSnapshotBuilder{1}.set(0, QueryKnobValue{42}, KnobSource::kDefault)) - .build(); - ASSERT_EQ(snap.get(0), 42); + auto snap = std::move(QueryKnobSnapshotBuilder{1}.set( + QueryKnobId{0}, QueryKnobValue{42}, KnobSource::kDefault)) + .build(); + ASSERT_EQ(snap.get(QueryKnobId{0}), 42); } TEST(QueryKnobSnapshotTest, RoundTripLongLong) { auto snap = std::move(QueryKnobSnapshotBuilder{1}.set( - 0, QueryKnobValue{123456789LL}, KnobSource::kDefault)) + QueryKnobId{0}, QueryKnobValue{123456789LL}, KnobSource::kDefault)) .build(); - ASSERT_EQ(snap.get(0), 123456789LL); + ASSERT_EQ(snap.get(QueryKnobId{0}), 123456789LL); } TEST(QueryKnobSnapshotTest, RoundTripDouble) { - auto snap = - std::move(QueryKnobSnapshotBuilder{1}.set(0, QueryKnobValue{2.718}, KnobSource::kDefault)) - .build(); - ASSERT_APPROX_EQUAL(snap.get(0), 2.718, 1e-9); + auto snap = std::move(QueryKnobSnapshotBuilder{1}.set( + QueryKnobId{0}, QueryKnobValue{2.718}, KnobSource::kDefault)) + .build(); + ASSERT_APPROX_EQUAL(snap.get(QueryKnobId{0}), 2.718, 1e-9); } TEST(QueryKnobSnapshotTest, RoundTripBool) { - auto snapFalse = - std::move(QueryKnobSnapshotBuilder{1}.set(0, QueryKnobValue{false}, KnobSource::kDefault)) - .build(); - ASSERT_EQ(snapFalse.get(0), false); + auto snapFalse = std::move(QueryKnobSnapshotBuilder{1}.set( + QueryKnobId{0}, QueryKnobValue{false}, KnobSource::kDefault)) + .build(); + ASSERT_EQ(snapFalse.get(QueryKnobId{0}), false); - auto snapTrue = - std::move(QueryKnobSnapshotBuilder{1}.set(0, QueryKnobValue{true}, KnobSource::kDefault)) - .build(); - ASSERT_EQ(snapTrue.get(0), true); + auto snapTrue = std::move(QueryKnobSnapshotBuilder{1}.set( + QueryKnobId{0}, QueryKnobValue{true}, KnobSource::kDefault)) + .build(); + ASSERT_EQ(snapTrue.get(QueryKnobId{0}), true); } TEST(QueryKnobSnapshotTest, EnumCastRoundTrip) { auto enumVal = QueryFrameworkControlEnum::kForceClassicEngine; - auto snap = std::move(QueryKnobSnapshotBuilder{1}.set( - 0, QueryKnobValue{static_cast(enumVal)}, KnobSource::kDefault)) + auto snap = std::move(QueryKnobSnapshotBuilder{1}.set(QueryKnobId{0}, + QueryKnobValue{static_cast(enumVal)}, + KnobSource::kDefault)) .build(); - ASSERT_EQ(snap.get(0), enumVal); + ASSERT_EQ(snap.get(QueryKnobId{0}), enumVal); } TEST(QueryKnobSnapshotTest, EnumCastAllValues) { auto snap = std::move( QueryKnobSnapshotBuilder{3} - .set(0, + .set(QueryKnobId{0}, QueryKnobValue{static_cast(QueryFrameworkControlEnum::kTrySbeEngine)}, KnobSource::kDefault) - .set(1, + .set(QueryKnobId{1}, QueryKnobValue{static_cast(QueryFrameworkControlEnum::kTrySbeRestricted)}, KnobSource::kDefault) - .set(2, + .set(QueryKnobId{2}, QueryKnobValue{ static_cast(QueryFrameworkControlEnum::kForceClassicEngine)}, KnobSource::kDefault)) .build(); - ASSERT_EQ(snap.get(0), QueryFrameworkControlEnum::kTrySbeEngine); - ASSERT_EQ(snap.get(1), QueryFrameworkControlEnum::kTrySbeRestricted); - ASSERT_EQ(snap.get(2), + ASSERT_EQ(snap.get(QueryKnobId{0}), + QueryFrameworkControlEnum::kTrySbeEngine); + ASSERT_EQ(snap.get(QueryKnobId{1}), + QueryFrameworkControlEnum::kTrySbeRestricted); + ASSERT_EQ(snap.get(QueryKnobId{2}), QueryFrameworkControlEnum::kForceClassicEngine); } TEST(QueryKnobSnapshotTest, SourceTrackingSetParameter) { - auto snap = - std::move(QueryKnobSnapshotBuilder{1}.set(0, QueryKnobValue{7}, KnobSource::kSetParameter)) - .build(); - ASSERT_EQ(snap.getSource(0), KnobSource::kSetParameter); + auto snap = std::move(QueryKnobSnapshotBuilder{1}.set( + QueryKnobId{0}, QueryKnobValue{7}, KnobSource::kSetParameter)) + .build(); + ASSERT_EQ(snap.getSource(QueryKnobId{0}), KnobSource::kSetParameter); } TEST(QueryKnobSnapshotTest, SourceTrackingQuerySettings) { - auto snap = - std::move(QueryKnobSnapshotBuilder{1}.set(0, QueryKnobValue{7}, KnobSource::kQuerySettings)) - .build(); - ASSERT_EQ(snap.getSource(0), KnobSource::kQuerySettings); + auto snap = std::move(QueryKnobSnapshotBuilder{1}.set( + QueryKnobId{0}, QueryKnobValue{7}, KnobSource::kQuerySettings)) + .build(); + ASSERT_EQ(snap.getSource(QueryKnobId{0}), KnobSource::kQuerySettings); } TEST(QueryKnobSnapshotTest, MultipleSlotSourcesAreIndependent) { auto snap = std::move(QueryKnobSnapshotBuilder{3} - .set(0, QueryKnobValue{1}, KnobSource::kDefault) - .set(1, QueryKnobValue{2}, KnobSource::kSetParameter) - .set(2, QueryKnobValue{3}, KnobSource::kQuerySettings)) + .set(QueryKnobId{0}, QueryKnobValue{1}, KnobSource::kDefault) + .set(QueryKnobId{1}, QueryKnobValue{2}, KnobSource::kSetParameter) + .set(QueryKnobId{2}, QueryKnobValue{3}, KnobSource::kQuerySettings)) .build(); - ASSERT_EQ(snap.getSource(0), KnobSource::kDefault); - ASSERT_EQ(snap.getSource(1), KnobSource::kSetParameter); - ASSERT_EQ(snap.getSource(2), KnobSource::kQuerySettings); + ASSERT_EQ(snap.getSource(QueryKnobId{0}), KnobSource::kDefault); + ASSERT_EQ(snap.getSource(QueryKnobId{1}), KnobSource::kSetParameter); + ASSERT_EQ(snap.getSource(QueryKnobId{2}), KnobSource::kQuerySettings); } TEST(QueryKnobSnapshotTest, CopyIsIndependent) { - auto original = std::move(QueryKnobSnapshotBuilder{2} - .set(0, QueryKnobValue{10}, KnobSource::kDefault) - .set(1, QueryKnobValue{20LL}, KnobSource::kSetParameter)) - .build(); + auto original = + std::move(QueryKnobSnapshotBuilder{2} + .set(QueryKnobId{0}, QueryKnobValue{10}, KnobSource::kDefault) + .set(QueryKnobId{1}, QueryKnobValue{20LL}, KnobSource::kSetParameter)) + .build(); // Copy-construct from original. QueryKnobSnapshot copy = original; - ASSERT_EQ(copy.get(0), 10); - ASSERT_EQ(copy.get(1), 20LL); - ASSERT_EQ(copy.getSource(0), KnobSource::kDefault); - ASSERT_EQ(copy.getSource(1), KnobSource::kSetParameter); + ASSERT_EQ(copy.get(QueryKnobId{0}), 10); + ASSERT_EQ(copy.get(QueryKnobId{1}), 20LL); + ASSERT_EQ(copy.getSource(QueryKnobId{0}), KnobSource::kDefault); + ASSERT_EQ(copy.getSource(QueryKnobId{1}), KnobSource::kSetParameter); // Assigning a new snapshot to copy does not affect original. copy = std::move(QueryKnobSnapshotBuilder{2} - .set(0, QueryKnobValue{99}, KnobSource::kQuerySettings) - .set(1, QueryKnobValue{999LL}, KnobSource::kQuerySettings)) + .set(QueryKnobId{0}, QueryKnobValue{99}, KnobSource::kQuerySettings) + .set(QueryKnobId{1}, QueryKnobValue{999LL}, KnobSource::kQuerySettings)) .build(); - ASSERT_EQ(original.get(0), 10); - ASSERT_EQ(original.get(1), 20LL); - ASSERT_EQ(original.getSource(0), KnobSource::kDefault); - ASSERT_EQ(original.getSource(1), KnobSource::kSetParameter); + ASSERT_EQ(original.get(QueryKnobId{0}), 10); + ASSERT_EQ(original.get(QueryKnobId{1}), 20LL); + ASSERT_EQ(original.getSource(QueryKnobId{0}), KnobSource::kDefault); + ASSERT_EQ(original.getSource(QueryKnobId{1}), KnobSource::kSetParameter); } TEST(QueryKnobSnapshotTest, LastWriteWins) { auto snap = std::move(QueryKnobSnapshotBuilder{1} - .set(0, QueryKnobValue{5}, KnobSource::kDefault) - .set(0, QueryKnobValue{42}, KnobSource::kSetParameter)) + .set(QueryKnobId{0}, QueryKnobValue{5}, KnobSource::kDefault) + .set(QueryKnobId{0}, QueryKnobValue{42}, KnobSource::kSetParameter)) .build(); - ASSERT_EQ(snap.get(0), 42); - ASSERT_EQ(snap.getSource(0), KnobSource::kSetParameter); + ASSERT_EQ(snap.get(QueryKnobId{0}), 42); + ASSERT_EQ(snap.getSource(QueryKnobId{0}), KnobSource::kSetParameter); } DEATH_TEST_REGEX(QueryKnobSnapshotDeathTest, GetOutOfBounds, "12312300") { - QueryKnobSnapshotBuilder{0}.build().get(2); + QueryKnobSnapshotBuilder{0}.build().get(QueryKnobId{2}); } DEATH_TEST_REGEX(QueryKnobSnapshotDeathTest, GetSourceOutOfBounds, "12312301") { - std::move(QueryKnobSnapshotBuilder{1}.set(0, QueryKnobValue{0}, KnobSource::kDefault)) + std::move( + QueryKnobSnapshotBuilder{1}.set(QueryKnobId{0}, QueryKnobValue{0}, KnobSource::kDefault)) .build() - .getSource(2); + .getSource(QueryKnobId{2}); } DEATH_TEST_REGEX(QueryKnobSnapshotDeathTest, SetOutOfBounds, "12312302") { - QueryKnobSnapshotBuilder{2}.set(5, QueryKnobValue{1}, KnobSource::kDefault); + QueryKnobSnapshotBuilder{2}.set(QueryKnobId{5}, QueryKnobValue{1}, KnobSource::kDefault); } DEATH_TEST_REGEX(QueryKnobSnapshotDeathTest, SetDeleteQueryKnobOverrideValue, "12312303") { - QueryKnobSnapshotBuilder{1}.set(0, DeleteQueryKnobOverride(), KnobSource::kDefault); + QueryKnobSnapshotBuilder{1}.set( + QueryKnobId{0}, DeleteQueryKnobOverride(), KnobSource::kDefault); } DEATH_TEST_REGEX(QueryKnobSnapshotDeathTest, diff --git a/src/mongo/db/query/query_knob_test.cpp b/src/mongo/db/query/query_knob_test.cpp index 0ff06ca66a7..2cad8c224f4 100644 --- a/src/mongo/db/query/query_knob_test.cpp +++ b/src/mongo/db/query/query_knob_test.cpp @@ -81,11 +81,11 @@ TEST(QueryKnobTest, SyntheticKnobsSelfRegister) { } TEST(QueryKnobTest, SentinelIndex) { - ASSERT_EQ(test_knobs::testIntKnob.index, ~size_t{0}); - ASSERT_EQ(test_knobs::testDoubleKnob.index, ~size_t{0}); - ASSERT_EQ(test_knobs::testBoolKnob.index, ~size_t{0}); - ASSERT_EQ(test_knobs::testLLKnob.index, ~size_t{0}); - ASSERT_EQ(test_knobs::testEnumKnob.index, ~size_t{0}); + ASSERT_FALSE(test_knobs::testIntKnob.id.initialized()); + ASSERT_FALSE(test_knobs::testDoubleKnob.id.initialized()); + ASSERT_FALSE(test_knobs::testBoolKnob.id.initialized()); + ASSERT_FALSE(test_knobs::testLLKnob.id.initialized()); + ASSERT_FALSE(test_knobs::testEnumKnob.id.initialized()); } TEST(QueryKnobTest, ReadGlobalInt) {