summaryrefslogtreecommitdiff
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 14:28:18 +0000
commit907de1c96699460cd5be04ad579d14567c90639f (patch)
tree50c8d4f42aca99e18b2592046b3138a817b71ba8
parent58e82dba8e734c5dd06e23ae0da8cb29d5fc45b9 (diff)
downloadmongo-907de1c96699460cd5be04ad579d14567c90639f.tar.gz
SERVER-52654 HMAC keys monitoring thread should never sleep longer than 20 days
(cherry picked from commit e804031ae4ea69c2cfbfcca47202fcc468d826b2)
-rw-r--r--src/mongo/db/keys_collection_manager_sharding.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_sharding.cpp b/src/mongo/db/keys_collection_manager_sharding.cpp
index ccb9c56f75d..3d3061873f4 100644
--- a/src/mongo/db/keys_collection_manager_sharding.cpp
+++ b/src/mongo/db/keys_collection_manager_sharding.cpp
@@ -54,7 +54,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(Hours(24) * 20);
// Prevents the refresher thread from waiting longer than the given number of milliseconds, even on
// a successful refresh.
@@ -78,11 +82,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
@@ -256,8 +256,8 @@ void KeysCollectionManagerSharding::PeriodicRunner::_doPeriodicRefresh(
} else {
errorCount += 1;
nextWakeup = Milliseconds(kRefreshIntervalIfErrored.count() * errorCount);
- if (nextWakeup > kMaxRefreshWaitTime) {
- nextWakeup = kMaxRefreshWaitTime;
+ if (nextWakeup > kMaxRefreshWaitTimeIfErrored) {
+ nextWakeup = kMaxRefreshWaitTimeIfErrored;
}
}
} else {
diff --git a/src/mongo/db/keys_collection_manager_sharding_test.cpp b/src/mongo/db/keys_collection_manager_sharding_test.cpp
index 8bde5344ea6..812dd7e1ded 100644
--- a/src/mongo/db/keys_collection_manager_sharding_test.cpp
+++ b/src/mongo/db/keys_collection_manager_sharding_test.cpp
@@ -400,26 +400,66 @@ 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 logical time in the LogicalClock, 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, Hours(24) * 20);
+}
+
+TEST(KeysCollectionManagerUtilTest, HowMuchSleepNeedForIsNeverLongerThan20Days) {
+ auto secondsSinceEpoch = durationCount<Seconds>(Date_t::now().toDurationSinceEpoch());
+ auto keysRotationInterval = Seconds(Hours(24) * 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, Hours(24) * 20);
+}
+
+TEST(KeysCollectionManagerUtilTest, HowMuchSleepNeedForIsNeverHigherThanRotationInterval) {
+ auto secondsSinceEpoch = durationCount<Seconds>(Date_t::now().toDurationSinceEpoch());
+ auto keysRotationInterval = Seconds(Hours(24) * 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 mongo