@based/db 0.0.28 → 0.0.30
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/README.md +1 -399
- package/dist/lib/darwin_aarch64/include/selva/db.h +8 -4
- package/dist/lib/darwin_aarch64/include/selva/fields.h +10 -2
- package/dist/lib/darwin_aarch64/include/selva/selva_hash128.h +17 -7
- package/dist/lib/darwin_aarch64/include/selva/sort.h +21 -14
- package/dist/lib/darwin_aarch64/libdeflate.dylib +0 -0
- package/dist/lib/darwin_aarch64/libjemalloc_selva.2.dylib +0 -0
- package/dist/lib/darwin_aarch64/libnode-v20.node +0 -0
- package/dist/lib/darwin_aarch64/libnode-v21.node +0 -0
- package/dist/lib/darwin_aarch64/libnode-v22.node +0 -0
- package/dist/lib/darwin_aarch64/libnode-v23.node +0 -0
- package/dist/lib/darwin_aarch64/libselva.dylib +0 -0
- package/dist/lib/darwin_aarch64/libxxhash.dylib +0 -0
- package/dist/lib/linux_aarch64/include/selva/db.h +8 -4
- package/dist/lib/linux_aarch64/include/selva/fields.h +10 -2
- package/dist/lib/linux_aarch64/include/selva/selva_hash128.h +17 -7
- package/dist/lib/linux_aarch64/include/selva/sort.h +21 -14
- package/dist/lib/linux_aarch64/libdeflate.so +0 -0
- package/dist/lib/linux_aarch64/libjemalloc_selva.so.2 +0 -0
- package/dist/lib/linux_aarch64/libnode-v20.node +0 -0
- package/dist/lib/linux_aarch64/libnode-v21.node +0 -0
- package/dist/lib/linux_aarch64/libnode-v22.node +0 -0
- package/dist/lib/linux_aarch64/libnode-v23.node +0 -0
- package/dist/lib/linux_aarch64/libselva.so +0 -0
- package/dist/lib/linux_x86_64/include/selva/db.h +8 -4
- package/dist/lib/linux_x86_64/include/selva/fields.h +10 -2
- package/dist/lib/linux_x86_64/include/selva/selva_hash128.h +17 -7
- package/dist/lib/linux_x86_64/include/selva/sort.h +21 -14
- package/dist/lib/linux_x86_64/libjemalloc_selva.so.2 +0 -0
- package/dist/lib/linux_x86_64/libnode-v20.node +0 -0
- package/dist/lib/linux_x86_64/libnode-v21.node +0 -0
- package/dist/lib/linux_x86_64/libnode-v22.node +0 -0
- package/dist/lib/linux_x86_64/libnode-v23.node +0 -0
- package/dist/lib/linux_x86_64/libselva.so +0 -0
- package/dist/src/client/flushModify.d.ts +1 -1
- package/dist/src/client/flushModify.js +15 -19
- package/dist/src/client/index.d.ts +8 -10
- package/dist/src/client/index.js +19 -8
- package/dist/src/client/modify/ModifyRes.d.ts +2 -4
- package/dist/src/client/modify/ModifyRes.js +15 -21
- package/dist/src/client/modify/create.js +1 -2
- package/dist/src/client/modify/delete.js +1 -2
- package/dist/src/client/modify/fixed.js +43 -8
- package/dist/src/client/modify/modify.js +0 -5
- package/dist/src/client/modify/references/{appendRefs.d.ts → appendEdgeRefs.d.ts} +1 -1
- package/dist/src/client/modify/references/{appendRefs.js → appendEdgeRefs.js} +5 -2
- package/dist/src/client/modify/references/edge.js +182 -175
- package/dist/src/client/modify/references/reference.js +4 -8
- package/dist/src/client/modify/references/references.js +18 -14
- package/dist/src/client/modify/setCursor.js +1 -1
- package/dist/src/client/modify/string.js +0 -3
- package/dist/src/client/modify/text.js +11 -3
- package/dist/src/client/modify/types.d.ts +11 -0
- package/dist/src/client/modify/types.js +10 -0
- package/dist/src/client/modify/update.js +5 -3
- package/dist/src/client/modify/vector.js +13 -4
- package/dist/src/client/query/BasedDbQuery.d.ts +1 -1
- package/dist/src/client/query/BasedDbQuery.js +2 -2
- package/dist/src/client/query/BasedIterable.d.ts +1 -1
- package/dist/src/client/query/BasedIterable.js +7 -2
- package/dist/src/client/query/filter/createFixedFilterBuffer.d.ts +2 -1
- package/dist/src/client/query/filter/createFixedFilterBuffer.js +11 -28
- package/dist/src/client/query/filter/createReferenceFilter.d.ts +2 -1
- package/dist/src/client/query/filter/createReferenceFilter.js +10 -9
- package/dist/src/client/query/filter/createVariableFilterBuffer.d.ts +2 -1
- package/dist/src/client/query/filter/createVariableFilterBuffer.js +8 -10
- package/dist/src/client/query/filter/parseFilterValue.js +1 -1
- package/dist/src/client/query/filter/primitiveFilter.js +9 -9
- package/dist/src/client/query/filter/toBuffer.js +0 -15
- package/dist/src/client/query/filter/types.d.ts +1 -0
- package/dist/src/client/query/filter/types.js +1 -0
- package/dist/src/client/query/include/walk.js +0 -1
- package/dist/src/client/query/read/read.js +16 -7
- package/dist/src/client/query/search/index.js +11 -15
- package/dist/src/client/query/subscription/index.d.ts +1 -2
- package/dist/src/client/query/subscription/index.js +3 -50
- package/dist/src/client/query/subscription/markers.js +1 -2
- package/dist/src/client/query/subscription/run.js +0 -2
- package/dist/src/client/query/subscription/types.d.ts +1 -29
- package/dist/src/client/query/subscription/types.js +8 -1
- package/dist/src/client/query/thresholds.d.ts +0 -2
- package/dist/src/client/query/thresholds.js +0 -2
- package/dist/src/client/query/toBuffer.js +16 -42
- package/dist/src/client/query/types.d.ts +3 -2
- package/dist/src/client/query/validation.d.ts +1 -3
- package/dist/src/client/query/validation.js +6 -18
- package/dist/src/client/string.d.ts +2 -0
- package/dist/src/client/string.js +10 -14
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +11 -15
- package/dist/src/native.d.ts +3 -3
- package/dist/src/native.js +6 -4
- package/dist/src/server/csmt/draw-dot.js +2 -2
- package/dist/src/server/csmt/tree.js +57 -6
- package/dist/src/server/csmt/types.d.ts +5 -0
- package/dist/src/server/index.d.ts +4 -3
- package/dist/src/server/index.js +44 -44
- package/dist/src/server/migrate/index.js +47 -29
- package/dist/src/server/migrate/worker.js +2 -2
- package/dist/src/server/save.js +40 -28
- package/dist/src/server/start.js +7 -19
- package/dist/src/server/tree.d.ts +2 -0
- package/dist/src/server/tree.js +34 -2
- package/dist/src/server/worker.js +3 -3
- package/dist/src/utils.d.ts +3 -1
- package/dist/src/utils.js +43 -19
- package/package.json +9 -3
- package/dist/lib/darwin_aarch64/include/selva/base64.h +0 -59
- package/dist/lib/darwin_aarch64/include/selva/base64url.h +0 -59
- package/dist/lib/linux_aarch64/include/selva/base64.h +0 -59
- package/dist/lib/linux_aarch64/include/selva/base64url.h +0 -59
- package/dist/lib/linux_x86_64/include/selva/base64.h +0 -59
- package/dist/lib/linux_x86_64/include/selva/base64url.h +0 -59
- package/dist/src/client/timestamp.d.ts +0 -1
- package/dist/src/client/timestamp.js +0 -68
package/dist/src/index.js
CHANGED
|
@@ -2,8 +2,8 @@ import { compress, decompress } from './client/string.js';
|
|
|
2
2
|
import { ModifyCtx } from './client/flushModify.js';
|
|
3
3
|
import { DbServer } from './server/index.js';
|
|
4
4
|
import { DbClient } from './client/index.js';
|
|
5
|
-
import picocolors from 'picocolors';
|
|
6
5
|
import { wait } from '@saulx/utils';
|
|
6
|
+
import { debugMode, debugServer } from './utils.js';
|
|
7
7
|
export * from './client/modify/modify.js';
|
|
8
8
|
export { compress, decompress };
|
|
9
9
|
export { ModifyCtx }; // TODO move this somewhere
|
|
@@ -23,16 +23,11 @@ export class BasedDb {
|
|
|
23
23
|
constructor(opts) {
|
|
24
24
|
this.#init(opts);
|
|
25
25
|
if (opts.debug) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const str = [`[${key}]`, ...arguments].join(' ');
|
|
32
|
-
console.info(picocolors.dim(str));
|
|
33
|
-
return fn.apply(this, arguments);
|
|
34
|
-
};
|
|
35
|
-
}
|
|
26
|
+
if (opts.debug === 'server') {
|
|
27
|
+
debugServer(this.server);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
debugMode(this);
|
|
36
31
|
}
|
|
37
32
|
}
|
|
38
33
|
}
|
|
@@ -49,7 +44,10 @@ export class BasedDb {
|
|
|
49
44
|
const client = new DbClient({
|
|
50
45
|
maxModifySize,
|
|
51
46
|
hooks: {
|
|
52
|
-
|
|
47
|
+
subscribe(q, onData, onError) {
|
|
48
|
+
console.warn('Subscription not supported without based-server!');
|
|
49
|
+
return () => { };
|
|
50
|
+
},
|
|
53
51
|
setSchema(schema, fromStart) {
|
|
54
52
|
return Promise.resolve(server.setSchema(schema, fromStart));
|
|
55
53
|
},
|
|
@@ -59,8 +57,6 @@ export class BasedDb {
|
|
|
59
57
|
offsets,
|
|
60
58
|
});
|
|
61
59
|
},
|
|
62
|
-
flushReady: () => { },
|
|
63
|
-
flushIsReady: new Promise(() => { }),
|
|
64
60
|
getQueryBuf(buf) {
|
|
65
61
|
return Promise.resolve(server.getQueryBuf(buf));
|
|
66
62
|
},
|
|
@@ -127,7 +123,7 @@ export class BasedDb {
|
|
|
127
123
|
await this.isModified();
|
|
128
124
|
// Tmp fix: Gives node time to GC existing buffers else it can incorrectly re-asign to mem
|
|
129
125
|
// Todo: clear all active queries, queues ETC
|
|
130
|
-
await wait(Math.max(this.client.
|
|
126
|
+
await wait(Math.max(this.client.flushTime + 10, 10));
|
|
131
127
|
this.client.destroy();
|
|
132
128
|
await this.server.destroy();
|
|
133
129
|
}
|
package/dist/src/native.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
declare const
|
|
1
|
+
declare const native: {
|
|
2
2
|
historyAppend(history: any, typeId: number, nodeId: number, dbCtx: any): any;
|
|
3
3
|
historyCreate(pathname: string, mainLen: number): any;
|
|
4
4
|
workerCtxInit: () => void;
|
|
@@ -21,7 +21,7 @@ declare const _default: {
|
|
|
21
21
|
createSortIndex: (buf: Uint8Array, dbCtx: any) => any;
|
|
22
22
|
destroySortIndex: (buf: Uint8Array, dbCtx: any) => any;
|
|
23
23
|
xxHash64: (buf: Uint8Array, target: Uint8Array, index: number) => any;
|
|
24
|
-
base64encode: (dst: Uint8Array, src: Uint8Array, lineMax: number) => Uint8Array;
|
|
25
24
|
equals: (a: Uint8Array, b: Uint8Array) => boolean;
|
|
25
|
+
expire: (dbCtx: any) => void;
|
|
26
26
|
};
|
|
27
|
-
export default
|
|
27
|
+
export default native;
|
package/dist/src/native.js
CHANGED
|
@@ -11,7 +11,7 @@ function SelvaIoErrlogToString(buf) {
|
|
|
11
11
|
let len = (i = buf.indexOf(0)) >= 0 ? i : buf.byteLength;
|
|
12
12
|
return DECODER.decode(selvaIoErrlog.slice(0, len));
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
const native = {
|
|
15
15
|
historyAppend(history, typeId, nodeId, dbCtx) {
|
|
16
16
|
return db.historyAppend(history, typeId, nodeId, dbCtx);
|
|
17
17
|
},
|
|
@@ -90,11 +90,13 @@ export default {
|
|
|
90
90
|
xxHash64: (buf, target, index) => {
|
|
91
91
|
return db.xxHash64(buf, target, index);
|
|
92
92
|
},
|
|
93
|
-
base64encode: (dst, src, lineMax) => {
|
|
94
|
-
return db.base64encode(dst, src, lineMax);
|
|
95
|
-
},
|
|
96
93
|
equals: (a, b) => {
|
|
97
94
|
return !!db.equals(a, b);
|
|
98
95
|
},
|
|
96
|
+
expire: (dbCtx) => {
|
|
97
|
+
db.expire(dbCtx);
|
|
98
|
+
},
|
|
99
99
|
};
|
|
100
|
+
global.__basedDb__native__ = native;
|
|
101
|
+
export default native;
|
|
100
102
|
//# sourceMappingURL=native.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { encodeBase64 } from '@saulx/utils';
|
|
2
2
|
function makeLabel(node) {
|
|
3
|
-
return `${node.key}\n${
|
|
3
|
+
return `${node.key}\n${encodeBase64(node.hash).substring(0, 5)}`;
|
|
4
4
|
}
|
|
5
5
|
export default function draw(csmt) {
|
|
6
6
|
const root = csmt.getRoot();
|
|
@@ -12,9 +12,7 @@ export function createTree(createHash) {
|
|
|
12
12
|
return createHash().update(lHash).update(rHash).digest();
|
|
13
13
|
}
|
|
14
14
|
function createNode(left, right) {
|
|
15
|
-
const hash = left && right
|
|
16
|
-
? genNodeHash(left.hash, right.hash)
|
|
17
|
-
: emptyHash;
|
|
15
|
+
const hash = left && right ? genNodeHash(left.hash, right.hash) : emptyHash;
|
|
18
16
|
return {
|
|
19
17
|
hash,
|
|
20
18
|
key: max(left, right),
|
|
@@ -56,7 +54,7 @@ export function createTree(createHash) {
|
|
|
56
54
|
return createNode(newLeaf, node);
|
|
57
55
|
}
|
|
58
56
|
else {
|
|
59
|
-
throw new Error(
|
|
57
|
+
throw new Error(`k=${k} exists`);
|
|
60
58
|
}
|
|
61
59
|
}
|
|
62
60
|
const lDist = distance(k, (left && left.key) || TreeKeyNil);
|
|
@@ -120,6 +118,47 @@ export function createTree(createHash) {
|
|
|
120
118
|
}
|
|
121
119
|
}
|
|
122
120
|
}
|
|
121
|
+
function updateNodeHash(node) {
|
|
122
|
+
if (node.left && node.right) {
|
|
123
|
+
node.hash = genNodeHash(node.left.hash, node.right.hash);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
function updateHash(node, k, hash) {
|
|
127
|
+
if (!node)
|
|
128
|
+
return;
|
|
129
|
+
const { left, right } = node;
|
|
130
|
+
if (k === node.key && !left && !right) {
|
|
131
|
+
node.hash = hash;
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
if (left && left.key === k) {
|
|
135
|
+
updateHash(left, k, hash);
|
|
136
|
+
updateNodeHash(left);
|
|
137
|
+
updateNodeHash(node);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
if (right && right.key === k) {
|
|
141
|
+
updateHash(right, k, hash);
|
|
142
|
+
updateNodeHash(right);
|
|
143
|
+
updateNodeHash(node);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const lDist = distance(k, (left && left.key) || TreeKeyNil);
|
|
147
|
+
const rDist = distance(k, (right && right.key) || TreeKeyNil);
|
|
148
|
+
if (left && lDist <= rDist) {
|
|
149
|
+
updateHash(left, k, hash);
|
|
150
|
+
updateNodeHash(left);
|
|
151
|
+
updateNodeHash(node);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (right && rDist <= lDist) {
|
|
155
|
+
updateHash(right, k, hash);
|
|
156
|
+
updateNodeHash(right);
|
|
157
|
+
updateNodeHash(node);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
123
162
|
function diffAB(diffA, diffB, nodeA, nodeB) {
|
|
124
163
|
if (nodeA &&
|
|
125
164
|
nodeB &&
|
|
@@ -190,13 +229,20 @@ export function createTree(createHash) {
|
|
|
190
229
|
if (!node || (k === node.key && !node.left && !node.right))
|
|
191
230
|
return node;
|
|
192
231
|
const { left, right } = node;
|
|
193
|
-
if (left &&
|
|
232
|
+
if (left && left.key === k)
|
|
233
|
+
return search(left, k);
|
|
234
|
+
if (right && right.key === k)
|
|
235
|
+
return search(right, k);
|
|
236
|
+
const lDist = distance(k, (left && left.key) || TreeKeyNil);
|
|
237
|
+
const rDist = distance(k, (right && right.key) || TreeKeyNil);
|
|
238
|
+
if (left && lDist <= rDist)
|
|
194
239
|
return search(left, k);
|
|
195
|
-
if (right &&
|
|
240
|
+
if (right && rDist <= lDist)
|
|
196
241
|
return search(right, k);
|
|
197
242
|
return null;
|
|
198
243
|
}
|
|
199
244
|
return {
|
|
245
|
+
emptyHash,
|
|
200
246
|
getRoot: () => root,
|
|
201
247
|
insert: (k, h, data = null) => {
|
|
202
248
|
if (!(h instanceof Uint8Array)) {
|
|
@@ -205,6 +251,11 @@ export function createTree(createHash) {
|
|
|
205
251
|
const newLeaf = createLeaf(k, h, data);
|
|
206
252
|
root = root ? insert(root, newLeaf) : newLeaf;
|
|
207
253
|
},
|
|
254
|
+
update: (k, h) => {
|
|
255
|
+
if (root) {
|
|
256
|
+
updateHash(root, k, h);
|
|
257
|
+
}
|
|
258
|
+
},
|
|
208
259
|
delete: (k) => {
|
|
209
260
|
if (root) {
|
|
210
261
|
root = deleteNode(root, k);
|
|
@@ -15,6 +15,7 @@ export interface TreeDiff {
|
|
|
15
15
|
right: KeyHashPair[];
|
|
16
16
|
}
|
|
17
17
|
export interface Csmt {
|
|
18
|
+
emptyHash: Uint8Array;
|
|
18
19
|
/**
|
|
19
20
|
* Get the root node.
|
|
20
21
|
*/
|
|
@@ -27,6 +28,10 @@ export interface Csmt {
|
|
|
27
28
|
* Delete a key-hash pair from the tree.
|
|
28
29
|
*/
|
|
29
30
|
delete: (k: TreeKey) => void;
|
|
31
|
+
/**
|
|
32
|
+
* Update node hash.
|
|
33
|
+
*/
|
|
34
|
+
update: (k: TreeKey, h: Hash) => void;
|
|
30
35
|
/**
|
|
31
36
|
* Compute the diff between this and a given tree.
|
|
32
37
|
*/
|
|
@@ -50,10 +50,11 @@ export declare class DbServer {
|
|
|
50
50
|
stopped: boolean;
|
|
51
51
|
onSchemaChange: OnSchemaChange;
|
|
52
52
|
unlistenExit: ReturnType<typeof exitHook>;
|
|
53
|
-
constructor({ path, maxModifySize, onSchemaChange, }: {
|
|
53
|
+
constructor({ path, maxModifySize, onSchemaChange, debug, }: {
|
|
54
54
|
path: string;
|
|
55
55
|
maxModifySize?: number;
|
|
56
56
|
onSchemaChange?: OnSchemaChange;
|
|
57
|
+
debug?: boolean;
|
|
57
58
|
});
|
|
58
59
|
start(opts?: {
|
|
59
60
|
clean?: boolean;
|
|
@@ -85,14 +86,14 @@ export declare class DbServer {
|
|
|
85
86
|
lastId: number;
|
|
86
87
|
}>;
|
|
87
88
|
createSortIndexBuffer(typeId: number, field: number, start: number, lang: number): SortIndex;
|
|
88
|
-
updateMerkleTree(): void;
|
|
89
89
|
setSchema(strictSchema: StrictSchema, fromStart?: boolean, transformFns?: TransformFns): (StrictSchema & {
|
|
90
90
|
lastId: number;
|
|
91
91
|
}) | Promise<StrictSchema & {
|
|
92
92
|
lastId: number;
|
|
93
93
|
}>;
|
|
94
94
|
modify(buf: Uint8Array): Record<number, number>;
|
|
95
|
-
|
|
95
|
+
addToQueryQueue(resolve: any, buf: any): void;
|
|
96
|
+
getQueryBuf(buf: Uint8Array, fromQueue?: boolean): Promise<Uint8Array>;
|
|
96
97
|
onQueryEnd(): void;
|
|
97
98
|
stop(noSave?: boolean): Promise<void>;
|
|
98
99
|
destroy(): Promise<void>;
|
package/dist/src/server/index.js
CHANGED
|
@@ -4,14 +4,14 @@ import { rm, writeFile } from 'node:fs/promises';
|
|
|
4
4
|
import { dirname, join } from 'node:path';
|
|
5
5
|
import { getPropType, langCodesMap, } from '@based/schema';
|
|
6
6
|
import { updateTypeDefs, schemaToSelvaBuffer, } from '@based/schema/def';
|
|
7
|
-
import { hashEq } from './csmt/index.js';
|
|
8
7
|
import { start } from './start.js';
|
|
9
|
-
import {
|
|
8
|
+
import { initCsmt, makeCsmtKey, makeCsmtKeyFromNodeId } from './tree.js';
|
|
10
9
|
import { save } from './save.js';
|
|
11
10
|
import { Worker, MessageChannel } from 'node:worker_threads';
|
|
12
11
|
import { fileURLToPath } from 'node:url';
|
|
13
12
|
import { setTimeout } from 'node:timers/promises';
|
|
14
13
|
import { migrate } from './migrate/index.js';
|
|
14
|
+
import { debugServer } from '../utils.js';
|
|
15
15
|
export const SCHEMA_FILE = 'schema.json';
|
|
16
16
|
export const WRITELOG_FILE = 'writelog.json';
|
|
17
17
|
const __filename = fileURLToPath(import.meta.url);
|
|
@@ -45,10 +45,6 @@ export class DbWorker {
|
|
|
45
45
|
transferList: [port2],
|
|
46
46
|
});
|
|
47
47
|
port1.on('message', (buf) => {
|
|
48
|
-
// TODO FIX TYPES CHECK IF THIS MAKES A COPY
|
|
49
|
-
// It's a copy, if you don't want a copy you'd need to make it an explicit view
|
|
50
|
-
// to the underlying buffer:
|
|
51
|
-
// new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength)
|
|
52
48
|
this.resolvers.shift()(new Uint8Array(buf));
|
|
53
49
|
this.db.onQueryEnd();
|
|
54
50
|
});
|
|
@@ -93,11 +89,14 @@ export class DbServer {
|
|
|
93
89
|
stopped;
|
|
94
90
|
onSchemaChange;
|
|
95
91
|
unlistenExit;
|
|
96
|
-
constructor({ path, maxModifySize = 100 * 1e3 * 1e3, onSchemaChange, }) {
|
|
92
|
+
constructor({ path, maxModifySize = 100 * 1e3 * 1e3, onSchemaChange, debug, }) {
|
|
97
93
|
this.maxModifySize = maxModifySize;
|
|
98
94
|
this.fileSystemPath = path;
|
|
99
95
|
this.sortIndexes = {};
|
|
100
96
|
this.onSchemaChange = onSchemaChange;
|
|
97
|
+
if (debug) {
|
|
98
|
+
debugServer(this);
|
|
99
|
+
}
|
|
101
100
|
}
|
|
102
101
|
#resizeModifyDirtyRanges() {
|
|
103
102
|
let maxNrChanges = 0;
|
|
@@ -141,7 +140,7 @@ export class DbServer {
|
|
|
141
140
|
for (const lang in this.sortIndexes[type][field][start]) {
|
|
142
141
|
const sortIndex = this.sortIndexes[type][field][start][lang];
|
|
143
142
|
sortIndex.cnt /= 2;
|
|
144
|
-
if (sortIndex.cnt < 1) {
|
|
143
|
+
if (sortIndex.cnt < 1 && !this.processingQueries) {
|
|
145
144
|
native.destroySortIndex(sortIndex.buf, this.dbCtxExternal);
|
|
146
145
|
delete this.sortIndexes[type][field][start][lang];
|
|
147
146
|
}
|
|
@@ -179,7 +178,7 @@ export class DbServer {
|
|
|
179
178
|
if (sortIndex) {
|
|
180
179
|
return sortIndex;
|
|
181
180
|
}
|
|
182
|
-
const buf = new Uint8Array(
|
|
181
|
+
const buf = new Uint8Array(9);
|
|
183
182
|
// size [2 type] [1 field] [2 start] [2 len] [propIndex] [lang]
|
|
184
183
|
// call createSortBuf here
|
|
185
184
|
buf[0] = t.id;
|
|
@@ -208,7 +207,6 @@ export class DbServer {
|
|
|
208
207
|
}
|
|
209
208
|
let sortIndex = fields[prop.start];
|
|
210
209
|
if (sortIndex) {
|
|
211
|
-
// [2 type] [1 field] [2 start] [1 lang]
|
|
212
210
|
const buf = new Uint8Array(6);
|
|
213
211
|
buf[0] = t.id;
|
|
214
212
|
buf[1] = t.id >>> 8;
|
|
@@ -279,29 +277,6 @@ export class DbServer {
|
|
|
279
277
|
fields[start][lang] = sortIndex;
|
|
280
278
|
return sortIndex;
|
|
281
279
|
}
|
|
282
|
-
updateMerkleTree() {
|
|
283
|
-
foreachDirtyBlock(this, (mtKey, typeId, start, end) => {
|
|
284
|
-
const oldLeaf = this.merkleTree.search(mtKey);
|
|
285
|
-
const hash = new Uint8Array(16);
|
|
286
|
-
native.getNodeRangeHash(typeId, start, end, hash, this.dbCtxExternal);
|
|
287
|
-
if (oldLeaf) {
|
|
288
|
-
if (hashEq(oldLeaf.hash, hash)) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
try {
|
|
292
|
-
this.merkleTree.delete(mtKey);
|
|
293
|
-
}
|
|
294
|
-
catch (err) { }
|
|
295
|
-
}
|
|
296
|
-
const data = {
|
|
297
|
-
file: '', // not saved yet
|
|
298
|
-
typeId,
|
|
299
|
-
start,
|
|
300
|
-
end,
|
|
301
|
-
};
|
|
302
|
-
this.merkleTree.insert(mtKey, hash, data);
|
|
303
|
-
});
|
|
304
|
-
}
|
|
305
280
|
setSchema(strictSchema, fromStart = false, transformFns) {
|
|
306
281
|
if (!fromStart && Object.keys(this.schema.types).length > 0) {
|
|
307
282
|
return this.migrateSchema(strictSchema, transformFns);
|
|
@@ -373,6 +348,7 @@ export class DbServer {
|
|
|
373
348
|
}
|
|
374
349
|
if (strictSchema.props) {
|
|
375
350
|
// insert a root node
|
|
351
|
+
// TODO fix this add it in schema at least
|
|
376
352
|
const data = [2, 1, 0, 0, 0, 1, 9, 1, 0, 0, 0, 7, 1, 0, 1];
|
|
377
353
|
const blockKey = makeCsmtKey(1, 1);
|
|
378
354
|
const buf = new Uint8Array(data.length + 2 + 8 + 4);
|
|
@@ -387,6 +363,7 @@ export class DbServer {
|
|
|
387
363
|
view.setUint32(buf.length - 4, data.length, true);
|
|
388
364
|
this.modify(buf);
|
|
389
365
|
}
|
|
366
|
+
initCsmt(this);
|
|
390
367
|
}
|
|
391
368
|
this.onSchemaChange?.(this.schema);
|
|
392
369
|
return this.schema;
|
|
@@ -401,7 +378,16 @@ export class DbServer {
|
|
|
401
378
|
i += 2;
|
|
402
379
|
const startId = readUint32LE(buf, i);
|
|
403
380
|
const def = this.schemaTypesParsedById[typeId];
|
|
404
|
-
|
|
381
|
+
let offset = def.lastId - startId;
|
|
382
|
+
if (offset < 0) {
|
|
383
|
+
console.log('-----------------');
|
|
384
|
+
console.log(def.type, {
|
|
385
|
+
offset,
|
|
386
|
+
serverId: def.lastId,
|
|
387
|
+
clientId: startId,
|
|
388
|
+
});
|
|
389
|
+
offset = 0;
|
|
390
|
+
}
|
|
405
391
|
buf[i++] = offset;
|
|
406
392
|
buf[i++] = offset >>> 8;
|
|
407
393
|
buf[i++] = offset >>> 16;
|
|
@@ -411,6 +397,7 @@ export class DbServer {
|
|
|
411
397
|
def.lastId = lastId + offset;
|
|
412
398
|
offsets[typeId] = offset;
|
|
413
399
|
}
|
|
400
|
+
// console.log('modify', this.processingQueries)
|
|
414
401
|
if (this.processingQueries) {
|
|
415
402
|
this.modifyQueue.push(new Uint8Array(buf));
|
|
416
403
|
}
|
|
@@ -449,10 +436,17 @@ export class DbServer {
|
|
|
449
436
|
this.dirtyRanges.add(key);
|
|
450
437
|
}
|
|
451
438
|
}
|
|
452
|
-
|
|
439
|
+
addToQueryQueue(resolve, buf) {
|
|
440
|
+
if (this.queryQueue.size === 16777216) {
|
|
441
|
+
resolve(new Error('Query queue exceeded'));
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
this.queryQueue.set(resolve, buf);
|
|
445
|
+
}
|
|
446
|
+
getQueryBuf(buf, fromQueue = false) {
|
|
453
447
|
if (this.modifyQueue.length) {
|
|
454
448
|
return new Promise((resolve) => {
|
|
455
|
-
this.
|
|
449
|
+
this.addToQueryQueue(resolve, buf);
|
|
456
450
|
});
|
|
457
451
|
}
|
|
458
452
|
else {
|
|
@@ -469,7 +463,7 @@ export class DbServer {
|
|
|
469
463
|
if (!sortIndex) {
|
|
470
464
|
if (this.processingQueries) {
|
|
471
465
|
return new Promise((resolve) => {
|
|
472
|
-
this.
|
|
466
|
+
this.addToQueryQueue(resolve, buf);
|
|
473
467
|
});
|
|
474
468
|
}
|
|
475
469
|
sortIndex = this.createSortIndexBuffer(typeId, field, start, sort[sort.byteLength - 1]);
|
|
@@ -482,6 +476,9 @@ export class DbServer {
|
|
|
482
476
|
else if (queryType == 1) {
|
|
483
477
|
// This will be more advanced - sometimes has indexes / sometimes not
|
|
484
478
|
}
|
|
479
|
+
if (!fromQueue) {
|
|
480
|
+
native.expire(this.dbCtxExternal);
|
|
481
|
+
}
|
|
485
482
|
this.availableWorkerIndex =
|
|
486
483
|
(this.availableWorkerIndex + 1) % this.workers.length;
|
|
487
484
|
return this.workers[this.availableWorkerIndex].getQueryBuf(buf);
|
|
@@ -491,16 +488,19 @@ export class DbServer {
|
|
|
491
488
|
this.processingQueries--;
|
|
492
489
|
if (this.processingQueries === 0) {
|
|
493
490
|
if (this.modifyQueue.length) {
|
|
494
|
-
|
|
491
|
+
const modifyQueue = this.modifyQueue;
|
|
492
|
+
this.modifyQueue = [];
|
|
493
|
+
for (const buf of modifyQueue) {
|
|
495
494
|
this.#modify(buf);
|
|
496
495
|
}
|
|
497
|
-
this.modifyQueue = [];
|
|
498
496
|
}
|
|
499
497
|
if (this.queryQueue.size) {
|
|
500
|
-
|
|
501
|
-
|
|
498
|
+
const queryQueue = this.queryQueue;
|
|
499
|
+
this.queryQueue = new Map();
|
|
500
|
+
native.expire(this.dbCtxExternal);
|
|
501
|
+
for (const [resolve, buf] of queryQueue) {
|
|
502
|
+
resolve(this.getQueryBuf(buf, true));
|
|
502
503
|
}
|
|
503
|
-
this.queryQueue.clear();
|
|
504
504
|
}
|
|
505
505
|
}
|
|
506
506
|
}
|
|
@@ -510,7 +510,7 @@ export class DbServer {
|
|
|
510
510
|
}
|
|
511
511
|
this.stopped = true;
|
|
512
512
|
clearTimeout(this.cleanupTimer);
|
|
513
|
-
this
|
|
513
|
+
this.unlistenExit();
|
|
514
514
|
try {
|
|
515
515
|
if (!noSave) {
|
|
516
516
|
await this.save();
|
|
@@ -518,7 +518,7 @@ export class DbServer {
|
|
|
518
518
|
await Promise.all(this.workers.map(({ worker }) => worker.terminate()));
|
|
519
519
|
this.workers = [];
|
|
520
520
|
native.stop(this.dbCtxExternal);
|
|
521
|
-
await setTimeout();
|
|
521
|
+
await setTimeout(20);
|
|
522
522
|
}
|
|
523
523
|
catch (e) {
|
|
524
524
|
this.stopped = false;
|
|
@@ -4,7 +4,7 @@ import { tmpdir } from 'os';
|
|
|
4
4
|
import { Worker, MessageChannel, receiveMessageOnPort, } from 'node:worker_threads';
|
|
5
5
|
import native from '../../native.js';
|
|
6
6
|
import './worker.js';
|
|
7
|
-
import { foreachDirtyBlock } from '../tree.js';
|
|
7
|
+
import { destructureCsmtKey, foreachDirtyBlock, specialBlock } from '../tree.js';
|
|
8
8
|
import { SCHEMA_FILE } from '../index.js';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
10
|
import { deepMerge } from '@saulx/utils';
|
|
@@ -35,7 +35,7 @@ export const migrate = async (fromDbServer, toSchema, transform) => {
|
|
|
35
35
|
fromDbServer.migrating = migrationId;
|
|
36
36
|
const abort = () => fromDbServer.migrating !== migrationId;
|
|
37
37
|
const toDb = new BasedDb({
|
|
38
|
-
path: join(tmpdir(), (~~Math.random()).toString(36)),
|
|
38
|
+
path: join(tmpdir(), (~~(Math.random() * 1e9)).toString(36)),
|
|
39
39
|
});
|
|
40
40
|
await toDb.start({ clean: true });
|
|
41
41
|
if (abort()) {
|
|
@@ -43,6 +43,10 @@ export const migrate = async (fromDbServer, toSchema, transform) => {
|
|
|
43
43
|
return fromDbServer.schema;
|
|
44
44
|
}
|
|
45
45
|
toSchema = await toDb.setSchema(toSchema);
|
|
46
|
+
if (abort()) {
|
|
47
|
+
await toDb.destroy();
|
|
48
|
+
return fromDbServer.schema;
|
|
49
|
+
}
|
|
46
50
|
const fromSchema = fromDbServer.schema;
|
|
47
51
|
const fromCtx = fromDbServer.dbCtxExternal;
|
|
48
52
|
const toCtx = toDb.server.dbCtxExternal;
|
|
@@ -67,14 +71,18 @@ export const migrate = async (fromDbServer, toSchema, transform) => {
|
|
|
67
71
|
worker.on('error', console.error);
|
|
68
72
|
let i = 0;
|
|
69
73
|
let ranges = [];
|
|
70
|
-
// fromDbServer.updateMerkleTree()
|
|
71
|
-
// fromDbServer.dirtyRanges.clear()
|
|
72
74
|
await fromDbServer.save();
|
|
73
75
|
fromDbServer.merkleTree.visitLeafNodes((leaf) => {
|
|
76
|
+
const [_typeId, start] = destructureCsmtKey(leaf.key);
|
|
77
|
+
if (start == specialBlock)
|
|
78
|
+
return; // skip the type specialBlock
|
|
74
79
|
ranges.push(leaf.data);
|
|
75
80
|
});
|
|
76
81
|
await Atomics.waitAsync(atomics, 0, 1).value;
|
|
77
82
|
while (i < ranges.length) {
|
|
83
|
+
if (abort()) {
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
78
86
|
// block modifies
|
|
79
87
|
fromDbServer.processingQueries++;
|
|
80
88
|
const leafData = ranges[i++];
|
|
@@ -86,38 +94,48 @@ export const migrate = async (fromDbServer, toSchema, transform) => {
|
|
|
86
94
|
await Atomics.waitAsync(atomics, 0, 1).value;
|
|
87
95
|
// exec queued modifies
|
|
88
96
|
fromDbServer.onQueryEnd();
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
end,
|
|
97
|
+
if (i === ranges.length) {
|
|
98
|
+
if (fromDbServer.dirtyRanges.size) {
|
|
99
|
+
ranges = [];
|
|
100
|
+
i = 0;
|
|
101
|
+
foreachDirtyBlock(fromDbServer, (_mtKey, typeId, start, end) => {
|
|
102
|
+
ranges.push({
|
|
103
|
+
typeId,
|
|
104
|
+
start,
|
|
105
|
+
end,
|
|
106
|
+
});
|
|
100
107
|
});
|
|
101
|
-
|
|
102
|
-
|
|
108
|
+
fromDbServer.dirtyRanges.clear();
|
|
109
|
+
}
|
|
103
110
|
}
|
|
104
111
|
}
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
fromDbServer.dbCtxExternal = toCtx;
|
|
116
|
-
toDb.server.dbCtxExternal = fromCtx;
|
|
112
|
+
if (abort()) {
|
|
113
|
+
await Promise.all([toDb.destroy(), worker.terminate()]);
|
|
114
|
+
return fromDbServer.schema;
|
|
115
|
+
}
|
|
116
|
+
let msg;
|
|
117
|
+
let schema;
|
|
118
|
+
let schemaTypesParsed;
|
|
119
|
+
while ((msg = receiveMessageOnPort(port1))) {
|
|
120
|
+
;
|
|
121
|
+
[schema, schemaTypesParsed] = msg.message;
|
|
117
122
|
}
|
|
123
|
+
fromDbServer.dbCtxExternal = toCtx;
|
|
124
|
+
fromDbServer.sortIndexes = {};
|
|
125
|
+
fromDbServer.schema = deepMerge(toDb.server.schema, schema);
|
|
126
|
+
fromDbServer.schemaTypesParsed = deepMerge(toDb.server.schemaTypesParsed, schemaTypesParsed);
|
|
127
|
+
fromDbServer.schemaTypesParsedById = {};
|
|
128
|
+
for (const key in fromDbServer.schemaTypesParsed) {
|
|
129
|
+
const def = fromDbServer.schemaTypesParsed[key];
|
|
130
|
+
fromDbServer.schemaTypesParsedById[def.id] = def;
|
|
131
|
+
}
|
|
132
|
+
toDb.server.dbCtxExternal = fromCtx;
|
|
118
133
|
const promises = fromDbServer.workers.map((worker) => worker.updateCtx(toAddress));
|
|
119
134
|
promises.push(toDb.destroy(), worker.terminate(), fromDbServer.save({ forceFullDump: true }), writeFile(join(fromDbServer.fileSystemPath, SCHEMA_FILE), JSON.stringify(fromDbServer.schema)));
|
|
120
135
|
await Promise.all(promises);
|
|
136
|
+
if (abort()) {
|
|
137
|
+
return fromDbServer.schema;
|
|
138
|
+
}
|
|
121
139
|
fromDbServer.onSchemaChange?.(fromDbServer.schema);
|
|
122
140
|
return fromDbServer.schema;
|
|
123
141
|
};
|
|
@@ -66,7 +66,7 @@ else {
|
|
|
66
66
|
const nodes = fromDb
|
|
67
67
|
.query(type)
|
|
68
68
|
.include(include)
|
|
69
|
-
.range(leafData.start - 1, leafData.end -
|
|
69
|
+
.range(leafData.start - 1, leafData.end - 1)
|
|
70
70
|
._getSync(fromCtx);
|
|
71
71
|
for (const node of nodes) {
|
|
72
72
|
const res = typeTransformFn(node);
|
|
@@ -85,7 +85,7 @@ else {
|
|
|
85
85
|
const nodes = fromDb
|
|
86
86
|
.query(type)
|
|
87
87
|
.include(include)
|
|
88
|
-
.range(leafData.start - 1, leafData.end -
|
|
88
|
+
.range(leafData.start - 1, leafData.end - 1)
|
|
89
89
|
._getSync(fromCtx);
|
|
90
90
|
for (const node of nodes) {
|
|
91
91
|
toDb.create(type, node, { unsafe: true });
|