From 8a8b4d41ca567cfdefaffc2dc269b8137394fe3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20B=C3=A9raud?= Date: Tue, 17 Mar 2026 00:01:13 -0400 Subject: [PATCH] op_cache, proxy_client: honor GetCallback return and guard push refresh expiry - SearchCache::get: if gcb returns false, call dcb(false, {}) instead of silently proceeding with dcb(true, {}). - DhtProxyClient push refresh: skip expiration of old values when the get() completion reports failure (ok == false), preventing spurious expires on transient errors. In pushNotificationReceived, track the set of value IDs received in the refresh GET and only expire values whose IDs are not in the new set. Previously all old values were expired on refresh, incorrectly expiring edited values. --- src/dht_proxy_client.cpp | 18 +++++++++++++++--- src/op_cache.cpp | 16 +++++++++------- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/dht_proxy_client.cpp b/src/dht_proxy_client.cpp index 9d07c922..f43e9d93 100644 --- a/src/dht_proxy_client.cpp +++ b/src/dht_proxy_client.cpp @@ -1310,13 +1310,25 @@ DhtProxyClient::pushNotificationReceived([[maybe_unused]] const std::map>(); get( key, - [cb, sendTime](const std::vector>& vals) { return cb(vals, false, sendTime); }, - [cb, oldValues, sendTime](bool /*ok*/) { + [cb, sendTime, receivedIds](const std::vector>& vals) { + for (const auto& v : vals) + receivedIds->insert(v->id); + return cb(vals, false, sendTime); + }, + [cb, oldValues, sendTime, receivedIds](bool ok) { + if (!ok) + return; // Decrement old values refcount to expire values not // present in the new list - cb(oldValues, true, sendTime); + std::vector> toExpire; + for (const auto& v : oldValues) + if (receivedIds->find(v->id) == receivedIds->end()) + toExpire.emplace_back(v); + if (!toExpire.empty()) + cb(toExpire, true, sendTime); }); ret = PushNotificationResult::Values; } else { diff --git a/src/op_cache.cpp b/src/op_cache.cpp index 127d5931..5bc4ee3e 100644 --- a/src/op_cache.cpp +++ b/src/op_cache.cpp @@ -244,15 +244,17 @@ SearchCache::expire(const time_point& now, const std::function& on bool SearchCache::get(const Value::Filter& f, const Sp& q, const GetCallback& gcb, const DoneCallback& dcb) const { + if (not gcb) + return false; auto op = getOp(q); - if (op != ops.end() and op->second->isSynced()) { - auto vals = op->second->get(f); - if (not vals.empty()) - gcb(vals); + if (op == ops.end() or not op->second->isSynced()) + return false; + auto vals = op->second->get(f); + if (not vals.empty()) + gcb(vals); // a consumer stopping early is not a failure + if (dcb) dcb(true, {}); - return true; - } - return false; + return true; } std::vector>