summaryrefslogtreecommitdiff
path: root/src/mongo/db/logical_clock.cpp
diff options
context:
space:
mode:
authorJack Mulrow <jack.mulrow@mongodb.com>2017-03-15 12:13:35 -0400
committerJack Mulrow <jack.mulrow@mongodb.com>2017-03-17 10:38:11 -0400
commit9c47a56c17f9c155f7794c09020893bfa80cb05d (patch)
treeb24fc3fdc51ce9438897e7492682d5162797cc04 /src/mongo/db/logical_clock.cpp
parent9e7974e4b6e2b3fe5e7741dce6549624113af196 (diff)
downloadmongo-9c47a56c17f9c155f7794c09020893bfa80cb05d.tar.gz
SERVER-27721 Implement rate limiter check for advancing logical clocks
Diffstat (limited to 'src/mongo/db/logical_clock.cpp')
-rw-r--r--src/mongo/db/logical_clock.cpp55
1 files changed, 53 insertions, 2 deletions
diff --git a/src/mongo/db/logical_clock.cpp b/src/mongo/db/logical_clock.cpp
index 5e4150467a5..34a11fc163c 100644
--- a/src/mongo/db/logical_clock.cpp
+++ b/src/mongo/db/logical_clock.cpp
@@ -34,12 +34,39 @@
#include "mongo/base/status.h"
#include "mongo/db/operation_context.h"
+#include "mongo/db/server_parameters.h"
#include "mongo/db/service_context.h"
#include "mongo/db/time_proof_service.h"
#include "mongo/util/log.h"
namespace mongo {
+constexpr Seconds LogicalClock::kMaxAcceptableLogicalClockDrift;
+
+server_parameter_storage_type<long long, ServerParameterType::kStartupOnly>::value_type
+ maxAcceptableLogicalClockDrift(LogicalClock::kMaxAcceptableLogicalClockDrift.count());
+
+class MaxAcceptableLogicalClockDrift
+ : public ExportedServerParameter<long long, ServerParameterType::kStartupOnly> {
+public:
+ MaxAcceptableLogicalClockDrift()
+ : ExportedServerParameter<long long, ServerParameterType::kStartupOnly>(
+ ServerParameterSet::getGlobal(),
+ "maxAcceptableLogicalClockDrift",
+ &maxAcceptableLogicalClockDrift) {}
+
+ Status validate(const long long& potentialNewValue) {
+ if (potentialNewValue < 0) {
+ return Status(ErrorCodes::BadValue,
+ str::stream() << "maxAcceptableLogicalClockDrift cannot be negative, but "
+ "attempted to set to: "
+ << potentialNewValue);
+ }
+
+ return Status::OK();
+ }
+} maxAcceptableLogicalClockDriftParameter;
+
namespace {
const auto getLogicalClock = ServiceContext::declareDecoration<std::unique_ptr<LogicalClock>>();
}
@@ -83,8 +110,7 @@ Status LogicalClock::advanceClusterTime(const SignedLogicalTime& newTime) {
return res;
}
- stdx::lock_guard<stdx::mutex> lock(_mutex);
- return _advanceClusterTime_inlock(newTime);
+ return advanceClusterTimeFromTrustedSource(newTime);
}
Status LogicalClock::_advanceClusterTime_inlock(SignedLogicalTime newTime) {
@@ -97,6 +123,11 @@ Status LogicalClock::_advanceClusterTime_inlock(SignedLogicalTime newTime) {
Status LogicalClock::advanceClusterTimeFromTrustedSource(SignedLogicalTime newTime) {
stdx::lock_guard<stdx::mutex> lock(_mutex);
+ auto rateLimitStatus = _passesRateLimiter_inlock(newTime.getTime());
+ if (!rateLimitStatus.isOK()) {
+ return rateLimitStatus;
+ }
+
return _advanceClusterTime_inlock(std::move(newTime));
}
@@ -140,7 +171,27 @@ LogicalTime LogicalClock::reserveTicks(uint64_t ticks) {
void LogicalClock::initClusterTimeFromTrustedSource(LogicalTime newTime) {
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.
_clusterTime = _makeSignedLogicalTime(newTime);
}
+Status LogicalClock::_passesRateLimiter_inlock(LogicalTime newTime) {
+ const unsigned wallClockSecs =
+ durationCount<Seconds>(_service->getFastClockSource()->now().toDurationSinceEpoch());
+ auto maxAcceptableDrift = static_cast<const unsigned>(maxAcceptableLogicalClockDrift);
+ auto newTimeSecs = newTime.asTimestamp().getSecs();
+
+ // Both values are unsigned, so compare them first to avoid wrap-around.
+ if ((newTimeSecs > wallClockSecs) && (newTimeSecs - wallClockSecs) > maxAcceptableDrift) {
+ return Status(ErrorCodes::ClusterTimeFailsRateLimiter,
+ str::stream() << "New cluster time, " << newTimeSecs
+ << ", is too far from this node's wall clock time, "
+ << wallClockSecs
+ << ".");
+ }
+
+ return Status::OK();
+}
+
} // namespace mongo