Skip to content

Commit 2d7aa47

Browse files
authored
feat: align storage transaction and shim in regards to log / activity and status (#1445)
1 parent 531c9aa commit 2d7aa47

File tree

13 files changed

+174
-186
lines changed

13 files changed

+174
-186
lines changed

packages/runner/src/builtins/compile-and-run.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ export function compileAndRun(
164164
// All this code runside outside the original action, and the
165165
// transaction above might have closed by the time this is called. If
166166
// so, we create a new one to set the error.
167-
const asyncTx = tx.status().ok?.open ? tx : runtime.edit();
167+
const status = tx.status();
168+
const asyncTx = status.status === "ready" ? tx : runtime.edit();
168169

169170
// Extract structured errors if this is a CompilerError
170171
if (err instanceof CompilerError) {
@@ -189,7 +190,8 @@ export function compileAndRun(
189190
// All this code runside outside the original action, and the
190191
// transaction above might have closed by the time this is called. If
191192
// so, we create a new one to set the status.
192-
const asyncTx = tx.status().ok?.open ? tx : runtime.edit();
193+
const status = tx.status();
194+
const asyncTx = status.status === "ready" ? tx : runtime.edit();
193195
pendingWithLog.withTx(asyncTx).set(false);
194196
if (asyncTx !== tx) asyncTx.commit();
195197
});
@@ -204,7 +206,8 @@ export function compileAndRun(
204206
// All this code runside outside the original action, and the
205207
// transaction above might have closed by the time this is called. If
206208
// so, we create a new one to start the charm.
207-
const asyncTx = tx.status().ok?.open ? tx : runtime.edit();
209+
const status = tx.status();
210+
const asyncTx = status.status === "ready" ? tx : runtime.edit();
208211
await runtime.runSynced(result.withTx(asyncTx), recipe, input.get());
209212
if (asyncTx !== tx) asyncTx.commit();
210213
}

packages/runner/src/builtins/fetch-data.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ export function fetchData(
129129
// All this code runside outside the original action, and the
130130
// transaction above might have closed by the time this is called. If
131131
// so, we create a new one to set the result.
132-
const asyncTx = tx.status().ok?.open ? tx : runtime.edit();
132+
const status = tx.status();
133+
const asyncTx = status.status === "ready" ? tx : runtime.edit();
133134

134135
pendingWithLog.withTx(asyncTx).set(false);
135136
resultWithLog.withTx(asyncTx).set(data);
@@ -145,7 +146,8 @@ export function fetchData(
145146
// All this code runside outside the original action, and the
146147
// transaction above might have closed by the time this is called. If
147148
// so, we create a new one to set the error.
148-
const asyncTx = tx.status().ok?.open ? tx : runtime.edit();
149+
const status = tx.status();
150+
const asyncTx = status.status === "ready" ? tx : runtime.edit();
149151

150152
pendingWithLog.withTx(asyncTx).set(false);
151153
errorWithLog.withTx(asyncTx).set(err);

packages/runner/src/builtins/llm.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,8 @@ export function llm(
158158
// All this code runside outside the original action, and the
159159
// transaction above might have closed by the time this is called. If
160160
// so, we create a new one to set the result.
161-
const asyncTx = tx.status().ok?.open ? tx : runtime.edit();
161+
const status = tx.status();
162+
const asyncTx = status.status === "ready" ? tx : runtime.edit();
162163

163164
pendingWithLog.withTx(asyncTx).set(false);
164165
resultWithLog.withTx(asyncTx).set(text);
@@ -177,7 +178,8 @@ export function llm(
177178
// All this code runside outside the original action, and the
178179
// transaction above might have closed by the time this is called. If
179180
// so, we create a new one to set the result.
180-
const asyncTx = tx.status().ok?.open ? tx : runtime.edit();
181+
const status = tx.status();
182+
const asyncTx = status.status === "ready" ? tx : runtime.edit();
181183

182184
pendingWithLog.withTx(asyncTx).set(false);
183185
resultWithLog.withTx(asyncTx).set(undefined);
@@ -330,7 +332,8 @@ export function generateObject<T extends Record<string, unknown>>(
330332
// All this code runside outside the original action, and the
331333
// transaction above might have closed by the time this is called. If
332334
// so, we create a new one to set the result.
333-
const asyncTx = tx.status().ok?.open ? tx : runtime.edit();
335+
const status = tx.status();
336+
const asyncTx = status.status === "ready" ? tx : runtime.edit();
334337

335338
pendingWithLog.withTx(asyncTx).set(false);
336339
resultWithLog.withTx(asyncTx).set(response.object);
@@ -348,7 +351,8 @@ export function generateObject<T extends Record<string, unknown>>(
348351
// All this code runside outside the original action, and the
349352
// transaction above might have closed by the time this is called. If
350353
// so, we create a new one to set the result.
351-
const asyncTx = tx.status().ok?.open ? tx : runtime.edit();
354+
const status = tx.status();
355+
const asyncTx = status.status === "ready" ? tx : runtime.edit();
352356

353357
pendingWithLog.withTx(asyncTx).set(false);
354358
resultWithLog.withTx(asyncTx).set({} as any); // FIXME(ja): setting result to undefined causes a storage conflict

packages/runner/src/builtins/stream-data.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ export function streamData(
181181

182182
await runtime.idle();
183183

184-
const asyncTx = tx.status().ok?.open ? tx : runtime.edit();
184+
const status = tx.status();
185+
const asyncTx = status.status === "ready" ? tx : runtime.edit();
185186
pendingWithLog.withTx(asyncTx).set(false);
186187
resultWithLog.withTx(asyncTx).set(undefined);
187188
errorWithLog.withTx(asyncTx).set(e);

packages/runner/src/query-result-proxy.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ export function createQueryResultProxy<T>(
8989
}
9090

9191
// Resolve path and follow links to actual value.
92-
const readTx = tx?.status().ok?.open ? tx : runtime.edit();
92+
const txStatus = tx?.status();
93+
const readTx = (txStatus?.status === "ready" && tx) ? tx : runtime.edit();
9394
link = resolveLinkToValue(readTx, link);
9495
const target = readTx.readValueOrThrow(link) as any;
9596

packages/runner/src/runner.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ export class Runner implements IRunner {
287287
// scheduler if the transaction isn't committed before the first functions
288288
// run. Though most likely the worst case is just extra invocations.
289289
this.run(
290-
resultCell.tx?.status().ok?.open ? resultCell.tx : undefined,
290+
resultCell.tx?.status().status === "ready" ? resultCell.tx : undefined,
291291
recipe,
292292
inputs,
293293
resultCell,

packages/runner/src/scheduler.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -446,17 +446,21 @@ export function txToReactivityLog(
446446
tx: IExtendedStorageTransaction,
447447
): ReactivityLog {
448448
const log: ReactivityLog = { reads: [], writes: [] };
449-
for (const change of tx.log()) {
450-
if ("read" in change) {
449+
for (const activity of tx.journal.activity()) {
450+
if ("read" in activity && activity.read) {
451451
log.reads.push({
452-
...change.read!.address,
453-
path: change.read!.address.path.slice(1), // Remove the "value" prefix
452+
space: activity.read.space,
453+
id: activity.read.id,
454+
type: activity.read.type,
455+
path: activity.read.path.slice(1), // Remove the "value" prefix
454456
});
455457
}
456-
if ("write" in change) {
458+
if ("write" in activity && activity.write) {
457459
log.writes.push({
458-
...change.write!.address,
459-
path: change.write!.address.path.slice(1),
460+
space: activity.write.space,
461+
id: activity.write.id,
462+
type: activity.write.type,
463+
path: activity.write.path.slice(1),
460464
});
461465
}
462466
}

packages/runner/src/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ export function validateAndTransform(
270270
// from the tx. Once tx.commit() is called, all that data is either available
271271
// via other transactions or has been rolled back. Either way, we want to
272272
// reflect that reality.
273-
if (!tx?.status().ok?.open) tx = undefined;
273+
if (tx?.status().status !== "ready") tx = undefined;
274274

275275
// Reconstruct doc, path, schema, rootSchema from link and runtime
276276
const schema = link.schema;

packages/runner/src/storage/interface.ts

Lines changed: 22 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -56,18 +56,6 @@ export type Read = IAttestation;
5656
*/
5757
export type Write = IAttestation;
5858

59-
export interface IStorageTransactionInvariant {
60-
read?: IStorageInvariant;
61-
write?: IStorageInvariant;
62-
}
63-
64-
export interface IStorageTransactionLog {
65-
get(address: IMemorySpaceAddress): IStorageTransactionInvariant;
66-
addRead(read: IStorageInvariant): void;
67-
addWrite(write: IStorageInvariant): void;
68-
[Symbol.iterator](): Iterator<IStorageTransactionInvariant>;
69-
}
70-
7159
// This type is used to tag a document with any important metadata.
7260
// Currently, the only supported type is the classification.
7361
export type Labels = {
@@ -371,20 +359,15 @@ export interface IMemoryChange {
371359
after: JSONValue | undefined;
372360
}
373361

374-
export type IStorageTransactionProgress = Variant<{
375-
open: IStorageTransactionLog;
376-
pending: IStorageTransactionLog;
377-
done: IStorageTransactionLog;
378-
}>;
379-
export type StorageTransactionStatus = Result<
380-
IStorageTransactionState,
381-
StorageTransactionFailed
382-
>;
383-
384-
export type IStorageTransactionState =
362+
export type StorageTransactionStatus =
385363
| { status: "ready"; journal: ITransactionJournal }
386364
| { status: "pending"; journal: ITransactionJournal }
387-
| { status: "done"; journal: ITransactionJournal };
365+
| { status: "done"; journal: ITransactionJournal }
366+
| {
367+
status: "error";
368+
journal: ITransactionJournal;
369+
error: StorageTransactionFailed;
370+
};
388371

389372
/**
390373
* Representation of a storage transaction, which can be used to query facts and
@@ -400,19 +383,22 @@ export type IStorageTransactionState =
400383
*/
401384
export interface IStorageTransaction {
402385
/**
403-
* Describes current status of the transaction. If transaction has failed
404-
* or was cancelled result will be an error with a corresponding error variant.
405-
* If transaction is being built it will have `open` status, if commit was
406-
* called but promise has not resolved yet it will be `pending`. If commit
407-
* successfully completed it will be `done`.
408-
*
409-
* Please note that if storage was updated since transaction was created such
410-
* that any of the invariants have changed status will be change to
411-
* `IStorageConsistencyError` even though transaction has not being commited.
412-
* This allows transactor to cancel and recreate transaction with a current
413-
* state without having to build up a whole transaction and commiting it.
386+
* The transaction journal containing all read and write activities.
387+
* Provides access to transaction operations and dependency tracking.
388+
*/
389+
readonly journal: ITransactionJournal;
390+
391+
/**
392+
* Describes current status of the transaction. Returns a union type with
393+
* status field indicating the current state:
394+
* - `"ready"`: Transaction is being built and ready for operations
395+
* - `"pending"`: Commit was called but promise has not resolved yet
396+
* - `"done"`: Commit successfully completed
397+
* - `"error"`: Transaction has failed or was cancelled, includes error details
398+
399+
* Each status variant includes a `journal` field with transaction operations.
414400
*/
415-
// status(): StorageTransactionStatus;
401+
status(): StorageTransactionStatus;
416402

417403
/**
418404
* Helper that is the same as `reader().read()` but more convenient, as it
@@ -495,21 +481,6 @@ export interface IStorageTransaction {
495481
}
496482

497483
export interface IExtendedStorageTransaction extends IStorageTransaction {
498-
/**
499-
* Describes current status of the transaction. If transaction has failed
500-
* or was cancelled result will be an error with a corresponding error variant.
501-
* If transaction is being built it will have `open` status, if commit was
502-
* called but promise has not resolved yet it will be `pending`. If commit
503-
* successfully completed it will be `done`.
504-
*
505-
* Please note that if storage was updated since transaction was created such
506-
* that any of the invariants have changed status will be change to
507-
* `IStorageConsistencyError` even though transaction has not being commited.
508-
* This allows transactor to cancel and recreate transaction with a current
509-
* state without having to build up a whole transaction and commiting it.
510-
*/
511-
status(): Result<IStorageTransactionProgress, StorageTransactionFailed>;
512-
513484
/**
514485
* Reads a value from a (local) memory address and throws on error, except for
515486
* `NotFoundError` which is returned as undefined.
@@ -556,19 +527,6 @@ export interface IExtendedStorageTransaction extends IStorageTransaction {
556527
value: JSONValue | undefined,
557528
): void;
558529

559-
/**
560-
* Returns the log of the transaction.
561-
*
562-
* The log is a list of changes that have been made to the transaction.
563-
* It is used to track the dependencies of the transaction.
564-
*
565-
* If the transaction is aborted, the log reflects the attempted reads and
566-
* writes. If the transaction is committed, the log reflects the actual reads
567-
* and writes.
568-
*
569-
* @deprecated
570-
*/
571-
log(): IStorageTransactionLog;
572530
}
573531

574532
export interface ITransactionReader {
@@ -842,32 +800,6 @@ export interface ITransactionJournal {
842800

843801
novelty(space: MemorySpace): Iterable<IAttestation>;
844802
history(space: MemorySpace): Iterable<IAttestation>;
845-
846-
reader(
847-
space: MemorySpace,
848-
): Result<ITransactionReader, InactiveTransactionError>;
849-
850-
writer(
851-
space: MemorySpace,
852-
): Result<ITransactionWriter, InactiveTransactionError>;
853-
854-
/**
855-
* Closes underlying transaction, making it non-editable going forward. Any
856-
* attempts to edit it will fail.
857-
*/
858-
close(): Result<Map<MemorySpace, ITransaction>, InactiveTransactionError>;
859-
860-
/**
861-
* Aborts underlying transaction, making it non-editable going forward. Any
862-
* attempts to edit it will fail.
863-
*/
864-
abort(reason?: unknown): Result<Unit, InactiveTransactionError>;
865-
}
866-
867-
export interface EditableJournal {
868-
activity(): Iterable<Activity>;
869-
novelty: Iterable<IAttestation>;
870-
history(): Iterable<IAttestation>;
871803
}
872804

873805
export interface ITransaction {
@@ -929,8 +861,3 @@ export interface IAttestation {
929861
readonly address: IMemoryAddress;
930862
readonly value?: JSONValue;
931863
}
932-
933-
export interface IStorageInvariant {
934-
readonly address: IMemorySpaceAddress;
935-
readonly value?: JSONValue;
936-
}

0 commit comments

Comments
 (0)