diff options
author | Jack Mulrow <jack.mulrow@mongodb.com> | 2020-12-07 15:41:45 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-12-10 14:12:16 +0000 |
commit | 6dd2aee6bd51adcba6c34520b28d956379bf0a3d (patch) | |
tree | e503bb122c85326426d978a2a85ba59c45904465 | |
parent | dcd06945691b7cdd520b4c28428d941ee685104d (diff) | |
download | mongo-6dd2aee6bd51adcba6c34520b28d956379bf0a3d.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.cpp | 16 | ||||
-rw-r--r-- | src/mongo/db/keys_collection_manager_sharding_test.cpp | 62 |
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 ff11c1779c3..b876bc66dcf 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; } } diff --git a/src/mongo/db/keys_collection_manager_sharding_test.cpp b/src/mongo/db/keys_collection_manager_sharding_test.cpp index 60fe90cf60e..a26d4be7d5a 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 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, 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 |