summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2020-01-20 10:03:08 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-02-15 11:19:48 +0000
commit611979eb5cafba7bb5369a19948f82453f117c65 (patch)
treefe04826f378fbd3b05d9f49173f6074726da5c00
parent44a107ad428459cad6260490ae98bca442e07385 (diff)
downloadmongo-611979eb5cafba7bb5369a19948f82453f117c65.tar.gz
SERVER-44978 Thread-through ServiceContext and ThreadPool to ReadThroughCache
There are no functional changes to this CR, it just instantiates every usage of ReadThroughCache with a ServiceContext and ThreadPool, which will be used for making the acquire method asynchronous.
-rw-r--r--src/mongo/db/SConscript1
-rw-r--r--src/mongo/db/auth/authorization_manager.cpp4
-rw-r--r--src/mongo/db/auth/authorization_manager.h2
-rw-r--r--src/mongo/db/auth/authorization_manager_global.cpp2
-rw-r--r--src/mongo/db/auth/authorization_manager_impl.cpp53
-rw-r--r--src/mongo/db/auth/authorization_manager_impl.h45
-rw-r--r--src/mongo/db/auth/authorization_manager_test.cpp21
-rw-r--r--src/mongo/db/auth/authorization_session_test.cpp3
-rw-r--r--src/mongo/db/auth/sasl_authentication_session_test.cpp7
-rw-r--r--src/mongo/db/auth/sasl_mechanism_registry_test.cpp4
-rw-r--r--src/mongo/db/auth/sasl_scram_test.cpp3
-rw-r--r--src/mongo/db/logical_session_cache_test.cpp3
-rw-r--r--src/mongo/db/logical_session_id_test.cpp3
-rw-r--r--src/mongo/db/read_write_concern_defaults.cpp21
-rw-r--r--src/mongo/db/read_write_concern_defaults.h6
-rw-r--r--src/mongo/embedded/embedded_auth_manager.cpp2
-rw-r--r--src/mongo/util/SConscript4
-rw-r--r--src/mongo/util/read_through_cache.cpp15
-rw-r--r--src/mongo/util/read_through_cache.h38
-rw-r--r--src/mongo/util/read_through_cache_test.cpp23
20 files changed, 167 insertions, 93 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index c1099bfa5bf..f1810e06368 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -382,6 +382,7 @@ env.Library(
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/util/caching',
+ '$BUILD_DIR/mongo/util/concurrency/thread_pool',
'logical_clock',
],
)
diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp
index 0a2eaf493f0..5ad982559dc 100644
--- a/src/mongo/db/auth/authorization_manager.cpp
+++ b/src/mongo/db/auth/authorization_manager.cpp
@@ -71,9 +71,9 @@ const int AuthorizationManager::schemaVersion26Upgrade;
const int AuthorizationManager::schemaVersion26Final;
const int AuthorizationManager::schemaVersion28SCRAM;
-std::unique_ptr<AuthorizationManager> AuthorizationManager::create() {
+std::unique_ptr<AuthorizationManager> AuthorizationManager::create(ServiceContext* serviceContext) {
static auto w = MONGO_WEAK_FUNCTION_DEFINITION(AuthorizationManager::create);
- return w();
+ return w(serviceContext);
}
} // namespace mongo
diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h
index 3ac6c7cc7ce..a14122cad30 100644
--- a/src/mongo/db/auth/authorization_manager.h
+++ b/src/mongo/db/auth/authorization_manager.h
@@ -80,7 +80,7 @@ public:
static AuthorizationManager* get(ServiceContext& service);
static void set(ServiceContext* service, std::unique_ptr<AuthorizationManager> authzManager);
- static std::unique_ptr<AuthorizationManager> create();
+ static std::unique_ptr<AuthorizationManager> create(ServiceContext* serviceContext);
AuthorizationManager() = default;
diff --git a/src/mongo/db/auth/authorization_manager_global.cpp b/src/mongo/db/auth/authorization_manager_global.cpp
index af3342c1c5d..9a7651bb91f 100644
--- a/src/mongo/db/auth/authorization_manager_global.cpp
+++ b/src/mongo/db/auth/authorization_manager_global.cpp
@@ -44,7 +44,7 @@ ServiceContext::ConstructorActionRegisterer createAuthorizationManager(
"CreateAuthorizationManager",
{"OIDGeneration", "EndStartupOptionStorage"},
[](ServiceContext* service) {
- auto authzManager = AuthorizationManager::create();
+ auto authzManager = AuthorizationManager::create(service);
authzManager->setAuthEnabled(serverGlobalParams.authState ==
ServerGlobalParams::AuthState::kEnabled);
authzManager->setShouldValidateAuthSchemaOnStartup(gStartupAuthSchemaValidation);
diff --git a/src/mongo/db/auth/authorization_manager_impl.cpp b/src/mongo/db/auth/authorization_manager_impl.cpp
index 603cf4c924c..a1314fddee0 100644
--- a/src/mongo/db/auth/authorization_manager_impl.cpp
+++ b/src/mongo/db/auth/authorization_manager_impl.cpp
@@ -285,8 +285,10 @@ Status initializeUserFromPrivilegeDocument(User* user, const BSONObj& privDoc) {
return Status::OK();
}
-std::unique_ptr<AuthorizationManager> authorizationManagerCreateImpl() {
- return std::make_unique<AuthorizationManagerImpl>();
+std::unique_ptr<AuthorizationManager> authorizationManagerCreateImpl(
+ ServiceContext* serviceContext) {
+ return std::make_unique<AuthorizationManagerImpl>(serviceContext,
+ AuthzManagerExternalState::create());
}
auto authorizationManagerCreateRegistration =
@@ -310,17 +312,35 @@ Status AuthorizationManagerPinnedUsersServerParameter::setFromString(const std::
return authorizationManagerPinnedUsers.setFromString(str);
}
-AuthorizationManagerImpl::AuthorizationManagerImpl()
- : AuthorizationManagerImpl(AuthzManagerExternalState::create(),
- InstallMockForTestingOrAuthImpl{}) {}
-
AuthorizationManagerImpl::AuthorizationManagerImpl(
- std::unique_ptr<AuthzManagerExternalState> externalState, InstallMockForTestingOrAuthImpl)
+ ServiceContext* service, std::unique_ptr<AuthzManagerExternalState> externalState)
: _externalState(std::move(externalState)),
- _authSchemaVersionCache(_externalState.get()),
- _userCache(&_authSchemaVersionCache, _externalState.get(), authorizationManagerCacheSize) {}
+ _threadPool([] {
+ ThreadPool::Options options;
+ options.poolName = "AuthorizationManager";
+ options.minThreads = 0;
+ options.maxThreads = ThreadPool::Options::kUnlimited;
+
+ // Ensure all threads have a client
+ options.onCreateThread = [](const std::string& threadName) {
+ Client::initThread(threadName.c_str());
+ };
-AuthorizationManagerImpl::~AuthorizationManagerImpl() {}
+ return options;
+ }()),
+ _authSchemaVersionCache(service, _threadPool, _externalState.get()),
+ _userCache(service,
+ _threadPool,
+ authorizationManagerCacheSize,
+ &_authSchemaVersionCache,
+ _externalState.get()) {
+ _threadPool.startup();
+}
+
+AuthorizationManagerImpl::~AuthorizationManagerImpl() {
+ _threadPool.shutdown();
+ _threadPool.join();
+}
std::unique_ptr<AuthorizationSession> AuthorizationManagerImpl::makeAuthorizationSession() {
return std::make_unique<AuthorizationSessionImpl>(
@@ -593,8 +613,11 @@ std::vector<AuthorizationManager::CachedUserInfo> AuthorizationManagerImpl::getU
}
AuthorizationManagerImpl::AuthSchemaVersionCache::AuthSchemaVersionCache(
+ ServiceContext* service,
+ ThreadPoolInterface& threadPool,
AuthzManagerExternalState* externalState)
- : ReadThroughCache(1, _mutex), _externalState(externalState) {}
+ : ReadThroughCache(_mutex, service, threadPool, 1 /* cacheSize */),
+ _externalState(externalState) {}
boost::optional<int> AuthorizationManagerImpl::AuthSchemaVersionCache::lookup(
OperationContext* opCtx, const int& unusedKey) {
@@ -607,10 +630,12 @@ boost::optional<int> AuthorizationManagerImpl::AuthSchemaVersionCache::lookup(
}
AuthorizationManagerImpl::UserCacheImpl::UserCacheImpl(
+ ServiceContext* service,
+ ThreadPoolInterface& threadPool,
+ int cacheSize,
AuthSchemaVersionCache* authSchemaVersionCache,
- AuthzManagerExternalState* externalState,
- int cacheSize)
- : UserCache(cacheSize, _mutex),
+ AuthzManagerExternalState* externalState)
+ : UserCache(_mutex, service, threadPool, cacheSize),
_authSchemaVersionCache(authSchemaVersionCache),
_externalState(externalState) {}
diff --git a/src/mongo/db/auth/authorization_manager_impl.h b/src/mongo/db/auth/authorization_manager_impl.h
index 81951ab3680..72f7e8f6969 100644
--- a/src/mongo/db/auth/authorization_manager_impl.h
+++ b/src/mongo/db/auth/authorization_manager_impl.h
@@ -34,6 +34,7 @@
#include "mongo/platform/mutex.h"
#include "mongo/stdx/condition_variable.h"
#include "mongo/stdx/unordered_map.h"
+#include "mongo/util/concurrency/thread_pool.h"
namespace mongo {
@@ -42,16 +43,14 @@ namespace mongo {
*/
class AuthorizationManagerImpl : public AuthorizationManager {
public:
- ~AuthorizationManagerImpl() override;
-
- AuthorizationManagerImpl();
-
struct InstallMockForTestingOrAuthImpl {
explicit InstallMockForTestingOrAuthImpl() = default;
};
- AuthorizationManagerImpl(std::unique_ptr<AuthzManagerExternalState> externalState,
- InstallMockForTestingOrAuthImpl);
+ AuthorizationManagerImpl(ServiceContext* service,
+ std::unique_ptr<AuthzManagerExternalState> externalState);
+ ~AuthorizationManagerImpl();
+
std::unique_ptr<AuthorizationSession> makeAuthorizationSession() override;
@@ -137,32 +136,30 @@ private:
std::unique_ptr<AuthzManagerExternalState> _externalState;
- /**
- * True if AuthSchema startup checks should be applied in this AuthorizationManager.
- *
- * Changes to its value are not synchronized, so it should only be set at initalization-time.
- */
+ // True if AuthSchema startup checks should be applied in this AuthorizationManager. Changes to
+ // its value are not synchronized, so it should only be set once, at initalization time.
bool _startupAuthSchemaValidation{true};
- /**
- * True if access control enforcement is enabled in this AuthorizationManager.
- *
- * Changes to its value are not synchronized, so it should only be set at initalization-time.
- */
+ // True if access control enforcement is enabled in this AuthorizationManager. Changes to its
+ // value are not synchronized, so it should only be set once, at initalization time.
bool _authEnabled{false};
- /**
- * A cache of whether there are any users set up for the cluster.
- */
+ // A cache of whether there are any users set up for the cluster.
AtomicWord<bool> _privilegeDocsExist{false};
+ // Thread pool on which to perform the blocking activities that load the user credentials from
+ // storage
+ ThreadPool _threadPool;
+
/**
* Cache which contains at most a single entry (which has key 0), whose value is the version of
* the auth schema.
*/
class AuthSchemaVersionCache : public ReadThroughCache<int, int> {
public:
- AuthSchemaVersionCache(AuthzManagerExternalState* externalState);
+ AuthSchemaVersionCache(ServiceContext* service,
+ ThreadPoolInterface& threadPool,
+ AuthzManagerExternalState* externalState);
// Even though the dist cache permits for lookup to return boost::none for non-existent
// values, the contract of the authorization manager is that it should throw an exception if
@@ -181,9 +178,11 @@ private:
*/
class UserCacheImpl : public UserCache {
public:
- UserCacheImpl(AuthSchemaVersionCache* authSchemaVersionCache,
- AuthzManagerExternalState* externalState,
- int cacheSize);
+ UserCacheImpl(ServiceContext* service,
+ ThreadPoolInterface& threadPool,
+ int cacheSize,
+ AuthSchemaVersionCache* authSchemaVersionCache,
+ AuthzManagerExternalState* externalState);
// Even though the dist cache permits for lookup to return boost::none for non-existent
// values, the contract of the authorization manager is that it should throw an exception if
diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp
index 30a9c19a766..f381d76ae47 100644
--- a/src/mongo/db/auth/authorization_manager_test.cpp
+++ b/src/mongo/db/auth/authorization_manager_test.cpp
@@ -85,8 +85,7 @@ public:
auto localExternalState = std::make_unique<AuthzManagerExternalStateMock>();
externalState = localExternalState.get();
auto localAuthzManager = std::make_unique<AuthorizationManagerImpl>(
- std::move(localExternalState),
- AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{});
+ getServiceContext(), std::move(localExternalState));
authzManager = localAuthzManager.get();
externalState->setAuthorizationManager(authzManager);
authzManager->setAuthEnabled(true);
@@ -258,24 +257,6 @@ private:
}
};
-class AuthorizationManagerWithExplicitUserPrivilegesTest : public ::mongo::unittest::Test {
-public:
- virtual void setUp() {
- auto localExternalState =
- std::make_unique<AuthzManagerExternalStateMockWithExplicitUserPrivileges>();
- externalState = localExternalState.get();
- externalState->setAuthzVersion(AuthorizationManager::schemaVersion26Final);
- authzManager = std::make_unique<AuthorizationManagerImpl>(
- std::move(localExternalState),
- AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{});
- externalState->setAuthorizationManager(authzManager.get());
- authzManager->setAuthEnabled(true);
- }
-
- std::unique_ptr<AuthorizationManager> authzManager;
- AuthzManagerExternalStateMockWithExplicitUserPrivileges* externalState;
-};
-
// Tests SERVER-21535, unrecognized actions should be ignored rather than causing errors.
TEST_F(AuthorizationManagerTest, testAcquireV2UserWithUnrecognizedActions) {
diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp
index f7df2444e5e..febccc348d2 100644
--- a/src/mongo/db/auth/authorization_session_test.cpp
+++ b/src/mongo/db/auth/authorization_session_test.cpp
@@ -103,8 +103,7 @@ public:
managerState = localManagerState.get();
managerState->setAuthzVersion(AuthorizationManager::schemaVersion26Final);
auto uniqueAuthzManager = std::make_unique<AuthorizationManagerImpl>(
- std::move(localManagerState),
- AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{});
+ serviceContext.get(), std::move(localManagerState));
authzManager = uniqueAuthzManager.get();
AuthorizationManager::set(serviceContext.get(), std::move(uniqueAuthzManager));
auto localSessionState = std::make_unique<AuthzSessionExternalStateMock>(authzManager);
diff --git a/src/mongo/db/auth/sasl_authentication_session_test.cpp b/src/mongo/db/auth/sasl_authentication_session_test.cpp
index bdf8edc175d..d83f8455a23 100644
--- a/src/mongo/db/auth/sasl_authentication_session_test.cpp
+++ b/src/mongo/db/auth/sasl_authentication_session_test.cpp
@@ -55,7 +55,6 @@
#include "mongo/util/password_digest.h"
namespace mongo {
-
namespace {
class SaslConversation : public ServiceContextTest {
@@ -94,10 +93,10 @@ SaslConversation::SaslConversation(std::string mech)
: opCtx(makeOperationContext()),
authManagerExternalState(new AuthzManagerExternalStateMock),
authManager(new AuthorizationManagerImpl(
- std::unique_ptr<AuthzManagerExternalState>(authManagerExternalState),
- AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{})),
+ getServiceContext(),
+ std::unique_ptr<AuthzManagerExternalState>(authManagerExternalState))),
authSession(authManager->makeAuthorizationSession()),
- registry(opCtx->getServiceContext(), {"SCRAM-SHA-1", "SCRAM-SHA-256", "PLAIN"}),
+ registry(getServiceContext(), {"SCRAM-SHA-1", "SCRAM-SHA-256", "PLAIN"}),
mechanism(mech) {
AuthorizationManager::set(getServiceContext(),
diff --git a/src/mongo/db/auth/sasl_mechanism_registry_test.cpp b/src/mongo/db/auth/sasl_mechanism_registry_test.cpp
index a969c00b47a..e26efea8140 100644
--- a/src/mongo/db/auth/sasl_mechanism_registry_test.cpp
+++ b/src/mongo/db/auth/sasl_mechanism_registry_test.cpp
@@ -181,8 +181,8 @@ public:
: opCtx(makeOperationContext()),
authManagerExternalState(new AuthzManagerExternalStateMock()),
authManager(new AuthorizationManagerImpl(
- std::unique_ptr<AuthzManagerExternalStateMock>(authManagerExternalState),
- AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{})),
+ getServiceContext(),
+ std::unique_ptr<AuthzManagerExternalStateMock>(authManagerExternalState))),
// By default the registry is initialized with all mechanisms enabled.
registry(opCtx->getServiceContext(), {"FOO", "BAR", "InternalAuth"}) {
AuthorizationManager::set(getServiceContext(),
diff --git a/src/mongo/db/auth/sasl_scram_test.cpp b/src/mongo/db/auth/sasl_scram_test.cpp
index 4b2ec0b84d5..81b89590101 100644
--- a/src/mongo/db/auth/sasl_scram_test.cpp
+++ b/src/mongo/db/auth/sasl_scram_test.cpp
@@ -191,8 +191,7 @@ protected:
std::make_unique<AuthzManagerExternalStateMock>();
authzManagerExternalState = uniqueAuthzManagerExternalStateMock.get();
auto newManager = std::make_unique<AuthorizationManagerImpl>(
- std::move(uniqueAuthzManagerExternalStateMock),
- AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{});
+ serviceContext.get(), std::move(uniqueAuthzManagerExternalStateMock));
authzSession = std::make_unique<AuthorizationSessionImpl>(
std::make_unique<AuthzSessionExternalStateMock>(newManager.get()),
AuthorizationSessionImpl::InstallMockForTestingOrAuthImpl{});
diff --git a/src/mongo/db/logical_session_cache_test.cpp b/src/mongo/db/logical_session_cache_test.cpp
index b4a301e6b92..d1a6be816e1 100644
--- a/src/mongo/db/logical_session_cache_test.cpp
+++ b/src/mongo/db/logical_session_cache_test.cpp
@@ -70,7 +70,8 @@ public:
: _service(std::make_shared<MockServiceLiaisonImpl>()),
_sessions(std::make_shared<MockSessionsCollectionImpl>()) {
- AuthorizationManager::set(getServiceContext(), AuthorizationManager::create());
+ AuthorizationManager::set(getServiceContext(),
+ AuthorizationManager::create(getServiceContext()));
// Re-initialize the client after setting the AuthorizationManager to get an
// AuthorizationSession.
diff --git a/src/mongo/db/logical_session_id_test.cpp b/src/mongo/db/logical_session_id_test.cpp
index 30a2529fec6..91a9efdbf8e 100644
--- a/src/mongo/db/logical_session_id_test.cpp
+++ b/src/mongo/db/logical_session_id_test.cpp
@@ -77,8 +77,7 @@ public:
managerState = localManagerState.get();
managerState->setAuthzVersion(AuthorizationManager::schemaVersion26Final);
auto authzManager = std::make_unique<AuthorizationManagerImpl>(
- std::move(localManagerState),
- AuthorizationManagerImpl::InstallMockForTestingOrAuthImpl{});
+ getServiceContext(), std::move(localManagerState));
authzManager->setAuthEnabled(true);
AuthorizationManager::set(getServiceContext(), std::move(authzManager));
Client::releaseCurrent();
diff --git a/src/mongo/db/read_write_concern_defaults.cpp b/src/mongo/db/read_write_concern_defaults.cpp
index 020d094cd72..a09653a1a31 100644
--- a/src/mongo/db/read_write_concern_defaults.cpp
+++ b/src/mongo/db/read_write_concern_defaults.cpp
@@ -208,13 +208,28 @@ void ReadWriteConcernDefaults::create(ServiceContext* service, FetchDefaultsFn f
}
ReadWriteConcernDefaults::ReadWriteConcernDefaults(FetchDefaultsFn fetchDefaultsFn)
- : _defaults([fetchDefaultsFn = std::move(fetchDefaultsFn)](
+ : _threadPool([] {
+ ThreadPool::Options options;
+ options.poolName = "ReadWriteConcernDefaults";
+ options.minThreads = 0;
+ options.maxThreads = 1;
+
+ // Ensure all threads have a client
+ options.onCreateThread = [](const std::string& threadName) {
+ Client::initThread(threadName.c_str());
+ };
+
+ return options;
+ }()),
+ _defaults(_threadPool,
+ [fetchDefaultsFn = std::move(fetchDefaultsFn)](
OperationContext* opCtx, const Type&) { return fetchDefaultsFn(opCtx); }) {}
ReadWriteConcernDefaults::~ReadWriteConcernDefaults() = default;
-ReadWriteConcernDefaults::Cache::Cache(LookupFn lookupFn)
- : ReadThroughCache(1, _mutex), _lookupFn(lookupFn) {}
+ReadWriteConcernDefaults::Cache::Cache(ThreadPoolInterface& threadPool, LookupFn lookupFn)
+ : ReadThroughCache(_mutex, getGlobalServiceContext(), threadPool, 1 /* cacheSize */),
+ _lookupFn(std::move(lookupFn)) {}
boost::optional<RWConcernDefault> ReadWriteConcernDefaults::Cache::lookup(
OperationContext* opCtx, const ReadWriteConcernDefaults::Type& key) {
diff --git a/src/mongo/db/read_write_concern_defaults.h b/src/mongo/db/read_write_concern_defaults.h
index d493fdf2cc3..259a3eafd24 100644
--- a/src/mongo/db/read_write_concern_defaults.h
+++ b/src/mongo/db/read_write_concern_defaults.h
@@ -37,6 +37,7 @@
#include "mongo/db/service_context.h"
#include "mongo/db/write_concern_options.h"
#include "mongo/platform/mutex.h"
+#include "mongo/util/concurrency/thread_pool.h"
#include "mongo/util/concurrency/with_lock.h"
#include "mongo/util/read_through_cache.h"
@@ -161,7 +162,7 @@ private:
Cache& operator=(const Cache&) = delete;
public:
- Cache(LookupFn lookupFn);
+ Cache(ThreadPoolInterface& threadPool, LookupFn lookupFn);
virtual ~Cache() = default;
boost::optional<RWConcernDefault> lookup(OperationContext* opCtx, const Type& key) override;
@@ -172,6 +173,9 @@ private:
LookupFn _lookupFn;
};
+ // Thread pool on which to perform loading of the cached RWC defaults
+ ThreadPool _threadPool;
+
Cache _defaults;
};
diff --git a/src/mongo/embedded/embedded_auth_manager.cpp b/src/mongo/embedded/embedded_auth_manager.cpp
index bb8c81c5907..671fab3c41d 100644
--- a/src/mongo/embedded/embedded_auth_manager.cpp
+++ b/src/mongo/embedded/embedded_auth_manager.cpp
@@ -149,7 +149,7 @@ private:
namespace {
-std::unique_ptr<AuthorizationManager> authorizationManagerCreateImpl() {
+std::unique_ptr<AuthorizationManager> authorizationManagerCreateImpl(ServiceContext*) {
return std::make_unique<embedded::AuthorizationManager>();
}
diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript
index 0cf1b69be67..b2793e906c9 100644
--- a/src/mongo/util/SConscript
+++ b/src/mongo/util/SConscript
@@ -207,8 +207,9 @@ env.Library(
source=[
'read_through_cache.cpp',
],
- LIBDEPS=[
+ LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/base',
+ '$BUILD_DIR/mongo/db/service_context',
]
)
@@ -609,6 +610,7 @@ icuEnv.CppUnitTest(
'caching',
'clock_source_mock',
'clock_sources',
+ 'concurrency/thread_pool',
'diagnostic_info',
'dns_query',
'fail_point',
diff --git a/src/mongo/util/read_through_cache.cpp b/src/mongo/util/read_through_cache.cpp
index a46f93c326f..877421fac9e 100644
--- a/src/mongo/util/read_through_cache.cpp
+++ b/src/mongo/util/read_through_cache.cpp
@@ -31,9 +31,14 @@
#include "mongo/util/read_through_cache.h"
+#include "mongo/db/client.h"
+
namespace mongo {
-ReadThroughCacheBase::ReadThroughCacheBase(Mutex& mutex) : _cacheWriteMutex(mutex) {}
+ReadThroughCacheBase::ReadThroughCacheBase(Mutex& mutex,
+ ServiceContext* service,
+ ThreadPoolInterface& threadPool)
+ : _serviceContext(service), _threadPool(threadPool), _cacheWriteMutex(mutex) {}
ReadThroughCacheBase::~ReadThroughCacheBase() = default;
@@ -42,6 +47,14 @@ OID ReadThroughCacheBase::getCacheGeneration() const {
return _fetchGeneration;
}
+void ReadThroughCacheBase::_asyncWork(WorkWithOpContext work) {
+ _threadPool.schedule([this, work = std::move(work)](Status status) {
+ ThreadClient tc(_serviceContext);
+ auto opCtxHolder = tc->makeOperationContext();
+ work(opCtxHolder.get());
+ });
+}
+
void ReadThroughCacheBase::_updateCacheGeneration(const CacheGuard&) {
_fetchGeneration = OID::gen();
}
diff --git a/src/mongo/util/read_through_cache.h b/src/mongo/util/read_through_cache.h
index f13cd486e13..54e5d4bfc45 100644
--- a/src/mongo/util/read_through_cache.h
+++ b/src/mongo/util/read_through_cache.h
@@ -35,6 +35,8 @@
#include "mongo/db/operation_context.h"
#include "mongo/platform/mutex.h"
#include "mongo/stdx/condition_variable.h"
+#include "mongo/util/concurrency/thread_pool_interface.h"
+#include "mongo/util/functional.h"
#include "mongo/util/invalidating_lru_cache.h"
namespace mongo {
@@ -53,7 +55,7 @@ public:
OID getCacheGeneration() const;
protected:
- ReadThroughCacheBase(Mutex& mutex);
+ ReadThroughCacheBase(Mutex& mutex, ServiceContext* service, ThreadPoolInterface& threadPool);
virtual ~ReadThroughCacheBase();
@@ -178,11 +180,29 @@ protected:
friend class ReadThroughCacheBase::CacheGuard;
/**
+ * Creates a client and an operation context and executes the specified 'work' under that
+ * environment.
+ */
+ using WorkWithOpContext = unique_function<void(OperationContext*)>;
+ void _asyncWork(WorkWithOpContext work);
+
+ /**
* Updates _fetchGeneration to a new OID
*/
void _updateCacheGeneration(const CacheGuard&);
/**
+ * Service context under which this cache has been instantiated (used for access to service-wide
+ * functionality, such as client/operation context creation)
+ */
+ ServiceContext* const _serviceContext;
+
+ /**
+ * Thread pool, to be used for invoking the blocking loader work.
+ */
+ ThreadPoolInterface& _threadPool;
+
+ /**
* Protects _fetchGeneration and _isFetchPhaseBusy. Manipulated via CacheGuard.
*/
Mutex& _cacheWriteMutex;
@@ -329,8 +349,7 @@ public:
if (guard.isSameCacheGeneration())
return ValueHandle(_cache.insertOrAssignAndGet(
- key,
- {std::move(*value), opCtx->getServiceContext()->getFastClockSource()->now()}));
+ key, {std::move(*value), _serviceContext->getFastClockSource()->now()}));
// If the cache generation changed while this thread was in fetch mode, the data
// associated with the value may now be invalid, so we will throw out the fetched value
@@ -379,14 +398,17 @@ public:
protected:
/**
- * ReadThroughCache constructor, to be called by sub-classes. Accepts the initial size of the
- * cache, and a reference to a Mutex. The Mutex is for the exclusive use of the
+ * ReadThroughCache constructor, to be called by sub-classes. The 'cacheSize' parameter
+ * represents the maximum size of the cache and 'mutex' is for the exclusive use of the
* ReadThroughCache, the sub-class should never actually use it (apart from passing it to this
- * constructor). Having the Mutex stored by the sub-class allows latch diagnostics to be
+ * constructor). Having the Mutex stored by the sub-class allows latch diagnostics to be
* correctly associated with the sub-class (not the generic ReadThroughCache class).
*/
- ReadThroughCache(int cacheSize, Mutex& mutex)
- : ReadThroughCacheBase(mutex), _cache(cacheSize) {}
+ ReadThroughCache(Mutex& mutex,
+ ServiceContext* service,
+ ThreadPoolInterface& threadPool,
+ int cacheSize)
+ : ReadThroughCacheBase(mutex, service, threadPool), _cache(cacheSize) {}
private:
/**
diff --git a/src/mongo/util/read_through_cache_test.cpp b/src/mongo/util/read_through_cache_test.cpp
index f7420a235be..fe7372e411d 100644
--- a/src/mongo/util/read_through_cache_test.cpp
+++ b/src/mongo/util/read_through_cache_test.cpp
@@ -33,6 +33,7 @@
#include "mongo/db/service_context_test_fixture.h"
#include "mongo/unittest/unittest.h"
+#include "mongo/util/concurrency/thread_pool.h"
#include "mongo/util/read_through_cache.h"
namespace mongo {
@@ -44,14 +45,28 @@ struct CachedValue {
class Cache : public ReadThroughCache<std::string, CachedValue> {
public:
- Cache(size_t size, LookupFn lookupFn)
- : ReadThroughCache(size, _mutex), _lookupFn(std::move(lookupFn)) {}
+ Cache(ServiceContext* service, size_t size, LookupFn lookupFn)
+ : ReadThroughCache(_mutex, service, _threadPool, size), _lookupFn(std::move(lookupFn)) {}
private:
boost::optional<CachedValue> lookup(OperationContext* opCtx, const std::string& key) override {
return _lookupFn(opCtx, key);
}
+ ThreadPool _threadPool{[] {
+ ThreadPool::Options options;
+ options.poolName = "ReadThroughCacheTest";
+ options.minThreads = 0;
+ options.maxThreads = 1;
+
+ // Ensure all threads have a client
+ options.onCreateThread = [](const std::string& threadName) {
+ Client::initThread(threadName.c_str());
+ };
+
+ return options;
+ }()};
+
Mutex _mutex = MONGO_MAKE_LATCH("ReadThroughCacheTest::Cache");
LookupFn _lookupFn;
@@ -65,7 +80,7 @@ protected:
TEST_F(ReadThroughCacheTest, FetchInvalidateAndRefetch) {
int countLookups = 0;
- Cache cache(1, [&](OperationContext*, const std::string& key) {
+ Cache cache(getServiceContext(), 1, [&](OperationContext*, const std::string& key) {
ASSERT_EQ("TestKey", key);
countLookups++;
@@ -87,7 +102,7 @@ TEST_F(ReadThroughCacheTest, FetchInvalidateAndRefetch) {
TEST_F(ReadThroughCacheTest, CacheSizeZero) {
int countLookups = 0;
- Cache cache(0, [&](OperationContext*, const std::string& key) {
+ Cache cache(getServiceContext(), 0, [&](OperationContext*, const std::string& key) {
ASSERT_EQ("TestKey", key);
countLookups++;