summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/SConscript24
-rw-r--r--src/mongo/db/commands/dbcommands.cpp12
-rw-r--r--src/mongo/db/keys_collection_cache_reader_and_updater.cpp2
-rw-r--r--src/mongo/db/keys_collection_cache_reader_and_updater_test.cpp18
-rw-r--r--src/mongo/db/keys_collection_manager.cpp2
-rw-r--r--src/mongo/db/keys_collection_manager_test.cpp9
-rw-r--r--src/mongo/db/logical_clock.cpp98
-rw-r--r--src/mongo/db/logical_clock.h66
-rw-r--r--src/mongo/db/logical_clock_test.cpp76
-rw-r--r--src/mongo/db/logical_clock_test_fixture.cpp19
-rw-r--r--src/mongo/db/logical_clock_test_fixture.h9
-rw-r--r--src/mongo/db/logical_time_metadata_hook.cpp16
-rw-r--r--src/mongo/db/logical_time_validator.cpp110
-rw-r--r--src/mongo/db/logical_time_validator.h75
-rw-r--r--src/mongo/db/logical_time_validator_test.cpp85
-rw-r--r--src/mongo/db/read_concern.cpp2
-rw-r--r--src/mongo/db/repl/oplog.cpp2
-rw-r--r--src/mongo/rpc/SConscript2
-rw-r--r--src/mongo/rpc/metadata.cpp18
-rw-r--r--src/mongo/rpc/metadata/logical_time_metadata.cpp2
-rw-r--r--src/mongo/s/commands/strategy.cpp20
-rw-r--r--src/mongo/s/sharding_initialization.cpp7
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();
}