]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
lmdb-safe: Improve the scalability of transaction maps
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 27 Jun 2025 10:12:29 +0000 (12:12 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 27 Jun 2025 10:15:35 +0000 (12:15 +0200)
This commit improves the scalability of the transaction maps by
moving from a `mutex` to a `shared_mutex` and making the stored value
atomic. This allows accessing the maps concurrently from different threads
as long as the entry for the thread exists, and we fall back to
taking a full lock otherwise.

Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
ext/lmdb-safe/lmdb-safe.cc
ext/lmdb-safe/lmdb-safe.hh

index 84866cfa225fcc358ad2d1e2f60dc77cb1b607b2..e567d0884b4de6807353518fdfa8504ce0f4da41 100644 (file)
@@ -135,37 +135,84 @@ Various other options may also need to be set before opening the handle, e.g. md
 
 void MDBEnv::incROTX()
 {
-  std::lock_guard<std::mutex> l(d_countmutex);
-  ++d_ROtransactionsOut[std::this_thread::get_id()];
+  auto threadId = std::this_thread::get_id();
+  {
+    std::shared_lock<std::shared_mutex> lock(d_countmutex);
+    if (auto transactionsIt = d_ROtransactionsOut.find(threadId); transactionsIt != d_ROtransactionsOut.end()) {
+      ++transactionsIt->second;
+      return;
+    }
+  }
+
+  {
+    std::unique_lock<std::shared_mutex> lock(d_countmutex);
+    auto [transactionsIt, inserted] = d_ROtransactionsOut.emplace(threadId, 1);
+    if (!inserted) {
+      ++transactionsIt->second;
+    }
+  }
 }
 
 void MDBEnv::decROTX()
 {
-  std::lock_guard<std::mutex> l(d_countmutex);
-  --d_ROtransactionsOut[std::this_thread::get_id()];
+  auto threadId = std::this_thread::get_id();
+  {
+    std::shared_lock<std::shared_mutex> lock(d_countmutex);
+    d_ROtransactionsOut.at(threadId)--;
+  }
 }
 
 void MDBEnv::incRWTX()
 {
-  std::lock_guard<std::mutex> l(d_countmutex);
-  ++d_RWtransactionsOut[std::this_thread::get_id()];
+  auto threadId = std::this_thread::get_id();
+  {
+    std::shared_lock<std::shared_mutex> lock(d_countmutex);
+    if (auto transactionsIt = d_RWtransactionsOut.find(threadId); transactionsIt != d_RWtransactionsOut.end()) {
+      ++transactionsIt->second;
+      return;
+    }
+  }
+
+  {
+    std::unique_lock<std::shared_mutex> lock(d_countmutex);
+    auto [transactionsIt, inserted] = d_RWtransactionsOut.emplace(threadId, 1);
+    if (!inserted) {
+      ++transactionsIt->second;
+    }
+  }
 }
 
 void MDBEnv::decRWTX()
 {
-  std::lock_guard<std::mutex> l(d_countmutex);
-  --d_RWtransactionsOut[std::this_thread::get_id()];
+  auto threadId = std::this_thread::get_id();
+  {
+    std::shared_lock<std::shared_mutex> lock(d_countmutex);
+    d_RWtransactionsOut.at(threadId)--;
+  }
 }
 
 int MDBEnv::getRWTX()
 {
-  std::lock_guard<std::mutex> l(d_countmutex);
-  return d_RWtransactionsOut[std::this_thread::get_id()];
+  auto threadId = std::this_thread::get_id();
+  {
+    std::shared_lock<std::shared_mutex> lock(d_countmutex);
+    if (auto transactionsIt = d_RWtransactionsOut.find(threadId); transactionsIt != d_RWtransactionsOut.end()) {
+      return transactionsIt->second.load();
+    }
+  }
+  return 0;
 }
+
 int MDBEnv::getROTX()
 {
-  std::lock_guard<std::mutex> l(d_countmutex);
-  return d_ROtransactionsOut[std::this_thread::get_id()];
+  auto threadId = std::this_thread::get_id();
+  {
+    std::shared_lock<std::shared_mutex> lock(d_countmutex);
+    if (auto transactionsIt = d_RWtransactionsOut.find(threadId); transactionsIt != d_RWtransactionsOut.end()) {
+      return transactionsIt->second.load();
+    }
+  }
+  return 0;
 }
 
 
index 7b775d3a76aaa41291bf818ba57b834ee3c413b3..80f4f408a4fd49bd02c40cfbf4906cda0cc48d7f 100644 (file)
@@ -13,6 +13,7 @@
 #include <mutex>
 #include <vector>
 #include <algorithm>
+#include <shared_mutex>
 #include <string>
 #include <string_view>
 #include <atomic>
@@ -114,9 +115,9 @@ public:
   void decROTX();
 private:
   std::mutex d_openmut;
-  std::mutex d_countmutex;
-  std::map<std::thread::id, int> d_RWtransactionsOut;
-  std::map<std::thread::id, int> d_ROtransactionsOut;
+  std::shared_mutex d_countmutex;
+  std::map<std::thread::id, std::atomic<int>> d_RWtransactionsOut;
+  std::map<std::thread::id, std::atomic<int>> d_ROtransactionsOut;
 };
 
 std::shared_ptr<MDBEnv> getMDBEnv(const char* fname, int flags, int mode, uint64_t mapsizeMB);