KeysCollectionManager is installed on the service context so the LogicalClock can get the key that matches the signature generation.
Its also owns and manages KeysCollection
Pseudo code:
KeysCollectionManager {
public:
// for reading
StatusWith<KeysCollectionDocument> getKeyForValidation(OperationContext* opCtx,
long long keyId,
const LogicalTime& forThisTime) {
auto keyStatus = _getKeyWithKeyIdCheck(keyId, forThisTime);
if (keyStatus != ErrorCodes::KeyNotFound) {
return keyStatus;
}
auto refreshRequest = _requestRefresh();
// note: waitFor waits min(maxTimeMS, deadline)
if (!refreshRequest.waitFor(opCtx, kDeadline)) {
// return refresh interrupted/timed out
}
return _getKeyWithKeyIdCheck(keyId, forThisTime);
}
// for signing
StatusWith<KeysCollectionDocument> getKeyForSigning(OperationContext* opCtx,
const LogicalTime& forThisTime) {
auto keyStatus = _getKey(forThisTime);
if (keyStatus != ErrorCodes::KeyNotFound) {
return keyStatus;
}
{
// refresh retry logic until key.expiresAt > forThisTime or timeout
}
return _getKey(forThisTime);
}
void start(ServiceContext*); // start bg refresher
void shutDown(); // shutdown bg refresher
void switchMode(Mode); // switch between reader or updater
private:
void backgroundThread() { // consider moving thread logic to separate nested class
// all necessary setup
while (true) {
auto opCtx = makeOperationContext();
std::shared_ptr<KeysCollectionCache> currentCacheImpl;
{
std::lock_guard<std::mutex> lock(_mutex);
currentCacheImpl = _keysCache;
}
auto latestKey = currentCacheImpl->refresh(opCtx);
if (!latestKey.isOK()) {
// return if nextWakeUp returns inShutdown
// add back-off?
continue;
}
{
std::lock_guard<std::mutex> lock(_mutex);
if (_refreshRequest) {
_refreshRequest->notification.set();
_refreshRequest.reset();
}
}
auto nextWakeup = howMuchSleepNeedFor(latestKey.expiresAt);
// Add backoff to nextWakeup if it has a very small value in a row to avoid spinning.
MONGO_IDLE_THREAD_BLOCK;
auto status = opCtx.waitFor(nextWakeup);
// check status for shutdown
}
}
std::shared_ptr<Notification> _requestRefresh() {
std::lock_guard<std::mutex> lock(_mutex);
if (_refreshRequest) {
return _refreshRequest;
}
_refreshRequest = stdx::make_shared<Notification>();
return _refreshRequest;
}
StatusWith<KeysCollectionDocument> _getKeyWithKeyIdCheck(long long keyId,
const LogicalTime& forThisTime) {
auto keyStatus = _getKey(forThisTime);
if (!keyStatus.isOK()) {
return keyStatus;
}
auto key = keyStatus.getValue();
if (keyId == key.keyId) {
return _key;
}
if (key.keyId > keyId)
return ErrorCodes::OldKey; // caller should decide what to do
// Key not expired but keyId does not match!
return ErrorCodes::KeyNotFound;
}
StatusWith<KeysCollectionDocument> _getKey(const LogicalTime& forThisTime) {
std::lock_guard<std::mutex> lock(_mutex);
auto key = _keysCache.getKey(forThisTime);
if (key.expiresAt < forThisTime) {
return ErrorCodes::KeyNotFound;
}
return key;
}
stdx::mutex _mutex;
std::shared_ptr<Notification> _refreshRequest;
std::shared_ptr<KeysCollectionCache> _keysCache;
}
- is related to
-
SERVER-28435 Implement KeysCollectionCacheReader
-
- Closed
-