Loading src/backend.cpp +7 −10 Changes for src/backend.cpp: 7 added lines, 10 removed lines. Original line number Diff line number Diff line Loading @@ -69,22 +69,19 @@ void authdb::AuthBackend::write(const unsigned char* dest, size_t destsize){ } void authdb::AuthBackend::lock(){ // Cluster sync (network I/O) runs BEFORE acquiring the backend mutex. // This prevents distributed deadlocks where two nodes hold their // backend locks and wait for each other's peer fetch to complete. _Api->lock(); if (!_Lock.try_lock_for(std::chrono::seconds(5))) { // If we can't get the lock, undo the cluster fetch _Api->unlock(); if (!_Lock.try_lock_for(std::chrono::seconds(5))) throw AuthBackendError("backend lock timeout"); try { _Api->lock(); } catch (...) { _Lock.unlock(); throw; } } void authdb::AuthBackend::unlock(){ // Release the backend mutex BEFORE cluster push (network I/O) // so other local threads can proceed while replication happens. _Lock.unlock(); _Api->unlock(); _Lock.unlock(); } void authdb::AuthBackend::setPos(size_t pos){ Loading src/backends/cluster.cpp +3 −18 Changes for src/backends/cluster.cpp: 3 added lines, 18 removed lines. Original line number Diff line number Diff line Loading @@ -187,31 +187,16 @@ namespace authdb { } void ClusterBackend::lock() { // 1. Acquire _BufMtx first to protect _Buffer during fetch merge _BufLock = std::unique_lock<std::mutex>(_BufMtx); // 2. Fetch latest data (network I/O + merge into _Buffer) // _BufLock stays held after this so read/write are safe fetchFromCluster(); } void ClusterBackend::unlock() { // 1. Prepare push data while still holding _BufLock // pushToCluster() copies _Buffer internally before network I/O bool dirty = _Dirty; std::vector<uint8_t> buf_copy; uint64_t dgid = 0; if (dirty) { if (_Dirty) { newRevesion(); dgid = domainGroupId(); buf_copy = _Buffer; uint64_t dgid = domainGroupId(); pushToClusterAsync(dgid, _Buffer); _Dirty = false; } // 2. Release _BufMtx — other requests can now lock() if (_BufLock.owns_lock()) _BufLock.unlock(); // 3. Network I/O: push to peers (no locks held) if (dirty) pushToClusterAsync(dgid, buf_copy); } void ClusterBackend::pushToClusterAsync(uint64_t dgid, const std::vector<uint8_t> &buf) { Loading src/backends/cluster.h +3 −3 Changes for src/backends/cluster.h: 3 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ #include <vector> #include <cstdint> #include <atomic> #include <chrono> #include "../backend.h" #include "../authdb.h" Loading Loading @@ -70,9 +72,7 @@ namespace authdb { std::string _Domain; std::vector<uint8_t> _Buffer; size_t _Pos; bool _Dirty; std::atomic<bool> _Dirty; std::chrono::steady_clock::time_point _LastPeerFetch{}; std::mutex _BufMtx; std::unique_lock<std::mutex> _BufLock; // held between lock() and unlock() }; }; Loading
src/backend.cpp +7 −10 Changes for src/backend.cpp: 7 added lines, 10 removed lines. Original line number Diff line number Diff line Loading @@ -69,22 +69,19 @@ void authdb::AuthBackend::write(const unsigned char* dest, size_t destsize){ } void authdb::AuthBackend::lock(){ // Cluster sync (network I/O) runs BEFORE acquiring the backend mutex. // This prevents distributed deadlocks where two nodes hold their // backend locks and wait for each other's peer fetch to complete. _Api->lock(); if (!_Lock.try_lock_for(std::chrono::seconds(5))) { // If we can't get the lock, undo the cluster fetch _Api->unlock(); if (!_Lock.try_lock_for(std::chrono::seconds(5))) throw AuthBackendError("backend lock timeout"); try { _Api->lock(); } catch (...) { _Lock.unlock(); throw; } } void authdb::AuthBackend::unlock(){ // Release the backend mutex BEFORE cluster push (network I/O) // so other local threads can proceed while replication happens. _Lock.unlock(); _Api->unlock(); _Lock.unlock(); } void authdb::AuthBackend::setPos(size_t pos){ Loading
src/backends/cluster.cpp +3 −18 Changes for src/backends/cluster.cpp: 3 added lines, 18 removed lines. Original line number Diff line number Diff line Loading @@ -187,31 +187,16 @@ namespace authdb { } void ClusterBackend::lock() { // 1. Acquire _BufMtx first to protect _Buffer during fetch merge _BufLock = std::unique_lock<std::mutex>(_BufMtx); // 2. Fetch latest data (network I/O + merge into _Buffer) // _BufLock stays held after this so read/write are safe fetchFromCluster(); } void ClusterBackend::unlock() { // 1. Prepare push data while still holding _BufLock // pushToCluster() copies _Buffer internally before network I/O bool dirty = _Dirty; std::vector<uint8_t> buf_copy; uint64_t dgid = 0; if (dirty) { if (_Dirty) { newRevesion(); dgid = domainGroupId(); buf_copy = _Buffer; uint64_t dgid = domainGroupId(); pushToClusterAsync(dgid, _Buffer); _Dirty = false; } // 2. Release _BufMtx — other requests can now lock() if (_BufLock.owns_lock()) _BufLock.unlock(); // 3. Network I/O: push to peers (no locks held) if (dirty) pushToClusterAsync(dgid, buf_copy); } void ClusterBackend::pushToClusterAsync(uint64_t dgid, const std::vector<uint8_t> &buf) { Loading
src/backends/cluster.h +3 −3 Changes for src/backends/cluster.h: 3 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ #include <vector> #include <cstdint> #include <atomic> #include <chrono> #include "../backend.h" #include "../authdb.h" Loading Loading @@ -70,9 +72,7 @@ namespace authdb { std::string _Domain; std::vector<uint8_t> _Buffer; size_t _Pos; bool _Dirty; std::atomic<bool> _Dirty; std::chrono::steady_clock::time_point _LastPeerFetch{}; std::mutex _BufMtx; std::unique_lock<std::mutex> _BufLock; // held between lock() and unlock() }; };