Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-28436

Implement KeysCollectionManager

    • Type: Icon: Task Task
    • Resolution: Done
    • Priority: Icon: Major - P3 Major - P3
    • 3.5.7
    • Affects Version/s: None
    • Component/s: Sharding
    • None
    • Fully Compatible
    • Sharding 2017-05-08

      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

      {Reader Updater}

      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;
      }
      

            Assignee:
            randolph@mongodb.com Randolph Tan
            Reporter:
            misha.tyulenev@mongodb.com Misha Tyulenev (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: