@based/db 0.0.64 → 0.0.67
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 +2 -2
- package/dist/lib/darwin_aarch64/include/selva/colvec.h +71 -0
- package/dist/lib/darwin_aarch64/include/selva/db.h +33 -4
- package/dist/lib/darwin_aarch64/include/selva/fields.h +37 -25
- package/dist/lib/darwin_aarch64/include/selva/hll.h +5 -3
- package/dist/lib/darwin_aarch64/include/selva/membar.h +23 -0
- package/dist/lib/darwin_aarch64/include/selva/types.h +8 -1
- package/dist/lib/darwin_aarch64/include/selva/worker_ctx.h +19 -3
- 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/libnode-v24.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/colvec.h +71 -0
- package/dist/lib/linux_aarch64/include/selva/db.h +33 -4
- package/dist/lib/linux_aarch64/include/selva/fields.h +37 -25
- package/dist/lib/linux_aarch64/include/selva/hll.h +5 -3
- package/dist/lib/linux_aarch64/include/selva/membar.h +23 -0
- package/dist/lib/linux_aarch64/include/selva/types.h +8 -1
- package/dist/lib/linux_aarch64/include/selva/worker_ctx.h +19 -3
- 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/libnode-v24.node +0 -0
- package/dist/lib/linux_aarch64/libselva.so +0 -0
- package/dist/lib/linux_x86_64/include/selva/colvec.h +71 -0
- package/dist/lib/linux_x86_64/include/selva/db.h +33 -4
- package/dist/lib/linux_x86_64/include/selva/fields.h +37 -25
- package/dist/lib/linux_x86_64/include/selva/hll.h +5 -3
- package/dist/lib/linux_x86_64/include/selva/membar.h +23 -0
- package/dist/lib/linux_x86_64/include/selva/types.h +8 -1
- package/dist/lib/linux_x86_64/include/selva/worker_ctx.h +19 -3
- 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/libnode-v24.node +0 -0
- package/dist/lib/linux_x86_64/libselva.so +0 -0
- package/dist/src/client/flushModify.d.ts +2 -1
- package/dist/src/client/flushModify.js +12 -4
- package/dist/src/client/modify/create.js +11 -0
- package/dist/src/client/modify/delete.js +3 -0
- package/dist/src/client/modify/fixed.js +1 -1
- package/dist/src/client/modify/modify.js +2 -2
- package/dist/src/client/modify/setCursor.d.ts +2 -1
- package/dist/src/client/query/BasedDbQuery.d.ts +10 -4
- package/dist/src/client/query/BasedDbQuery.js +114 -6
- package/dist/src/client/query/aggregates/aggregation.js +24 -11
- package/dist/src/client/query/aggregates/types.d.ts +22 -2
- package/dist/src/client/query/aggregates/types.js +34 -1
- package/dist/src/client/query/display.js +8 -2
- package/dist/src/client/query/filter/createVariableFilterBuffer.d.ts +2 -3
- package/dist/src/client/query/filter/createVariableFilterBuffer.js +20 -7
- package/dist/src/client/query/filter/filter.js +13 -3
- package/dist/src/client/query/filter/primitiveFilter.d.ts +1 -2
- package/dist/src/client/query/include/props.js +18 -2
- package/dist/src/client/query/include/toBuffer.js +11 -3
- package/dist/src/client/query/include/walk.js +5 -1
- package/dist/src/client/query/queryDef.js +4 -1
- package/dist/src/client/query/read/read.js +52 -22
- package/dist/src/client/query/registerQuery.js +1 -0
- package/dist/src/client/query/search/index.d.ts +1 -1
- package/dist/src/client/query/search/index.js +21 -7
- package/dist/src/client/query/sort.d.ts +1 -1
- package/dist/src/client/query/toByteCode/default.d.ts +1 -1
- package/dist/src/client/query/toByteCode/default.js +0 -2
- package/dist/src/client/query/toByteCode/toBuffer.js +0 -7
- package/dist/src/client/query/types.d.ts +16 -5
- package/dist/src/client/query/validation.d.ts +3 -0
- package/dist/src/client/query/validation.js +34 -2
- package/dist/src/client/xxHash64.d.ts +1 -1
- package/dist/src/index.d.ts +1 -2
- package/dist/src/index.js +0 -1
- package/dist/src/native.d.ts +7 -4
- package/dist/src/native.js +23 -13
- package/dist/src/server/IoWorker.d.ts +8 -0
- package/dist/src/server/IoWorker.js +39 -0
- package/dist/src/server/QueryWorker.d.ts +8 -0
- package/dist/src/server/QueryWorker.js +26 -0
- package/dist/src/server/blocks.d.ts +24 -0
- package/dist/src/server/blocks.js +112 -0
- package/dist/src/server/dbHash.d.ts +1 -1
- package/dist/src/server/index.d.ts +10 -16
- package/dist/src/server/index.js +39 -15
- package/dist/src/server/migrate/index.d.ts +5 -0
- package/dist/src/server/migrate/index.js +11 -7
- package/dist/src/server/migrate/worker.js +3 -0
- package/dist/src/server/save.d.ts +8 -6
- package/dist/src/server/save.js +34 -78
- package/dist/src/server/schema.js +6 -5
- package/dist/src/server/start.js +57 -60
- package/dist/src/server/tree.d.ts +24 -13
- package/dist/src/server/tree.js +95 -66
- package/dist/src/server/workers/DbWorker.d.ts +17 -0
- package/dist/src/server/{DbWorker.js → workers/DbWorker.js} +15 -17
- package/dist/src/server/workers/io_worker.js +39 -0
- package/dist/src/server/workers/io_worker_types.d.ts +12 -0
- package/dist/src/server/workers/io_worker_types.js +2 -0
- package/dist/src/server/workers/query_worker.d.ts +1 -0
- package/dist/src/server/workers/query_worker.js +4 -0
- package/dist/src/server/workers/worker.d.ts +1 -0
- package/dist/src/server/workers/worker.js +41 -0
- package/dist/src/shared/Emitter.d.ts +1 -0
- package/dist/src/types.d.ts +1 -1
- package/dist/src/types.js +1 -1
- package/package.json +3 -3
- package/dist/lib/darwin_aarch64/include/selva/find.h +0 -47
- package/dist/lib/darwin_aarch64/include/selva/history.h +0 -64
- package/dist/lib/darwin_aarch64/include/selva/queue_r.h +0 -190
- package/dist/lib/darwin_aarch64/include/selva/traverse.h +0 -65
- package/dist/lib/linux_aarch64/include/selva/find.h +0 -47
- package/dist/lib/linux_aarch64/include/selva/history.h +0 -64
- package/dist/lib/linux_aarch64/include/selva/queue_r.h +0 -190
- package/dist/lib/linux_aarch64/include/selva/traverse.h +0 -65
- package/dist/lib/linux_x86_64/include/selva/find.h +0 -47
- package/dist/lib/linux_x86_64/include/selva/history.h +0 -64
- package/dist/lib/linux_x86_64/include/selva/queue_r.h +0 -190
- package/dist/lib/linux_x86_64/include/selva/traverse.h +0 -65
- package/dist/src/client/query/serialize.d.ts +0 -4
- package/dist/src/client/query/serialize.js +0 -26
- package/dist/src/server/DbWorker.d.ts +0 -13
- package/dist/src/server/csmt/draw-dot.d.ts +0 -4
- package/dist/src/server/csmt/draw-dot.js +0 -38
- package/dist/src/server/csmt/index.d.ts +0 -4
- package/dist/src/server/csmt/index.js +0 -5
- package/dist/src/server/csmt/match.d.ts +0 -7
- package/dist/src/server/csmt/match.js +0 -10
- package/dist/src/server/csmt/memebership-proof.d.ts +0 -7
- package/dist/src/server/csmt/memebership-proof.js +0 -122
- package/dist/src/server/csmt/tree-utils.d.ts +0 -6
- package/dist/src/server/csmt/tree-utils.js +0 -33
- package/dist/src/server/csmt/tree.d.ts +0 -3
- package/dist/src/server/csmt/tree.js +0 -270
- package/dist/src/server/csmt/types.d.ts +0 -46
- package/dist/src/server/csmt/types.js +0 -2
- package/dist/src/server/worker.js +0 -33
- /package/dist/src/server/{worker.d.ts → workers/io_worker.d.ts} +0 -0
package/dist/src/server/save.js
CHANGED
|
@@ -2,30 +2,26 @@ import native from '../native.js';
|
|
|
2
2
|
import { isMainThread } from 'node:worker_threads';
|
|
3
3
|
import { writeFile } from 'node:fs/promises';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import {
|
|
5
|
+
import { VerifTree, destructureTreeKey, } from './tree.js';
|
|
6
|
+
import { saveBlock, foreachBlock, foreachDirtyBlock, } from './blocks.js';
|
|
6
7
|
import { writeFileSync } from 'node:fs';
|
|
7
8
|
import { bufToHex } from '@saulx/utils';
|
|
8
9
|
import { COMMON_SDB_FILE, WRITELOG_FILE } from '../types.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const err = native.saveRange(path, typeId, start, end, db.dbCtxExternal, hashOut);
|
|
14
|
-
if (err == -8) {
|
|
15
|
-
// TODO ENOENT
|
|
16
|
-
return ''; // empty range
|
|
10
|
+
function hasPartialTypes(db) {
|
|
11
|
+
let res = false;
|
|
12
|
+
for (let id in db.schemaTypesParsedById) {
|
|
13
|
+
res = res || db.schemaTypesParsedById[id].partial;
|
|
17
14
|
}
|
|
18
|
-
|
|
19
|
-
// TODO print the error string
|
|
20
|
-
console.error(`Save ${typeId}:${start}-${end} failed: ${err}`);
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
return file;
|
|
15
|
+
return res;
|
|
24
16
|
}
|
|
25
17
|
export function save(db, sync = false, forceFullDump = false, skipMigrationCheck = false) {
|
|
26
18
|
if (!(isMainThread && (db.dirtyRanges.size || forceFullDump))) {
|
|
27
19
|
return;
|
|
28
20
|
}
|
|
21
|
+
if (forceFullDump && hasPartialTypes(db)) {
|
|
22
|
+
db.emit('error', 'forceFullDump is not allowed with partial types');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
29
25
|
if (db.migrating && !skipMigrationCheck) {
|
|
30
26
|
db.emit('info', 'Block save db is migrating');
|
|
31
27
|
return;
|
|
@@ -40,62 +36,21 @@ export function save(db, sync = false, forceFullDump = false, skipMigrationCheck
|
|
|
40
36
|
let err;
|
|
41
37
|
err = native.saveCommon(join(db.fileSystemPath, COMMON_SDB_FILE), db.dbCtxExternal);
|
|
42
38
|
if (err) {
|
|
43
|
-
|
|
39
|
+
db.emit('error', `Save common failed: ${err}`);
|
|
44
40
|
// Return ?
|
|
45
41
|
}
|
|
46
42
|
if (forceFullDump) {
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
const hash = new Uint8Array(16);
|
|
55
|
-
const file = saveRange(db, typeId, start, end, hash);
|
|
56
|
-
if (file === null) {
|
|
57
|
-
throw new Error('full dump failed');
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
const data = {
|
|
61
|
-
file,
|
|
62
|
-
typeId,
|
|
63
|
-
start,
|
|
64
|
-
end,
|
|
65
|
-
};
|
|
66
|
-
db.merkleTree.insert(mtKey, hash, data);
|
|
67
|
-
}
|
|
68
|
-
});
|
|
43
|
+
// reset the state just in case
|
|
44
|
+
db.verifTree = new VerifTree(db.schemaTypesParsed);
|
|
45
|
+
// We use db.verifTree.types instead of db.schemaTypesParsed because it's
|
|
46
|
+
// ordered.
|
|
47
|
+
for (const { typeId } of db.verifTree.types()) {
|
|
48
|
+
const def = db.schemaTypesParsedById[typeId];
|
|
49
|
+
foreachBlock(db, def, (start, end, _hash) => saveBlock(db, def.id, start, end));
|
|
69
50
|
}
|
|
70
51
|
}
|
|
71
52
|
else {
|
|
72
|
-
|
|
73
|
-
const hash = new Uint8Array(16);
|
|
74
|
-
const file = saveRange(db, typeId, start, end, hash);
|
|
75
|
-
if (file === null) {
|
|
76
|
-
// The previous state should remain in the merkle tree for
|
|
77
|
-
// load and sync purposes.
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
else {
|
|
81
|
-
const oldLeaf = db.merkleTree.search(mtKey);
|
|
82
|
-
// If (file.length === 0) then the range is empty but that's fine,
|
|
83
|
-
// we'll keep them around for now to maintain the order of the tree.
|
|
84
|
-
if (oldLeaf) {
|
|
85
|
-
oldLeaf.data.file = file;
|
|
86
|
-
db.merkleTree.update(mtKey, hash);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
const data = {
|
|
90
|
-
file,
|
|
91
|
-
typeId,
|
|
92
|
-
start,
|
|
93
|
-
end,
|
|
94
|
-
};
|
|
95
|
-
db.merkleTree.insert(mtKey, hash, data);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
});
|
|
53
|
+
foreachDirtyBlock(db, (_mtKey, typeId, start, end) => saveBlock(db, typeId, start, end));
|
|
99
54
|
}
|
|
100
55
|
db.dirtyRanges.clear();
|
|
101
56
|
const types = {};
|
|
@@ -105,22 +60,24 @@ export function save(db, sync = false, forceFullDump = false, skipMigrationCheck
|
|
|
105
60
|
types[id] = { lastId, blockCapacity };
|
|
106
61
|
rangeDumps[id] = [];
|
|
107
62
|
}
|
|
108
|
-
db.
|
|
109
|
-
const [typeId, start] =
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const data =
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
63
|
+
db.verifTree.foreachBlock((block) => {
|
|
64
|
+
const [typeId, start] = destructureTreeKey(block.key);
|
|
65
|
+
const def = db.schemaTypesParsedById[typeId];
|
|
66
|
+
const end = start + def.blockCapacity - 1;
|
|
67
|
+
const data = {
|
|
68
|
+
file: db.verifTree.getBlockFile(block),
|
|
69
|
+
hash: bufToHex(block.hash),
|
|
70
|
+
start,
|
|
71
|
+
end,
|
|
72
|
+
};
|
|
73
|
+
rangeDumps[typeId].push(data);
|
|
117
74
|
});
|
|
118
75
|
const data = {
|
|
119
76
|
ts,
|
|
120
77
|
types,
|
|
121
78
|
commonDump: COMMON_SDB_FILE,
|
|
122
79
|
rangeDumps,
|
|
123
|
-
hash: bufToHex(db.
|
|
80
|
+
hash: bufToHex(db.verifTree.hash), // TODO `hash('hex')`
|
|
124
81
|
};
|
|
125
82
|
const filePath = join(db.fileSystemPath, WRITELOG_FILE);
|
|
126
83
|
const content = JSON.stringify(data);
|
|
@@ -137,8 +94,7 @@ export function save(db, sync = false, forceFullDump = false, skipMigrationCheck
|
|
|
137
94
|
resolve(v);
|
|
138
95
|
})
|
|
139
96
|
.catch((err) => {
|
|
140
|
-
|
|
141
|
-
db.emit('info', `Save: writing writeLog failed ${err.message}`);
|
|
97
|
+
db.emit('error', `Save: writing writeLog failed ${err.message}`);
|
|
142
98
|
db.saveInProgress = false;
|
|
143
99
|
reject(err);
|
|
144
100
|
});
|
|
@@ -146,7 +102,7 @@ export function save(db, sync = false, forceFullDump = false, skipMigrationCheck
|
|
|
146
102
|
}
|
|
147
103
|
}
|
|
148
104
|
catch (err) {
|
|
149
|
-
db.emit('
|
|
105
|
+
db.emit('error', `Save failed ${err.message}`);
|
|
150
106
|
db.saveInProgress = false;
|
|
151
107
|
throw err;
|
|
152
108
|
}
|
|
@@ -2,11 +2,11 @@ import { schemaToSelvaBuffer, updateTypeDefs } from '@based/schema/def';
|
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { writeFile } from 'node:fs/promises';
|
|
4
4
|
import native from '../native.js';
|
|
5
|
-
import {
|
|
5
|
+
import { makeTreeKey } from './tree.js';
|
|
6
6
|
import { deepCopy, writeUint64 } from '@saulx/utils';
|
|
7
7
|
import { SCHEMA_FILE } from '../types.js';
|
|
8
8
|
import { hash } from '@saulx/hash';
|
|
9
|
-
import { getPropType } from '@based/schema';
|
|
9
|
+
import { getPropType, serialize } from '@based/schema';
|
|
10
10
|
export const setSchemaOnServer = (server, schema) => {
|
|
11
11
|
const { schemaTypesParsed, schemaTypesParsedById } = updateTypeDefs(schema);
|
|
12
12
|
server.schema = schema;
|
|
@@ -16,7 +16,7 @@ export const setSchemaOnServer = (server, schema) => {
|
|
|
16
16
|
export const writeSchemaFile = async (server, schema) => {
|
|
17
17
|
const schemaFilePath = join(server.fileSystemPath, SCHEMA_FILE);
|
|
18
18
|
try {
|
|
19
|
-
await writeFile(schemaFilePath,
|
|
19
|
+
await writeFile(schemaFilePath, serialize(schema));
|
|
20
20
|
}
|
|
21
21
|
catch (err) {
|
|
22
22
|
throw new Error(`Error writing schema to a file path ${schemaFilePath}}`);
|
|
@@ -38,7 +38,7 @@ export const setNativeSchema = (server, schema) => {
|
|
|
38
38
|
if (schema.types._root) {
|
|
39
39
|
// TODO fix server add it in schema at least
|
|
40
40
|
const data = [2, 1, 0, 0, 0, 1, 9, 1, 0, 0, 0, 7, 1, 0, 1];
|
|
41
|
-
const blockKey =
|
|
41
|
+
const blockKey = makeTreeKey(1, 1);
|
|
42
42
|
const buf = new Uint8Array(8 + data.length + 2 + 8 + 4);
|
|
43
43
|
const view = new DataView(buf.buffer, 0, buf.byteLength);
|
|
44
44
|
// set schema hash
|
|
@@ -52,8 +52,9 @@ export const setNativeSchema = (server, schema) => {
|
|
|
52
52
|
// add dataLen
|
|
53
53
|
view.setUint32(buf.length - 4, data.length, true);
|
|
54
54
|
server.modify(buf);
|
|
55
|
-
|
|
55
|
+
//server.verifTree = new VerifTree(.schemaTypesParsed)
|
|
56
56
|
}
|
|
57
|
+
server.verifTree.updateTypes(server.schemaTypesParsed);
|
|
57
58
|
};
|
|
58
59
|
export const strictSchemaToDbSchema = (schema) => {
|
|
59
60
|
// @ts-ignore
|
package/dist/src/server/start.js
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { availableParallelism } from 'node:os';
|
|
2
|
+
import { QueryWorker } from './QueryWorker.js';
|
|
3
|
+
import { IoWorker } from './IoWorker.js';
|
|
2
4
|
import native from '../native.js';
|
|
3
5
|
import { rm, mkdir, readFile } from 'node:fs/promises';
|
|
4
6
|
import { join } from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
+
import { VerifTree, makeTreeKey } from './tree.js';
|
|
8
|
+
import { foreachBlock } from './blocks.js';
|
|
7
9
|
import exitHook from 'exit-hook';
|
|
8
10
|
import { save } from './save.js';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
+
import { deSerialize } from '@based/schema';
|
|
12
|
+
import { BLOCK_CAPACITY_DEFAULT } from '@based/schema/def';
|
|
13
|
+
import { bufToHex, equals, hexToBuf, wait } from '@saulx/utils';
|
|
11
14
|
import { SCHEMA_FILE, WRITELOG_FILE } from '../types.js';
|
|
12
15
|
import { setSchemaOnServer } from './schema.js';
|
|
16
|
+
function startWorkers(db, opts) {
|
|
17
|
+
const queryThreads = opts?.queryThreads ?? availableParallelism();
|
|
18
|
+
const address = native.intFromExternal(db.dbCtxExternal);
|
|
19
|
+
db.workers = [];
|
|
20
|
+
for (let i = 0; i < queryThreads; i++) {
|
|
21
|
+
db.workers.push(new QueryWorker(address, db, i));
|
|
22
|
+
}
|
|
23
|
+
db.ioWorker = new IoWorker(address, db);
|
|
24
|
+
}
|
|
13
25
|
export async function start(db, opts) {
|
|
14
26
|
const path = db.fileSystemPath;
|
|
15
27
|
const noop = () => { };
|
|
@@ -19,6 +31,7 @@ export async function start(db, opts) {
|
|
|
19
31
|
await mkdir(path, { recursive: true }).catch(noop);
|
|
20
32
|
db.dbCtxExternal = native.start();
|
|
21
33
|
let writelog = null;
|
|
34
|
+
let partials = []; // Blocks that exists but were not loaded [key, hash]
|
|
22
35
|
try {
|
|
23
36
|
writelog = JSON.parse((await readFile(join(path, WRITELOG_FILE))).toString());
|
|
24
37
|
// Load the common dump
|
|
@@ -29,81 +42,66 @@ export async function start(db, opts) {
|
|
|
29
42
|
console.error(e.message);
|
|
30
43
|
throw e;
|
|
31
44
|
}
|
|
45
|
+
const schema = await readFile(join(path, SCHEMA_FILE));
|
|
46
|
+
if (schema) {
|
|
47
|
+
const s = deSerialize(schema);
|
|
48
|
+
setSchemaOnServer(db, s);
|
|
49
|
+
}
|
|
32
50
|
// Load all range dumps
|
|
33
51
|
for (const typeId in writelog.rangeDumps) {
|
|
34
52
|
const dumps = writelog.rangeDumps[typeId];
|
|
53
|
+
const def = db.schemaTypesParsedById[typeId];
|
|
35
54
|
for (const dump of dumps) {
|
|
36
55
|
const fname = dump.file;
|
|
37
56
|
if (fname?.length > 0) {
|
|
38
|
-
|
|
39
|
-
|
|
57
|
+
if (!def.partial) {
|
|
58
|
+
try {
|
|
59
|
+
// Can't use loadBlock() yet because verifTree is not avail
|
|
60
|
+
native.loadBlock(join(path, fname), db.dbCtxExternal);
|
|
61
|
+
}
|
|
62
|
+
catch (e) {
|
|
63
|
+
console.error(e.message);
|
|
64
|
+
}
|
|
40
65
|
}
|
|
41
|
-
|
|
42
|
-
|
|
66
|
+
else {
|
|
67
|
+
partials.push([
|
|
68
|
+
makeTreeKey(def.id, dump.start),
|
|
69
|
+
hexToBuf(dump.hash),
|
|
70
|
+
]);
|
|
43
71
|
}
|
|
44
72
|
}
|
|
45
73
|
}
|
|
46
74
|
}
|
|
47
|
-
const schema = await readFile(join(path, SCHEMA_FILE));
|
|
48
|
-
if (schema) {
|
|
49
|
-
const s = JSON.parse(schema.toString());
|
|
50
|
-
setSchemaOnServer(db, s);
|
|
51
|
-
}
|
|
52
75
|
}
|
|
53
76
|
catch (err) {
|
|
54
77
|
// TODO In some cases we really should give up!
|
|
55
78
|
}
|
|
56
|
-
|
|
57
|
-
for (const
|
|
58
|
-
const def =
|
|
79
|
+
db.verifTree = new VerifTree(db.schemaTypesParsed);
|
|
80
|
+
for (const { typeId } of db.verifTree.types()) {
|
|
81
|
+
const def = db.schemaTypesParsedById[typeId];
|
|
59
82
|
const [total, lastId] = native.getTypeInfo(def.id, db.dbCtxExternal);
|
|
60
83
|
def.lastId = writelog?.types[def.id]?.lastId || lastId;
|
|
61
84
|
def.blockCapacity =
|
|
62
|
-
writelog?.types[def.id]?.blockCapacity ||
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
db.merkleTree.insert(mtKey, hash, data);
|
|
74
|
-
}, true);
|
|
85
|
+
writelog?.types[def.id]?.blockCapacity ||
|
|
86
|
+
def.blockCapacity ||
|
|
87
|
+
BLOCK_CAPACITY_DEFAULT;
|
|
88
|
+
foreachBlock(db, def, (start, _end, hash) => {
|
|
89
|
+
const mtKey = makeTreeKey(def.id, start);
|
|
90
|
+
db.verifTree.update(mtKey, hash);
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// Insert partials to make the hash match
|
|
94
|
+
for (const [key, hash] of partials) {
|
|
95
|
+
db.verifTree.update(key, hash, false);
|
|
75
96
|
}
|
|
76
97
|
if (writelog?.hash) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
// console.error(
|
|
82
|
-
// `WARN: CSMT hash mismatch. expected: ${writelog.hash} actual: ${bufToHex(newHash)}`,
|
|
83
|
-
// )
|
|
84
|
-
//}
|
|
85
|
-
const oldHashSet = new Set();
|
|
86
|
-
const newHashSet = new Set();
|
|
87
|
-
for (let k in writelog.rangeDumps)
|
|
88
|
-
writelog.rangeDumps[k].forEach(({ hash }) => oldHashSet.add(hash));
|
|
89
|
-
db.merkleTree.visitLeafNodes(({ key, hash }) => {
|
|
90
|
-
const [_typeId, start] = destructureCsmtKey(key);
|
|
91
|
-
if (start == specialBlock)
|
|
92
|
-
return; // skip the type specialBlock
|
|
93
|
-
newHashSet.add(bufToHex(hash));
|
|
94
|
-
});
|
|
95
|
-
const setEq = (a, b) => a.size === b.size && [...a].every((value) => b.has(value));
|
|
96
|
-
if (!setEq(oldHashSet, newHashSet)) {
|
|
97
|
-
console.error(`WARN: CSMT hash mismatch.`);
|
|
98
|
+
const oldHash = hexToBuf(writelog.hash);
|
|
99
|
+
const newHash = db.verifTree.hash;
|
|
100
|
+
if (!equals(oldHash, newHash)) {
|
|
101
|
+
console.error(`WARN: DB hash mismatch. expected: ${writelog.hash} actual: ${bufToHex(newHash)}`);
|
|
98
102
|
}
|
|
99
103
|
}
|
|
100
|
-
|
|
101
|
-
const queryThreads = opts?.queryThreads ?? availableParallelism();
|
|
102
|
-
const address = native.intFromExternal(db.dbCtxExternal);
|
|
103
|
-
db.workers = [];
|
|
104
|
-
for (let i = 0; i < queryThreads; i++) {
|
|
105
|
-
db.workers.push(new DbWorker(address, db, i));
|
|
106
|
-
}
|
|
104
|
+
startWorkers(db, opts);
|
|
107
105
|
if (!opts?.hosted) {
|
|
108
106
|
db.unlistenExit = exitHook((signal) => {
|
|
109
107
|
const blockSig = () => { };
|
|
@@ -118,9 +116,8 @@ export async function start(db, opts) {
|
|
|
118
116
|
signals.forEach((sig) => process.off(sig, blockSig));
|
|
119
117
|
});
|
|
120
118
|
}
|
|
121
|
-
const d = performance.now();
|
|
122
119
|
await Promise.all(db.workers.map(({ readyPromise }) => readyPromise));
|
|
123
|
-
db.emit('info',
|
|
120
|
+
db.emit('info', 'All workers ready');
|
|
124
121
|
// use timeout
|
|
125
122
|
if (db.saveIntervalInSeconds > 0) {
|
|
126
123
|
db.saveInterval ??= setInterval(() => {
|
|
@@ -1,15 +1,26 @@
|
|
|
1
|
-
import { DbServer } from './index.js';
|
|
2
1
|
import { SchemaTypeDef } from '@based/schema/def';
|
|
3
|
-
export
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
export declare const destructureTreeKey: (key: number) => number[];
|
|
3
|
+
export declare const makeTreeKey: (typeId: number, start: number) => number;
|
|
4
|
+
export declare const nodeId2Start: (blockCapacity: number, nodeId: number) => number;
|
|
5
|
+
export declare const makeTreeKeyFromNodeId: (typeId: number, blockCapacity: number, nodeId: number) => number;
|
|
6
|
+
type Hash = Uint8Array;
|
|
7
|
+
export type VerifBlock = {
|
|
8
|
+
key: number;
|
|
9
|
+
hash: Hash;
|
|
10
|
+
inmem: boolean;
|
|
11
|
+
loadPromise: null | Promise<void>;
|
|
8
12
|
};
|
|
9
|
-
export declare
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
export declare class VerifTree {
|
|
14
|
+
#private;
|
|
15
|
+
constructor(schemaTypesParsed: Record<string, SchemaTypeDef>);
|
|
16
|
+
types(): Generator<any, void, unknown>;
|
|
17
|
+
foreachBlock(cb: (block: VerifBlock) => void): void;
|
|
18
|
+
get hash(): Uint8Array;
|
|
19
|
+
update(key: number, hash: Hash, inmem?: boolean): void;
|
|
20
|
+
remove(key: number): void;
|
|
21
|
+
static blockSdbFile(typeId: number, start: number, end: number): string;
|
|
22
|
+
getBlock(key: number): VerifBlock;
|
|
23
|
+
getBlockFile(block: VerifBlock): string;
|
|
24
|
+
updateTypes(schemaTypesParsed: Record<string, SchemaTypeDef>): void;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
package/dist/src/server/tree.js
CHANGED
|
@@ -1,80 +1,109 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
// This is a special start id set for every type to somewhat lock the order of the csmt.
|
|
4
|
-
// While the id is valid, it's never a true start id of a block.
|
|
5
|
-
export const specialBlock = 2147483647;
|
|
6
|
-
export const destructureCsmtKey = (key) => [
|
|
1
|
+
import createDbHash from './dbHash.js';
|
|
2
|
+
export const destructureTreeKey = (key) => [
|
|
7
3
|
(key / 4294967296) | 0, // typeId
|
|
8
4
|
(key >>> 31) * 2147483648 + (key & 0x7fffffff), // start_node_id
|
|
9
5
|
];
|
|
10
|
-
export const
|
|
11
|
-
export const
|
|
6
|
+
export const makeTreeKey = (typeId, start) => typeId * 4294967296 + start;
|
|
7
|
+
export const nodeId2Start = (blockCapacity, nodeId) => ((nodeId - +!(nodeId % blockCapacity)) / blockCapacity) | 0;
|
|
8
|
+
const nodeId2BlockI = (nodeId, blockCapacity) => ((nodeId - 1) - ((nodeId - 1) % blockCapacity)) / blockCapacity;
|
|
9
|
+
export const makeTreeKeyFromNodeId = (typeId, blockCapacity, nodeId) => {
|
|
12
10
|
const tmp = nodeId - +!(nodeId % blockCapacity);
|
|
13
11
|
return typeId * 4294967296 + ((tmp / blockCapacity) | 0) * blockCapacity + 1;
|
|
14
12
|
};
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
13
|
+
const HASH_SIZE = 16;
|
|
14
|
+
export class VerifTree {
|
|
15
|
+
#types;
|
|
16
|
+
#h = createDbHash();
|
|
17
|
+
constructor(schemaTypesParsed) {
|
|
18
|
+
this.#types = VerifTree.#makeTypes(schemaTypesParsed);
|
|
19
|
+
}
|
|
20
|
+
static #makeTypes(schemaTypesParsed) {
|
|
21
|
+
return Object.preventExtensions(Object.keys(schemaTypesParsed)
|
|
22
|
+
.sort((a, b) => schemaTypesParsed[a].id - schemaTypesParsed[b].id)
|
|
23
|
+
.reduce((obj, key) => {
|
|
24
|
+
const def = schemaTypesParsed[key];
|
|
25
|
+
const typeId = def.id;
|
|
26
|
+
obj[typeId] = {
|
|
27
|
+
typeId,
|
|
28
|
+
blockCapacity: def.blockCapacity,
|
|
29
|
+
hash: new Uint8Array(HASH_SIZE),
|
|
30
|
+
blocks: [],
|
|
31
|
+
};
|
|
32
|
+
return obj;
|
|
33
|
+
}, {}));
|
|
34
|
+
}
|
|
35
|
+
*types() {
|
|
36
|
+
for (const k of Object.keys(this.#types)) {
|
|
37
|
+
yield this.#types[k];
|
|
36
38
|
}
|
|
37
|
-
catch (_) { }
|
|
38
39
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const res = native.getNodeRangeHash(def.id, start, end, hash, db.dbCtxExternal);
|
|
47
|
-
if (res || includeEmptyBlocks) {
|
|
48
|
-
cb(start, end, hash);
|
|
40
|
+
foreachBlock(cb) {
|
|
41
|
+
for (const k of Object.keys(this.#types)) {
|
|
42
|
+
const { blocks } = this.#types[k];
|
|
43
|
+
for (let block of blocks) {
|
|
44
|
+
if (block)
|
|
45
|
+
cb(block);
|
|
46
|
+
}
|
|
49
47
|
}
|
|
50
48
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
get hash() {
|
|
50
|
+
this.#h.reset();
|
|
51
|
+
this.foreachBlock((block) => this.#h.update(block.hash));
|
|
52
|
+
return this.#h.digest();
|
|
53
|
+
}
|
|
54
|
+
update(key, hash, inmem = true) {
|
|
55
|
+
const [typeId, start] = destructureTreeKey(key);
|
|
56
|
+
const type = this.#types[typeId];
|
|
57
|
+
if (!type) {
|
|
58
|
+
throw new Error(`type ${typeId} not found`);
|
|
59
|
+
}
|
|
60
|
+
const blockI = nodeId2BlockI(start, type.blockCapacity);
|
|
61
|
+
const block = type.blocks[blockI] ?? (type.blocks[blockI] = Object.preventExtensions({ key, hash, inmem, loadPromise: null }));
|
|
62
|
+
block.hash = hash;
|
|
63
|
+
block.inmem = inmem;
|
|
64
|
+
}
|
|
65
|
+
remove(key) {
|
|
66
|
+
const [typeId, start] = destructureTreeKey(key);
|
|
67
|
+
const type = this.#types[typeId];
|
|
68
|
+
if (!type) {
|
|
69
|
+
throw new Error(`type ${typeId} not found`);
|
|
70
|
+
}
|
|
71
|
+
const blockI = nodeId2BlockI(start, type.blockCapacity);
|
|
72
|
+
delete type.blocks[blockI];
|
|
73
|
+
}
|
|
74
|
+
static blockSdbFile(typeId, start, end) {
|
|
75
|
+
return `${typeId}_${start}_${end}.sdb`;
|
|
76
|
+
}
|
|
77
|
+
getBlock(key) {
|
|
78
|
+
const [typeId, start] = destructureTreeKey(key);
|
|
79
|
+
const type = this.#types[typeId];
|
|
80
|
+
if (!type) {
|
|
81
|
+
throw new Error(`type ${typeId} not found`);
|
|
82
|
+
}
|
|
83
|
+
const blockI = nodeId2BlockI(start, type.blockCapacity);
|
|
84
|
+
return type.blocks[blockI];
|
|
58
85
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
86
|
+
getBlockFile(block) {
|
|
87
|
+
const [typeId, start] = destructureTreeKey(block.key);
|
|
88
|
+
const type = this.#types[typeId];
|
|
89
|
+
if (!type) {
|
|
90
|
+
throw new Error(`type ${typeId} not found`);
|
|
91
|
+
}
|
|
92
|
+
const end = start + type.blockCapacity - 1;
|
|
93
|
+
return VerifTree.blockSdbFile(typeId, start, end);
|
|
94
|
+
}
|
|
95
|
+
updateTypes(schemaTypesParsed) {
|
|
96
|
+
const oldTypes = this.#types;
|
|
97
|
+
const newTypes = VerifTree.#makeTypes(schemaTypesParsed);
|
|
98
|
+
for (const k of Object.keys(oldTypes)) {
|
|
99
|
+
const oldType = oldTypes[k];
|
|
100
|
+
const newType = newTypes[k];
|
|
101
|
+
if (newType) {
|
|
102
|
+
newType.hash = oldType.hash;
|
|
103
|
+
newType.blocks = oldType.blocks;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
this.#types = newTypes;
|
|
78
107
|
}
|
|
79
108
|
}
|
|
80
109
|
//# sourceMappingURL=tree.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { DbServer } from '../index.js';
|
|
2
|
+
export declare abstract class DbWorker {
|
|
3
|
+
constructor(address: BigInt, db: DbServer, onExit: (code: number) => void, workerName: string);
|
|
4
|
+
protected db: DbServer;
|
|
5
|
+
private channel;
|
|
6
|
+
private worker;
|
|
7
|
+
protected resolvers: ((x: any) => any)[];
|
|
8
|
+
readyPromise: Promise<true>;
|
|
9
|
+
terminate(): Promise<number>;
|
|
10
|
+
abstract handleMsg(buf: any): void;
|
|
11
|
+
protected callback: (resolve: (x: any) => any) => void;
|
|
12
|
+
/**
|
|
13
|
+
* Send msg to the worker thread and return a promise to the response.
|
|
14
|
+
*/
|
|
15
|
+
protected call(msg: any): Promise<Uint8Array>;
|
|
16
|
+
updateCtx(address: BigInt): Promise<void>;
|
|
17
|
+
}
|