summaryrefslogtreecommitdiff
path: root/src/mongo/db
diff options
context:
space:
mode:
authorJack Mulrow <jack.mulrow@mongodb.com>2020-12-07 15:41:45 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-12-10 01:39:07 +0000
commite804031ae4ea69c2cfbfcca47202fcc468d826b2 (patch)
treeaae6b34565c11979f738b86b2a4b95e397de3952 /src/mongo/db
parent20ab705ce483932ad8e2f1c75c797320a21f73c5 (diff)
downloadmongo-e804031ae4ea69c2cfbfcca47202fcc468d826b2.tar.gz
SERVER-52654 HMAC keys monitoring thread should never sleep longer than 20 days
Diffstat (limited to 'src/mongo/db')
-rw-r--r--src/mongo/db/keys_collection_manager.cpp16
-rw-r--r--src/mongo/db/keys_collection_manager_sharding_test.cpp62
2 files changed, 59 insertions, 19 deletions
diff --git a/src/mongo/db/keys_collection_manager.cpp b/src/mongo/db/keys_collection_manager.cpp
index 86a95a1a864..45d81b2aa96 100644
--- a/src/mongo/db/keys_collection_manager.cpp
+++ b/src/mongo/db/keys_collection_manager.cpp
@@ -55,7 +55,11 @@ namespace {
Milliseconds kDefaultRefreshWaitTime(30 * 1000);
Milliseconds kRefreshIntervalIfErrored(200);
-Milliseconds kMaxRefreshWaitTime(10 * 60 * 1000);
+Milliseconds kMaxRefreshWaitTimeIfErrored(10 * 60 * 1000);
+// Never wait more than the number of milliseconds in 20 days to avoid sleeping for a number greater
+// than can fit in a signed 32 bit integer.
+// 20 days = 1000 * 60 * 60 * 24 * 20 = 1,728,000,000 vs signed integer max of 2,147,483,648.
+Milliseconds kMaxRefreshWaitTimeOnSuccess(Days(20));
// Prevents the refresher thread from waiting longer than the given number of milliseconds, even on
// a successful refresh.
@@ -79,11 +83,7 @@ Milliseconds howMuchSleepNeedFor(const LogicalTime& currentTime,
Milliseconds millisBeforeExpire = Milliseconds(expiredSecs) - Milliseconds(currentSecs);
- if (interval <= millisBeforeExpire) {
- return interval;
- }
-
- return millisBeforeExpire;
+ return std::min({millisBeforeExpire, interval, kMaxRefreshWaitTimeOnSuccess});
}
} // namespace keys_collection_manager_util
@@ -261,8 +261,8 @@ void KeysCollectionManager::PeriodicRunner::_doPeriodicRefresh(ServiceContext* s
} else {
errorCount += 1;
nextWakeup = Milliseconds(kRefreshIntervalIfErrored.count() * errorCount);
- if (nextWakeup > kMaxRefreshWaitTime) {
- nextWakeup = kMaxRefreshWaitTime;
+ if (nextWakeup > kMaxRefreshWaitTimeIfErrored) {
+ nextWakeup = kMaxRefreshWaitTimeIfErrored;
}
LOGV2(4939300,
"Failed to refresh key cache",
diff --git a/src/mongo/db/keys_collection_manager_sharding_test.cpp b/src/mongo/db/keys_collection_manager_sharding_test.cpp
index dc19e7f5c9e..ced4613ef26 100644
--- a/src/mongo/db/keys_collection_manager_sharding_test.cpp
+++ b/src/mongo/db/keys_collection_manager_sharding_test.cpp
@@ -376,27 +376,67 @@ LogicalTime addSeconds(const LogicalTime& logicalTime, const Seconds& seconds) {
return LogicalTime(Timestamp(asTimestamp.getSecs() + seconds.count(), asTimestamp.getInc()));
}
-TEST(KeysCollectionManagerUtilTest, HowMuchSleepNeededForCalculationDoesNotOverflow) {
+TEST(KeysCollectionManagerUtilTest, HowMuchSleepNeedForWithDefaultKeysRotationIntervalIs20Days) {
auto secondsSinceEpoch = durationCount<Seconds>(Date_t::now().toDurationSinceEpoch());
auto defaultKeysIntervalSeconds = Seconds(KeysRotationIntervalSec);
- // Mock inputs that would have caused an overflow without the changes from SERVER-48709.
- // "currentTime" is the current clusterTime in the VectorClock, which will typically be close
- // to a timestamp constructed from the number of seconds since the unix epoch. "latestExpiredAt"
- // is the highest expiration logical time of any key, which will at most be currentTime +
- // (default key rotation interval * 2) because two valid keys are kept at a time. "interval" is
- // the duration a key is valid for, which defaults to 90 days = 7,776,000 seconds.
auto currentTime = LogicalTime(Timestamp(secondsSinceEpoch, 0));
auto latestExpiredAt = addSeconds(currentTime, defaultKeysIntervalSeconds * 2);
- auto interval = Milliseconds(defaultKeysIntervalSeconds);
+ auto defaultInterval = Milliseconds(defaultKeysIntervalSeconds);
+
+ auto nextWakeupMillis = keys_collection_manager_util::howMuchSleepNeedFor(
+ currentTime, latestExpiredAt, defaultInterval);
+ ASSERT_EQ(nextWakeupMillis, Days(20));
+}
+
+TEST(KeysCollectionManagerUtilTest, HowMuchSleepNeedForIsNeverLongerThan20Days) {
+ auto secondsSinceEpoch = durationCount<Seconds>(Date_t::now().toDurationSinceEpoch());
+ auto keysRotationInterval = Seconds(Days(50));
+
+ auto currentTime = LogicalTime(Timestamp(secondsSinceEpoch, 0));
+ auto latestExpiredAt = addSeconds(currentTime, keysRotationInterval * 2);
+ auto interval = Milliseconds(keysRotationInterval);
+
+ auto nextWakeupMillis =
+ keys_collection_manager_util::howMuchSleepNeedFor(currentTime, latestExpiredAt, interval);
+ ASSERT_EQ(nextWakeupMillis, Days(20));
+}
+
+TEST(KeysCollectionManagerUtilTest, HowMuchSleepNeedForIsNeverHigherThanRotationInterval) {
+ auto secondsSinceEpoch = durationCount<Seconds>(Date_t::now().toDurationSinceEpoch());
+ auto keysRotationInterval = Seconds(Days(5));
+
+ auto currentTime = LogicalTime(Timestamp(secondsSinceEpoch, 0));
+ auto latestExpiredAt = addSeconds(currentTime, keysRotationInterval * 2);
+ auto interval = Milliseconds(keysRotationInterval);
- // Despite the default rotation interval seconds * 1000 not fitting in a 32 bit unsigned
- // integer (7,776,000,000 vs. 4,294,967,295), the calculation should not overflow, and the next
- // wakeup should correctly be the default interval.
auto nextWakeupMillis =
keys_collection_manager_util::howMuchSleepNeedFor(currentTime, latestExpiredAt, interval);
ASSERT_EQ(nextWakeupMillis, interval);
}
+LogicalTime subtractSeconds(const LogicalTime& logicalTime, const Seconds& seconds) {
+ auto asTimestamp = logicalTime.asTimestamp();
+ return LogicalTime(Timestamp(asTimestamp.getSecs() - seconds.count(), asTimestamp.getInc()));
+}
+
+TEST(KeysCollectionManagerUtilTest, HowMuchSleepNeedForAfterNotFindingKeys) {
+ // Default refresh interval if keys could not be found.
+ const Milliseconds kRefreshIntervalIfErrored(200);
+
+ auto secondsSinceEpoch = durationCount<Seconds>(Date_t::now().toDurationSinceEpoch());
+ auto keysRotationInterval = Milliseconds(5000);
+
+ // The latest found key expired before the current time, which means no new keys were found
+ // despite the previous refresh succeeding.
+ auto currentTime = LogicalTime(Timestamp(secondsSinceEpoch, 0));
+ auto latestExpiredAt = subtractSeconds(currentTime, Seconds(1));
+ auto interval = Milliseconds(keysRotationInterval);
+
+ auto nextWakeupMillis =
+ keys_collection_manager_util::howMuchSleepNeedFor(currentTime, latestExpiredAt, interval);
+ ASSERT_EQ(nextWakeupMillis, kRefreshIntervalIfErrored);
+}
+
} // namespace
} // namespace mongo