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 01:39:07 +0000 |
commit | e804031ae4ea69c2cfbfcca47202fcc468d826b2 (patch) | |
tree | aae6b34565c11979f738b86b2a4b95e397de3952 /src/mongo/db | |
parent | 20ab705ce483932ad8e2f1c75c797320a21f73c5 (diff) | |
download | mongo-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.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 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 |