diff --git a/src/rgw/driver/sfs/sqlite/dbconn.cc b/src/rgw/driver/sfs/sqlite/dbconn.cc index b6ceabcce0fe2..5dfd8d50b7f65 100644 --- a/src/rgw/driver/sfs/sqlite/dbconn.cc +++ b/src/rgw/driver/sfs/sqlite/dbconn.cc @@ -113,11 +113,16 @@ static int sqlite_profile_callback( } DBConn::DBConn(CephContext* _cct) - : storage(_make_storage(getDBPath(_cct))), + : main_thread(std::this_thread::get_id()), + storage_pool_mutex(), first_sqlite_conn(nullptr), cct(_cct), profile_enabled(_cct->_conf.get_val("rgw_sfs_sqlite_profile")) { sqlite3_config(SQLITE_CONFIG_LOG, &sqlite_error_callback, cct); + // get_storage() relies on there already being an entry in the pool + // for the main thread (i.e. the thread that created the DBConn). + storage_pool.emplace(main_thread, _make_storage(getDBPath(cct))); + StorageRef storage = get_storage(); storage->on_open = [this](sqlite3* db) { if (first_sqlite_conn == nullptr) { first_sqlite_conn = db; @@ -156,6 +161,28 @@ DBConn::DBConn(CephContext* _cct) storage->sync_schema(); } +StorageRef DBConn::get_storage() { + std::thread::id this_thread = std::this_thread::get_id(); + try { + std::shared_lock lock(storage_pool_mutex); + return &storage_pool.at(this_thread); + } catch (const std::out_of_range& ex) { + std::unique_lock lock(storage_pool_mutex); + auto [it, _] = + storage_pool.emplace(this_thread, storage_pool.at(main_thread)); + StorageRef storage = &(*it).second; + // A copy of the main thread's Storage object won't have an open DB + // connection yet, so we'd better make it have one (otherwise we're + // back to a gadzillion sqlite3_open()/sqlite3_close() calls again) + storage->open_forever(); + storage->busy_timeout(5000); + lsubdout(cct, rgw, 10) << "[SQLITE CONNECTION NEW] Added Storage " + << storage << " to pool for thread " << std::hex + << this_thread << std::dec << dendl; + return storage; + } +} + void DBConn::check_metadata_is_compatible() const { bool sync_error = false; std::string result_message; @@ -359,6 +386,7 @@ static void upgrade_metadata( } void DBConn::maybe_upgrade_metadata() { + StorageRef storage = get_storage(); int db_version = get_version(cct, storage); lsubdout(cct, rgw, 10) << "db user version: " << db_version << dendl; diff --git a/src/rgw/driver/sfs/sqlite/dbconn.h b/src/rgw/driver/sfs/sqlite/dbconn.h index c1132b658c4e3..27fd1b4f12c6d 100644 --- a/src/rgw/driver/sfs/sqlite/dbconn.h +++ b/src/rgw/driver/sfs/sqlite/dbconn.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "buckets/bucket_definitions.h" #include "buckets/multipart_definitions.h" @@ -251,12 +252,14 @@ inline auto _make_storage(const std::string& path) { ); } -using StorageImpl = decltype(_make_storage("")); -using StorageRef = StorageImpl*; +using Storage = decltype(_make_storage("")); +using StorageRef = Storage*; class DBConn { private: - StorageImpl storage; + std::unordered_map storage_pool; + const std::thread::id main_thread; + mutable std::shared_mutex storage_pool_mutex; public: sqlite3* first_sqlite_conn; @@ -269,7 +272,7 @@ class DBConn { DBConn(const DBConn&) = delete; DBConn& operator=(const DBConn&) = delete; - inline auto get_storage() { return &storage; } + StorageRef get_storage(); static std::string getDBPath(CephContext* cct) { auto rgw_sfs_path = cct->_conf.get_val("rgw_sfs_data_path");