diff options
22 files changed, 273 insertions, 401 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index 6cf5d02acca..6aa7c0699d7 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -973,21 +973,11 @@ env.Library( 'logical_clock.cpp', ], LIBDEPS=[ - 'logical_time', 'server_parameters', 'service_context', - ], -) - -env.Library( - target='logical_time_validator', - source=[ - 'logical_time_validator.cpp', - ], - LIBDEPS=[ - 'service_context', 'signed_logical_time', 'time_proof_service', + '$BUILD_DIR/mongo/util/clock_source_mock' ], ) @@ -1033,23 +1023,12 @@ env.CppUnitTest( ], ) -env.CppUnitTest( - target='logical_time_validator_test', - source=[ - 'logical_time_validator_test.cpp', - ], - LIBDEPS=[ - 'logical_time_validator', - ], -) - env.Library( target= 'logical_time_metadata_hook', source= [ 'logical_time_metadata_hook.cpp', ], LIBDEPS= [ - 'logical_time_validator', 'signed_logical_time', '$BUILD_DIR/mongo/rpc/metadata', ], @@ -1064,7 +1043,6 @@ env.Library( 'logical_clock', 'signed_logical_time', '$BUILD_DIR/mongo/s/sharding_mongod_test_fixture', - '$BUILD_DIR/mongo/util/clock_source_mock' ], ) diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index 537b8f1004e..da379905d84 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -76,7 +76,6 @@ #include "mongo/db/keypattern.h" #include "mongo/db/lasterror.h" #include "mongo/db/logical_clock.h" -#include "mongo/db/logical_time_validator.h" #include "mongo/db/matcher/extensions_callback_disallow_extensions.h" #include "mongo/db/namespace_string.h" #include "mongo/db/op_observer.h" @@ -1323,12 +1322,9 @@ void appendReplyMetadata(OperationContext* opCtx, .writeToMetadata(metadataBob); } - auto validator = LogicalTimeValidator::get(opCtx); - if (validator) { - - auto currentTime = - validator->signLogicalTime(LogicalClock::get(opCtx)->getClusterTime()); - rpc::LogicalTimeMetadata logicalTimeMetadata(currentTime); + if (LogicalClock::get(opCtx)->canVerifyAndSign()) { + rpc::LogicalTimeMetadata logicalTimeMetadata( + LogicalClock::get(opCtx)->getClusterTime()); logicalTimeMetadata.writeToMetadata(metadataBob); } } @@ -1721,7 +1717,7 @@ void mongo::execCommandDatabase(OperationContext* opCtx, // // TODO: SERVER-28445 change this to use computeOperationTime once the exception handling // path is moved into Command::run() - auto operationTime = LogicalClock::get(opCtx)->getClusterTime(); + auto operationTime = LogicalClock::get(opCtx)->getClusterTime().getTime(); // An uninitialized operation time means the cluster time is not propagated, so the // operation time should not be attached to the error response. diff --git a/src/mongo/db/keys_collection_cache_reader_and_updater.cpp b/src/mongo/db/keys_collection_cache_reader_and_updater.cpp index 965482ebf8e..7c959c5f6c0 100644 --- a/src/mongo/db/keys_collection_cache_reader_and_updater.cpp +++ b/src/mongo/db/keys_collection_cache_reader_and_updater.cpp @@ -78,7 +78,7 @@ KeysCollectionCacheReaderAndUpdater::KeysCollectionCacheReaderAndUpdater( StatusWith<KeysCollectionDocument> KeysCollectionCacheReaderAndUpdater::refresh( OperationContext* opCtx) { - auto currentTime = LogicalClock::get(opCtx)->getClusterTime(); + auto currentTime = LogicalClock::get(opCtx)->getClusterTime().getTime(); auto keyStatus = Grid::get(opCtx)->catalogClient(opCtx)->getNewKeys( opCtx, _purpose, currentTime, repl::ReadConcernLevel::kLocalReadConcern); diff --git a/src/mongo/db/keys_collection_cache_reader_and_updater_test.cpp b/src/mongo/db/keys_collection_cache_reader_and_updater_test.cpp index 2639af95ced..540b4af8898 100644 --- a/src/mongo/db/keys_collection_cache_reader_and_updater_test.cpp +++ b/src/mongo/db/keys_collection_cache_reader_and_updater_test.cpp @@ -66,7 +66,7 @@ TEST_F(CacheUpdaterTest, ShouldCreate2KeysFromEmpty) { KeysCollectionCacheReaderAndUpdater updater("dummy", Seconds(5)); const LogicalTime currentTime(LogicalTime(Timestamp(100, 2))); - LogicalClock::get(operationContext())->setClusterTimeFromTrustedSource(currentTime); + LogicalClock::get(operationContext())->initClusterTimeFromTrustedSource(currentTime); { auto keyStatus = updater.refresh(operationContext()); @@ -99,7 +99,7 @@ TEST_F(CacheUpdaterTest, ShouldPropagateWriteError) { KeysCollectionCacheReaderAndUpdater updater("dummy", Seconds(5)); const LogicalTime currentTime(LogicalTime(Timestamp(100, 2))); - LogicalClock::get(operationContext())->setClusterTimeFromTrustedSource(currentTime); + LogicalClock::get(operationContext())->initClusterTimeFromTrustedSource(currentTime); FailPointEnableBlock failWriteBlock("failCollectionInserts"); @@ -111,7 +111,7 @@ TEST_F(CacheUpdaterTest, ShouldCreateAnotherKeyIfOnlyOneKeyExists) { KeysCollectionCacheReaderAndUpdater updater("dummy", Seconds(5)); LogicalClock::get(operationContext()) - ->setClusterTimeFromTrustedSource(LogicalTime(Timestamp(100, 2))); + ->initClusterTimeFromTrustedSource(LogicalTime(Timestamp(100, 2))); KeysCollectionDocument origKey1( 1, "dummy", TimeProofService::generateRandomKey(), LogicalTime(Timestamp(105, 0))); @@ -129,7 +129,7 @@ TEST_F(CacheUpdaterTest, ShouldCreateAnotherKeyIfOnlyOneKeyExists) { ASSERT_EQ(Timestamp(105, 0), key1.getExpiresAt().asTimestamp()); } - auto currentTime = LogicalClock::get(operationContext())->getClusterTime(); + auto currentTime = LogicalClock::get(operationContext())->getClusterTime().getTime(); { auto keyStatus = updater.refresh(operationContext()); @@ -165,7 +165,7 @@ TEST_F(CacheUpdaterTest, ShouldCreateAnotherKeyIfNoValidKeyAfterCurrent) { KeysCollectionCacheReaderAndUpdater updater("dummy", Seconds(5)); LogicalClock::get(operationContext()) - ->setClusterTimeFromTrustedSource(LogicalTime(Timestamp(108, 2))); + ->initClusterTimeFromTrustedSource(LogicalTime(Timestamp(108, 2))); KeysCollectionDocument origKey1( 1, "dummy", TimeProofService::generateRandomKey(), LogicalTime(Timestamp(105, 0))); @@ -193,7 +193,7 @@ TEST_F(CacheUpdaterTest, ShouldCreateAnotherKeyIfNoValidKeyAfterCurrent) { ASSERT_EQ(Timestamp(110, 0), key2.getExpiresAt().asTimestamp()); } - auto currentTime = LogicalClock::get(operationContext())->getClusterTime(); + auto currentTime = LogicalClock::get(operationContext())->getClusterTime().getTime(); { auto keyStatus = updater.refresh(operationContext()); @@ -256,7 +256,7 @@ TEST_F(CacheUpdaterTest, ShouldCreate2KeysIfAllKeysAreExpired) { KeysCollectionCacheReaderAndUpdater updater("dummy", Seconds(5)); LogicalClock::get(operationContext()) - ->setClusterTimeFromTrustedSource(LogicalTime(Timestamp(120, 2))); + ->initClusterTimeFromTrustedSource(LogicalTime(Timestamp(120, 2))); KeysCollectionDocument origKey1( 1, "dummy", TimeProofService::generateRandomKey(), LogicalTime(Timestamp(105, 0))); @@ -284,7 +284,7 @@ TEST_F(CacheUpdaterTest, ShouldCreate2KeysIfAllKeysAreExpired) { ASSERT_EQ(Timestamp(110, 0), key2.getExpiresAt().asTimestamp()); } - auto currentTime = LogicalClock::get(operationContext())->getClusterTime(); + auto currentTime = LogicalClock::get(operationContext())->getClusterTime().getTime(); { auto keyStatus = updater.refresh(operationContext()); @@ -360,7 +360,7 @@ TEST_F(CacheUpdaterTest, ShouldNotCreateNewKeyIfThereAre2UnexpiredKeys) { KeysCollectionCacheReaderAndUpdater updater("dummy", Seconds(5)); LogicalClock::get(operationContext()) - ->setClusterTimeFromTrustedSource(LogicalTime(Timestamp(100, 2))); + ->initClusterTimeFromTrustedSource(LogicalTime(Timestamp(100, 2))); KeysCollectionDocument origKey1( 1, "dummy", TimeProofService::generateRandomKey(), LogicalTime(Timestamp(105, 0))); diff --git a/src/mongo/db/keys_collection_manager.cpp b/src/mongo/db/keys_collection_manager.cpp index 61cd43f73f1..f65e1163e8f 100644 --- a/src/mongo/db/keys_collection_manager.cpp +++ b/src/mongo/db/keys_collection_manager.cpp @@ -243,7 +243,7 @@ void KeysCollectionManager::PeriodicRunner::_doPeriodicRefresh(ServiceContext* s auto latestKeyStatusWith = (*doRefresh)(opCtx.get()); if (latestKeyStatusWith.getStatus().isOK()) { const auto& latestKey = latestKeyStatusWith.getValue(); - auto currentTime = LogicalClock::get(service)->getClusterTime(); + auto currentTime = LogicalClock::get(service)->getClusterTime().getTime(); nextWakeup = howMuchSleepNeedFor(currentTime, latestKey.getExpiresAt(), refreshInterval); diff --git a/src/mongo/db/keys_collection_manager_test.cpp b/src/mongo/db/keys_collection_manager_test.cpp index 28b6a3fc786..f2c19f6a6c5 100644 --- a/src/mongo/db/keys_collection_manager_test.cpp +++ b/src/mongo/db/keys_collection_manager_test.cpp @@ -234,7 +234,7 @@ TEST_F(KeysManagerTest, ShouldCreateKeysIfKeyGeneratorEnabled) { keyManager()->startMonitoring(getServiceContext()); const LogicalTime currentTime(LogicalTime(Timestamp(100, 0))); - LogicalClock::get(operationContext())->setClusterTimeFromTrustedSource(currentTime); + LogicalClock::get(operationContext())->initClusterTimeFromTrustedSource(currentTime); keyManager()->enableKeyGenerator(operationContext(), true); @@ -250,7 +250,7 @@ TEST_F(KeysManagerTest, EnableModeFlipFlopStressTest) { keyManager()->startMonitoring(getServiceContext()); const LogicalTime currentTime(LogicalTime(Timestamp(100, 0))); - LogicalClock::get(operationContext())->setClusterTimeFromTrustedSource(currentTime); + LogicalClock::get(operationContext())->initClusterTimeFromTrustedSource(currentTime); bool doEnable = true; @@ -275,8 +275,9 @@ TEST_F(KeysManagerTest, ShouldStillBeAbleToUpdateCacheEvenIfItCantCreateKeys) { operationContext(), NamespaceString(KeysCollectionDocument::ConfigNS), origKey1.toBSON())); // Set the time to be very ahead so the updater will be forced to create new keys. - const LogicalTime fakeTime(Timestamp(20000, 0)); - LogicalClock::get(operationContext())->setClusterTimeFromTrustedSource(fakeTime); + const LogicalTime currentTime(LogicalTime(Timestamp(20000, 0))); + const SignedLogicalTime fakeTime(currentTime, 2); + ASSERT_OK(LogicalClock::get(operationContext())->advanceClusterTimeFromTrustedSource(fakeTime)); FailPointEnableBlock failWriteBlock("failCollectionInserts"); diff --git a/src/mongo/db/logical_clock.cpp b/src/mongo/db/logical_clock.cpp index c40324f7120..6a4df1e6c60 100644 --- a/src/mongo/db/logical_clock.cpp +++ b/src/mongo/db/logical_clock.cpp @@ -86,35 +86,107 @@ void LogicalClock::set(ServiceContext* service, std::unique_ptr<LogicalClock> cl LogicalClock::LogicalClock(ServiceContext* service) : _service(service) {} -LogicalTime LogicalClock::getClusterTime() { +SignedLogicalTime LogicalClock::getClusterTime() { stdx::lock_guard<stdx::mutex> lock(_mutex); return _clusterTime; } -Status LogicalClock::advanceClusterTime(const LogicalTime newTime) { +void LogicalClock::setTimeProofService(std::unique_ptr<TimeProofService> tps) { stdx::lock_guard<stdx::mutex> lock(_mutex); + _timeProofService = std::move(tps); + + // Ensure a clock with a time proof service cannot have a cluster time without a proof to + // simplify reasoning about signed logical times. + if (!_clusterTime.getProof()) { + _clusterTime = _makeSignedLogicalTime_inlock(_clusterTime.getTime()); + } +} + +bool LogicalClock::canVerifyAndSign() { + stdx::lock_guard<stdx::mutex> lock(_mutex); + return !!_timeProofService; +} + +SignedLogicalTime LogicalClock::_makeSignedLogicalTime_inlock(LogicalTime logicalTime) { + if (_timeProofService) { + // TODO: SERVER-28436 Implement KeysCollectionManager + // Replace dummy keyId with real id from key manager. + return SignedLogicalTime( + logicalTime, _timeProofService->getProof(logicalTime, _tempKey), 0); + } + return SignedLogicalTime(logicalTime, 0); +} + +Status LogicalClock::advanceClusterTime(const SignedLogicalTime& newTime) { + stdx::lock_guard<stdx::mutex> lock(_mutex); + if (!_timeProofService) { + return Status(ErrorCodes::CannotVerifyAndSignLogicalTime, + "Cannot accept logicalTime: " + newTime.getTime().toString() + + ". May not be a part of a sharded cluster"); + } + + const auto& newLogicalTime = newTime.getTime(); + + // No need to check proof if no time was given. + if (newLogicalTime == LogicalTime::kUninitialized) { + return Status::OK(); + } + + const auto newProof = newTime.getProof(); + // Logical time is only sent if a server's clock can verify and sign logical times, so any + // received logical times should have proofs. + invariant(newProof); + + auto res = _timeProofService->checkProof(newLogicalTime, newProof.get(), _tempKey); + if (res != Status::OK()) { + return res; + } // The rate limiter check cannot be moved into _advanceClusterTime_inlock to avoid code // repetition because it shouldn't be called on direct oplog operations. - auto rateLimitStatus = _passesRateLimiter_inlock(newTime); + auto rateLimitStatus = _passesRateLimiter_inlock(newTime.getTime()); if (!rateLimitStatus.isOK()) { return rateLimitStatus; } - if (newTime > _clusterTime) { + return _advanceClusterTime_inlock(std::move(newTime)); +} + +Status LogicalClock::_advanceClusterTime_inlock(SignedLogicalTime newTime) { + if (newTime.getTime() > _clusterTime.getTime()) { _clusterTime = newTime; } return Status::OK(); } +Status LogicalClock::advanceClusterTimeFromTrustedSource(SignedLogicalTime newTime) { + stdx::lock_guard<stdx::mutex> lock(_mutex); + // The rate limiter check cannot be moved into _advanceClusterTime_inlock to avoid code + // repetition because it shouldn't be called on direct oplog operations. + auto rateLimitStatus = _passesRateLimiter_inlock(newTime.getTime()); + if (!rateLimitStatus.isOK()) { + return rateLimitStatus; + } + + return _advanceClusterTime_inlock(std::move(newTime)); +} + +Status LogicalClock::signAndAdvanceClusterTime(LogicalTime newTime) { + stdx::lock_guard<stdx::mutex> lock(_mutex); + auto newSignedTime = _makeSignedLogicalTime_inlock(newTime); + + return _advanceClusterTime_inlock(std::move(newSignedTime)); +} + LogicalTime LogicalClock::reserveTicks(uint64_t nTicks) { invariant(nTicks > 0 && nTicks < (1U << 31)); stdx::lock_guard<stdx::mutex> lock(_mutex); - LogicalTime clusterTime = _clusterTime; + LogicalTime clusterTime = _clusterTime.getTime(); + LogicalTime nextClusterTime; const unsigned wallClockSecs = durationCount<Seconds>(_service->getFastClockSource()->now().toDurationSinceEpoch()); @@ -140,25 +212,23 @@ LogicalTime LogicalClock::reserveTicks(uint64_t nTicks) { // Save the next cluster time. clusterTime.addTicks(1); - _clusterTime = clusterTime; + nextClusterTime = clusterTime; // Add the rest of the requested ticks if needed. if (nTicks > 1) { - _clusterTime.addTicks(nTicks - 1); + clusterTime.addTicks(nTicks - 1); } - return clusterTime; + _clusterTime = _makeSignedLogicalTime_inlock(clusterTime); + return nextClusterTime; } -void LogicalClock::setClusterTimeFromTrustedSource(LogicalTime newTime) { +void LogicalClock::initClusterTimeFromTrustedSource(LogicalTime newTime) { stdx::lock_guard<stdx::mutex> lock(_mutex); - + invariant(_clusterTime.getTime() == LogicalTime::kUninitialized); // Rate limit checks are skipped here so a server with no activity for longer than // maxAcceptableLogicalClockDrift seconds can still have its cluster time initialized. - - if (newTime > _clusterTime) { - _clusterTime = newTime; - } + _clusterTime = _makeSignedLogicalTime_inlock(newTime); } Status LogicalClock::_passesRateLimiter_inlock(LogicalTime newTime) { diff --git a/src/mongo/db/logical_clock.h b/src/mongo/db/logical_clock.h index 6d0b73385e5..001d91eb9e6 100644 --- a/src/mongo/db/logical_clock.h +++ b/src/mongo/db/logical_clock.h @@ -38,7 +38,10 @@ class OperationContext; /** * LogicalClock maintain the clusterTime for a clusterNode. Every cluster node in a replica set has - * an instance of the LogicalClock installed as a ServiceContext decoration. + * an instance of the LogicalClock installed as a ServiceContext decoration. LogicalClock owns the + * TimeProofService that allows it to generate proofs to sign LogicalTime values and to validate the + * proofs of SignedLogicalTime values.LogicalClock instance must be created before the instance + * starts up. */ class LogicalClock { public: @@ -56,17 +59,40 @@ public: LogicalClock(ServiceContext*); /** - * The method sets current time to newTime if the newTime > current time and it passes the rate - * check. - * - * Returns an error if the newTime does not pass the rate check. + * Attach a pointer to a TimeProofService to the logical clock. Will overwrite an existing + * pointer if a TimeProofService has already been attached. + */ + void setTimeProofService(std::unique_ptr<TimeProofService>); + + /** + * Returns true if a TimeProofService has been attached to the logical clock. */ - Status advanceClusterTime(const LogicalTime newTime); + bool canVerifyAndSign(); + + /** + * The method sets clusterTime to the newTime if the newTime > _clusterTime and the newTime + * passes the rate check and proof validation. + * Returns an error if the newTime does not pass the rate check or proof validation, + * OK otherwise. + */ + Status advanceClusterTime(const SignedLogicalTime&); + + /** + * Similar to advanceClusterTime, but only does rate checking and not proof validation. + */ + Status advanceClusterTimeFromTrustedSource(SignedLogicalTime newTime); + + /** + * Similar to advanceClusterTimeFromTrustedSource, but also signs the new time. Note that this + * should only be used on trusted LogicalTime (for example, LogicalTime extracted from local + * oplog entry). + */ + Status signAndAdvanceClusterTime(LogicalTime newTime); /** * Returns the current clusterTime. */ - LogicalTime getClusterTime(); + SignedLogicalTime getClusterTime(); /** * Returns the next clusterTime value and provides a guarantee that any future call to @@ -76,13 +102,20 @@ public: LogicalTime reserveTicks(uint64_t nTicks); /** - * Resets current time to newTime. Should only be used for initializing this clock from an - * oplog timestamp. + * Resets _clusterTime to the signed time created from newTime. Should be used at the + * initialization after reading the oplog. Must not be called on already initialized clock. */ - void setClusterTimeFromTrustedSource(LogicalTime newTime); + void initClusterTimeFromTrustedSource(LogicalTime newTime); private: /** + * Utility to create valid SignedLogicalTime from LogicalTime. + */ + SignedLogicalTime _makeSignedLogicalTime_inlock(LogicalTime); + + Status _advanceClusterTime_inlock(SignedLogicalTime newTime); + + /** * Rate limiter for advancing logical time. Rejects newTime if its seconds value is more than * kMaxAcceptableLogicalClockDrift seconds ahead of this node's wall clock. */ @@ -90,9 +123,18 @@ private: ServiceContext* const _service; - // The mutex protects _clusterTime. + // The mutex protects _clusterTime and _timeProofService. stdx::mutex _mutex; - LogicalTime _clusterTime; + SignedLogicalTime _clusterTime; + std::unique_ptr<TimeProofService> _timeProofService; + + /** + * Temporary key only used for unit tests. + * + * TODO: SERVER-28436 Implement KeysCollectionManager + * Remove _tempKey and its uses from logical clock, and pass actual key from key manager. + */ + TimeProofService::Key _tempKey = {}; }; } // namespace mongo diff --git a/src/mongo/db/logical_clock_test.cpp b/src/mongo/db/logical_clock_test.cpp index dd259b7d7e2..7a9b2fc4a9b 100644 --- a/src/mongo/db/logical_clock_test.cpp +++ b/src/mongo/db/logical_clock_test.cpp @@ -37,6 +37,8 @@ #include "mongo/db/logical_clock_test_fixture.h" #include "mongo/db/logical_time.h" #include "mongo/db/repl/replication_coordinator_mock.h" +#include "mongo/db/signed_logical_time.h" +#include "mongo/db/time_proof_service.h" #include "mongo/stdx/memory.h" #include "mongo/unittest/unittest.h" #include "mongo/util/clock_source_mock.h" @@ -54,10 +56,10 @@ TEST_F(LogicalClockTest, roundtrip) { Timestamp tX(1); auto time = LogicalTime(tX); - getClock()->setClusterTimeFromTrustedSource(time); + getClock()->initClusterTimeFromTrustedSource(time); auto storedTime(getClock()->getClusterTime()); - ASSERT_TRUE(storedTime == time); + ASSERT_TRUE(storedTime.getTime() == time); } // Verify the reserve ticks functionality. @@ -67,10 +69,10 @@ TEST_F(LogicalClockTest, reserveTicks) { auto t1 = getClock()->reserveTicks(1); auto t2(getClock()->getClusterTime()); - ASSERT_TRUE(t1 == t2); + ASSERT_TRUE(t1 == t2.getTime()); // Make sure we synchronized with the wall clock. - ASSERT_TRUE(t2.asTimestamp().getSecs() == 10); + ASSERT_TRUE(t2.getTime().asTimestamp().getSecs() == 10); auto t3 = getClock()->reserveTicks(1); t1.addTicks(1); @@ -85,9 +87,9 @@ TEST_F(LogicalClockTest, reserveTicks) { ASSERT_TRUE(t3 == t1); // Ensure overflow to a new second. - auto initTimeSecs = getClock()->getClusterTime().asTimestamp().getSecs(); + auto initTimeSecs = getClock()->getClusterTime().getTime().asTimestamp().getSecs(); getClock()->reserveTicks((1U << 31) - 1); - auto newTimeSecs = getClock()->getClusterTime().asTimestamp().getSecs(); + auto newTimeSecs = getClock()->getClusterTime().getTime().asTimestamp().getSecs(); ASSERT_TRUE(newTimeSecs == initTimeSecs + 1); } @@ -95,8 +97,10 @@ TEST_F(LogicalClockTest, reserveTicks) { TEST_F(LogicalClockTest, advanceClusterTime) { auto t1 = getClock()->reserveTicks(1); t1.addTicks(100); - ASSERT_OK(getClock()->advanceClusterTime(t1)); - ASSERT_TRUE(t1 == getClock()->getClusterTime()); + SignedLogicalTime l1 = makeSignedLogicalTime(t1); + ASSERT_OK(getClock()->advanceClusterTimeFromTrustedSource(l1)); + auto l2(getClock()->getClusterTime()); + ASSERT_TRUE(l1.getTime() == l2.getTime()); } // Verify rate limiter rejects logical times whose seconds values are too far ahead. @@ -108,9 +112,11 @@ TEST_F(LogicalClockTest, RateLimiterRejectsLogicalTimesTooFarAhead) { durationCount<Seconds>(LogicalClock::kMaxAcceptableLogicalClockDrift) + 10, // Add 10 seconds to ensure limit is exceeded. 1); - LogicalTime t1(tooFarAheadTimestamp); + SignedLogicalTime l1 = makeSignedLogicalTime(LogicalTime(tooFarAheadTimestamp)); - ASSERT_EQ(ErrorCodes::ClusterTimeFailsRateLimiter, getClock()->advanceClusterTime(t1)); + ASSERT_EQ(ErrorCodes::ClusterTimeFailsRateLimiter, getClock()->advanceClusterTime(l1)); + ASSERT_EQ(ErrorCodes::ClusterTimeFailsRateLimiter, + getClock()->advanceClusterTimeFromTrustedSource(l1)); } // Verify cluster time can be initialized to a very old time. @@ -122,9 +128,47 @@ TEST_F(LogicalClockTest, InitFromTrustedSourceCanAcceptVeryOldLogicalTime) { durationCount<Seconds>(getMockClockSourceTime().toDurationSinceEpoch()) - (durationCount<Seconds>(LogicalClock::kMaxAcceptableLogicalClockDrift) * 5)); auto veryOldTime = LogicalTime(veryOldTimestamp); - getClock()->setClusterTimeFromTrustedSource(veryOldTime); + getClock()->initClusterTimeFromTrustedSource(veryOldTime); - ASSERT_TRUE(getClock()->getClusterTime() == veryOldTime); + ASSERT_TRUE(getClock()->getClusterTime().getTime() == veryOldTime); +} + +// A clock with no TimeProofService should reject new times in advanceClusterTime. +TEST_F(LogicalClockTest, AdvanceClusterTimeFailsWithoutTimeProofService) { + LogicalTime initialTime(Timestamp(10)); + getClock()->initClusterTimeFromTrustedSource(initialTime); + + unsetTimeProofService(); + + SignedLogicalTime l1 = makeSignedLogicalTime(LogicalTime(Timestamp(100))); + ASSERT_EQ(ErrorCodes::CannotVerifyAndSignLogicalTime, getClock()->advanceClusterTime(l1)); + ASSERT_TRUE(getClock()->getClusterTime().getTime() == initialTime); + + resetTimeProofService(); + + SignedLogicalTime l2 = makeSignedLogicalTime(LogicalTime(Timestamp(200))); + ASSERT_OK(getClock()->advanceClusterTime(l2)); + ASSERT_TRUE(getClock()->getClusterTime().getTime() == l2.getTime()); +} + +// A clock with no TimeProofService can still advance its time through certain methods. +TEST_F(LogicalClockTest, CertainMethodsCanAdvanceClockWithoutTimeProofService) { + unsetTimeProofService(); + + LogicalTime t1(Timestamp(100)); + getClock()->initClusterTimeFromTrustedSource(t1); + ASSERT_TRUE(getClock()->getClusterTime().getTime() == t1); + + auto t2 = getClock()->reserveTicks(1); + ASSERT_TRUE(getClock()->getClusterTime().getTime() == t2); + + LogicalTime t3(Timestamp(300)); + ASSERT_OK(getClock()->signAndAdvanceClusterTime(t3)); + ASSERT_TRUE(getClock()->getClusterTime().getTime() == t3); + + SignedLogicalTime l4 = makeSignedLogicalTime(LogicalTime(Timestamp(400))); + ASSERT_OK(getClock()->advanceClusterTimeFromTrustedSource(l4)); + ASSERT_TRUE(getClock()->getClusterTime().getTime() == l4.getTime()); } // Verify writes to the oplog advance cluster time. @@ -132,12 +176,12 @@ TEST_F(LogicalClockTest, WritesToOplogAdvanceClusterTime) { Timestamp tX(1); auto initialTime = LogicalTime(tX); - getClock()->setClusterTimeFromTrustedSource(initialTime); - ASSERT_TRUE(getClock()->getClusterTime() == initialTime); + getClock()->initClusterTimeFromTrustedSource(initialTime); + ASSERT_TRUE(getClock()->getClusterTime().getTime() == initialTime); getDBClient()->insert(kDummyNamespaceString, BSON("x" << 1)); - ASSERT_TRUE(getClock()->getClusterTime() > initialTime); - ASSERT_EQ(getClock()->getClusterTime().asTimestamp(), + ASSERT_TRUE(getClock()->getClusterTime().getTime() > initialTime); + ASSERT_EQ(getClock()->getClusterTime().getTime().asTimestamp(), replicationCoordinator()->getMyLastAppliedOpTime().getTimestamp()); } diff --git a/src/mongo/db/logical_clock_test_fixture.cpp b/src/mongo/db/logical_clock_test_fixture.cpp index 588ff7dd766..d7f6e8036b6 100644 --- a/src/mongo/db/logical_clock_test_fixture.cpp +++ b/src/mongo/db/logical_clock_test_fixture.cpp @@ -56,6 +56,10 @@ void LogicalClockTestFixture::setUp() { LogicalClock::set(service, std::move(logicalClock)); _clock = LogicalClock::get(service); + auto pTps = stdx::make_unique<TimeProofService>(); + _timeProofService = pTps.get(); + _clock->setTimeProofService(std::move(pTps)); + service->setFastClockSource(stdx::make_unique<SharedClockSourceAdapter>(_mockClockSource)); service->setPreciseClockSource(stdx::make_unique<SharedClockSourceAdapter>(_mockClockSource)); @@ -88,6 +92,21 @@ Date_t LogicalClockTestFixture::getMockClockSourceTime() const { return _mockClockSource->now(); } +SignedLogicalTime LogicalClockTestFixture::makeSignedLogicalTime(LogicalTime logicalTime) const { + TimeProofService::Key key = {}; + return SignedLogicalTime(logicalTime, _timeProofService->getProof(logicalTime, key), 0); +} + +void LogicalClockTestFixture::resetTimeProofService() { + auto pTps = stdx::make_unique<TimeProofService>(); + _timeProofService = pTps.get(); + _clock->setTimeProofService(std::move(pTps)); +} + +void LogicalClockTestFixture::unsetTimeProofService() const { + _clock->setTimeProofService(std::unique_ptr<TimeProofService>()); +} + DBDirectClient* LogicalClockTestFixture::getDBClient() const { return _dbDirectClient.get(); } diff --git a/src/mongo/db/logical_clock_test_fixture.h b/src/mongo/db/logical_clock_test_fixture.h index 9a3115b79d3..4c11f31e704 100644 --- a/src/mongo/db/logical_clock_test_fixture.h +++ b/src/mongo/db/logical_clock_test_fixture.h @@ -37,6 +37,8 @@ class ClockSourceMock; class DBDirectClient; class LogicalClock; class LogicalTime; +class SignedLogicalTime; +class TimeProofService; /** * A test fixture that installs a LogicalClock instance with a TimeProofService onto a service @@ -65,10 +67,17 @@ protected: Date_t getMockClockSourceTime() const; + SignedLogicalTime makeSignedLogicalTime(LogicalTime logicalTime) const; + + void resetTimeProofService(); + + void unsetTimeProofService() const; + DBDirectClient* getDBClient() const; private: LogicalClock* _clock; + TimeProofService* _timeProofService; std::shared_ptr<ClockSourceMock> _mockClockSource = std::make_shared<ClockSourceMock>(); std::unique_ptr<DBDirectClient> _dbDirectClient; }; diff --git a/src/mongo/db/logical_time_metadata_hook.cpp b/src/mongo/db/logical_time_metadata_hook.cpp index 29949e36c82..bb4124d611b 100644 --- a/src/mongo/db/logical_time_metadata_hook.cpp +++ b/src/mongo/db/logical_time_metadata_hook.cpp @@ -31,7 +31,6 @@ #include "mongo/db/logical_time_metadata_hook.h" #include "mongo/db/logical_clock.h" -#include "mongo/db/logical_time_validator.h" #include "mongo/rpc/metadata/logical_time_metadata.h" #include "mongo/stdx/memory.h" @@ -43,13 +42,11 @@ LogicalTimeMetadataHook::LogicalTimeMetadataHook(ServiceContext* service) : _ser Status LogicalTimeMetadataHook::writeRequestMetadata(OperationContext* opCtx, BSONObjBuilder* metadataBob) { - auto validator = LogicalTimeValidator::get(_service); - if (!validator) { + if (!LogicalClock::get(_service)->canVerifyAndSign()) { return Status::OK(); } - auto newTime = LogicalClock::get(_service)->getClusterTime(); - LogicalTimeMetadata metadata(validator->signLogicalTime(newTime)); + LogicalTimeMetadata metadata(LogicalClock::get(_service)->getClusterTime()); metadata.writeToMetadata(metadataBob); return Status::OK(); } @@ -60,21 +57,14 @@ Status LogicalTimeMetadataHook::readReplyMetadata(StringData replySource, if (!parseStatus.isOK()) { return parseStatus.getStatus(); } - auto& signedTime = parseStatus.getValue().getSignedTime(); - // LogicalTimeMetadata is default constructed if no logical time metadata was sent, so a // default constructed SignedLogicalTime should be ignored. if (signedTime.getTime() == LogicalTime::kUninitialized) { return Status::OK(); } - auto validator = LogicalTimeValidator::get(_service); - if (validator) { - validator->updateCacheTrustedSource(signedTime); - } - - return LogicalClock::get(_service)->advanceClusterTime(signedTime.getTime()); + return LogicalClock::get(_service)->advanceClusterTimeFromTrustedSource(signedTime); } } // namespace rpc diff --git a/src/mongo/db/logical_time_validator.cpp b/src/mongo/db/logical_time_validator.cpp deleted file mode 100644 index 3e6e4466742..00000000000 --- a/src/mongo/db/logical_time_validator.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/** - * Copyright (C) 2017 MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/db/logical_time_validator.h" - -#include "mongo/db/operation_context.h" -#include "mongo/db/service_context.h" - -namespace mongo { - -namespace { -const auto getLogicalClockValidator = - ServiceContext::declareDecoration<std::unique_ptr<LogicalTimeValidator>>(); -stdx::mutex validatorMutex; - -// TODO: SERVER-28127 Implement KeysCollectionManager -// Remove _tempKey and its uses from logical clock, and pass actual key from key manager. -TimeProofService::Key tempKey = {}; -} - -LogicalTimeValidator* LogicalTimeValidator::get(ServiceContext* service) { - stdx::lock_guard<stdx::mutex> lk(validatorMutex); - return getLogicalClockValidator(service).get(); -} - -LogicalTimeValidator* LogicalTimeValidator::get(OperationContext* ctx) { - return get(ctx->getClient()->getServiceContext()); -} - -void LogicalTimeValidator::set(ServiceContext* service, - std::unique_ptr<LogicalTimeValidator> newValidator) { - stdx::lock_guard<stdx::mutex> lk(validatorMutex); - auto& validator = getLogicalClockValidator(service); - validator = std::move(newValidator); -} - -SignedLogicalTime LogicalTimeValidator::signLogicalTime(const LogicalTime& newTime) { - // Compare and calculate HMAC inside mutex to prevent multiple threads computing HMAC for the - // same logical time. - stdx::lock_guard<stdx::mutex> lk(_mutex); - if (newTime == _lastSeenValidTime.getTime()) { - return _lastSeenValidTime; - } - - auto signature = _timeProofService.getProof(newTime, tempKey); - SignedLogicalTime newSignedTime(newTime, std::move(signature), 0); - - if (newTime > _lastSeenValidTime.getTime()) { - _lastSeenValidTime = newSignedTime; - } - - return newSignedTime; -} - -Status LogicalTimeValidator::validate(const SignedLogicalTime& newTime) { - { - stdx::lock_guard<stdx::mutex> lk(_mutex); - if (newTime.getTime() == _lastSeenValidTime.getTime()) { - return Status::OK(); - } - } - - const auto newProof = newTime.getProof(); - // Logical time is only sent if a server's clock can verify and sign logical times, so any - // received logical times should have proofs. - invariant(newProof); - - auto res = _timeProofService.checkProof(newTime.getTime(), newProof.get(), tempKey); - if (res != Status::OK()) { - return res; - } - - return Status::OK(); -} - -void LogicalTimeValidator::updateCacheTrustedSource(const SignedLogicalTime& newTime) { - stdx::lock_guard<stdx::mutex> lk(_mutex); - if (newTime.getTime() > _lastSeenValidTime.getTime()) { - _lastSeenValidTime = newTime; - } -} - -} // namespace mongo diff --git a/src/mongo/db/logical_time_validator.h b/src/mongo/db/logical_time_validator.h deleted file mode 100644 index 74bf93077bf..00000000000 --- a/src/mongo/db/logical_time_validator.h +++ /dev/null @@ -1,75 +0,0 @@ -/** - * Copyright (C) 2017 MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#pragma once - -#include <memory> - -#include "mongo/db/signed_logical_time.h" -#include "mongo/db/time_proof_service.h" -#include "mongo/stdx/mutex.h" - -namespace mongo { - -class OperationContext; -class ServiceContext; - -/** - * This is responsible for signing logical times that can be used to sent to other servers and - * verifying signatures of signed logical times. - */ -class LogicalTimeValidator { -public: - // Decorate ServiceContext with LogicalTimeValidator instance. - static LogicalTimeValidator* get(ServiceContext* service); - static LogicalTimeValidator* get(OperationContext* ctx); - static void set(ServiceContext* service, std::unique_ptr<LogicalTimeValidator> validator); - - /** - * Returns the newTime with a valid signature. - */ - SignedLogicalTime signLogicalTime(const LogicalTime& newTime); - - /** - * Returns true if the signature of newTime is valid. - */ - Status validate(const SignedLogicalTime& newTime); - - /** - * Saves the newTime if it is newer than the last seen valid LogicalTime without performing - * validation. - */ - void updateCacheTrustedSource(const SignedLogicalTime& newTime); - -private: - stdx::mutex _mutex; - SignedLogicalTime _lastSeenValidTime; - TimeProofService _timeProofService; -}; - -} // namespace mongo diff --git a/src/mongo/db/logical_time_validator_test.cpp b/src/mongo/db/logical_time_validator_test.cpp deleted file mode 100644 index 3eb328c7044..00000000000 --- a/src/mongo/db/logical_time_validator_test.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - * Copyright (C) 2017 MongoDB, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects for - * all of the code used other than as permitted herein. If you modify file(s) - * with this exception, you may extend this exception to your version of the - * file(s), but you are not obligated to do so. If you do not wish to do so, - * delete this exception statement from your version. If you delete this - * exception statement from all source files in the program, then also delete - * it in the license file. - */ - -#include "mongo/platform/basic.h" - -#include "mongo/bson/timestamp.h" -#include "mongo/db/logical_clock.h" -#include "mongo/db/logical_time.h" -#include "mongo/db/logical_time_validator.h" -#include "mongo/db/service_context_noop.h" -#include "mongo/db/signed_logical_time.h" -#include "mongo/db/time_proof_service.h" -#include "mongo/platform/basic.h" -#include "mongo/stdx/memory.h" -#include "mongo/unittest/unittest.h" -#include "mongo/util/clock_source_mock.h" - -namespace mongo { -namespace { - -TEST(LogicalTimeValidator, GetTimeWithIncreasingTimes) { - LogicalTimeValidator validator; - - LogicalTime t1(Timestamp(10, 0)); - auto newTime = validator.signLogicalTime(t1); - - ASSERT_EQ(t1.asTimestamp(), newTime.getTime().asTimestamp()); - ASSERT_TRUE(newTime.getProof()); - - LogicalTime t2(Timestamp(20, 0)); - auto newTime2 = validator.signLogicalTime(t2); - - ASSERT_EQ(t2.asTimestamp(), newTime2.getTime().asTimestamp()); - ASSERT_TRUE(newTime2.getProof()); -} - -TEST(LogicalTimeValidator, ValidateReturnsOkForValidSignature) { - LogicalTimeValidator validator; - - LogicalTime t1(Timestamp(20, 0)); - auto newTime = validator.signLogicalTime(t1); - - ASSERT_OK(validator.validate(newTime)); -} - -TEST(LogicalTimeValidator, ValidateErrorsOnInvalidTime) { - LogicalTimeValidator validator; - - LogicalTime t1(Timestamp(20, 0)); - auto newTime = validator.signLogicalTime(t1); - - TimeProofService::TimeProof invalidProof = {{1, 2, 3}}; - SignedLogicalTime invalidTime(LogicalTime(Timestamp(30, 0)), invalidProof, 0); - - auto status = validator.validate(invalidTime); - ASSERT_EQ(ErrorCodes::TimeProofMismatch, status); -} - -} // unnamed namespace -} // namespace mongo diff --git a/src/mongo/db/read_concern.cpp b/src/mongo/db/read_concern.cpp index 03b278b22be..2b3a0c7c184 100644 --- a/src/mongo/db/read_concern.cpp +++ b/src/mongo/db/read_concern.cpp @@ -126,7 +126,7 @@ Status waitForReadConcern(OperationContext* opCtx, const repl::ReadConcernArgs& auto afterClusterTime = readConcernArgs.getArgsClusterTime(); if (afterClusterTime) { - auto currentTime = LogicalClock::get(opCtx)->getClusterTime(); + auto currentTime = LogicalClock::get(opCtx)->getClusterTime().getTime(); if (currentTime < *afterClusterTime) { return {ErrorCodes::InvalidOptions, "readConcern afterClusterTime must not be greater than clusterTime value"}; diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 8b8c14a7c32..0e9c293ab7c 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -1127,7 +1127,7 @@ Status applyCommand_inlock(OperationContext* opCtx, void setNewTimestamp(ServiceContext* service, const Timestamp& newTime) { stdx::lock_guard<stdx::mutex> lk(newOpMutex); - LogicalClock::get(service)->setClusterTimeFromTrustedSource(LogicalTime(newTime)); + LogicalClock::get(service)->signAndAdvanceClusterTime(LogicalTime(newTime)); lastSetTimestamp = newTime; newTimestampNotifier.notify_all(); } diff --git a/src/mongo/rpc/SConscript b/src/mongo/rpc/SConscript index 3d7982e6a34..19635a49756 100644 --- a/src/mongo/rpc/SConscript +++ b/src/mongo/rpc/SConscript @@ -146,8 +146,8 @@ env.Clone().InjectModule("enterprise").Library( '$BUILD_DIR/mongo/bson/util/bson_extract', '$BUILD_DIR/mongo/client/read_preference', '$BUILD_DIR/mongo/db/auth/authcore', - '$BUILD_DIR/mongo/db/logical_time_validator', '$BUILD_DIR/mongo/db/repl/optime', + '$BUILD_DIR/mongo/db/logical_clock', '$BUILD_DIR/mongo/db/signed_logical_time', '$BUILD_DIR/mongo/util/decorable', ], diff --git a/src/mongo/rpc/metadata.cpp b/src/mongo/rpc/metadata.cpp index 07cdfef9fca..d0e837302c4 100644 --- a/src/mongo/rpc/metadata.cpp +++ b/src/mongo/rpc/metadata.cpp @@ -38,7 +38,6 @@ #include "mongo/db/auth/privilege.h" #include "mongo/db/jsobj.h" #include "mongo/db/logical_clock.h" -#include "mongo/db/logical_time_validator.h" #include "mongo/rpc/metadata/audit_metadata.h" #include "mongo/rpc/metadata/client_metadata_ismaster.h" #include "mongo/rpc/metadata/config_server_metadata.h" @@ -132,7 +131,7 @@ Status readRequestMetadata(OperationContext* opCtx, const BSONObj& metadataObj) auto logicalClock = LogicalClock::get(opCtx); if (logicalClock) { - auto logicalTimeMetadata = rpc::LogicalTimeMetadata::readFromMetadata(logicalTimeElem); + auto logicalTimeMetadata = LogicalTimeMetadata::readFromMetadata(logicalTimeElem); if (!logicalTimeMetadata.isOK()) { return logicalTimeMetadata.getStatus(); } @@ -144,24 +143,19 @@ Status readRequestMetadata(OperationContext* opCtx, const BSONObj& metadataObj) return Status::OK(); } - auto logicalTimeValidator = LogicalTimeValidator::get(opCtx); if (isAuthorizedToAdvanceClock(opCtx)) { - if (logicalTimeValidator) { - logicalTimeValidator->updateCacheTrustedSource(signedTime); + auto advanceClockStatus = logicalClock->advanceClusterTimeFromTrustedSource(signedTime); + + if (!advanceClockStatus.isOK()) { + return advanceClockStatus; } - } else if (!logicalTimeValidator) { - return Status(ErrorCodes::CannotVerifyAndSignLogicalTime, - "Cannot accept logicalTime: " + signedTime.getTime().toString() + - ". May not be a part of a sharded cluster"); } else { - auto advanceClockStatus = logicalTimeValidator->validate(signedTime); + auto advanceClockStatus = logicalClock->advanceClusterTime(signedTime); if (!advanceClockStatus.isOK()) { return advanceClockStatus; } } - - logicalClock->advanceClusterTime(signedTime.getTime()); } return Status::OK(); diff --git a/src/mongo/rpc/metadata/logical_time_metadata.cpp b/src/mongo/rpc/metadata/logical_time_metadata.cpp index d7ad869c9e8..235fc0d99bb 100644 --- a/src/mongo/rpc/metadata/logical_time_metadata.cpp +++ b/src/mongo/rpc/metadata/logical_time_metadata.cpp @@ -105,7 +105,7 @@ void LogicalTimeMetadata::writeToMetadata(BSONObjBuilder* metadataBuilder) const _clusterTime.getTime().asTimestamp().append(subObjBuilder.bb(), kClusterTimeFieldName); BSONObjBuilder signatureObjBuilder(subObjBuilder.subobjStart(kSignatureFieldName)); - // Logical time metadata is only written when the LogicalTimeValidator is set, which + // Logical time metadata is only written when LogicalClock::canVerifyAndSign returns true, which // means the cluster time should always have a proof. invariant(_clusterTime.getProof()); _clusterTime.getProof()->appendAsBinData(signatureObjBuilder, kSignatureHashFieldName); diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index 5c24d16bdc1..25ac876dfd2 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -44,7 +44,6 @@ #include "mongo/db/commands.h" #include "mongo/db/lasterror.h" #include "mongo/db/logical_clock.h" -#include "mongo/db/logical_time_validator.h" #include "mongo/db/matcher/extensions_callback_noop.h" #include "mongo/db/namespace_string.h" #include "mongo/db/operation_time_tracker.h" @@ -150,29 +149,30 @@ Status processCommandMetadata(OperationContext* opCtx, const BSONObj& cmdObj) { } auto authSession = AuthorizationSession::get(opCtx->getClient()); - auto logicalTimeValidator = LogicalTimeValidator::get(opCtx); - const auto& signedTime = logicalTimeMetadata.getValue().getSignedTime(); - if (authSession->getAuthorizationManager().isAuthEnabled()) { - auto advanceClockStatus = logicalTimeValidator->validate(signedTime); + auto advanceClockStatus = + logicalClock->advanceClusterTime(logicalTimeMetadata.getValue().getSignedTime()); if (!advanceClockStatus.isOK()) { return advanceClockStatus; } } else { - logicalTimeValidator->updateCacheTrustedSource(signedTime); + auto advanceClockStatus = logicalClock->advanceClusterTimeFromTrustedSource( + logicalTimeMetadata.getValue().getSignedTime()); + + if (!advanceClockStatus.isOK()) { + return advanceClockStatus; + } } - return logicalClock->advanceClusterTime(signedTime.getTime()); + return Status::OK(); } /** * Append required fields to command response. */ void appendRequiredFieldsToResponse(OperationContext* opCtx, BSONObjBuilder* responseBuilder) { - auto validator = LogicalTimeValidator::get(opCtx); - auto currentTime = validator->signLogicalTime(LogicalClock::get(opCtx)->getClusterTime()); - rpc::LogicalTimeMetadata logicalTimeMetadata(currentTime); + rpc::LogicalTimeMetadata logicalTimeMetadata(LogicalClock::get(opCtx)->getClusterTime()); logicalTimeMetadata.writeToMetadata(responseBuilder); auto tracker = OperationTimeTracker::get(opCtx); if (tracker) { diff --git a/src/mongo/s/sharding_initialization.cpp b/src/mongo/s/sharding_initialization.cpp index 9220176f29e..30403eb725e 100644 --- a/src/mongo/s/sharding_initialization.cpp +++ b/src/mongo/s/sharding_initialization.cpp @@ -38,7 +38,6 @@ #include "mongo/client/remote_command_targeter_factory_impl.h" #include "mongo/db/audit.h" #include "mongo/db/logical_clock.h" -#include "mongo/db/logical_time_validator.h" #include "mongo/db/s/sharding_task_executor.h" #include "mongo/db/server_options.h" #include "mongo/db/server_parameters.h" @@ -209,6 +208,9 @@ Status initializeGlobalShardingState(OperationContext* opCtx, std::move(executorPool), networkPtr); + auto timeProofService = stdx::make_unique<TimeProofService>(); + LogicalClock::get(opCtx)->setTimeProofService(std::move(timeProofService)); + // must be started once the grid is initialized grid.shardRegistry()->startup(opCtx); @@ -225,9 +227,6 @@ Status initializeGlobalShardingState(OperationContext* opCtx, } } - LogicalTimeValidator::set(opCtx->getServiceContext(), - stdx::make_unique<LogicalTimeValidator>()); - return Status::OK(); } |