From 705eeab816ca709b44cd8c469ee3b2a778c7c6e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20Engstr=C3=B6m?= Date: Mon, 27 Apr 2026 13:33:55 +0200 Subject: [PATCH] fix(unreal): suppress spurious OnInsert on overlapping subscription refcount bump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ClientCache::ApplyDiff phase 2 unconditionally appended every incoming row to Diff.Inserts, even when the row was already cached and only the refcount needed to bump. BroadcastDiff then fired OnInsert for every entry, so any table subscribed via two overlapping queries (e.g. a global SELECT plus a per-row WHERE) re-fired its insert handler on every later subscription apply. Mirror the delete path: only emit a Diff.Inserts entry when the row-bytes key transitions from absent to refcount=1. Real updates are unaffected — update bytes differ from old bytes, take the !Entry path, and DeriveUpdatesByPrimaryKey still reconciles them into OnUpdate. --- .../SpacetimeDbSdk/Public/DBCache/ClientCache.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/DBCache/ClientCache.h b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/DBCache/ClientCache.h index d5e1ca9a0f7..70693f4338c 100644 --- a/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/DBCache/ClientCache.h +++ b/sdks/unreal/src/SpacetimeDbSdk/Source/SpacetimeDbSdk/Public/DBCache/ClientCache.h @@ -120,20 +120,24 @@ class UClientCache TSharedPtr NewRow = MakeShared(Row); - // This is a new row or an update to an existing row that was not deleted. FRowEntry* Entry = Table->Entries.Find(Key); if (!Entry) { - // True insert + // True insert — these row-bytes are not cached yet. Either a + // genuinely new row, or the insert half of an update (the + // paired delete of different bytes is tracked in phase 1/3; + // DeriveUpdatesByPrimaryKey reconciles them by PK afterward). Table->Entries.Add(Key, FRowEntry{NewRow, 1}); + Diff.Inserts.Add(Key, *NewRow); } else { - // True update + // Refcount bump — an overlapping subscription brought an + // identical row already in cache. Mirror the delete path + // (which only emits Diff.Deletes on refcount == 0) by not + // emitting a spurious Diff.Inserts entry here. Table->Entries.Add(Key, FRowEntry{NewRow, Entry->RefCount + 1}); } - - Diff.Inserts.Add(Key, *NewRow); } // Phase 3: Finalize Deletes and Update Indices