@optimystic/db-core 0.5.2 → 0.6.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 +3 -0
- package/dist/src/collection/collection.d.ts.map +1 -1
- package/dist/src/collection/collection.js +6 -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 +9 -1
- package/dist/src/transaction/coordinator.d.ts.map +1 -1
- package/dist/src/transaction/coordinator.js +76 -8
- 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 +7 -3
- package/dist/src/transaction/session.d.ts.map +1 -1
- package/dist/src/transaction/session.js +23 -10
- 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.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 +9 -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 +86 -9
- package/src/transaction/index.ts +4 -2
- package/src/transaction/session.ts +34 -10
- package/src/transaction/transaction.ts +23 -10
- package/src/transaction/validator.ts +34 -7
- package/src/transactor/network-transactor.ts +92 -11
- 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 +7 -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
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Pending } from "./pending.js";
|
|
2
|
+
import { createLogger } from "../logger.js";
|
|
3
|
+
const log = createLogger('batch-coordinator');
|
|
2
4
|
/**
|
|
3
5
|
* Creates batches for a given payload, grouped by the coordinating peer for each block id
|
|
4
6
|
*/
|
|
@@ -93,6 +95,7 @@ export async function processBatches(batches, process, getBlockIds, getBlockPayl
|
|
|
93
95
|
.catch(async (e) => {
|
|
94
96
|
if (expiration > Date.now()) {
|
|
95
97
|
const excludedPeers = [batch.peerId, ...(batch.excludedPeers ?? [])];
|
|
98
|
+
log('retry peer=%s excluded=%d', batch.peerId.toString(), excludedPeers.length);
|
|
96
99
|
const retries = await createBatchesForPayload(getBlockIds(batch), batch.payload, getBlockPayload, excludedPeers, findCoordinator);
|
|
97
100
|
if (retries.length > 0 && expiration > Date.now()) {
|
|
98
101
|
const root = rootOf.get(batch) ?? batch;
|
|
@@ -121,6 +124,8 @@ export async function createBatchesForPayload(blockIds, payload, getBlockPayload
|
|
|
121
124
|
// Find coordinator for each key
|
|
122
125
|
const blockIdPeerId = await Promise.all(Array.from(distinctBlockIds).map(async (bid) => [bid, await findCoordinator(bid, { excludedPeers })]));
|
|
123
126
|
// Group blocks around their coordinating peers
|
|
124
|
-
|
|
127
|
+
const batches = makeBatchesByPeer(blockIdPeerId, payload, getBlockPayload, excludedPeers);
|
|
128
|
+
log('createBatches blockIds=%d batches=%d excluded=%d', distinctBlockIds.size, batches.length, excludedPeers.length);
|
|
129
|
+
return batches;
|
|
125
130
|
}
|
|
126
131
|
//# sourceMappingURL=batch-coordinator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"batch-coordinator.js","sourceRoot":"","sources":["../../../src/utility/batch-coordinator.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"batch-coordinator.js","sourceRoot":"","sources":["../../../src/utility/batch-coordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* This is a non-cryptographic hash suitable for generating short identifiers.
|
|
5
|
-
* For security-critical hashing, use SHA-256 from multiformats/hashes/sha2.
|
|
2
|
+
* SHA-256 string hash function.
|
|
6
3
|
*
|
|
7
4
|
* @param str - The string to hash
|
|
8
|
-
* @returns A
|
|
5
|
+
* @returns A base64url-encoded SHA-256 hash string
|
|
9
6
|
*/
|
|
10
|
-
export declare function hashString(str: string): string
|
|
7
|
+
export declare function hashString(str: string): Promise<string>;
|
|
11
8
|
//# sourceMappingURL=hash-string.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash-string.d.ts","sourceRoot":"","sources":["../../../src/utility/hash-string.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hash-string.d.ts","sourceRoot":"","sources":["../../../src/utility/hash-string.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAI7D"}
|
|
@@ -1,17 +1,14 @@
|
|
|
1
|
+
import { sha256 } from 'multiformats/hashes/sha2';
|
|
2
|
+
import { toString } from 'uint8arrays/to-string';
|
|
1
3
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* This is a non-cryptographic hash suitable for generating short identifiers.
|
|
5
|
-
* For security-critical hashing, use SHA-256 from multiformats/hashes/sha2.
|
|
4
|
+
* SHA-256 string hash function.
|
|
6
5
|
*
|
|
7
6
|
* @param str - The string to hash
|
|
8
|
-
* @returns A
|
|
7
|
+
* @returns A base64url-encoded SHA-256 hash string
|
|
9
8
|
*/
|
|
10
|
-
export function hashString(str) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
return Math.abs(hash).toString(36);
|
|
9
|
+
export async function hashString(str) {
|
|
10
|
+
const input = new TextEncoder().encode(str);
|
|
11
|
+
const mh = await sha256.digest(input);
|
|
12
|
+
return toString(mh.digest, 'base64url');
|
|
16
13
|
}
|
|
17
14
|
//# sourceMappingURL=hash-string.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash-string.js","sourceRoot":"","sources":["../../../src/utility/hash-string.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"hash-string.js","sourceRoot":"","sources":["../../../src/utility/hash-string.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC3C,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,EAAE,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACtC,OAAO,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;AACzC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple LRU (Least Recently Used) map backed by JavaScript's Map insertion order.
|
|
3
|
+
* Accessing or setting an entry refreshes it to the most-recently-used position.
|
|
4
|
+
* When the map exceeds maxSize, the least-recently-used entry is evicted.
|
|
5
|
+
*/
|
|
6
|
+
export declare class LruMap<K, V> {
|
|
7
|
+
private readonly maxSize;
|
|
8
|
+
private readonly map;
|
|
9
|
+
constructor(maxSize: number);
|
|
10
|
+
get(key: K): V | undefined;
|
|
11
|
+
set(key: K, value: V): this;
|
|
12
|
+
has(key: K): boolean;
|
|
13
|
+
delete(key: K): boolean;
|
|
14
|
+
clear(): void;
|
|
15
|
+
get size(): number;
|
|
16
|
+
[Symbol.iterator](): IterableIterator<[K, V]>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=lru-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lru-map.d.ts","sourceRoot":"","sources":["../../../src/utility/lru-map.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,MAAM,CAAC,CAAC,EAAE,CAAC;IAGX,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAmB;gBAEV,OAAO,EAAE,MAAM;IAI5C,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,SAAS;IAU1B,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI;IAa3B,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAIpB,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO;IAIvB,KAAK,IAAI,IAAI;IAIb,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAG7C"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A simple LRU (Least Recently Used) map backed by JavaScript's Map insertion order.
|
|
3
|
+
* Accessing or setting an entry refreshes it to the most-recently-used position.
|
|
4
|
+
* When the map exceeds maxSize, the least-recently-used entry is evicted.
|
|
5
|
+
*/
|
|
6
|
+
export class LruMap {
|
|
7
|
+
maxSize;
|
|
8
|
+
map = new Map();
|
|
9
|
+
constructor(maxSize) {
|
|
10
|
+
this.maxSize = maxSize;
|
|
11
|
+
if (maxSize < 1)
|
|
12
|
+
throw new Error('LruMap maxSize must be >= 1');
|
|
13
|
+
}
|
|
14
|
+
get(key) {
|
|
15
|
+
const value = this.map.get(key);
|
|
16
|
+
if (value !== undefined) {
|
|
17
|
+
// Refresh: delete and re-insert to move to end (most recent)
|
|
18
|
+
this.map.delete(key);
|
|
19
|
+
this.map.set(key, value);
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
set(key, value) {
|
|
24
|
+
// If already present, delete first to refresh position
|
|
25
|
+
if (this.map.has(key)) {
|
|
26
|
+
this.map.delete(key);
|
|
27
|
+
}
|
|
28
|
+
else if (this.map.size >= this.maxSize) {
|
|
29
|
+
// Evict the oldest (first) entry
|
|
30
|
+
const oldest = this.map.keys().next().value;
|
|
31
|
+
this.map.delete(oldest);
|
|
32
|
+
}
|
|
33
|
+
this.map.set(key, value);
|
|
34
|
+
return this;
|
|
35
|
+
}
|
|
36
|
+
has(key) {
|
|
37
|
+
return this.map.has(key);
|
|
38
|
+
}
|
|
39
|
+
delete(key) {
|
|
40
|
+
return this.map.delete(key);
|
|
41
|
+
}
|
|
42
|
+
clear() {
|
|
43
|
+
this.map.clear();
|
|
44
|
+
}
|
|
45
|
+
get size() {
|
|
46
|
+
return this.map.size;
|
|
47
|
+
}
|
|
48
|
+
[Symbol.iterator]() {
|
|
49
|
+
return this.map[Symbol.iterator]();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=lru-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lru-map.js","sourceRoot":"","sources":["../../../src/utility/lru-map.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,MAAM;IAGW;IAFZ,GAAG,GAAG,IAAI,GAAG,EAAQ,CAAC;IAEvC,YAA6B,OAAe;QAAf,YAAO,GAAP,OAAO,CAAQ;QAC3C,IAAI,OAAO,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACjE,CAAC;IAED,GAAG,CAAC,GAAM;QACT,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,6DAA6D;YAC7D,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACrB,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,GAAG,CAAC,GAAM,EAAE,KAAQ;QACnB,uDAAuD;QACvD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;aAAM,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC1C,iCAAiC;YACjC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAM,CAAC;YAC7C,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACzB,OAAO,IAAI,CAAC;IACb,CAAC;IAED,GAAG,CAAC,GAAM;QACT,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,CAAC,GAAM;QACZ,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK;QACJ,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;IAED,IAAI,IAAI;QACP,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IACtB,CAAC;IAED,CAAC,MAAM,CAAC,QAAQ,CAAC;QAChB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;IACpC,CAAC;CACD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@optimystic/db-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Core database functionality for Optimystic",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
".": {
|
|
16
16
|
"types": "./dist/src/index.d.ts",
|
|
17
17
|
"import": "./dist/src/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./test": {
|
|
20
|
+
"types": "./dist/test/test-transactor.d.ts",
|
|
21
|
+
"import": "./dist/test/test-transactor.js"
|
|
18
22
|
}
|
|
19
23
|
},
|
|
20
24
|
"repository": {
|
|
@@ -36,12 +40,9 @@
|
|
|
36
40
|
"acid"
|
|
37
41
|
],
|
|
38
42
|
"scripts": {
|
|
39
|
-
"clean": "
|
|
40
|
-
"build": "
|
|
41
|
-
"
|
|
42
|
-
"test": "aegir test",
|
|
43
|
-
"test:node": "aegir test -t node",
|
|
44
|
-
"dep-check": "aegir dep-check"
|
|
43
|
+
"clean": "rimraf dist",
|
|
44
|
+
"build": "tsc",
|
|
45
|
+
"test": "node --import ./register.mjs node_modules/mocha/bin/mocha.js \"test/**/*.spec.ts\" --colors --reporter min"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|
|
47
48
|
"@libp2p/crypto": "^5.1.13",
|
|
@@ -49,9 +50,15 @@
|
|
|
49
50
|
"@libp2p/peer-id": "^6.0.4",
|
|
50
51
|
"@libp2p/peer-id-factory": "^4.2.4",
|
|
51
52
|
"@multiformats/multiaddr": "^13.0.1",
|
|
53
|
+
"@types/chai-as-promised": "^8.0.2",
|
|
54
|
+
"@types/debug": "^4.1.12",
|
|
52
55
|
"@types/mocha": "^10.0.10",
|
|
53
56
|
"@types/node": "^25.1.0",
|
|
54
|
-
"
|
|
57
|
+
"chai": "^6.2.2",
|
|
58
|
+
"chai-as-promised": "^8.0.2",
|
|
59
|
+
"mocha": "^11.7.5",
|
|
60
|
+
"rimraf": "^6.1.2",
|
|
61
|
+
"ts-node": "^10.9.2",
|
|
55
62
|
"typescript": "^5.9.3"
|
|
56
63
|
},
|
|
57
64
|
"dependencies": {
|
package/src/btree/btree.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { apply, get } from "../blocks/index.js";
|
|
|
4
4
|
import { TreeLeafBlockType, TreeBranchBlockType, entries$, nodes$, partitions$ } from "./nodes.js";
|
|
5
5
|
import type { BranchNode, ITreeNode, LeafNode } from "./nodes.js";
|
|
6
6
|
import type { TreeBlock } from "./tree-block.js";
|
|
7
|
+
import { AtomicProxy } from "../transform/atomic-proxy.js";
|
|
7
8
|
|
|
8
9
|
export const NodeCapacity = 64;
|
|
9
10
|
|
|
@@ -15,6 +16,7 @@ export const NodeCapacity = 64;
|
|
|
15
16
|
*/
|
|
16
17
|
export class BTree<TKey, TEntry> {
|
|
17
18
|
protected _version = 0; // only for path invalidation
|
|
19
|
+
private _proxy?: AtomicProxy<ITreeNode>;
|
|
18
20
|
|
|
19
21
|
/**
|
|
20
22
|
* @param [compare=(a: TKey, b: TKey) => a < b ? -1 : a > b ? 1 : 0] a comparison function for keys. The default uses < and > operators.
|
|
@@ -28,6 +30,10 @@ export class BTree<TKey, TEntry> {
|
|
|
28
30
|
) {
|
|
29
31
|
}
|
|
30
32
|
|
|
33
|
+
private atomic<T>(fn: () => Promise<T>): Promise<T> {
|
|
34
|
+
return this._proxy ? this._proxy.atomic(fn) : fn();
|
|
35
|
+
}
|
|
36
|
+
|
|
31
37
|
static createRoot(
|
|
32
38
|
store: BlockStore<ITreeNode>
|
|
33
39
|
) {
|
|
@@ -41,10 +47,13 @@ export class BTree<TKey, TEntry> {
|
|
|
41
47
|
compare = (a: TKey, b: TKey) => a < b ? -1 : a > b ? 1 : 0,
|
|
42
48
|
newId?: BlockId,
|
|
43
49
|
) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
const proxy = new AtomicProxy(store);
|
|
51
|
+
const root = BTree.createRoot(proxy as BlockStore<TreeBlock>);
|
|
52
|
+
proxy.insert(root);
|
|
53
|
+
const trunk = createTrunk(proxy as BlockStore<TreeBlock>, root.header.id, newId);
|
|
54
|
+
const tree = new BTree(proxy, trunk, keyFromEntry, compare);
|
|
55
|
+
tree._proxy = proxy;
|
|
56
|
+
return tree;
|
|
48
57
|
}
|
|
49
58
|
|
|
50
59
|
/** @returns a path to the first entry (on = false if no entries) */
|
|
@@ -118,12 +127,14 @@ export class BTree<TKey, TEntry> {
|
|
|
118
127
|
* Added entries are frozen to ensure immutability
|
|
119
128
|
* @returns path to the new (on = true) or conflicting (on = false) row. */
|
|
120
129
|
async insert(entry: TEntry): Promise<Path<TKey, TEntry>> {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
path.
|
|
125
|
-
|
|
126
|
-
|
|
130
|
+
return this.atomic(async () => {
|
|
131
|
+
Object.freeze(entry); // Ensure immutability
|
|
132
|
+
const path = await this.internalInsert(entry);
|
|
133
|
+
if (path.on) {
|
|
134
|
+
path.version = ++this._version;
|
|
135
|
+
}
|
|
136
|
+
return path;
|
|
137
|
+
});
|
|
127
138
|
}
|
|
128
139
|
|
|
129
140
|
/** Updates the entry at the given path to the given value. Deletes and inserts if the key changes.
|
|
@@ -135,30 +146,34 @@ export class BTree<TKey, TEntry> {
|
|
|
135
146
|
* * wasUpdate = true, given path is not on an entry
|
|
136
147
|
* * else newEntry's new key already present; returned path is "near" existing entry */
|
|
137
148
|
async updateAt(path: Path<TKey, TEntry>, newEntry: TEntry): Promise<[path: Path<TKey, TEntry>, wasUpdate: boolean]> {
|
|
138
|
-
this.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
result[0].
|
|
145
|
-
|
|
146
|
-
|
|
149
|
+
return this.atomic(async () => {
|
|
150
|
+
this.validatePath(path);
|
|
151
|
+
if (path.on) {
|
|
152
|
+
Object.freeze(newEntry);
|
|
153
|
+
}
|
|
154
|
+
const result = await this.internalUpdate(path, newEntry);
|
|
155
|
+
if (result[0].on) {
|
|
156
|
+
result[0].version = ++this._version;
|
|
157
|
+
}
|
|
158
|
+
return result;
|
|
159
|
+
});
|
|
147
160
|
}
|
|
148
161
|
|
|
149
162
|
/** Inserts the entry if it doesn't exist, or updates it if it does.
|
|
150
163
|
* The entry is frozen to ensure immutability.
|
|
151
164
|
* @returns path to the new entry. on = true if existing; on = false if new. */
|
|
152
165
|
async upsert(entry: TEntry): Promise<Path<TKey, TEntry>> {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
166
|
+
return this.atomic(async () => {
|
|
167
|
+
const path = await this.find(this.keyFromEntry(entry));
|
|
168
|
+
Object.freeze(entry);
|
|
169
|
+
if (path.on) {
|
|
170
|
+
this.updateEntry(path, entry);
|
|
171
|
+
} else {
|
|
172
|
+
await this.internalInsertAt(path, entry);
|
|
173
|
+
}
|
|
174
|
+
path.version = ++this._version;
|
|
175
|
+
return path;
|
|
176
|
+
});
|
|
162
177
|
}
|
|
163
178
|
|
|
164
179
|
/** Inserts or updates depending on the existence of the given key, using callbacks to generate the new value.
|
|
@@ -167,18 +182,20 @@ export class BTree<TKey, TEntry> {
|
|
|
167
182
|
* @returns path to new entry and whether an update or insert attempted.
|
|
168
183
|
* If getUpdated callback returns a row that is already present, the resulting path will not be on. */
|
|
169
184
|
async merge(newEntry: TEntry, getUpdated: (existing: TEntry) => TEntry): Promise<[path: Path<TKey, TEntry>, wasUpdate: boolean]> {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
185
|
+
return this.atomic(async () => {
|
|
186
|
+
const newKey = await this.keyFromEntry(newEntry);
|
|
187
|
+
const path = await this.find(newKey);
|
|
188
|
+
if (path.on) {
|
|
189
|
+
const result = await this.updateAt(path, getUpdated(this.getEntry(path))); // Don't use internalUpdate - need to freeze and check for mutation
|
|
190
|
+
// Note: updateAt already increments version, so don't double-increment here
|
|
191
|
+
return result;
|
|
192
|
+
} else {
|
|
193
|
+
await this.internalInsertAt(path, Object.freeze(newEntry));
|
|
194
|
+
path.on = true;
|
|
195
|
+
path.version = ++this._version;
|
|
196
|
+
return [path, false];
|
|
197
|
+
}
|
|
198
|
+
});
|
|
182
199
|
}
|
|
183
200
|
|
|
184
201
|
/** Deletes the entry at the given path.
|
|
@@ -186,19 +203,23 @@ export class BTree<TKey, TEntry> {
|
|
|
186
203
|
* @returns true if the delete succeeded (the key was found); false otherwise.
|
|
187
204
|
*/
|
|
188
205
|
async deleteAt(path: Path<TKey, TEntry>): Promise<boolean> {
|
|
189
|
-
this.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
206
|
+
return this.atomic(async () => {
|
|
207
|
+
this.validatePath(path);
|
|
208
|
+
const result = await this.internalDelete(path);
|
|
209
|
+
if (result) {
|
|
210
|
+
++this._version;
|
|
211
|
+
}
|
|
212
|
+
return result;
|
|
213
|
+
});
|
|
195
214
|
}
|
|
196
215
|
|
|
197
216
|
async drop() { // Node: only when a root treeBlock
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
this.
|
|
201
|
-
|
|
217
|
+
return this.atomic(async () => {
|
|
218
|
+
const root = await this.trunk.get();
|
|
219
|
+
for await (const id of this.nodeIds(root)) {
|
|
220
|
+
this.store.delete(id);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
202
223
|
}
|
|
203
224
|
|
|
204
225
|
/** Iterates forward starting from the path location (inclusive) to the end.
|
package/src/cluster/structs.ts
CHANGED
|
@@ -27,6 +27,13 @@ export type ClusterRecord = {
|
|
|
27
27
|
networkSizeHint?: number;
|
|
28
28
|
/** Confidence in the network size estimate (0-1) */
|
|
29
29
|
networkSizeConfidence?: number;
|
|
30
|
+
/** Transaction proceeded despite minority rejections */
|
|
31
|
+
disputed?: boolean;
|
|
32
|
+
/** Evidence of the dispute: which peers rejected and why */
|
|
33
|
+
disputeEvidence?: {
|
|
34
|
+
rejectingPeers: string[];
|
|
35
|
+
rejectReasons: { [peerId: string]: string };
|
|
36
|
+
};
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
export interface ClusterConsensusConfig {
|
|
@@ -42,4 +49,8 @@ export interface ClusterConsensusConfig {
|
|
|
42
49
|
clusterSizeTolerance: number;
|
|
43
50
|
/** Window for detecting partition in milliseconds (default 60000 = 1 min) */
|
|
44
51
|
partitionDetectionWindow: number;
|
|
52
|
+
/** Enable dispute escalation protocol (default false) */
|
|
53
|
+
disputeEnabled?: boolean;
|
|
54
|
+
/** Timeout for dispute arbitration in milliseconds (default 60000) */
|
|
55
|
+
disputeArbitrationTimeoutMs?: number;
|
|
45
56
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { IBlock, Action, ActionType, ActionHandler, BlockId, ITransactor, BlockStore } from "../index.js";
|
|
2
2
|
import { Log, Atomic, Tracker, copyTransforms, CacheSource, isTransformsEmpty, TransactorSource } from "../index.js";
|
|
3
3
|
import type { CollectionHeaderBlock, CollectionId, ICollection } from "./index.js";
|
|
4
|
+
import type { ReadDependency } from "../transaction/transaction.js";
|
|
4
5
|
import { randomBytes } from '@noble/hashes/utils.js';
|
|
5
6
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
|
|
6
7
|
import { Latches } from "../utility/latches.js";
|
|
@@ -207,6 +208,14 @@ export class Collection<TAction> implements ICollection<TAction> {
|
|
|
207
208
|
}
|
|
208
209
|
}
|
|
209
210
|
|
|
211
|
+
getReadDependencies(): ReadDependency[] {
|
|
212
|
+
return this.source.getReadDependencies();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
clearReadDependencies(): void {
|
|
216
|
+
this.source.clearReadDependencies();
|
|
217
|
+
}
|
|
218
|
+
|
|
210
219
|
/** Called for each local action that may be in conflict with a remote action (always called under latch).
|
|
211
220
|
* @param action - The local action to check
|
|
212
221
|
* @param potential - The remote action that is potentially in conflict
|
package/src/index.ts
CHANGED
package/src/log/log.ts
CHANGED
|
@@ -56,7 +56,7 @@ export class Log<TAction> {
|
|
|
56
56
|
/** Gets the action context of the log. */
|
|
57
57
|
async getActionContext(): Promise<ActionContext | undefined> {
|
|
58
58
|
const tailPath = await this.chain.getTail();
|
|
59
|
-
if (!tailPath) {
|
|
59
|
+
if (!tailPath || tailPath.block.entries.length === 0) {
|
|
60
60
|
return undefined;
|
|
61
61
|
}
|
|
62
62
|
const checkpoint = await this.findCheckpoint(tailPath);
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import debug from 'debug'
|
|
2
|
+
|
|
3
|
+
const BASE_NAMESPACE = 'optimystic:db-core'
|
|
4
|
+
|
|
5
|
+
export function createLogger(subNamespace: string): debug.Debugger {
|
|
6
|
+
return debug(`${BASE_NAMESPACE}:${subNamespace}`)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const verbose = typeof process !== 'undefined'
|
|
10
|
+
&& (process.env.OPTIMYSTIC_VERBOSE === '1' || process.env.OPTIMYSTIC_VERBOSE === 'true');
|