@optimystic/db-core 0.5.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/btree/btree.d.ts +2 -0
- package/dist/src/btree/btree.d.ts.map +1 -1
- package/dist/src/btree/btree.js +72 -52
- package/dist/src/btree/btree.js.map +1 -1
- package/dist/src/cluster/structs.d.ts +13 -0
- package/dist/src/cluster/structs.d.ts.map +1 -1
- package/dist/src/collection/collection.d.ts +10 -0
- package/dist/src/collection/collection.d.ts.map +1 -1
- package/dist/src/collection/collection.js +34 -0
- package/dist/src/collection/collection.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/log/log.js +1 -1
- package/dist/src/log/log.js.map +1 -1
- package/dist/src/logger.d.ts +4 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +8 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/transaction/coordinator.d.ts +31 -8
- package/dist/src/transaction/coordinator.d.ts.map +1 -1
- package/dist/src/transaction/coordinator.js +206 -53
- package/dist/src/transaction/coordinator.js.map +1 -1
- package/dist/src/transaction/index.d.ts +2 -2
- package/dist/src/transaction/index.d.ts.map +1 -1
- package/dist/src/transaction/index.js +1 -1
- package/dist/src/transaction/index.js.map +1 -1
- package/dist/src/transaction/session.d.ts +11 -7
- package/dist/src/transaction/session.d.ts.map +1 -1
- package/dist/src/transaction/session.js +27 -14
- package/dist/src/transaction/session.js.map +1 -1
- package/dist/src/transaction/transaction.d.ts +9 -3
- package/dist/src/transaction/transaction.d.ts.map +1 -1
- package/dist/src/transaction/transaction.js +14 -7
- package/dist/src/transaction/transaction.js.map +1 -1
- package/dist/src/transaction/validator.d.ts +9 -2
- package/dist/src/transaction/validator.d.ts.map +1 -1
- package/dist/src/transaction/validator.js +26 -6
- package/dist/src/transaction/validator.js.map +1 -1
- package/dist/src/transactor/network-transactor.d.ts.map +1 -1
- package/dist/src/transactor/network-transactor.js +84 -9
- package/dist/src/transactor/network-transactor.js.map +1 -1
- package/dist/src/transactor/transactor-source.d.ts +4 -0
- package/dist/src/transactor/transactor-source.d.ts.map +1 -1
- package/dist/src/transactor/transactor-source.js +25 -9
- package/dist/src/transactor/transactor-source.js.map +1 -1
- package/dist/src/transform/atomic-proxy.d.ts +26 -0
- package/dist/src/transform/atomic-proxy.d.ts.map +1 -0
- package/dist/src/transform/atomic-proxy.js +47 -0
- package/dist/src/transform/atomic-proxy.js.map +1 -0
- package/dist/src/transform/cache-source.d.ts +3 -2
- package/dist/src/transform/cache-source.d.ts.map +1 -1
- package/dist/src/transform/cache-source.js +15 -3
- package/dist/src/transform/cache-source.js.map +1 -1
- package/dist/src/transform/index.d.ts +1 -0
- package/dist/src/transform/index.d.ts.map +1 -1
- package/dist/src/transform/index.js +1 -0
- package/dist/src/transform/index.js.map +1 -1
- package/dist/src/utility/batch-coordinator.d.ts +2 -0
- package/dist/src/utility/batch-coordinator.d.ts.map +1 -1
- package/dist/src/utility/batch-coordinator.js +6 -1
- package/dist/src/utility/batch-coordinator.js.map +1 -1
- package/dist/src/utility/hash-string.d.ts +3 -6
- package/dist/src/utility/hash-string.d.ts.map +1 -1
- package/dist/src/utility/hash-string.js +8 -11
- package/dist/src/utility/hash-string.js.map +1 -1
- package/dist/src/utility/lru-map.d.ts +18 -0
- package/dist/src/utility/lru-map.d.ts.map +1 -0
- package/dist/src/utility/lru-map.js +52 -0
- package/dist/src/utility/lru-map.js.map +1 -0
- package/package.json +15 -8
- package/src/btree/btree.ts +71 -50
- package/src/cluster/structs.ts +11 -0
- package/src/collection/collection.ts +44 -0
- package/src/index.ts +1 -0
- package/src/log/log.ts +1 -1
- package/src/logger.ts +10 -0
- package/src/transaction/coordinator.ts +244 -57
- package/src/transaction/index.ts +4 -2
- package/src/transaction/session.ts +38 -14
- package/src/transaction/transaction.ts +23 -10
- package/src/transaction/validator.ts +34 -7
- package/src/transactor/network-transactor.ts +94 -13
- package/src/transactor/transactor-source.ts +28 -9
- package/src/transform/atomic-proxy.ts +49 -0
- package/src/transform/cache-source.ts +18 -4
- package/src/transform/index.ts +1 -0
- package/src/utility/batch-coordinator.ts +9 -1
- package/src/utility/hash-string.ts +14 -17
- package/src/utility/lru-map.ts +55 -0
- package/dist/index.min.js +0 -9
- package/dist/index.min.js.map +0 -7
|
@@ -12,7 +12,7 @@ import type { ExecutionResult, ITransactionEngine, TransactionStamp, CollectionA
|
|
|
12
12
|
* - The Transaction is then committed through coordinator.commit() for PEND/COMMIT orchestration
|
|
13
13
|
*
|
|
14
14
|
* Usage:
|
|
15
|
-
* const session =
|
|
15
|
+
* const session = await TransactionSession.create(coordinator, engine);
|
|
16
16
|
* await session.execute('INSERT INTO users (id, name) VALUES (?, ?)', [1, 'Alice']);
|
|
17
17
|
* await session.execute('SELECT * FROM orders WHERE user_id = ?', [1]);
|
|
18
18
|
* const result = await session.commit();
|
|
@@ -26,8 +26,12 @@ export declare class TransactionSession {
|
|
|
26
26
|
private readonly stamp;
|
|
27
27
|
private committed;
|
|
28
28
|
private rolledBack;
|
|
29
|
-
constructor(
|
|
30
|
-
|
|
29
|
+
private constructor();
|
|
30
|
+
/**
|
|
31
|
+
* Create a new TransactionSession.
|
|
32
|
+
* Uses async factory because stamp creation requires SHA-256 hashing.
|
|
33
|
+
*/
|
|
34
|
+
static create(coordinator: TransactionCoordinator, engine: ITransactionEngine, peerId?: string, schemaHash?: string, ttlMs?: number): Promise<TransactionSession>;
|
|
31
35
|
/**
|
|
32
36
|
* Execute a statement.
|
|
33
37
|
*
|
|
@@ -49,11 +53,11 @@ export declare class TransactionSession {
|
|
|
49
53
|
*/
|
|
50
54
|
commit(): Promise<ExecutionResult>;
|
|
51
55
|
/**
|
|
52
|
-
* Rollback the transaction (
|
|
56
|
+
* Rollback the transaction (undo this session's applied actions).
|
|
53
57
|
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
58
|
+
* Delegates to coordinator.rollback(stampId) which restores collection
|
|
59
|
+
* trackers to the pre-session snapshot and replays any later sessions'
|
|
60
|
+
* actions to preserve their transforms.
|
|
57
61
|
*/
|
|
58
62
|
rollback(): Promise<void>;
|
|
59
63
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/transaction/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAAe,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG9H;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,kBAAkB;IAO7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/transaction/session.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,KAAK,EAAe,eAAe,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAG9H;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,kBAAkB;IAO7B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IAPxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;IACzC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO;IAQP;;;OAGG;WACU,MAAM,CAClB,WAAW,EAAE,sBAAsB,EACnC,MAAM,EAAE,kBAAkB,EAC1B,MAAM,GAAE,MAAgB,EACxB,UAAU,GAAE,MAAW,EACvB,KAAK,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,kBAAkB,CAAC;IAW9B;;;;;;;;;OASG;IACG,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,EAAE,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA2C9G;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC;IAgCxC;;;;;;OAMG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAe/B;;OAEG;IACH,UAAU,IAAI,MAAM;IAIpB;;OAEG;IACH,QAAQ,IAAI,gBAAgB;IAI5B;;OAEG;IACH,aAAa,IAAI,SAAS,MAAM,EAAE;IAIlC;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,YAAY,IAAI,OAAO;CAGvB"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createTransactionStamp, createTransactionId } from "./transaction.js";
|
|
1
|
+
import { createTransactionStamp, createTransactionId, isTransactionExpired } from "./transaction.js";
|
|
2
2
|
/**
|
|
3
3
|
* TransactionSession manages incremental transaction building.
|
|
4
4
|
*
|
|
@@ -11,7 +11,7 @@ import { createTransactionStamp, createTransactionId } from "./transaction.js";
|
|
|
11
11
|
* - The Transaction is then committed through coordinator.commit() for PEND/COMMIT orchestration
|
|
12
12
|
*
|
|
13
13
|
* Usage:
|
|
14
|
-
* const session =
|
|
14
|
+
* const session = await TransactionSession.create(coordinator, engine);
|
|
15
15
|
* await session.execute('INSERT INTO users (id, name) VALUES (?, ?)', [1, 'Alice']);
|
|
16
16
|
* await session.execute('SELECT * FROM orders WHERE user_id = ?', [1]);
|
|
17
17
|
* const result = await session.commit();
|
|
@@ -25,14 +25,19 @@ export class TransactionSession {
|
|
|
25
25
|
stamp;
|
|
26
26
|
committed = false;
|
|
27
27
|
rolledBack = false;
|
|
28
|
-
constructor(coordinator, engine,
|
|
29
|
-
schemaHash = '' // TODO: Get from engine
|
|
30
|
-
) {
|
|
28
|
+
constructor(coordinator, engine, stamp) {
|
|
31
29
|
this.coordinator = coordinator;
|
|
32
30
|
this.engine = engine;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
this.stamp = stamp;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create a new TransactionSession.
|
|
35
|
+
* Uses async factory because stamp creation requires SHA-256 hashing.
|
|
36
|
+
*/
|
|
37
|
+
static async create(coordinator, engine, peerId = 'local', schemaHash = '', ttlMs) {
|
|
38
|
+
const stamp = await createTransactionStamp(peerId, Date.now(), schemaHash, 'unknown', // TODO: Get engine ID from engine
|
|
39
|
+
ttlMs);
|
|
40
|
+
return new TransactionSession(coordinator, engine, stamp);
|
|
36
41
|
}
|
|
37
42
|
/**
|
|
38
43
|
* Execute a statement.
|
|
@@ -96,24 +101,31 @@ export class TransactionSession {
|
|
|
96
101
|
if (this.rolledBack) {
|
|
97
102
|
return { success: false, error: 'Transaction already rolled back' };
|
|
98
103
|
}
|
|
104
|
+
if (isTransactionExpired(this.stamp)) {
|
|
105
|
+
return { success: false, error: `Transaction expired at ${this.stamp.expiration}` };
|
|
106
|
+
}
|
|
107
|
+
// Collect read dependencies from all participating collections
|
|
108
|
+
const reads = this.coordinator.getReadDependencies();
|
|
99
109
|
// Create the complete transaction
|
|
100
110
|
const transaction = {
|
|
101
111
|
stamp: this.stamp,
|
|
102
112
|
statements: this.statements,
|
|
103
|
-
reads
|
|
104
|
-
id: createTransactionId(this.stamp.id, this.statements,
|
|
113
|
+
reads,
|
|
114
|
+
id: await createTransactionId(this.stamp.id, this.statements, reads)
|
|
105
115
|
};
|
|
106
116
|
// Commit through coordinator (which will orchestrate PEND/COMMIT)
|
|
107
117
|
await this.coordinator.commit(transaction);
|
|
118
|
+
// Clear read dependencies after successful commit
|
|
119
|
+
this.coordinator.clearReadDependencies();
|
|
108
120
|
this.committed = true;
|
|
109
121
|
return { success: true };
|
|
110
122
|
}
|
|
111
123
|
/**
|
|
112
|
-
* Rollback the transaction (
|
|
124
|
+
* Rollback the transaction (undo this session's applied actions).
|
|
113
125
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
126
|
+
* Delegates to coordinator.rollback(stampId) which restores collection
|
|
127
|
+
* trackers to the pre-session snapshot and replays any later sessions'
|
|
128
|
+
* actions to preserve their transforms.
|
|
117
129
|
*/
|
|
118
130
|
async rollback() {
|
|
119
131
|
if (this.committed) {
|
|
@@ -124,6 +136,7 @@ export class TransactionSession {
|
|
|
124
136
|
}
|
|
125
137
|
// Rollback through coordinator
|
|
126
138
|
await this.coordinator.rollback(this.stamp.id);
|
|
139
|
+
this.coordinator.clearReadDependencies();
|
|
127
140
|
this.rolledBack = true;
|
|
128
141
|
this.statements.length = 0;
|
|
129
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/transaction/session.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/transaction/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,6 +15,8 @@ export type TransactionStamp = {
|
|
|
15
15
|
schemaHash: string;
|
|
16
16
|
/** Which engine (e.g., 'quereus@0.5.3', 'actions@1.0.0') */
|
|
17
17
|
engineId: string;
|
|
18
|
+
/** Absolute ms epoch after which transaction is invalid */
|
|
19
|
+
expiration: number;
|
|
18
20
|
/** Hash of the stamp fields (computed) - stable identifier throughout transaction */
|
|
19
21
|
id: string;
|
|
20
22
|
};
|
|
@@ -54,16 +56,20 @@ export type ReadDependency = {
|
|
|
54
56
|
* Just the transaction ID - full transaction can be looked up separately if needed.
|
|
55
57
|
*/
|
|
56
58
|
export type TransactionRef = string;
|
|
59
|
+
/** Default transaction time-to-live in milliseconds (30 seconds). */
|
|
60
|
+
export declare const DEFAULT_TRANSACTION_TTL_MS = 30000;
|
|
61
|
+
/** Check whether a transaction stamp has expired. */
|
|
62
|
+
export declare function isTransactionExpired(stamp: TransactionStamp): boolean;
|
|
57
63
|
/**
|
|
58
64
|
* Create a transaction stamp with computed id.
|
|
59
|
-
* The id is a hash of the stamp fields.
|
|
65
|
+
* The id is a hash of the stamp fields (including expiration).
|
|
60
66
|
*/
|
|
61
|
-
export declare function createTransactionStamp(peerId: string, timestamp: number, schemaHash: string, engineId: string): TransactionStamp
|
|
67
|
+
export declare function createTransactionStamp(peerId: string, timestamp: number, schemaHash: string, engineId: string, ttlMs?: number): Promise<TransactionStamp>;
|
|
62
68
|
/**
|
|
63
69
|
* Create a transaction id from stamp id, statements, and reads.
|
|
64
70
|
* This is the final transaction identity used in logs.
|
|
65
71
|
*/
|
|
66
|
-
export declare function createTransactionId(stampId: string, statements: string[], reads: ReadDependency[]): string
|
|
72
|
+
export declare function createTransactionId(stampId: string, statements: string[], reads: ReadDependency[]): Promise<string>;
|
|
67
73
|
/**
|
|
68
74
|
* Transaction engine interface.
|
|
69
75
|
* Pluggable engines implement this to process transaction statements.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../../src/transaction/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG3D;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC9B,0CAA0C;IAC1C,MAAM,EAAE,MAAM,CAAC;IAEf,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAElB,+CAA+C;IAC/C,UAAU,EAAE,MAAM,CAAC;IAEnB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAC;IAEjB,qFAAqF;IACrF,EAAE,EAAE,MAAM,CAAC;CACX,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG;IACzB,iDAAiD;IACjD,KAAK,EAAE,gBAAgB,CAAC;IAExB;;;;OAIG;IACH,UAAU,EAAE,MAAM,EAAE,CAAC;IAErB,2DAA2D;IAC3D,KAAK,EAAE,cAAc,EAAE,CAAC;IAExB;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;CACX,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,CAAC;AAEpC;;;GAGG;AACH,
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../../../src/transaction/transaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
import { hashString } from "../utility/hash-string.js";
|
|
2
|
+
/** Default transaction time-to-live in milliseconds (30 seconds). */
|
|
3
|
+
export const DEFAULT_TRANSACTION_TTL_MS = 30_000;
|
|
4
|
+
/** Check whether a transaction stamp has expired. */
|
|
5
|
+
export function isTransactionExpired(stamp) {
|
|
6
|
+
return Date.now() > stamp.expiration;
|
|
7
|
+
}
|
|
2
8
|
/**
|
|
3
9
|
* Create a transaction stamp with computed id.
|
|
4
|
-
* The id is a hash of the stamp fields.
|
|
10
|
+
* The id is a hash of the stamp fields (including expiration).
|
|
5
11
|
*/
|
|
6
|
-
export function createTransactionStamp(peerId, timestamp, schemaHash, engineId) {
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
12
|
+
export async function createTransactionStamp(peerId, timestamp, schemaHash, engineId, ttlMs = DEFAULT_TRANSACTION_TTL_MS) {
|
|
13
|
+
const expiration = timestamp + ttlMs;
|
|
14
|
+
const stampData = JSON.stringify({ peerId, timestamp, schemaHash, engineId, expiration });
|
|
15
|
+
const id = `stamp:${await hashString(stampData)}`;
|
|
16
|
+
return { peerId, timestamp, schemaHash, engineId, expiration, id };
|
|
10
17
|
}
|
|
11
18
|
/**
|
|
12
19
|
* Create a transaction id from stamp id, statements, and reads.
|
|
13
20
|
* This is the final transaction identity used in logs.
|
|
14
21
|
*/
|
|
15
|
-
export function createTransactionId(stampId, statements, reads) {
|
|
22
|
+
export async function createTransactionId(stampId, statements, reads) {
|
|
16
23
|
const txData = JSON.stringify({ stampId, statements, reads });
|
|
17
|
-
return `tx:${hashString(txData)}`;
|
|
24
|
+
return `tx:${await hashString(txData)}`;
|
|
18
25
|
}
|
|
19
26
|
/**
|
|
20
27
|
* Helper to create an actions-based transaction statements array.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../../src/transaction/transaction.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../../src/transaction/transaction.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAsEvD,qEAAqE;AACrE,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AAEjD,qDAAqD;AACrD,MAAM,UAAU,oBAAoB,CAAC,KAAuB;IAC3D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC3C,MAAc,EACd,SAAiB,EACjB,UAAkB,EAClB,QAAgB,EAChB,QAAgB,0BAA0B;IAE1C,MAAM,UAAU,GAAG,SAAS,GAAG,KAAK,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAC1F,MAAM,EAAE,GAAG,SAAS,MAAM,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;IAClD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;AACpE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACxC,OAAe,EACf,UAAoB,EACpB,KAAuB;IAEvB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9D,OAAO,MAAM,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;AACzC,CAAC;AAmDD;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,WAAgC;IACvE,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { CollectionId, Transforms } from '../index.js';
|
|
1
|
+
import type { BlockId, CollectionId, Transforms } from '../index.js';
|
|
2
2
|
import type { Transaction, ITransactionEngine, ITransactionValidator, ValidationResult, CollectionActions } from './transaction.js';
|
|
3
|
+
import type { BlockActionState } from '../network/struct.js';
|
|
3
4
|
/**
|
|
4
5
|
* Engine registration for validation.
|
|
5
6
|
*/
|
|
@@ -21,6 +22,11 @@ export type ValidationCoordinatorFactory = () => {
|
|
|
21
22
|
/** Dispose of the validation coordinator */
|
|
22
23
|
dispose(): void;
|
|
23
24
|
};
|
|
25
|
+
/**
|
|
26
|
+
* Provides current block state for read dependency validation.
|
|
27
|
+
* Returns the latest BlockActionState for a given block, or undefined if the block doesn't exist.
|
|
28
|
+
*/
|
|
29
|
+
export type BlockStateProvider = (blockId: BlockId) => Promise<BlockActionState | undefined>;
|
|
24
30
|
/**
|
|
25
31
|
* Transaction validator implementation.
|
|
26
32
|
*
|
|
@@ -30,7 +36,8 @@ export type ValidationCoordinatorFactory = () => {
|
|
|
30
36
|
export declare class TransactionValidator implements ITransactionValidator {
|
|
31
37
|
private readonly engines;
|
|
32
38
|
private readonly createValidationCoordinator;
|
|
33
|
-
|
|
39
|
+
private readonly blockStateProvider?;
|
|
40
|
+
constructor(engines: Map<string, EngineRegistration>, createValidationCoordinator: ValidationCoordinatorFactory, blockStateProvider?: BlockStateProvider | undefined);
|
|
34
41
|
validate(transaction: Transaction, operationsHash: string): Promise<ValidationResult>;
|
|
35
42
|
getSchemaHash(engineId: string): Promise<string | undefined>;
|
|
36
43
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/transaction/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../../src/transaction/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAA2B,UAAU,EAAe,MAAM,aAAa,CAAC;AAC3G,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,gBAAgB,EAAE,iBAAiB,EAAkB,MAAM,kBAAkB,CAAC;AACpJ,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAe7D;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAChC,sCAAsC;IACtC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,kDAAkD;IAClD,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,4BAA4B,GAAG,MAAM;IAChD,qDAAqD;IACrD,YAAY,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3E,mDAAmD;IACnD,aAAa,IAAI,GAAG,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC;IAC/C,4CAA4C;IAC5C,OAAO,IAAI,IAAI,CAAC;CAChB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC;AAE7F;;;;;GAKG;AACH,qBAAa,oBAAqB,YAAW,qBAAqB;IAEhE,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,2BAA2B;IAC5C,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC;gBAFnB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACxC,2BAA2B,EAAE,4BAA4B,EACzD,kBAAkB,CAAC,EAAE,kBAAkB,YAAA;IAGnD,QAAQ,CAAC,WAAW,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmFrF,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IAKlE;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAczB;;;OAGG;YACW,cAAc;CAI5B"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isTransactionExpired } from './transaction.js';
|
|
1
2
|
import { hashString } from '../utility/hash-string.js';
|
|
2
3
|
/**
|
|
3
4
|
* Transaction validator implementation.
|
|
@@ -8,12 +9,21 @@ import { hashString } from '../utility/hash-string.js';
|
|
|
8
9
|
export class TransactionValidator {
|
|
9
10
|
engines;
|
|
10
11
|
createValidationCoordinator;
|
|
11
|
-
|
|
12
|
+
blockStateProvider;
|
|
13
|
+
constructor(engines, createValidationCoordinator, blockStateProvider) {
|
|
12
14
|
this.engines = engines;
|
|
13
15
|
this.createValidationCoordinator = createValidationCoordinator;
|
|
16
|
+
this.blockStateProvider = blockStateProvider;
|
|
14
17
|
}
|
|
15
18
|
async validate(transaction, operationsHash) {
|
|
16
19
|
const { stamp, statements } = transaction;
|
|
20
|
+
// 0. Check expiration before any other work
|
|
21
|
+
if (isTransactionExpired(stamp)) {
|
|
22
|
+
return {
|
|
23
|
+
valid: false,
|
|
24
|
+
reason: `Transaction expired at ${stamp.expiration}`
|
|
25
|
+
};
|
|
26
|
+
}
|
|
17
27
|
// 1. Verify engine exists
|
|
18
28
|
const registration = this.engines.get(stamp.engineId);
|
|
19
29
|
if (!registration) {
|
|
@@ -31,8 +41,18 @@ export class TransactionValidator {
|
|
|
31
41
|
};
|
|
32
42
|
}
|
|
33
43
|
// 3. Verify read dependencies (optimistic concurrency)
|
|
34
|
-
|
|
35
|
-
|
|
44
|
+
if (this.blockStateProvider && transaction.reads.length > 0) {
|
|
45
|
+
for (const read of transaction.reads) {
|
|
46
|
+
const currentState = await this.blockStateProvider(read.blockId);
|
|
47
|
+
const currentRev = currentState?.latest?.rev ?? 0;
|
|
48
|
+
if (currentRev !== read.revision) {
|
|
49
|
+
return {
|
|
50
|
+
valid: false,
|
|
51
|
+
reason: `Stale read: block ${read.blockId} was at revision ${read.revision} but is now at ${currentRev}`
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
36
56
|
// 4. Create isolated validation coordinator
|
|
37
57
|
const validationCoordinator = this.createValidationCoordinator();
|
|
38
58
|
try {
|
|
@@ -52,7 +72,7 @@ export class TransactionValidator {
|
|
|
52
72
|
const transforms = validationCoordinator.getTransforms();
|
|
53
73
|
const allOperations = this.collectOperations(transforms);
|
|
54
74
|
// 8. Compute hash
|
|
55
|
-
const computedHash = this.hashOperations(allOperations);
|
|
75
|
+
const computedHash = await this.hashOperations(allOperations);
|
|
56
76
|
// 9. Compare with sender's hash
|
|
57
77
|
if (computedHash !== operationsHash) {
|
|
58
78
|
return {
|
|
@@ -85,9 +105,9 @@ export class TransactionValidator {
|
|
|
85
105
|
* Compute hash of all operations.
|
|
86
106
|
* Must match TransactionCoordinator.hashOperations for consistent validation.
|
|
87
107
|
*/
|
|
88
|
-
hashOperations(operations) {
|
|
108
|
+
async hashOperations(operations) {
|
|
89
109
|
const operationsData = JSON.stringify(operations);
|
|
90
|
-
return `ops:${hashString(operationsData)}`;
|
|
110
|
+
return `ops:${await hashString(operationsData)}`;
|
|
91
111
|
}
|
|
92
112
|
}
|
|
93
113
|
//# sourceMappingURL=validator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/transaction/validator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../../src/transaction/validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network-transactor.d.ts","sourceRoot":"","sources":["../../../src/transactor/network-transactor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAA6B,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAc,aAAa,EAA+B,qBAAqB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"network-transactor.d.ts","sourceRoot":"","sources":["../../../src/transactor/network-transactor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAA6B,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAc,aAAa,EAA+B,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAS5S,KAAK,qBAAqB,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,WAAW,CAAC;IACxB,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,KAAK,CAAC;CACnC,CAAA;AAED,qBAAa,iBAAkB,YAAW,WAAW;IACpD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAc;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;gBAGnD,IAAI,EAAE,qBAAqB;IAQtB,GAAG,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,eAAe,CAAC;IAuHnD,SAAS,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;YAkC7D,uBAAuB;IA+F/B,IAAI,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA2FnD,MAAM,CAAC,SAAS,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAmB9C,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAOtE,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;YAqC7C,WAAW;IAezB,0EAA0E;YAC5D,YAAY;IAkC1B,8FAA8F;YAChF,iBAAiB;IAe/B,oHAAoH;YACtG,WAAW;IAqBzB,OAAO,CAAC,mBAAmB;CAY3B;AAGD;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,gBAAgB,EAAE,GAAG,gBAAgB,EAAE,CAIlG"}
|
|
@@ -3,6 +3,8 @@ import { transformForBlockId, groupBy, concatTransforms, concatTransform, transf
|
|
|
3
3
|
import { blockIdToBytes } from "../utility/block-id-to-bytes.js";
|
|
4
4
|
import { isRecordEmpty } from "../utility/is-record-empty.js";
|
|
5
5
|
import { makeBatchesByPeer, incompleteBatches, everyBatch, allBatches, mergeBlocks, processBatches, createBatchesForPayload } from "../utility/batch-coordinator.js";
|
|
6
|
+
import { createLogger, verbose } from "../logger.js";
|
|
7
|
+
const log = createLogger('network-transactor');
|
|
6
8
|
export class NetworkTransactor {
|
|
7
9
|
keyNetwork;
|
|
8
10
|
timeoutMs;
|
|
@@ -17,6 +19,8 @@ export class NetworkTransactor {
|
|
|
17
19
|
async get(blockGets) {
|
|
18
20
|
// Group by block id
|
|
19
21
|
const distinctBlockIds = Array.from(new Set(blockGets.blockIds));
|
|
22
|
+
const t0 = Date.now();
|
|
23
|
+
log('get blockIds=%d', distinctBlockIds.length);
|
|
20
24
|
const batches = await this.batchesForPayload(distinctBlockIds, distinctBlockIds, (gets, blockId, mergeWithGets) => [...(mergeWithGets ?? []), ...gets.filter(bid => bid === blockId)], []);
|
|
21
25
|
const expiration = Date.now() + this.timeoutMs;
|
|
22
26
|
let error;
|
|
@@ -44,6 +48,7 @@ export class NetworkTransactor {
|
|
|
44
48
|
// This provides tolerance for different cluster member views
|
|
45
49
|
const retryable = Array.from(allBatches(batches)).filter(b => !hasValidResponse(b) || !hasBlockInResponse(b));
|
|
46
50
|
if (retryable.length > 0 && Date.now() < expiration) {
|
|
51
|
+
log('get:retry retryable=%d', retryable.length);
|
|
47
52
|
try {
|
|
48
53
|
const excludedByRoot = new Map();
|
|
49
54
|
for (const b of retryable) {
|
|
@@ -81,6 +86,7 @@ export class NetworkTransactor {
|
|
|
81
86
|
// Ensure we have at least one response per requested block id
|
|
82
87
|
const missingIds = distinctBlockIds.filter(bid => !resultEntries.has(bid));
|
|
83
88
|
if (missingIds.length > 0) {
|
|
89
|
+
log('get:missing blockIds=%o', missingIds);
|
|
84
90
|
const details = this.formatBatchStatuses(batches, b => b.request?.isResponse ?? false, b => {
|
|
85
91
|
const status = b.request == null ? 'no-response' : (b.request.isResponse ? 'response' : 'in-flight');
|
|
86
92
|
return `${b.peerId.toString()}[block:${b.blockId}](${status})`;
|
|
@@ -89,6 +95,7 @@ export class NetworkTransactor {
|
|
|
89
95
|
aggregate.cause = error;
|
|
90
96
|
throw aggregate;
|
|
91
97
|
}
|
|
98
|
+
log('get:done blockIds=%d ms=%d', distinctBlockIds.length, Date.now() - t0);
|
|
92
99
|
return Object.fromEntries(resultEntries);
|
|
93
100
|
}
|
|
94
101
|
async getStatus(blockActions) {
|
|
@@ -122,27 +129,75 @@ export class NetworkTransactor {
|
|
|
122
129
|
}));
|
|
123
130
|
}
|
|
124
131
|
async consolidateCoordinators(blockIds, transforms, transformForBlock) {
|
|
125
|
-
|
|
132
|
+
// Use cluster intersections to minimize the number of coordinators.
|
|
133
|
+
// For each block, find its full cluster, then greedily assign blocks to
|
|
134
|
+
// peers that appear in the most clusters — reducing round trips when
|
|
135
|
+
// blocks share cluster members.
|
|
136
|
+
// Step 1: Get cluster peer sets for each block
|
|
137
|
+
const blockClusterPeerIds = new Map();
|
|
138
|
+
const fallbackBlocks = [];
|
|
139
|
+
await Promise.all(blockIds.map(async (bid) => {
|
|
140
|
+
try {
|
|
141
|
+
const clusterPeers = await this.keyNetwork.findCluster(await blockIdToBytes(bid));
|
|
142
|
+
blockClusterPeerIds.set(bid, new Set(Object.keys(clusterPeers)));
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
fallbackBlocks.push(bid);
|
|
146
|
+
}
|
|
147
|
+
}));
|
|
148
|
+
// Step 2: Build peer → blocks index (which blocks each peer can coordinate)
|
|
149
|
+
const peerBlocks = new Map();
|
|
150
|
+
for (const [blockId, peerIds] of blockClusterPeerIds) {
|
|
151
|
+
for (const peerId of peerIds) {
|
|
152
|
+
const blocks = peerBlocks.get(peerId) ?? [];
|
|
153
|
+
blocks.push(blockId);
|
|
154
|
+
peerBlocks.set(peerId, blocks);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// Step 3: Greedy set cover — assign blocks to peers covering the most uncovered blocks
|
|
158
|
+
const uncovered = new Set(blockClusterPeerIds.keys());
|
|
159
|
+
const assignments = new Map(); // peerIdStr → assigned blockIds
|
|
160
|
+
while (uncovered.size > 0) {
|
|
161
|
+
let bestPeer;
|
|
162
|
+
let bestCount = 0;
|
|
163
|
+
for (const [peerId, blocks] of peerBlocks) {
|
|
164
|
+
const coverCount = blocks.filter(bid => uncovered.has(bid)).length;
|
|
165
|
+
if (coverCount > bestCount) {
|
|
166
|
+
bestCount = coverCount;
|
|
167
|
+
bestPeer = peerId;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (!bestPeer || bestCount === 0)
|
|
171
|
+
break;
|
|
172
|
+
const covered = peerBlocks.get(bestPeer).filter(bid => uncovered.has(bid));
|
|
173
|
+
assignments.set(bestPeer, covered);
|
|
174
|
+
for (const bid of covered)
|
|
175
|
+
uncovered.delete(bid);
|
|
176
|
+
}
|
|
177
|
+
// Step 4: Any remaining uncovered blocks fall back to findCoordinator
|
|
178
|
+
for (const bid of uncovered)
|
|
179
|
+
fallbackBlocks.push(bid);
|
|
180
|
+
const fallbackCoordinators = await Promise.all(fallbackBlocks.map(async (bid) => ({
|
|
126
181
|
blockId: bid,
|
|
127
182
|
coordinator: await this.keyNetwork.findCoordinator(await blockIdToBytes(bid), { excludedPeers: [] })
|
|
128
183
|
})));
|
|
129
|
-
const
|
|
130
|
-
for (const { blockId, coordinator } of blockCoordinators) {
|
|
184
|
+
for (const { blockId, coordinator } of fallbackCoordinators) {
|
|
131
185
|
const key = coordinator.toString();
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
186
|
+
const existing = assignments.get(key) ?? [];
|
|
187
|
+
existing.push(blockId);
|
|
188
|
+
assignments.set(key, existing);
|
|
135
189
|
}
|
|
190
|
+
// Step 5: Convert assignments to batches
|
|
136
191
|
const batches = [];
|
|
137
|
-
for (const [
|
|
138
|
-
const
|
|
192
|
+
for (const [peerIdStr, consolidatedBlocks] of assignments) {
|
|
193
|
+
const peerId = peerIdFromString(peerIdStr);
|
|
139
194
|
let batchTransforms = { inserts: {}, updates: {}, deletes: [] };
|
|
140
195
|
for (const bid of consolidatedBlocks) {
|
|
141
196
|
const blockTransforms = transformForBlock(transforms, bid, batchTransforms);
|
|
142
197
|
batchTransforms = blockTransforms;
|
|
143
198
|
}
|
|
144
199
|
batches.push({
|
|
145
|
-
peerId
|
|
200
|
+
peerId,
|
|
146
201
|
payload: batchTransforms,
|
|
147
202
|
blockId: consolidatedBlocks[0],
|
|
148
203
|
coordinatingBlockIds: consolidatedBlocks,
|
|
@@ -152,6 +207,7 @@ export class NetworkTransactor {
|
|
|
152
207
|
return batches;
|
|
153
208
|
}
|
|
154
209
|
async pend(blockAction) {
|
|
210
|
+
const t0 = Date.now();
|
|
155
211
|
const transformForBlock = (payload, blockId, mergeWithPayload) => {
|
|
156
212
|
const filteredTransform = transformForBlockId(payload, blockId);
|
|
157
213
|
return mergeWithPayload
|
|
@@ -160,6 +216,17 @@ export class NetworkTransactor {
|
|
|
160
216
|
};
|
|
161
217
|
const blockIds = blockIdsForTransforms(blockAction.transforms);
|
|
162
218
|
const batches = await this.consolidateCoordinators(blockIds, blockAction.transforms, transformForBlock);
|
|
219
|
+
log('pend actionId=%s blockIds=%d batches=%d', blockAction.actionId, blockIds.length, batches.length);
|
|
220
|
+
if (verbose) {
|
|
221
|
+
const batchSummary = batches.map(b => ({
|
|
222
|
+
peer: b.peerId.toString().substring(0, 12),
|
|
223
|
+
blocks: b.coordinatingBlockIds ?? [b.blockId],
|
|
224
|
+
inserts: Object.keys(b.payload.inserts ?? {}).length,
|
|
225
|
+
updates: Object.keys(b.payload.updates ?? {}).length,
|
|
226
|
+
deletes: b.payload.deletes?.length ?? 0
|
|
227
|
+
}));
|
|
228
|
+
log('pend:batches actionId=%s detail=%o', blockAction.actionId, batchSummary);
|
|
229
|
+
}
|
|
163
230
|
const expiration = Date.now() + this.timeoutMs;
|
|
164
231
|
let error;
|
|
165
232
|
try {
|
|
@@ -196,9 +263,11 @@ export class NetworkTransactor {
|
|
|
196
263
|
error = aggregate;
|
|
197
264
|
}
|
|
198
265
|
if (error) { // If any failures, cancel all pending actions as background microtask
|
|
266
|
+
log('pend:cancel actionId=%s', blockAction.actionId);
|
|
199
267
|
void Promise.resolve().then(() => this.cancelBatch(batches, { blockIds, actionId: blockAction.actionId }));
|
|
200
268
|
const stale = Array.from(allBatches(batches, b => b.request?.isResponse && !b.request.response.success));
|
|
201
269
|
if (stale.length > 0) { // Any active stale failures should preempt reporting connection or other potential transient errors (we have information)
|
|
270
|
+
log('pend:stale actionId=%s staleCount=%d', blockAction.actionId, stale.length);
|
|
202
271
|
return {
|
|
203
272
|
success: false,
|
|
204
273
|
missing: distinctBlockActionTransforms(stale.flatMap(b => b.request.response.missing).filter((x) => x !== undefined)),
|
|
@@ -208,6 +277,7 @@ export class NetworkTransactor {
|
|
|
208
277
|
}
|
|
209
278
|
// Collect replies back into result structure
|
|
210
279
|
const completed = Array.from(allBatches(batches, b => b.request?.isResponse && b.request.response.success));
|
|
280
|
+
log('pend:done actionId=%s ms=%d batches=%d', blockAction.actionId, Date.now() - t0, batches.length);
|
|
211
281
|
return {
|
|
212
282
|
success: true,
|
|
213
283
|
pending: completed.flatMap(b => b.request.response.pending),
|
|
@@ -215,6 +285,7 @@ export class NetworkTransactor {
|
|
|
215
285
|
};
|
|
216
286
|
}
|
|
217
287
|
async cancel(actionRef) {
|
|
288
|
+
log('cancel actionId=%s blockIds=%d', actionRef.actionId, actionRef.blockIds.length);
|
|
218
289
|
const batches = await this.batchesForPayload(actionRef.blockIds, actionRef.blockIds, mergeBlocks, []);
|
|
219
290
|
const expiration = Date.now() + this.abortOrCancelTimeoutMs;
|
|
220
291
|
await processBatches(batches, (batch) => this.getRepo(batch.peerId).cancel({ actionId: actionRef.actionId, blockIds: batch.payload }, { expiration }), batch => batch.payload, mergeBlocks, expiration, async (blockId, options) => this.keyNetwork.findCoordinator(await blockIdToBytes(blockId), options));
|
|
@@ -226,6 +297,8 @@ export class NetworkTransactor {
|
|
|
226
297
|
return { nominees };
|
|
227
298
|
}
|
|
228
299
|
async commit(request) {
|
|
300
|
+
const t0 = Date.now();
|
|
301
|
+
log('commit actionId=%s rev=%d blockIds=%d', request.actionId, request.rev, request.blockIds.length);
|
|
229
302
|
const allBlockIds = [...new Set([...request.blockIds, request.tailId])];
|
|
230
303
|
// Commit the header block if provided and not already in blockIds
|
|
231
304
|
if (request.headerId && !request.blockIds.includes(request.headerId)) {
|
|
@@ -253,6 +326,7 @@ export class NetworkTransactor {
|
|
|
253
326
|
catch { /* ignore */ }
|
|
254
327
|
}
|
|
255
328
|
}
|
|
329
|
+
log('commit:done actionId=%s ms=%d', request.actionId, Date.now() - t0);
|
|
256
330
|
return { success: true };
|
|
257
331
|
}
|
|
258
332
|
async commitBlock(blockId, blockIds, actionId, rev) {
|
|
@@ -273,6 +347,7 @@ export class NetworkTransactor {
|
|
|
273
347
|
async commitBlocks({ blockIds, actionId, rev }) {
|
|
274
348
|
const expiration = Date.now() + this.timeoutMs;
|
|
275
349
|
const batches = await this.batchesForPayload(blockIds, blockIds, mergeBlocks, []);
|
|
350
|
+
log('commitBlocks actionId=%s rev=%d batches=%d', actionId, rev, batches.length);
|
|
276
351
|
let error;
|
|
277
352
|
try {
|
|
278
353
|
await processBatches(batches, (batch) => this.getRepo(batch.peerId).commit({ actionId, blockIds: batch.payload, rev }, { expiration }), batch => batch.payload, mergeBlocks, expiration, async (blockId, options) => this.keyNetwork.findCoordinator(await blockIdToBytes(blockId), options));
|