1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <memory> 34 35 #include "mongo/base/status_with.h" 36 #include "mongo/db/keys_collection_cache_reader.h" 37 #include "mongo/db/keys_collection_cache_reader_and_updater.h" 38 #include "mongo/db/keys_collection_document.h" 39 #include "mongo/db/keys_collection_manager.h" 40 #include "mongo/stdx/functional.h" 41 #include "mongo/stdx/mutex.h" 42 #include "mongo/stdx/thread.h" 43 #include "mongo/util/concurrency/notification.h" 44 #include "mongo/util/duration.h" 45 46 namespace mongo { 47 48 class OperationContext; 49 class LogicalTime; 50 class ServiceContext; 51 class KeysCollectionClient; 52 53 namespace keys_collection_manager_util { 54 55 /** 56 * Returns the amount of time to wait until the monitoring thread should attempt to refresh again. 57 */ 58 Milliseconds howMuchSleepNeedFor(const LogicalTime& currentTime, 59 const LogicalTime& latestExpiredAt, 60 const Milliseconds& interval); 61 62 } // namespace keys_collection_manager_util 63 64 /** 65 * This implementation of the KeysCollectionManager queries the config servers for keys. 66 * It maintains in internal background thread that is used to periodically refresh 67 * the local key cache against the keys collection stored on the config servers. 68 */ 69 class KeysCollectionManagerSharding : public KeysCollectionManager { 70 public: 71 static const Seconds kKeyValidInterval; 72 73 KeysCollectionManagerSharding(std::string purpose, 74 std::unique_ptr<KeysCollectionClient> client, 75 Seconds keyValidForInterval); 76 77 /** 78 * Return a key that is valid for the given time and also matches the keyId. Note that this call 79 * can block if it will need to do a refresh. 80 * 81 * Throws ErrorCode::ExceededTimeLimit if it times out. 82 */ 83 StatusWith<KeysCollectionDocument> getKeyForValidation(OperationContext* opCtx, 84 long long keyId, 85 const LogicalTime& forThisTime) override; 86 87 /** 88 * Returns a key that is valid for the given time. Note that unlike getKeyForValidation, this 89 * will never do a refresh. 90 * 91 * Throws ErrorCode::ExceededTimeLimit if it times out. 92 */ 93 StatusWith<KeysCollectionDocument> getKeyForSigning(OperationContext* opCtx, 94 const LogicalTime& forThisTime) override; 95 96 /** 97 * Request this manager to perform a refresh. 98 */ 99 void refreshNow(OperationContext* opCtx); 100 101 /** 102 * Starts a background thread that will constantly update the internal cache of keys. 103 * 104 * Cannot call this after stopMonitoring was called at least once. 105 */ 106 void startMonitoring(ServiceContext* service); 107 108 /** 109 * Stops the background thread updating the cache. 110 */ 111 void stopMonitoring(); 112 113 /** 114 * Enable writing new keys. 115 */ 116 void enableKeyGenerator(OperationContext* opCtx, bool doEnable); 117 118 /** 119 * Returns true if the refresher has ever successfully returned keys from the config server. 120 */ 121 bool hasSeenKeys(); 122 123 void clearCache() override; 124 125 private: 126 /** 127 * This is responsible for periodically performing refresh in the background. 128 */ 129 class PeriodicRunner { 130 public: 131 using RefreshFunc = stdx::function<StatusWith<KeysCollectionDocument>(OperationContext*)>; 132 133 /** 134 * Preemptively inform the monitoring thread it needs to perform a refresh. Returns an 135 * object 136 * that gets notified after the current round of refresh is over. Note that being notified 137 * can 138 * mean either of these things: 139 * 140 * 1. An error occurred and refresh was not performed. 141 * 2. No error occurred but no new key was found. 142 * 3. No error occurred and new keys were found. 143 */ 144 void refreshNow(OperationContext* opCtx); 145 146 /** 147 * Sets the refresh function to use. 148 * 149 * Should only be used to bootstrap this refresher with initial strategy. Also waits to make 150 * sure that the old strategy is not being used and will no longer be used after this call. 151 */ 152 void setFunc(RefreshFunc newRefreshStrategy); 153 154 /** 155 * Starts the refresh thread. 156 */ 157 void start(ServiceContext* service, 158 const std::string& threadName, 159 Milliseconds refreshInterval); 160 161 /** 162 * Stops the refresh thread. 163 */ 164 void stop(); 165 166 /** 167 * Returns true if keys have ever successfully been returned from the config server. 168 */ 169 bool hasSeenKeys(); 170 171 private: 172 void _doPeriodicRefresh(ServiceContext* service, 173 std::string threadName, 174 Milliseconds refreshInterval); 175 176 stdx::mutex _mutex; // protects all the member variables below. 177 std::shared_ptr<Notification<void>> _refreshRequest; 178 stdx::condition_variable _refreshNeededCV; 179 180 stdx::thread _backgroundThread; 181 std::shared_ptr<RefreshFunc> _doRefresh; 182 183 bool _hasSeenKeys = false; 184 bool _inShutdown = false; 185 }; 186 187 /** 188 * Return a key that is valid for the given time and also matches the keyId. 189 */ 190 StatusWith<KeysCollectionDocument> _getKeyWithKeyIdCheck(long long keyId, 191 const LogicalTime& forThisTime); 192 193 /** 194 * Return a key that is valid for the given time. 195 */ 196 StatusWith<KeysCollectionDocument> _getKey(const LogicalTime& forThisTime); 197 198 std::unique_ptr<KeysCollectionClient> _client; 199 const std::string _purpose; 200 const Seconds _keyValidForInterval; 201 202 // No mutex needed since the members below have their own mutexes. 203 KeysCollectionCacheReader _keysCache; 204 PeriodicRunner _refresher; 205 }; 206 207 } // namespace mongo 208