Skip to content

Fix large table issues #179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions examples/quickstart-chat/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ body,
}

body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
font-family:
-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',
'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
font-family:
source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;
}

/* ----- Buttons ----- */
Expand Down
4 changes: 4 additions & 0 deletions packages/sdk/src/connection_id.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ export class ConnectionId {
return this.data == other.data;
}

toPrimaryKey(): bigint {
return this.data;
}

/**
* Print the connection ID as a hexadecimal string.
*/
Expand Down
6 changes: 3 additions & 3 deletions packages/sdk/src/db_connection_impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,14 +520,14 @@ export class DbConnectionImpl<
tableUpdates: TableUpdate[],
eventContext: EventContextInterface
): PendingCallback[] {
const pendingCallbacks: PendingCallback[] = [];
let pendingCallbacks: PendingCallback[] = [];
for (let tableUpdate of tableUpdates) {
// Get table information for the table being updated
const tableName = tableUpdate.tableName;
const tableTypeInfo = this.#remoteModule.tables[tableName]!;
const table = this.clientCache.getOrCreateTable(tableTypeInfo);
pendingCallbacks.push(
...table.applyOperations(tableUpdate.operations, eventContext)
pendingCallbacks = pendingCallbacks.concat(
table.applyOperations(tableUpdate.operations, eventContext)
);
}
return pendingCallbacks;
Expand Down
4 changes: 4 additions & 0 deletions packages/sdk/src/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export class Identity {
return u256ToHexString(this.data);
}

toPrimaryKey(): string {
return this.toHexString();
}

/**
* Convert the address to a Uint8Array.
*/
Expand Down
63 changes: 0 additions & 63 deletions packages/sdk/src/operations_map.ts

This file was deleted.

67 changes: 40 additions & 27 deletions packages/sdk/src/table_cache.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { EventEmitter } from './event_emitter.ts';
import OperationsMap from './operations_map.ts';
import type { TableRuntimeTypeInfo } from './spacetime_module.ts';

import { type EventContextInterface } from './db_connection_impl.ts';
Expand Down Expand Up @@ -61,47 +60,61 @@ export class TableCache<RowType = any> {
): PendingCallback[] => {
const pendingCallbacks: PendingCallback[] = [];
if (this.tableTypeInfo.primaryKey !== undefined) {
let hasDelete = false;
const primaryKey = this.tableTypeInfo.primaryKey;
const insertMap = new OperationsMap<any, [Operation, number]>();
const deleteMap = new OperationsMap<any, [Operation, number]>();
const insertMap = new Map<any, [Operation, number]>();
const deleteMap = new Map<any, [Operation, number]>();
for (const op of operations) {
let key = op.row[primaryKey];
if (typeof key === 'object' && 'toPrimaryKey' in key) {
key = key.toPrimaryKey();
}

if (op.type === 'insert') {
const [_, prevCount] = insertMap.get(op.row[primaryKey]) || [op, 0];
insertMap.set(op.row[primaryKey], [op, prevCount + 1]);
const [_, prevCount] = insertMap.get(key) || [op, 0];
insertMap.set(key, [op, prevCount + 1]);
} else {
const [_, prevCount] = deleteMap.get(op.row[primaryKey]) || [op, 0];
deleteMap.set(op.row[primaryKey], [op, prevCount + 1]);
hasDelete = true;
const [_, prevCount] = deleteMap.get(key) || [op, 0];
deleteMap.set(key, [op, prevCount + 1]);
}
}
for (const {
key: primaryKey,
value: [insertOp, refCount],
} of insertMap) {
const deleteEntry = deleteMap.get(primaryKey);
if (deleteEntry) {
const [deleteOp, deleteCount] = deleteEntry;
// In most cases the refCountDelta will be either 0 or refCount, but if
// an update moves a row in or out of the result set of different queries, then
// other deltas are possible.
const refCountDelta = refCount - deleteCount;
const maybeCb = this.update(ctx, insertOp, deleteOp, refCountDelta);

if (hasDelete) {
for (const [primaryKey, [insertOp, refCount]] of insertMap.entries()) {
const deleteEntry = deleteMap.get(primaryKey);
if (deleteEntry) {
const [deleteOp, deleteCount] = deleteEntry;
// In most cases the refCountDelta will be either 0 or refCount, but if
// an update moves a row in or out of the result set of different queries, then
// other deltas are possible.
const refCountDelta = refCount - deleteCount;
const maybeCb = this.update(ctx, insertOp, deleteOp, refCountDelta);
if (maybeCb) {
pendingCallbacks.push(maybeCb);
}
deleteMap.delete(primaryKey);
} else {
const maybeCb = this.insert(ctx, insertOp, refCount);
if (maybeCb) {
pendingCallbacks.push(maybeCb);
}
}
}
for (const [deleteOp, refCount] of deleteMap.values()) {
const maybeCb = this.delete(ctx, deleteOp, refCount);
if (maybeCb) {
pendingCallbacks.push(maybeCb);
}
deleteMap.delete(primaryKey);
} else {
}
} else {
for (const [insertOp, refCount] of insertMap.values()) {
const maybeCb = this.insert(ctx, insertOp, refCount);
if (maybeCb) {
pendingCallbacks.push(maybeCb);
}
}
}
for (const [deleteOp, refCount] of deleteMap.values()) {
const maybeCb = this.delete(ctx, deleteOp, refCount);
if (maybeCb) {
pendingCallbacks.push(maybeCb);
}
}
} else {
for (const op of operations) {
if (op.type === 'insert') {
Expand Down