From 3b0e4e2fe2a7e640bc12a3dc13ca573a2ac2eb21 Mon Sep 17 00:00:00 2001 From: Pete Vilter Date: Sun, 9 Jun 2024 03:59:55 -0400 Subject: [PATCH] disallow versions with same txn id (#479) * disallow versions with same txn id * logging tweak --- apps/actors/systems/kvSync/client.ts | 4 +- apps/actors/systems/kvSync/examples/chat.tsx | 5 ++- .../kvSync/examples/common/kvInspector.tsx | 43 +++++++++---------- apps/actors/systems/kvSync/mutations/run.ts | 17 +++++++- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/apps/actors/systems/kvSync/client.ts b/apps/actors/systems/kvSync/client.ts index 518d58ea..cfa450fd 100644 --- a/apps/actors/systems/kvSync/client.ts +++ b/apps/actors/systems/kvSync/client.ts @@ -18,7 +18,7 @@ import { } from "./types"; import * as effects from "../../effects"; import { mapObj, randStep } from "../../../../util/util"; -import { runMutation } from "./mutations/run"; +import { addNewVersion, runMutation } from "./mutations/run"; import { InterpreterState } from "./mutations/builtins"; export type QueryStatus = "Loading" | "Online"; @@ -123,7 +123,7 @@ function processLiveQueryUpdate( const key = update.key; switch (update.type) { case "Updated": - newData[key] = [...(newData[key] || []), update.value]; + newData[key] = addNewVersion(newData, key, update.value); break; case "Deleted": delete newData[key]; // TODO: tombstone? diff --git a/apps/actors/systems/kvSync/examples/chat.tsx b/apps/actors/systems/kvSync/examples/chat.tsx index a4dfdc35..0bf1e568 100644 --- a/apps/actors/systems/kvSync/examples/chat.tsx +++ b/apps/actors/systems/kvSync/examples/chat.tsx @@ -174,7 +174,10 @@ function SendBox(props: { threadID: string; client: Client }) { if (status === "Online") { props.client.runMutation("markRead", [props.threadID, latestSeqNo]); } else { - console.log("not marking read because query status is", status); + console.warn( + "SendBox: not marking read because query status is", + status + ); } }} /> diff --git a/apps/actors/systems/kvSync/examples/common/kvInspector.tsx b/apps/actors/systems/kvSync/examples/common/kvInspector.tsx index e412d47f..6fbe764b 100644 --- a/apps/actors/systems/kvSync/examples/common/kvInspector.tsx +++ b/apps/actors/systems/kvSync/examples/common/kvInspector.tsx @@ -4,7 +4,7 @@ import { Table } from "./table"; import { VersionedValue } from "../../types"; import { getVisibleValue } from "../../mutations/common"; import { TransactionState, isTxnVisible } from "../../client"; -import { intersperse, reversed } from "../../../../../../util/util"; +import { reversed } from "../../../../../../util/util"; export function KVInspector(props: { client: Client; @@ -34,28 +34,25 @@ export function KVInspector(props: { { name: "Statuses", render: ([key, vvs]) => - intersperse( - <>, - reversed(vvs).map((vv) => ( - // TODO: clicking on this should show the txn trace - props.onSelectTxn(vv.transactionID)} - > - {iconForState( - props.client.state.transactions[vv.transactionID].state - )} - - )) - ), + reversed(vvs).map((vv) => ( + // TODO: clicking on this should show the txn trace + props.onSelectTxn(vv.transactionID)} + > + {iconForState( + props.client.state.transactions[vv.transactionID].state + )} + + )), }, ]} /> diff --git a/apps/actors/systems/kvSync/mutations/run.ts b/apps/actors/systems/kvSync/mutations/run.ts index da25132f..e4c299b2 100644 --- a/apps/actors/systems/kvSync/mutations/run.ts +++ b/apps/actors/systems/kvSync/mutations/run.ts @@ -324,7 +324,7 @@ function doWrite( const newVersionedValue: VersionedValue = { transactionID, value }; const newKVData: KVData = { ...kvData, - [key]: [...(kvData[key] || []), newVersionedValue], + [key]: addNewVersion(kvData, key, newVersionedValue), }; const oldValue = getVisibleValue(isTxnCommitted, kvData, key); if (kvData[key]) { @@ -346,3 +346,18 @@ function doWrite( }, ]; } + +export function addNewVersion( + kvData: KVData, + key: string, + newVersion: VersionedValue +) { + const versions = kvData[key] || []; + // Check if the transactionID is already in the list + // This can result from overlapping live queries + // TODO: this is O(n) and could be O(1) + if (versions.some((v) => v.transactionID === newVersion.transactionID)) { + return versions; + } + return [...versions, newVersion]; +}