Loading src/backends/cluster.cpp +56 −21 Changes for src/backends/cluster.cpp: 56 added lines, 21 removed lines. Original line number Diff line number Diff line Loading @@ -112,39 +112,74 @@ namespace authdb { } } // Merge into _Buffer — caller (lock()) holds _BufLock after this returns size_t local_rev = bufferRevision(local_data); size_t peer_rev = bufferRevision(peer_data); size_t cur_rev = bufferRevision(_Buffer); // Reject corrupt buffers before considering them if (!bufferValid(local_data)) local_data.clear(); if (!bufferValid(peer_data)) peer_data.clear(); std::vector<uint8_t> *best = nullptr; size_t best_rev = cur_rev; // Merge into _Buffer — caller (lock()) holds _BufLock after this returns. // Instead of picking a single "best revision" buffer, merge records from // ALL sources (in-memory, local store, peers) so that records created on // remote nodes become visible locally. vacuum() deduplicates by // (ruid, fieldname, type), keeping the last occurrence. size_t local_rev = bufferRevision(local_data); size_t peer_rev = bufferRevision(peer_data); size_t cur_rev = bufferRevision(_Buffer); bool local_has_records = (!local_data.empty() && local_data.size() > sizeof(AuthHeader)); bool peer_has_records = (!peer_data.empty() && peer_data.size() > sizeof(AuthHeader)); // Quick check: skip merge when local store matches in-memory buffer // and no peer data is available bool local_same = (!_Buffer.empty() && local_data.size() == _Buffer.size() && (local_data.empty() || std::memcmp(local_data.data(), _Buffer.data(), _Buffer.size()) == 0)); if (local_same && !peer_has_records) return; if (peer_rev > best_rev && !peer_data.empty()) { best = &peer_data; best_rev = peer_rev; // Ensure _Buffer has at least a valid header as merge base if (_Buffer.size() < sizeof(AuthHeader)) { if (local_data.size() >= sizeof(AuthHeader)) _Buffer.assign(local_data.begin(), local_data.begin() + sizeof(AuthHeader)); else if (peer_data.size() >= sizeof(AuthHeader)) _Buffer.assign(peer_data.begin(), peer_data.begin() + sizeof(AuthHeader)); else return; // no usable data anywhere } if (local_rev > best_rev && !local_data.empty()) { best = &local_data; best_rev = local_rev; // Append records from local store and peer store into _Buffer. // vacuum() will deduplicate afterwards. bool merged = false; if (local_has_records) { _Buffer.insert(_Buffer.end(), local_data.begin() + sizeof(AuthHeader), local_data.end()); merged = true; } if (best) { _Buffer = std::move(*best); if (peer_has_records) { _Buffer.insert(_Buffer.end(), peer_data.begin() + sizeof(AuthHeader), peer_data.end()); merged = true; } if (merged) { // Use the highest revision from any source size_t max_rev = std::max({cur_rev, local_rev, peer_rev}); AuthHeader head; std::memcpy(&head, _Buffer.data(), sizeof(AuthHeader)); head.Revesion = max_rev; std::memcpy(_Buffer.data(), &head, sizeof(AuthHeader)); vacuum(); store.store(dgid, 0, _Buffer.data(), _Buffer.size()); } else if (_Buffer.empty() && !local_data.empty()) { _Buffer = std::move(local_data); vacuum(); } else if (_Buffer.empty() && !peer_data.empty()) { _Buffer = std::move(peer_data); vacuum(); } } Loading Loading
src/backends/cluster.cpp +56 −21 Changes for src/backends/cluster.cpp: 56 added lines, 21 removed lines. Original line number Diff line number Diff line Loading @@ -112,39 +112,74 @@ namespace authdb { } } // Merge into _Buffer — caller (lock()) holds _BufLock after this returns size_t local_rev = bufferRevision(local_data); size_t peer_rev = bufferRevision(peer_data); size_t cur_rev = bufferRevision(_Buffer); // Reject corrupt buffers before considering them if (!bufferValid(local_data)) local_data.clear(); if (!bufferValid(peer_data)) peer_data.clear(); std::vector<uint8_t> *best = nullptr; size_t best_rev = cur_rev; // Merge into _Buffer — caller (lock()) holds _BufLock after this returns. // Instead of picking a single "best revision" buffer, merge records from // ALL sources (in-memory, local store, peers) so that records created on // remote nodes become visible locally. vacuum() deduplicates by // (ruid, fieldname, type), keeping the last occurrence. size_t local_rev = bufferRevision(local_data); size_t peer_rev = bufferRevision(peer_data); size_t cur_rev = bufferRevision(_Buffer); bool local_has_records = (!local_data.empty() && local_data.size() > sizeof(AuthHeader)); bool peer_has_records = (!peer_data.empty() && peer_data.size() > sizeof(AuthHeader)); // Quick check: skip merge when local store matches in-memory buffer // and no peer data is available bool local_same = (!_Buffer.empty() && local_data.size() == _Buffer.size() && (local_data.empty() || std::memcmp(local_data.data(), _Buffer.data(), _Buffer.size()) == 0)); if (local_same && !peer_has_records) return; if (peer_rev > best_rev && !peer_data.empty()) { best = &peer_data; best_rev = peer_rev; // Ensure _Buffer has at least a valid header as merge base if (_Buffer.size() < sizeof(AuthHeader)) { if (local_data.size() >= sizeof(AuthHeader)) _Buffer.assign(local_data.begin(), local_data.begin() + sizeof(AuthHeader)); else if (peer_data.size() >= sizeof(AuthHeader)) _Buffer.assign(peer_data.begin(), peer_data.begin() + sizeof(AuthHeader)); else return; // no usable data anywhere } if (local_rev > best_rev && !local_data.empty()) { best = &local_data; best_rev = local_rev; // Append records from local store and peer store into _Buffer. // vacuum() will deduplicate afterwards. bool merged = false; if (local_has_records) { _Buffer.insert(_Buffer.end(), local_data.begin() + sizeof(AuthHeader), local_data.end()); merged = true; } if (best) { _Buffer = std::move(*best); if (peer_has_records) { _Buffer.insert(_Buffer.end(), peer_data.begin() + sizeof(AuthHeader), peer_data.end()); merged = true; } if (merged) { // Use the highest revision from any source size_t max_rev = std::max({cur_rev, local_rev, peer_rev}); AuthHeader head; std::memcpy(&head, _Buffer.data(), sizeof(AuthHeader)); head.Revesion = max_rev; std::memcpy(_Buffer.data(), &head, sizeof(AuthHeader)); vacuum(); store.store(dgid, 0, _Buffer.data(), _Buffer.size()); } else if (_Buffer.empty() && !local_data.empty()) { _Buffer = std::move(local_data); vacuum(); } else if (_Buffer.empty() && !peer_data.empty()) { _Buffer = std::move(peer_data); vacuum(); } } Loading