Loading src/authdb.cpp +2 −7 Changes for src/authdb.cpp: 2 added lines, 7 removed lines. Original line number Diff line number Diff line Loading @@ -254,7 +254,6 @@ namespace authdb { } if(curreq.getRequestURL().compare(0,9,"/settings",9)==0){ AuthBackendLock admlock(_AdminBackend); try{ _AdminInterface.Request(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); Loading Loading @@ -346,7 +345,6 @@ namespace authdb { rep.send(curreq,"uuid not found!",12); } }else if(curreq.getRequestURL().compare(0,10,"/getavatar",10)==0){ AuthBackendLock admlock(_AdminBackend); try{ getAvatar(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); Loading Loading @@ -402,11 +400,8 @@ namespace authdb { ::uuid::uuid uid(cuid); // Lock the domain backend if different from admin (admin already locked by caller) std::unique_ptr<AuthBackendLock> domlock; if (backend != &_AdminBackend) { domlock = std::make_unique<AuthBackendLock>(*backend); } // Always lock the resolved backend AuthBackendLock domlock(*backend); size_t rd=sizeof(authdb::AuthHeader),end=backend->end(); Loading src/backends/cluster.cpp +22 −13 Changes for src/backends/cluster.cpp: 22 added lines, 13 removed lines. Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ namespace authdb { auto now = std::chrono::steady_clock::now(); bool do_peer_fetch = (now - _LastPeerFetch) >= std::chrono::seconds(5); // Network I/O runs WITHOUT _BufMtx to avoid blocking other threads if (do_peer_fetch) { auto &client = g_Cluster->getClient(); if (client) { Loading @@ -95,6 +96,9 @@ namespace authdb { } } // Only hold _BufMtx for the buffer merge — no network I/O here std::lock_guard<std::mutex> guard(_BufMtx); // Pick the buffer with the highest revision (most recent writes) size_t local_rev = bufferRevision(local_data); size_t peer_rev = bufferRevision(peer_data); Loading Loading @@ -129,32 +133,39 @@ namespace authdb { std::cerr << "ClusterBackend::pushToCluster: cluster not available" << std::endl; return; } // Copy buffer and state under _BufMtx, then release before network I/O std::vector<uint8_t> buf_copy; uint64_t dgid; { std::lock_guard<std::mutex> guard(_BufMtx); if (!_Dirty) { return; } // Bump revision so peers can detect newer data newRevesion(); uint64_t dgid = domainGroupId(); dgid = domainGroupId(); buf_copy = _Buffer; _Dirty = false; } // Store in local block store (file or memory backed) auto &store = g_Cluster->getStore(); if (!store.store(dgid, 0, _Buffer.data(), _Buffer.size())) { if (!store.store(dgid, 0, buf_copy.data(), buf_copy.size())) { std::cerr << "ClusterBackend::pushToCluster: store.store() failed for group " << std::hex << dgid << std::dec << " (domain=" << _Domain << " bufsize=" << _Buffer.size() << ")" << " (domain=" << _Domain << " bufsize=" << buf_copy.size() << ")" << std::endl; } // Replicate raw data to all peer nodes // Replicate raw data to all peer nodes — no _BufMtx held auto &client = g_Cluster->getClient(); if (client) { try { auto &cmtx = g_Cluster->getClientMutex(); std::unique_lock<std::timed_mutex> lock(cmtx, std::chrono::seconds(3)); if (lock.owns_lock()) { client->replicate_to_peers(dgid, 0, _Buffer.data(), _Buffer.size()); client->replicate_to_peers(dgid, 0, buf_copy.data(), buf_copy.size()); } else { std::cerr << "ClusterBackend::pushToCluster: skipped replication (lock busy)" << std::endl; } Loading @@ -164,8 +175,6 @@ namespace authdb { std::cerr << "Cluster replicate failed: " << e.what() << std::endl; } } _Dirty = false; } ClusterBackend::ClusterBackend(const char *domain, size_t version, const char *filepath) Loading Loading @@ -224,14 +233,14 @@ namespace authdb { } void ClusterBackend::lock() { // Network I/O: fetch latest data from cluster peers. // _BufMtx serializes concurrent fetch/push so _Buffer is safe. std::lock_guard<std::mutex> guard(_BufMtx); // fetchFromCluster handles _BufMtx internally — only during buffer merge, // NOT during network I/O, so other threads aren't blocked. fetchFromCluster(); } void ClusterBackend::unlock() { std::lock_guard<std::mutex> guard(_BufMtx); // pushToCluster handles _BufMtx internally — copies buffer under lock, // then does network I/O without holding it. pushToCluster(); } Loading Loading
src/authdb.cpp +2 −7 Changes for src/authdb.cpp: 2 added lines, 7 removed lines. Original line number Diff line number Diff line Loading @@ -254,7 +254,6 @@ namespace authdb { } if(curreq.getRequestURL().compare(0,9,"/settings",9)==0){ AuthBackendLock admlock(_AdminBackend); try{ _AdminInterface.Request(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); Loading Loading @@ -346,7 +345,6 @@ namespace authdb { rep.send(curreq,"uuid not found!",12); } }else if(curreq.getRequestURL().compare(0,10,"/getavatar",10)==0){ AuthBackendLock admlock(_AdminBackend); try{ getAvatar(curreq,tid,args); g_Log.access(clientAddr,method,curreq.getRequestURL(),200); Loading Loading @@ -402,11 +400,8 @@ namespace authdb { ::uuid::uuid uid(cuid); // Lock the domain backend if different from admin (admin already locked by caller) std::unique_ptr<AuthBackendLock> domlock; if (backend != &_AdminBackend) { domlock = std::make_unique<AuthBackendLock>(*backend); } // Always lock the resolved backend AuthBackendLock domlock(*backend); size_t rd=sizeof(authdb::AuthHeader),end=backend->end(); Loading
src/backends/cluster.cpp +22 −13 Changes for src/backends/cluster.cpp: 22 added lines, 13 removed lines. Original line number Diff line number Diff line Loading @@ -76,6 +76,7 @@ namespace authdb { auto now = std::chrono::steady_clock::now(); bool do_peer_fetch = (now - _LastPeerFetch) >= std::chrono::seconds(5); // Network I/O runs WITHOUT _BufMtx to avoid blocking other threads if (do_peer_fetch) { auto &client = g_Cluster->getClient(); if (client) { Loading @@ -95,6 +96,9 @@ namespace authdb { } } // Only hold _BufMtx for the buffer merge — no network I/O here std::lock_guard<std::mutex> guard(_BufMtx); // Pick the buffer with the highest revision (most recent writes) size_t local_rev = bufferRevision(local_data); size_t peer_rev = bufferRevision(peer_data); Loading Loading @@ -129,32 +133,39 @@ namespace authdb { std::cerr << "ClusterBackend::pushToCluster: cluster not available" << std::endl; return; } // Copy buffer and state under _BufMtx, then release before network I/O std::vector<uint8_t> buf_copy; uint64_t dgid; { std::lock_guard<std::mutex> guard(_BufMtx); if (!_Dirty) { return; } // Bump revision so peers can detect newer data newRevesion(); uint64_t dgid = domainGroupId(); dgid = domainGroupId(); buf_copy = _Buffer; _Dirty = false; } // Store in local block store (file or memory backed) auto &store = g_Cluster->getStore(); if (!store.store(dgid, 0, _Buffer.data(), _Buffer.size())) { if (!store.store(dgid, 0, buf_copy.data(), buf_copy.size())) { std::cerr << "ClusterBackend::pushToCluster: store.store() failed for group " << std::hex << dgid << std::dec << " (domain=" << _Domain << " bufsize=" << _Buffer.size() << ")" << " (domain=" << _Domain << " bufsize=" << buf_copy.size() << ")" << std::endl; } // Replicate raw data to all peer nodes // Replicate raw data to all peer nodes — no _BufMtx held auto &client = g_Cluster->getClient(); if (client) { try { auto &cmtx = g_Cluster->getClientMutex(); std::unique_lock<std::timed_mutex> lock(cmtx, std::chrono::seconds(3)); if (lock.owns_lock()) { client->replicate_to_peers(dgid, 0, _Buffer.data(), _Buffer.size()); client->replicate_to_peers(dgid, 0, buf_copy.data(), buf_copy.size()); } else { std::cerr << "ClusterBackend::pushToCluster: skipped replication (lock busy)" << std::endl; } Loading @@ -164,8 +175,6 @@ namespace authdb { std::cerr << "Cluster replicate failed: " << e.what() << std::endl; } } _Dirty = false; } ClusterBackend::ClusterBackend(const char *domain, size_t version, const char *filepath) Loading Loading @@ -224,14 +233,14 @@ namespace authdb { } void ClusterBackend::lock() { // Network I/O: fetch latest data from cluster peers. // _BufMtx serializes concurrent fetch/push so _Buffer is safe. std::lock_guard<std::mutex> guard(_BufMtx); // fetchFromCluster handles _BufMtx internally — only during buffer merge, // NOT during network I/O, so other threads aren't blocked. fetchFromCluster(); } void ClusterBackend::unlock() { std::lock_guard<std::mutex> guard(_BufMtx); // pushToCluster handles _BufMtx internally — copies buffer under lock, // then does network I/O without holding it. pushToCluster(); } Loading