@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.
Files changed (115) hide show
  1. package/README.md +1 -399
  2. package/dist/lib/darwin_aarch64/include/selva/db.h +8 -4
  3. package/dist/lib/darwin_aarch64/include/selva/fields.h +10 -2
  4. package/dist/lib/darwin_aarch64/include/selva/selva_hash128.h +17 -7
  5. package/dist/lib/darwin_aarch64/include/selva/sort.h +21 -14
  6. package/dist/lib/darwin_aarch64/libdeflate.dylib +0 -0
  7. package/dist/lib/darwin_aarch64/libjemalloc_selva.2.dylib +0 -0
  8. package/dist/lib/darwin_aarch64/libnode-v20.node +0 -0
  9. package/dist/lib/darwin_aarch64/libnode-v21.node +0 -0
  10. package/dist/lib/darwin_aarch64/libnode-v22.node +0 -0
  11. package/dist/lib/darwin_aarch64/libnode-v23.node +0 -0
  12. package/dist/lib/darwin_aarch64/libselva.dylib +0 -0
  13. package/dist/lib/darwin_aarch64/libxxhash.dylib +0 -0
  14. package/dist/lib/linux_aarch64/include/selva/db.h +8 -4
  15. package/dist/lib/linux_aarch64/include/selva/fields.h +10 -2
  16. package/dist/lib/linux_aarch64/include/selva/selva_hash128.h +17 -7
  17. package/dist/lib/linux_aarch64/include/selva/sort.h +21 -14
  18. package/dist/lib/linux_aarch64/libdeflate.so +0 -0
  19. package/dist/lib/linux_aarch64/libjemalloc_selva.so.2 +0 -0
  20. package/dist/lib/linux_aarch64/libnode-v20.node +0 -0
  21. package/dist/lib/linux_aarch64/libnode-v21.node +0 -0
  22. package/dist/lib/linux_aarch64/libnode-v22.node +0 -0
  23. package/dist/lib/linux_aarch64/libnode-v23.node +0 -0
  24. package/dist/lib/linux_aarch64/libselva.so +0 -0
  25. package/dist/lib/linux_x86_64/include/selva/db.h +8 -4
  26. package/dist/lib/linux_x86_64/include/selva/fields.h +10 -2
  27. package/dist/lib/linux_x86_64/include/selva/selva_hash128.h +17 -7
  28. package/dist/lib/linux_x86_64/include/selva/sort.h +21 -14
  29. package/dist/lib/linux_x86_64/libjemalloc_selva.so.2 +0 -0
  30. package/dist/lib/linux_x86_64/libnode-v20.node +0 -0
  31. package/dist/lib/linux_x86_64/libnode-v21.node +0 -0
  32. package/dist/lib/linux_x86_64/libnode-v22.node +0 -0
  33. package/dist/lib/linux_x86_64/libnode-v23.node +0 -0
  34. package/dist/lib/linux_x86_64/libselva.so +0 -0
  35. package/dist/src/client/flushModify.d.ts +1 -1
  36. package/dist/src/client/flushModify.js +15 -19
  37. package/dist/src/client/index.d.ts +8 -10
  38. package/dist/src/client/index.js +19 -8
  39. package/dist/src/client/modify/ModifyRes.d.ts +2 -4
  40. package/dist/src/client/modify/ModifyRes.js +15 -21
  41. package/dist/src/client/modify/create.js +1 -2
  42. package/dist/src/client/modify/delete.js +1 -2
  43. package/dist/src/client/modify/fixed.js +43 -8
  44. package/dist/src/client/modify/modify.js +0 -5
  45. package/dist/src/client/modify/references/{appendRefs.d.ts → appendEdgeRefs.d.ts} +1 -1
  46. package/dist/src/client/modify/references/{appendRefs.js → appendEdgeRefs.js} +5 -2
  47. package/dist/src/client/modify/references/edge.js +182 -175
  48. package/dist/src/client/modify/references/reference.js +4 -8
  49. package/dist/src/client/modify/references/references.js +18 -14
  50. package/dist/src/client/modify/setCursor.js +1 -1
  51. package/dist/src/client/modify/string.js +0 -3
  52. package/dist/src/client/modify/text.js +11 -3
  53. package/dist/src/client/modify/types.d.ts +11 -0
  54. package/dist/src/client/modify/types.js +10 -0
  55. package/dist/src/client/modify/update.js +5 -3
  56. package/dist/src/client/modify/vector.js +13 -4
  57. package/dist/src/client/query/BasedDbQuery.d.ts +1 -1
  58. package/dist/src/client/query/BasedDbQuery.js +2 -2
  59. package/dist/src/client/query/BasedIterable.d.ts +1 -1
  60. package/dist/src/client/query/BasedIterable.js +7 -2
  61. package/dist/src/client/query/filter/createFixedFilterBuffer.d.ts +2 -1
  62. package/dist/src/client/query/filter/createFixedFilterBuffer.js +11 -28
  63. package/dist/src/client/query/filter/createReferenceFilter.d.ts +2 -1
  64. package/dist/src/client/query/filter/createReferenceFilter.js +10 -9
  65. package/dist/src/client/query/filter/createVariableFilterBuffer.d.ts +2 -1
  66. package/dist/src/client/query/filter/createVariableFilterBuffer.js +8 -10
  67. package/dist/src/client/query/filter/parseFilterValue.js +1 -1
  68. package/dist/src/client/query/filter/primitiveFilter.js +9 -9
  69. package/dist/src/client/query/filter/toBuffer.js +0 -15
  70. package/dist/src/client/query/filter/types.d.ts +1 -0
  71. package/dist/src/client/query/filter/types.js +1 -0
  72. package/dist/src/client/query/include/walk.js +0 -1
  73. package/dist/src/client/query/read/read.js +16 -7
  74. package/dist/src/client/query/search/index.js +11 -15
  75. package/dist/src/client/query/subscription/index.d.ts +1 -2
  76. package/dist/src/client/query/subscription/index.js +3 -50
  77. package/dist/src/client/query/subscription/markers.js +1 -2
  78. package/dist/src/client/query/subscription/run.js +0 -2
  79. package/dist/src/client/query/subscription/types.d.ts +1 -29
  80. package/dist/src/client/query/subscription/types.js +8 -1
  81. package/dist/src/client/query/thresholds.d.ts +0 -2
  82. package/dist/src/client/query/thresholds.js +0 -2
  83. package/dist/src/client/query/toBuffer.js +16 -42
  84. package/dist/src/client/query/types.d.ts +3 -2
  85. package/dist/src/client/query/validation.d.ts +1 -3
  86. package/dist/src/client/query/validation.js +6 -18
  87. package/dist/src/client/string.d.ts +2 -0
  88. package/dist/src/client/string.js +10 -14
  89. package/dist/src/index.d.ts +1 -1
  90. package/dist/src/index.js +11 -15
  91. package/dist/src/native.d.ts +3 -3
  92. package/dist/src/native.js +6 -4
  93. package/dist/src/server/csmt/draw-dot.js +2 -2
  94. package/dist/src/server/csmt/tree.js +57 -6
  95. package/dist/src/server/csmt/types.d.ts +5 -0
  96. package/dist/src/server/index.d.ts +4 -3
  97. package/dist/src/server/index.js +44 -44
  98. package/dist/src/server/migrate/index.js +47 -29
  99. package/dist/src/server/migrate/worker.js +2 -2
  100. package/dist/src/server/save.js +40 -28
  101. package/dist/src/server/start.js +7 -19
  102. package/dist/src/server/tree.d.ts +2 -0
  103. package/dist/src/server/tree.js +34 -2
  104. package/dist/src/server/worker.js +3 -3
  105. package/dist/src/utils.d.ts +3 -1
  106. package/dist/src/utils.js +43 -19
  107. package/package.json +9 -3
  108. package/dist/lib/darwin_aarch64/include/selva/base64.h +0 -59
  109. package/dist/lib/darwin_aarch64/include/selva/base64url.h +0 -59
  110. package/dist/lib/linux_aarch64/include/selva/base64.h +0 -59
  111. package/dist/lib/linux_aarch64/include/selva/base64url.h +0 -59
  112. package/dist/lib/linux_x86_64/include/selva/base64.h +0 -59
  113. package/dist/lib/linux_x86_64/include/selva/base64url.h +0 -59
  114. package/dist/src/client/timestamp.d.ts +0 -1
  115. 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
- for (const key in this) {
27
- const fn = this[key];
28
- if (typeof fn === 'function') {
29
- // @ts-ignore
30
- this[key] = function () {
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
- flushTime: 0,
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.hooks.flushTime + 10, 10));
126
+ await wait(Math.max(this.client.flushTime + 10, 10));
131
127
  this.client.destroy();
132
128
  await this.server.destroy();
133
129
  }
@@ -1,4 +1,4 @@
1
- declare const _default: {
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 _default;
27
+ export default native;
@@ -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
- export default {
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 { base64encode } from '../../utils.js';
1
+ import { encodeBase64 } from '@saulx/utils';
2
2
  function makeLabel(node) {
3
- return `${node.key}\n${base64encode(node.hash, 0).substring(0, 5)}`;
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('Key exist');
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 && k <= left.key)
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 && k <= right.key)
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
- getQueryBuf(buf: Uint8Array): Promise<Uint8Array>;
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>;
@@ -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 { foreachDirtyBlock, makeCsmtKey, makeCsmtKeyFromNodeId, } from './tree.js';
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(8);
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
- const offset = def.lastId - startId;
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
- getQueryBuf(buf) {
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.queryQueue.set(resolve, buf);
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.queryQueue.set(resolve, buf);
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
- for (const buf of this.modifyQueue) {
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
- for (const [resolve, buf] of this.queryQueue) {
501
- resolve(this.getQueryBuf(buf));
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?.unlistenExit();
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 (abort()) {
90
- break;
91
- }
92
- if (i === ranges.length && fromDbServer.dirtyRanges.size) {
93
- ranges = [];
94
- i = 0;
95
- foreachDirtyBlock(fromDbServer, (_mtKey, typeId, start, end) => {
96
- ranges.push({
97
- typeId,
98
- start,
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
- fromDbServer.dirtyRanges.clear();
108
+ fromDbServer.dirtyRanges.clear();
109
+ }
103
110
  }
104
111
  }
105
- if (!abort()) {
106
- let msg;
107
- let schema;
108
- let schemaTypesParsed;
109
- while ((msg = receiveMessageOnPort(port1))) {
110
- ;
111
- [schema, schemaTypesParsed] = msg.message;
112
- }
113
- fromDbServer.schema = deepMerge(toDb.server.schema, schema);
114
- fromDbServer.schemaTypesParsed = deepMerge(toDb.server.schemaTypesParsed, schemaTypesParsed);
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 - leafData.start + 1)
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 - leafData.start + 1)
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 });