Details
Description
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;
|
}
|
Attachments
Issue Links
- is related to
-
SERVER-28435 Implement KeysCollectionCacheReader
-
- Closed
-