@based/db 0.0.20 → 0.0.21
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/basedDbNative.cjs +6 -2
- package/dist/lib/darwin_aarch64/include/selva/db.h +3 -3
- package/dist/lib/darwin_aarch64/include/selva/fast_memcmp.h +18 -0
- package/dist/lib/darwin_aarch64/include/selva/fields.h +3 -0
- 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/linux_aarch64/include/selva/db.h +3 -3
- package/dist/lib/linux_aarch64/include/selva/fast_memcmp.h +18 -0
- package/dist/lib/linux_aarch64/include/selva/fields.h +3 -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 +3 -3
- package/dist/lib/linux_x86_64/include/selva/fast_memcmp.h +18 -0
- package/dist/lib/linux_x86_64/include/selva/fields.h +3 -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/bitWise.js +0 -1
- package/dist/src/client/crc32.d.ts +1 -1
- package/dist/src/client/modify/alias.js +3 -3
- package/dist/src/client/modify/binary.d.ts +1 -1
- package/dist/src/client/modify/binary.js +7 -6
- package/dist/src/client/modify/cardinality.d.ts +3 -1
- package/dist/src/client/modify/cardinality.js +8 -4
- package/dist/src/client/modify/create.js +41 -5
- package/dist/src/client/modify/delete.js +9 -8
- package/dist/src/client/modify/expire.js +1 -1
- package/dist/src/client/modify/modify.js +3 -3
- package/dist/src/client/modify/references/edge.js +15 -1
- package/dist/src/client/modify/setCursor.js +0 -2
- package/dist/src/client/modify/string.d.ts +1 -1
- package/dist/src/client/modify/string.js +5 -3
- package/dist/src/client/modify/text.d.ts +1 -1
- package/dist/src/client/modify/text.js +52 -9
- package/dist/src/client/modify/types.d.ts +5 -1
- package/dist/src/client/modify/types.js +2 -1
- package/dist/src/client/modify/vector.js +4 -4
- package/dist/src/client/query/filter/convertFilter.js +3 -1
- package/dist/src/client/query/filter/createFixedFilterBuffer.js +1 -1
- package/dist/src/client/query/filter/createVariableFilterBuffer.js +10 -4
- package/dist/src/client/query/filter/parseFilterValue.js +13 -4
- package/dist/src/client/query/filter/primitiveFilter.js +13 -3
- package/dist/src/client/query/filter/toBuffer.js +13 -3
- package/dist/src/client/query/filter/types.d.ts +5 -3
- package/dist/src/client/query/filter/types.js +12 -0
- package/dist/src/client/query/read/read.js +7 -1
- package/dist/src/client/query/search/index.js +25 -19
- package/dist/src/client/query/serialize.d.ts +4 -0
- package/dist/src/client/query/serialize.js +26 -0
- package/dist/src/client/query/sort.d.ts +1 -1
- package/dist/src/client/query/sort.js +5 -5
- package/dist/src/client/query/subscription/run.js +1 -1
- package/dist/src/client/query/types.d.ts +6 -2
- package/dist/src/client/query/validation.js +14 -32
- package/dist/src/client/string.d.ts +2 -2
- package/dist/src/client/string.js +32 -29
- package/dist/src/client/tmpBuffer.d.ts +3 -0
- package/dist/src/client/tmpBuffer.js +20 -0
- package/dist/src/client/xxHash64.d.ts +1 -1
- package/dist/src/client/xxHash64.js +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/native.d.ts +14 -13
- package/dist/src/native.js +41 -25
- package/dist/src/server/csmt/draw-dot.js +2 -1
- package/dist/src/server/csmt/memebership-proof.d.ts +1 -1
- package/dist/src/server/csmt/tree.d.ts +2 -1
- package/dist/src/server/csmt/tree.js +10 -9
- package/dist/src/server/csmt/types.d.ts +4 -3
- package/dist/src/server/index.d.ts +5 -4
- package/dist/src/server/index.js +5 -6
- package/dist/src/server/save.js +4 -3
- package/dist/src/server/start.d.ts +1 -0
- package/dist/src/server/start.js +43 -16
- package/dist/src/server/tree.d.ts +1 -1
- package/dist/src/server/tree.js +17 -2
- package/dist/src/server/worker.js +2 -1
- package/dist/src/utils.d.ts +4 -0
- package/dist/src/utils.js +84 -0
- package/package.json +3 -3
- package/dist/lib/darwin_aarch64/libnode-v20.11.1.node +0 -0
- package/dist/lib/darwin_aarch64/libnode-v20.18.1.node +0 -0
- package/dist/lib/darwin_aarch64/libnode-v22.13.0.node +0 -0
- package/dist/lib/linux_aarch64/libnode-v20.11.1.node +0 -0
- package/dist/lib/linux_aarch64/libnode-v20.18.1.node +0 -0
- package/dist/lib/linux_aarch64/libnode-v22.13.0.node +0 -0
- package/dist/lib/linux_x86_64/libnode-v20.11.1.node +0 -0
- package/dist/lib/linux_x86_64/libnode-v20.18.1.node +0 -0
- package/dist/lib/linux_x86_64/libnode-v22.13.0.node +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import native from '../native.js';
|
|
2
2
|
import { readUint32 } from './bitWise.js';
|
|
3
|
+
import makeTmpBuffer from './tmpBuffer.js';
|
|
3
4
|
const DECODER = new TextDecoder('utf-8');
|
|
4
|
-
|
|
5
|
+
const ENCODER = new TextEncoder();
|
|
6
|
+
const { getUint8Array: getTmpBuffer } = makeTmpBuffer(4096); // the usual page size?
|
|
5
7
|
// type 0 = no compression; 1 = deflate
|
|
6
8
|
// [lang] [type] [uncompressed size 4] [compressed string] [crc32]
|
|
7
9
|
// var cnt = 0
|
|
@@ -11,24 +13,28 @@ const DECODER = new TextDecoder('utf-8');
|
|
|
11
13
|
export const write = (buf, value, offset, noCompression, lang) => {
|
|
12
14
|
value = value.normalize('NFKD');
|
|
13
15
|
buf[offset] = lang || 0;
|
|
16
|
+
const { written: l } = ENCODER.encodeInto(value, buf.subarray(offset + 2));
|
|
17
|
+
let crc = native.crc32(buf.subarray(offset + 2, offset + 2 + l));
|
|
14
18
|
// 50 maybe if lvl 1
|
|
15
19
|
if (value.length > 200 && !noCompression) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let crc = native.crc32(buf.subarray(offset + 6 + s, offset + 6 + 2 * s));
|
|
19
|
-
const size = native.compress(buf, offset + 6, s);
|
|
20
|
+
buf.copyWithin(offset + 6 + l, offset + 2, offset + 2 + l);
|
|
21
|
+
const size = native.compress(buf, offset + 6, l);
|
|
20
22
|
if (size === 0) {
|
|
21
23
|
buf[offset + 1] = 0; // not compressed
|
|
22
|
-
|
|
23
|
-
buf[offset +
|
|
24
|
-
buf[offset +
|
|
25
|
-
buf[offset +
|
|
26
|
-
buf[offset +
|
|
27
|
-
return
|
|
24
|
+
ENCODER.encodeInto(value, buf.subarray(offset + 2));
|
|
25
|
+
buf[offset + l + 2] = crc;
|
|
26
|
+
buf[offset + l + 3] = crc >>>= 8;
|
|
27
|
+
buf[offset + l + 4] = crc >>>= 8;
|
|
28
|
+
buf[offset + l + 5] = crc >>>= 8;
|
|
29
|
+
return l + 6;
|
|
28
30
|
}
|
|
29
31
|
else {
|
|
32
|
+
let len = l;
|
|
30
33
|
buf[offset + 1] = 1; // compressed
|
|
31
|
-
buf
|
|
34
|
+
buf[offset + 2] = len;
|
|
35
|
+
buf[offset + 3] = len >>>= 8;
|
|
36
|
+
buf[offset + 4] = len >>>= 8;
|
|
37
|
+
buf[offset + 5] = len >>>= 8;
|
|
32
38
|
buf[offset + size + 6] = crc;
|
|
33
39
|
buf[offset + size + 7] = crc >>>= 8;
|
|
34
40
|
buf[offset + size + 8] = crc >>>= 8;
|
|
@@ -38,23 +44,19 @@ export const write = (buf, value, offset, noCompression, lang) => {
|
|
|
38
44
|
}
|
|
39
45
|
else {
|
|
40
46
|
buf[offset + 1] = 0; // not compressed
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
buf[offset +
|
|
44
|
-
buf[offset +
|
|
45
|
-
|
|
46
|
-
buf[offset + len + 5] = crc >>>= 8;
|
|
47
|
-
return len + 6;
|
|
47
|
+
buf[offset + l + 2] = crc;
|
|
48
|
+
buf[offset + l + 3] = crc >>>= 8;
|
|
49
|
+
buf[offset + l + 4] = crc >>>= 8;
|
|
50
|
+
buf[offset + l + 5] = crc >>>= 8;
|
|
51
|
+
return l + 6;
|
|
48
52
|
}
|
|
49
53
|
};
|
|
50
|
-
let tmpCompressBlock;
|
|
51
54
|
export const compress = (str) => {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
tmpCompressBlock.copy(nBuffer, 0, 0, s);
|
|
55
|
+
const len = ENCODER.encode(str).byteLength;
|
|
56
|
+
const tmpCompressBlock = getTmpBuffer(len * 3);
|
|
57
|
+
const l = write(tmpCompressBlock, str, 0, false);
|
|
58
|
+
const nBuffer = new Uint8Array(l);
|
|
59
|
+
nBuffer.set(tmpCompressBlock.subarray(0, l));
|
|
58
60
|
return nBuffer;
|
|
59
61
|
};
|
|
60
62
|
export const decompress = (val) => {
|
|
@@ -64,9 +66,10 @@ export const read = (val, offset, len) => {
|
|
|
64
66
|
const type = val[offset + 1];
|
|
65
67
|
if (type == 1) {
|
|
66
68
|
const origSize = readUint32(val, offset + 2);
|
|
67
|
-
const newBuffer =
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
const newBuffer = getTmpBuffer(origSize);
|
|
70
|
+
// deflate in browser for this...
|
|
71
|
+
native.decompress(val, newBuffer, offset + 6, len - 6);
|
|
72
|
+
return DECODER.decode(newBuffer);
|
|
70
73
|
}
|
|
71
74
|
else if (type == 0) {
|
|
72
75
|
return DECODER.decode(val.subarray(offset + 2, len + offset - 4));
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export default function makeTmpBuffer(initialSize) {
|
|
2
|
+
// @ts-ignore
|
|
3
|
+
let tmpBuffer = new ArrayBuffer(initialSize, { maxByteLength: initialSize });
|
|
4
|
+
return {
|
|
5
|
+
getUint8Array: (size) => {
|
|
6
|
+
const opts = {
|
|
7
|
+
maxByteLength: Math.min(Math.round(1.5 * size), 274877906944)
|
|
8
|
+
};
|
|
9
|
+
// @ts-ignore
|
|
10
|
+
if (tmpBuffer.maxByteLength < size) {
|
|
11
|
+
// @ts-ignore
|
|
12
|
+
tmpBuffer = new ArrayBuffer(size, opts);
|
|
13
|
+
}
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
tmpBuffer.resize(size);
|
|
16
|
+
return new Uint8Array(tmpBuffer);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=tmpBuffer.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const xxHash64: (buf: Buffer, target?: Buffer, index?: number) => Buffer;
|
|
1
|
+
export declare const xxHash64: (buf: Buffer | Uint8Array, target?: Uint8Array | Buffer, index?: number) => Uint8Array | Buffer;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ export { ModifyCtx };
|
|
|
8
8
|
export { DbClient, DbServer };
|
|
9
9
|
export { xxHash64 } from './client/xxHash64.js';
|
|
10
10
|
export { crc32 } from './client/crc32.js';
|
|
11
|
+
export * from './client/query/serialize.js';
|
|
12
|
+
export * from './utils.js';
|
|
11
13
|
export declare class BasedDb {
|
|
12
14
|
#private;
|
|
13
15
|
client: DbClient;
|
package/dist/src/index.js
CHANGED
|
@@ -9,6 +9,8 @@ export { ModifyCtx }; // TODO move this somewhere
|
|
|
9
9
|
export { DbClient, DbServer };
|
|
10
10
|
export { xxHash64 } from './client/xxHash64.js';
|
|
11
11
|
export { crc32 } from './client/crc32.js';
|
|
12
|
+
export * from './client/query/serialize.js';
|
|
13
|
+
export * from './utils.js';
|
|
12
14
|
export class BasedDb {
|
|
13
15
|
client;
|
|
14
16
|
server;
|
package/dist/src/native.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
declare const _default: {
|
|
2
|
-
historyAppend(history: any, typeId: number, nodeId: number): any;
|
|
2
|
+
historyAppend(history: any, typeId: number, nodeId: number, dbCtx: any): any;
|
|
3
3
|
historyCreate(pathname: string, mainLen: number): any;
|
|
4
4
|
workerCtxInit: () => void;
|
|
5
|
-
markMerkleBlock: (buf: Buffer) => any;
|
|
6
5
|
externalFromInt(address: BigInt): any;
|
|
7
6
|
intFromExternal(external: any): BigInt;
|
|
8
7
|
modify: (data: Buffer, types: Buffer, dbCtx: any) => any;
|
|
@@ -10,22 +9,24 @@ declare const _default: {
|
|
|
10
9
|
start: (id: number) => any;
|
|
11
10
|
stop: (dbCtx: any) => any;
|
|
12
11
|
saveCommon: (path: string, dbCtx: any) => number;
|
|
13
|
-
saveRange: (path: string, typeCode: number, start: number, end: number, dbCtx: any, hashOut:
|
|
14
|
-
loadCommon: (path: string, dbCtx: any) =>
|
|
15
|
-
loadRange: (path: string, dbCtx: any) =>
|
|
16
|
-
updateSchemaType: (prefix: number, buf:
|
|
12
|
+
saveRange: (path: string, typeCode: number, start: number, end: number, dbCtx: any, hashOut: Uint8Array) => number;
|
|
13
|
+
loadCommon: (path: string, dbCtx: any) => void;
|
|
14
|
+
loadRange: (path: string, dbCtx: any) => void;
|
|
15
|
+
updateSchemaType: (prefix: number, buf: Uint8Array, dbCtx: any) => any;
|
|
17
16
|
getTypeInfo: (typeId: number, dbCtx: any) => any;
|
|
18
|
-
getNodeRangeHash: (typeId: number, start: number, end: number, bufOut:
|
|
17
|
+
getNodeRangeHash: (typeId: number, start: number, end: number, bufOut: Uint8Array, dbCtx: any) => any;
|
|
19
18
|
createHash: () => {
|
|
20
|
-
update: (buf: Buffer) => any;
|
|
21
|
-
digest: (encoding?:
|
|
19
|
+
update: (buf: Buffer | Uint8Array) => any;
|
|
20
|
+
digest: (encoding?: "hex") => Uint8Array | string;
|
|
22
21
|
reset: () => void;
|
|
23
22
|
};
|
|
24
|
-
compress: (buf: Buffer, offset: number, stringSize: number) => any;
|
|
25
|
-
decompress: (input: Buffer, output: Buffer, offset: number, len: number) => any;
|
|
26
|
-
crc32: (buf: Buffer) => any;
|
|
23
|
+
compress: (buf: Buffer | Uint8Array, offset: number, stringSize: number) => any;
|
|
24
|
+
decompress: (input: Buffer | Uint8Array, output: Buffer | Uint8Array, offset: number, len: number) => any;
|
|
25
|
+
crc32: (buf: Buffer | Uint8Array) => any;
|
|
27
26
|
createSortIndex: (buf: Buffer, dbCtx: any) => any;
|
|
28
27
|
destroySortIndex: (buf: Buffer, dbCtx: any) => any;
|
|
29
|
-
xxHash64: (buf: Buffer, target: Buffer, index: number) => any;
|
|
28
|
+
xxHash64: (buf: Buffer | Uint8Array, target: Buffer | Uint8Array, index: number) => any;
|
|
29
|
+
base64encode: (dst: Uint8Array, src: Uint8Array, lineMax: number) => Uint8Array;
|
|
30
|
+
equals: (a: Uint8Array, b: Uint8Array) => boolean;
|
|
30
31
|
};
|
|
31
32
|
export default _default;
|
package/dist/src/native.js
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
// @ts-ignore
|
|
2
2
|
import db from '../../basedDbNative.cjs';
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
import { bufToHex } from './utils.js';
|
|
4
|
+
const selvaIoErrlog = new Uint8Array(256);
|
|
5
|
+
const textEncoder = new TextEncoder();
|
|
6
|
+
var compressor = db.createCompressor();
|
|
7
|
+
var decompressor = db.createDecompressor();
|
|
8
|
+
function SelvaIoErrlogToString(buf) {
|
|
9
|
+
let i;
|
|
10
|
+
let len = (i = buf.indexOf(0)) >= 0 ? i : buf.byteLength;
|
|
11
|
+
return new TextDecoder().decode(selvaIoErrlog.slice(0, len));
|
|
12
|
+
}
|
|
5
13
|
export default {
|
|
6
|
-
historyAppend(history, typeId, nodeId) {
|
|
7
|
-
return db.
|
|
14
|
+
historyAppend(history, typeId, nodeId, dbCtx) {
|
|
15
|
+
return db.historyAppend(history, typeId, nodeId, dbCtx);
|
|
8
16
|
},
|
|
9
17
|
historyCreate(pathname, mainLen) {
|
|
10
|
-
|
|
18
|
+
const pathBuf = textEncoder.encode(pathname + '\0');
|
|
19
|
+
return db.historyCreate(pathBuf, mainLen + 16 - (mainLen % 16));
|
|
11
20
|
},
|
|
12
21
|
workerCtxInit: () => {
|
|
13
22
|
return db.workerCtxInit();
|
|
14
23
|
},
|
|
15
|
-
markMerkleBlock: (buf) => {
|
|
16
|
-
// pstart,
|
|
17
|
-
},
|
|
18
24
|
externalFromInt(address) {
|
|
19
25
|
return db.externalFromInt(address);
|
|
20
26
|
},
|
|
@@ -35,20 +41,26 @@ export default {
|
|
|
35
41
|
return db.stop(dbCtx);
|
|
36
42
|
},
|
|
37
43
|
saveCommon: (path, dbCtx) => {
|
|
38
|
-
const
|
|
39
|
-
return db.saveCommon(
|
|
44
|
+
const pathBuf = textEncoder.encode(path + '\0');
|
|
45
|
+
return db.saveCommon(pathBuf, dbCtx);
|
|
40
46
|
},
|
|
41
47
|
saveRange: (path, typeCode, start, end, dbCtx, hashOut) => {
|
|
42
|
-
const
|
|
43
|
-
return db.saveRange(
|
|
48
|
+
const pathBuf = textEncoder.encode(path + '\0');
|
|
49
|
+
return db.saveRange(pathBuf, typeCode, start, end, dbCtx, hashOut);
|
|
44
50
|
},
|
|
45
51
|
loadCommon: (path, dbCtx) => {
|
|
46
|
-
const
|
|
47
|
-
|
|
52
|
+
const pathBuf = textEncoder.encode(path + '\0');
|
|
53
|
+
const err = db.loadCommon(pathBuf, dbCtx, selvaIoErrlog);
|
|
54
|
+
if (err) {
|
|
55
|
+
throw new Error(`Failed to load common. selvaError: ${err} cause:\n${SelvaIoErrlogToString(selvaIoErrlog)}`);
|
|
56
|
+
}
|
|
48
57
|
},
|
|
49
58
|
loadRange: (path, dbCtx) => {
|
|
50
|
-
const
|
|
51
|
-
|
|
59
|
+
const pathBuf = textEncoder.encode(path + '\0');
|
|
60
|
+
const err = db.loadRange(pathBuf, dbCtx, selvaIoErrlog);
|
|
61
|
+
if (err) {
|
|
62
|
+
throw new Error(`Failed to load a range. selvaError: ${err} cause:\n${SelvaIoErrlogToString(selvaIoErrlog)}`);
|
|
63
|
+
}
|
|
52
64
|
},
|
|
53
65
|
updateSchemaType: (prefix, buf, dbCtx) => {
|
|
54
66
|
return db.updateSchema(prefix, buf, dbCtx);
|
|
@@ -67,9 +79,14 @@ export default {
|
|
|
67
79
|
return hash;
|
|
68
80
|
},
|
|
69
81
|
digest: (encoding) => {
|
|
70
|
-
const buf =
|
|
82
|
+
const buf = new Uint8Array(16);
|
|
71
83
|
db.hashDigest(state, buf);
|
|
72
|
-
|
|
84
|
+
if (encoding === 'hex') {
|
|
85
|
+
return bufToHex(buf);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
return buf;
|
|
89
|
+
}
|
|
73
90
|
},
|
|
74
91
|
reset: () => {
|
|
75
92
|
db.hashReset(state);
|
|
@@ -77,17 +94,10 @@ export default {
|
|
|
77
94
|
};
|
|
78
95
|
return hash;
|
|
79
96
|
},
|
|
80
|
-
// needs to pass dbCtx: any
|
|
81
97
|
compress: (buf, offset, stringSize) => {
|
|
82
|
-
if (compressor === null) {
|
|
83
|
-
compressor = db.createCompressor();
|
|
84
|
-
}
|
|
85
98
|
return db.compress(compressor, buf, offset, stringSize);
|
|
86
99
|
},
|
|
87
100
|
decompress: (input, output, offset, len) => {
|
|
88
|
-
if (decompressor === null) {
|
|
89
|
-
decompressor = db.createDecompressor();
|
|
90
|
-
}
|
|
91
101
|
return db.decompress(decompressor, input, output, offset, len);
|
|
92
102
|
},
|
|
93
103
|
crc32: (buf) => {
|
|
@@ -102,5 +112,11 @@ export default {
|
|
|
102
112
|
xxHash64: (buf, target, index) => {
|
|
103
113
|
return db.xxHash64(buf, target, index);
|
|
104
114
|
},
|
|
115
|
+
base64encode: (dst, src, lineMax) => {
|
|
116
|
+
return db.base64encode(dst, src, lineMax);
|
|
117
|
+
},
|
|
118
|
+
equals: (a, b) => {
|
|
119
|
+
return !!db.equals(a, b);
|
|
120
|
+
},
|
|
105
121
|
};
|
|
106
122
|
//# sourceMappingURL=native.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { base64encode } from '../../utils.js';
|
|
1
2
|
function makeLabel(node) {
|
|
2
|
-
return `${node.key}\n${node.hash
|
|
3
|
+
return `${node.key}\n${base64encode(node.hash, 0).substring(0, 5)}`;
|
|
3
4
|
}
|
|
4
5
|
export default function draw(csmt) {
|
|
5
6
|
const root = csmt.getRoot();
|
|
@@ -3,5 +3,5 @@ export declare enum Direction {
|
|
|
3
3
|
Left = "L",
|
|
4
4
|
Right = "R"
|
|
5
5
|
}
|
|
6
|
-
export type Proof = [TreeKey | null, TreeKey | null] | [TreeKey |
|
|
6
|
+
export type Proof = [TreeKey | null, TreeKey | null] | [TreeKey | Uint8Array, TreeKey | Direction][];
|
|
7
7
|
export default function membershipProof(root: TreeNode | null, k: TreeKey): Proof;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { TreeKeyNil } from './types.js';
|
|
2
2
|
import { distance, min, max } from './tree-utils.js';
|
|
3
3
|
import membershipProof from './memebership-proof.js';
|
|
4
|
+
import { equals } from '../../utils.js';
|
|
5
|
+
export function hashEq(a, b) {
|
|
6
|
+
return equals(a, b);
|
|
7
|
+
}
|
|
4
8
|
export function createTree(createHash) {
|
|
5
9
|
let root = null;
|
|
6
|
-
const emptyHash =
|
|
7
|
-
function genHash(s) {
|
|
8
|
-
return createHash().update(s).digest();
|
|
9
|
-
}
|
|
10
|
+
const emptyHash = createHash().digest();
|
|
10
11
|
function genNodeHash(lHash, rHash) {
|
|
11
12
|
return createHash().update(lHash).update(rHash).digest();
|
|
12
13
|
}
|
|
@@ -123,7 +124,7 @@ export function createTree(createHash) {
|
|
|
123
124
|
if (nodeA &&
|
|
124
125
|
nodeB &&
|
|
125
126
|
nodeA.key === nodeB.key &&
|
|
126
|
-
nodeA.hash
|
|
127
|
+
hashEq(nodeA.hash, nodeB.hash)) {
|
|
127
128
|
return;
|
|
128
129
|
}
|
|
129
130
|
// No hash match
|
|
@@ -134,7 +135,7 @@ export function createTree(createHash) {
|
|
|
134
135
|
// Check if this is a leaf that is missing from the right tree
|
|
135
136
|
if (nodeA && !leftA && !rightA) {
|
|
136
137
|
const bHash = diffB.get(nodeA.key);
|
|
137
|
-
if (bHash && bHash
|
|
138
|
+
if (bHash && hashEq(bHash, nodeA.hash)) {
|
|
138
139
|
// The same leaf appears to exist in both trees
|
|
139
140
|
diffB.delete(nodeA.key);
|
|
140
141
|
}
|
|
@@ -146,7 +147,7 @@ export function createTree(createHash) {
|
|
|
146
147
|
// Check if this is a leaf that is missing from the left tree
|
|
147
148
|
if (nodeB && !leftB && !rightB) {
|
|
148
149
|
const aHash = diffA.get(nodeB.key);
|
|
149
|
-
if (aHash && aHash
|
|
150
|
+
if (aHash && hashEq(aHash, nodeB.hash)) {
|
|
150
151
|
diffA.delete(nodeB.key);
|
|
151
152
|
}
|
|
152
153
|
else {
|
|
@@ -198,8 +199,8 @@ export function createTree(createHash) {
|
|
|
198
199
|
return {
|
|
199
200
|
getRoot: () => root,
|
|
200
201
|
insert: (k, h, data = null) => {
|
|
201
|
-
if (!(h instanceof
|
|
202
|
-
throw new TypeError('`h` must be a
|
|
202
|
+
if (!(h instanceof Uint8Array)) { // TODO can we extract the name somehow from Hash?
|
|
203
|
+
throw new TypeError('`h` must be a Uint8Array'); // TODO can we extract the name somehow from Hash?
|
|
203
204
|
}
|
|
204
205
|
const newLeaf = createLeaf(k, h, data);
|
|
205
206
|
root = root ? insert(root, newLeaf) : newLeaf;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { Proof } from './memebership-proof.js';
|
|
2
2
|
export type TreeKey = number;
|
|
3
3
|
export declare const TreeKeyNil = 0;
|
|
4
|
+
export type Hash = Uint8Array;
|
|
4
5
|
export interface TreeNode {
|
|
5
|
-
hash:
|
|
6
|
+
hash: Hash;
|
|
6
7
|
key: TreeKey;
|
|
7
8
|
data?: any;
|
|
8
9
|
left: TreeNode | null;
|
|
9
10
|
right: TreeNode | null;
|
|
10
11
|
}
|
|
11
|
-
export type KeyHashPair = [TreeKey,
|
|
12
|
+
export type KeyHashPair = [TreeKey, Hash];
|
|
12
13
|
export interface TreeDiff {
|
|
13
14
|
left: KeyHashPair[];
|
|
14
15
|
right: KeyHashPair[];
|
|
@@ -21,7 +22,7 @@ export interface Csmt {
|
|
|
21
22
|
/**
|
|
22
23
|
* Insert a new key-hash pair.
|
|
23
24
|
*/
|
|
24
|
-
insert: (k: TreeKey, h:
|
|
25
|
+
insert: (k: TreeKey, h: Hash, data?: any) => void;
|
|
25
26
|
/**
|
|
26
27
|
* Delete a key-hash pair from the tree.
|
|
27
28
|
*/
|
|
@@ -36,8 +36,8 @@ export declare class DbServer {
|
|
|
36
36
|
merkleTree: ReturnType<typeof createTree>;
|
|
37
37
|
dirtyRanges: Set<number>;
|
|
38
38
|
csmtHashFun: {
|
|
39
|
-
update: (buf: Buffer) => any;
|
|
40
|
-
digest: (encoding?:
|
|
39
|
+
update: (buf: Buffer | Uint8Array) => any;
|
|
40
|
+
digest: (encoding?: "hex") => Uint8Array | string;
|
|
41
41
|
reset: () => void;
|
|
42
42
|
};
|
|
43
43
|
workers: DbWorker[];
|
|
@@ -55,11 +55,12 @@ export declare class DbServer {
|
|
|
55
55
|
});
|
|
56
56
|
start(opts?: {
|
|
57
57
|
clean?: boolean;
|
|
58
|
+
hosted?: boolean;
|
|
58
59
|
}): Promise<void>;
|
|
59
60
|
save(): void | Promise<void>;
|
|
60
61
|
createCsmtHashFun: () => {
|
|
61
|
-
update: (buf: Buffer) => any;
|
|
62
|
-
digest: (encoding?:
|
|
62
|
+
update: (buf: Buffer | Uint8Array) => any;
|
|
63
|
+
digest: (encoding?: "hex") => Uint8Array | string;
|
|
63
64
|
reset: () => void;
|
|
64
65
|
};
|
|
65
66
|
sortIndexes: {
|
package/dist/src/server/index.js
CHANGED
|
@@ -2,9 +2,8 @@ import native from '../native.js';
|
|
|
2
2
|
import { rm, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import { getPropType, langCodesMap, } from '@based/schema';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
updateTypeDefs, schemaToSelvaBuffer, } from '@based/schema/def';
|
|
5
|
+
import { updateTypeDefs, schemaToSelvaBuffer, } from '@based/schema/def';
|
|
6
|
+
import { hashEq } from './csmt/index.js';
|
|
8
7
|
import { start } from './start.js';
|
|
9
8
|
import { foreachDirtyBlock, makeCsmtKey, makeCsmtKeyFromNodeId, } from './tree.js';
|
|
10
9
|
import { save } from './save.js';
|
|
@@ -251,7 +250,7 @@ export class DbServer {
|
|
|
251
250
|
const hash = Buffer.allocUnsafe(16);
|
|
252
251
|
native.getNodeRangeHash(typeId, start, end, hash, this.dbCtxExternal);
|
|
253
252
|
if (oldLeaf) {
|
|
254
|
-
if (oldLeaf.hash
|
|
253
|
+
if (hashEq(oldLeaf.hash, hash)) {
|
|
255
254
|
return;
|
|
256
255
|
}
|
|
257
256
|
try {
|
|
@@ -331,7 +330,7 @@ export class DbServer {
|
|
|
331
330
|
const type = this.schemaTypesParsed[types[i]];
|
|
332
331
|
// TODO should not crash!
|
|
333
332
|
try {
|
|
334
|
-
native.updateSchemaType(type.id, s[i], this.dbCtxExternal);
|
|
333
|
+
native.updateSchemaType(type.id, new Uint8Array(s[i]), this.dbCtxExternal);
|
|
335
334
|
}
|
|
336
335
|
catch (err) {
|
|
337
336
|
console.error('Cannot update schema on selva', type.type, err, s[i]);
|
|
@@ -465,7 +464,7 @@ export class DbServer {
|
|
|
465
464
|
}
|
|
466
465
|
this.stopped = true;
|
|
467
466
|
clearTimeout(this.cleanupTimer);
|
|
468
|
-
this
|
|
467
|
+
this?.unlistenExit();
|
|
469
468
|
try {
|
|
470
469
|
if (!noSave) {
|
|
471
470
|
await this.save();
|
package/dist/src/server/save.js
CHANGED
|
@@ -3,6 +3,7 @@ import { writeFile } from 'node:fs/promises';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { destructureCsmtKey, foreachDirtyBlock } from './tree.js';
|
|
5
5
|
import { writeFileSync } from 'node:fs';
|
|
6
|
+
import { bufToHex } from '../utils.js';
|
|
6
7
|
const WRITELOG_FILE = 'writelog.json';
|
|
7
8
|
const COMMON_SDB_FILE = 'common.sdb';
|
|
8
9
|
const block_sdb_file = (typeId, start, end) => `${typeId}_${start}_${end}.sdb`;
|
|
@@ -19,7 +20,7 @@ export function save(db, sync = false) {
|
|
|
19
20
|
foreachDirtyBlock(db, (mtKey, typeId, start, end) => {
|
|
20
21
|
const file = block_sdb_file(typeId, start, end);
|
|
21
22
|
const path = join(db.fileSystemPath, file);
|
|
22
|
-
const hash =
|
|
23
|
+
const hash = new Uint8Array(16);
|
|
23
24
|
err = native.saveRange(path, typeId, start, end, db.dbCtxExternal, hash);
|
|
24
25
|
if (err) {
|
|
25
26
|
console.error(`Save ${typeId}:${start}-${end} failed: ${err}`);
|
|
@@ -53,7 +54,7 @@ export function save(db, sync = false) {
|
|
|
53
54
|
db.merkleTree.visitLeafNodes((leaf) => {
|
|
54
55
|
const [typeId] = destructureCsmtKey(leaf.key);
|
|
55
56
|
const data = leaf.data;
|
|
56
|
-
dumps[typeId].push({ ...data, hash: leaf.hash
|
|
57
|
+
dumps[typeId].push({ ...data, hash: bufToHex(leaf.hash) });
|
|
57
58
|
});
|
|
58
59
|
const data = {
|
|
59
60
|
ts,
|
|
@@ -63,7 +64,7 @@ export function save(db, sync = false) {
|
|
|
63
64
|
};
|
|
64
65
|
const mtRoot = db.merkleTree.getRoot();
|
|
65
66
|
if (mtRoot) {
|
|
66
|
-
data.hash = mtRoot.hash
|
|
67
|
+
data.hash = bufToHex(mtRoot.hash);
|
|
67
68
|
}
|
|
68
69
|
const filePath = join(db.fileSystemPath, WRITELOG_FILE);
|
|
69
70
|
const content = JSON.stringify(data);
|
package/dist/src/server/start.js
CHANGED
|
@@ -3,13 +3,14 @@ import { DbWorker } from './index.js';
|
|
|
3
3
|
import native from '../native.js';
|
|
4
4
|
import { rm, mkdir, readFile } from 'node:fs/promises';
|
|
5
5
|
import { join } from 'node:path';
|
|
6
|
-
import { createTree } from './csmt/index.js';
|
|
6
|
+
import { createTree, hashEq } from './csmt/index.js';
|
|
7
7
|
import { foreachBlock } from './tree.js';
|
|
8
8
|
import { availableParallelism } from 'node:os';
|
|
9
9
|
import exitHook from 'exit-hook';
|
|
10
10
|
import './worker.js';
|
|
11
11
|
import { save } from './save.js';
|
|
12
12
|
import { DEFAULT_BLOCK_CAPACITY } from '@based/schema/def';
|
|
13
|
+
import { bufToHex, hexToBuf } from '../utils.js';
|
|
13
14
|
const SCHEMA_FILE = 'schema.json';
|
|
14
15
|
const WRITELOG_FILE = 'writelog.json';
|
|
15
16
|
const makeCsmtKey = (typeId, start) => typeId * 4294967296 + start;
|
|
@@ -28,15 +29,23 @@ export async function start(db, opts) {
|
|
|
28
29
|
try {
|
|
29
30
|
writelog = JSON.parse((await readFile(join(path, WRITELOG_FILE))).toString());
|
|
30
31
|
// Load the common dump
|
|
31
|
-
|
|
32
|
+
try {
|
|
33
|
+
native.loadCommon(join(path, writelog.commonDump), db.dbCtxExternal);
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
console.log(e.message);
|
|
37
|
+
throw e;
|
|
38
|
+
}
|
|
32
39
|
// Load all range dumps
|
|
33
40
|
for (const typeId in writelog.rangeDumps) {
|
|
34
41
|
const dumps = writelog.rangeDumps[typeId];
|
|
35
42
|
for (const dump of dumps) {
|
|
36
43
|
const fname = dump.file;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
try {
|
|
45
|
+
native.loadRange(join(path, fname), db.dbCtxExternal);
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
console.log(e.message);
|
|
40
49
|
}
|
|
41
50
|
}
|
|
42
51
|
}
|
|
@@ -46,13 +55,22 @@ export async function start(db, opts) {
|
|
|
46
55
|
db.putSchema(JSON.parse(schema.toString()), true);
|
|
47
56
|
}
|
|
48
57
|
}
|
|
49
|
-
catch (err) {
|
|
58
|
+
catch (err) {
|
|
59
|
+
// TODO In some cases we really should give up!
|
|
60
|
+
}
|
|
50
61
|
// The merkle tree should be empty at start.
|
|
51
62
|
if (!db.merkleTree || db.merkleTree.getRoot()) {
|
|
52
63
|
db.merkleTree = createTree(db.createCsmtHashFun);
|
|
53
64
|
}
|
|
54
|
-
|
|
55
|
-
|
|
65
|
+
// FDN-791 CSMT is unstable (not history independent)
|
|
66
|
+
// For now we just sort the types to ensure that we always
|
|
67
|
+
// load in the same order.
|
|
68
|
+
const types = Object.keys(db.schemaTypesParsed).sort((a, b) => db.schemaTypesParsed[a].id - db.schemaTypesParsed[b].id).reduce((obj, key) => {
|
|
69
|
+
obj[key] = db.schemaTypesParsed[key];
|
|
70
|
+
return obj;
|
|
71
|
+
}, {});
|
|
72
|
+
for (const key in types) {
|
|
73
|
+
const def = types[key];
|
|
56
74
|
const [total, lastId] = native.getTypeInfo(def.id, db.dbCtxExternal);
|
|
57
75
|
def.total = total;
|
|
58
76
|
def.lastId = writelog?.types[def.id]?.lastId || lastId;
|
|
@@ -71,10 +89,10 @@ export async function start(db, opts) {
|
|
|
71
89
|
});
|
|
72
90
|
}
|
|
73
91
|
if (writelog?.hash) {
|
|
74
|
-
const oldHash =
|
|
92
|
+
const oldHash = hexToBuf(writelog.hash);
|
|
75
93
|
const newHash = db.merkleTree.getRoot()?.hash;
|
|
76
|
-
if (!oldHash
|
|
77
|
-
console.error(`WARN: CSMT hash mismatch: ${writelog.hash} != ${newHash
|
|
94
|
+
if (!hashEq(oldHash, newHash)) {
|
|
95
|
+
console.error(`WARN: CSMT hash mismatch: ${writelog.hash} != ${bufToHex(newHash)}`);
|
|
78
96
|
}
|
|
79
97
|
}
|
|
80
98
|
// start workers
|
|
@@ -84,10 +102,19 @@ export async function start(db, opts) {
|
|
|
84
102
|
while (i--) {
|
|
85
103
|
db.workers[i] = new DbWorker(address, db);
|
|
86
104
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
105
|
+
if (!opts?.hosted) {
|
|
106
|
+
db.unlistenExit = exitHook(async (signal) => {
|
|
107
|
+
const blockSig = () => { };
|
|
108
|
+
const signals = ['SIGINT', 'SIGTERM', 'SIGHUP'];
|
|
109
|
+
// A really dumb way to block signals temporarily while saving.
|
|
110
|
+
// This is needed because there is no way to set the process signal mask
|
|
111
|
+
// in Node.js.
|
|
112
|
+
signals.forEach((sig) => process.on(sig, blockSig));
|
|
113
|
+
console.log(`Exiting with signal: ${signal}`);
|
|
114
|
+
save(db, true);
|
|
115
|
+
console.log('Successfully saved.');
|
|
116
|
+
signals.forEach((sig) => process.off(sig, blockSig));
|
|
117
|
+
});
|
|
118
|
+
}
|
|
92
119
|
}
|
|
93
120
|
//# sourceMappingURL=start.js.map
|
|
@@ -9,5 +9,5 @@ export type CsmtNodeRange = {
|
|
|
9
9
|
export declare const makeCsmtKey: (typeId: number, start: number) => number;
|
|
10
10
|
export declare const destructureCsmtKey: (key: number) => number[];
|
|
11
11
|
export declare const makeCsmtKeyFromNodeId: (typeId: number, blockCapacity: number, nodeId: number) => number;
|
|
12
|
-
export declare function foreachBlock(db: DbServer, def: SchemaTypeDef, cb: (start: number, end: number, hash:
|
|
12
|
+
export declare function foreachBlock(db: DbServer, def: SchemaTypeDef, cb: (start: number, end: number, hash: Uint8Array) => void): Promise<void>;
|
|
13
13
|
export declare function foreachDirtyBlock(db: DbServer, cb: (mtKey: number, typeId: number, start: number, end: number) => void): Promise<void>;
|