@lodestar/db 1.35.0-dev.83de5b8dea → 1.35.0-dev.8689cc3545
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/lib/abstractPrefixedRepository.d.ts.map +1 -0
- package/lib/abstractRepository.d.ts.map +1 -0
- package/lib/const.d.ts.map +1 -0
- package/lib/controller/index.d.ts.map +1 -0
- package/lib/controller/interface.d.ts.map +1 -0
- package/lib/controller/level.d.ts.map +1 -0
- package/lib/controller/metrics.d.ts.map +1 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/util.d.ts.map +1 -0
- package/package.json +8 -10
- package/src/abstractPrefixedRepository.ts +244 -0
- package/src/abstractRepository.ts +283 -0
- package/src/const.ts +2 -0
- package/src/controller/index.ts +3 -0
- package/src/controller/interface.ts +62 -0
- package/src/controller/level.ts +246 -0
- package/src/controller/metrics.ts +10 -0
- package/src/index.ts +5 -0
- package/src/util.ts +50 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abstractPrefixedRepository.d.ts","sourceRoot":"","sources":["../src/abstractPrefixedRepository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abstractRepository.d.ts","sourceRoot":"","sources":["../src/abstractRepository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"const.d.ts","sourceRoot":"","sources":["../src/const.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,aAAa,IAAI,CAAC;AAC/B,eAAO,MAAM,gBAAgB,IAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/controller/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAC,kBAAkB,EAAE,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAC,MAAM,gBAAgB,CAAC;AAC/F,OAAO,EAAC,iBAAiB,EAAC,MAAM,YAAY,CAAC;AAC7C,YAAY,EAAC,wBAAwB,EAAC,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/controller/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,wBAAwB,EAAC,MAAM,cAAc,CAAC;AAEtD,uDAAuD;AACvD,MAAM,MAAM,EAAE,GAAG,kBAAkB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;AAE5D,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,EAAE,CAAC,EAAE,CAAC,CAAC;IACP,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,EAAE,CAAC,EAAE,CAAC,CAAC;IACP,GAAG,CAAC,EAAE,CAAC,CAAC;IACR,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,SAAS,GAAG;IACtB,kBAAkB;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,WAAW,QAAQ,CAAC,CAAC,EAAE,CAAC;IAC5B,GAAG,EAAE,CAAC,CAAC;IACP,KAAK,EAAE,CAAC,CAAC;CACV;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC,EAAE,CAAC;IAGtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB,iDAAiD;IACjD,UAAU,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAIpD,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACjD,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;IAEhE,GAAG,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,MAAM,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAIhD,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,WAAW,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAIxD,UAAU,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IACtD,IAAI,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAE5C,YAAY,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IACxD,MAAM,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAE9C,aAAa,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,OAAO,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;CAC7D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"level.d.ts","sourceRoot":"","sources":["../../src/controller/level.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/controller/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAC,MAAM,iBAAiB,CAAC;AAE1D,MAAM,MAAM,wBAAwB,GAAG;IACrC,SAAS,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACrC,WAAW,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACvC,UAAU,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACtC,YAAY,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAC,CAAC;IACxC,WAAW,EAAE,KAAK,CAAC;IACnB,qBAAqB,EAAE,SAAS,CAAC;CAClC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,yBAAyB,CAAC;AACxC,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,IAAI,CAAC;AAEzB;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,CAiBhG;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAEhF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEhF;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAE9D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAE9D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lodestar/db",
|
|
3
|
-
"version": "1.35.0-dev.
|
|
3
|
+
"version": "1.35.0-dev.8689cc3545",
|
|
4
4
|
"description": "DB modules of Lodestar",
|
|
5
5
|
"author": "ChainSafe Systems",
|
|
6
6
|
"homepage": "https://github.com/ChainSafe/lodestar#readme",
|
|
@@ -20,11 +20,9 @@
|
|
|
20
20
|
},
|
|
21
21
|
"types": "./lib/index.d.ts",
|
|
22
22
|
"files": [
|
|
23
|
-
"
|
|
24
|
-
"lib
|
|
25
|
-
"
|
|
26
|
-
"*.d.ts",
|
|
27
|
-
"*.js"
|
|
23
|
+
"src",
|
|
24
|
+
"lib",
|
|
25
|
+
"!**/*.tsbuildinfo"
|
|
28
26
|
],
|
|
29
27
|
"scripts": {
|
|
30
28
|
"clean": "rm -rf lib && rm -f *.tsbuildinfo",
|
|
@@ -42,13 +40,13 @@
|
|
|
42
40
|
},
|
|
43
41
|
"dependencies": {
|
|
44
42
|
"@chainsafe/ssz": "^1.2.2",
|
|
45
|
-
"@lodestar/config": "1.35.0-dev.
|
|
46
|
-
"@lodestar/utils": "1.35.0-dev.
|
|
43
|
+
"@lodestar/config": "1.35.0-dev.8689cc3545",
|
|
44
|
+
"@lodestar/utils": "1.35.0-dev.8689cc3545",
|
|
47
45
|
"classic-level": "^1.4.1",
|
|
48
46
|
"it-all": "^3.0.4"
|
|
49
47
|
},
|
|
50
48
|
"devDependencies": {
|
|
51
|
-
"@lodestar/logger": "1.35.0-dev.
|
|
49
|
+
"@lodestar/logger": "1.35.0-dev.8689cc3545"
|
|
52
50
|
},
|
|
53
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "449ee7fae124e34a70536ffec343c7447830e2e6"
|
|
54
52
|
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import {Type} from "@chainsafe/ssz";
|
|
2
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
+
import {BUCKET_LENGTH} from "./const.js";
|
|
4
|
+
import {KeyValue} from "./controller/index.js";
|
|
5
|
+
import {Db, DbReqOpts, FilterOptions} from "./controller/interface.js";
|
|
6
|
+
import {encodeKey} from "./util.js";
|
|
7
|
+
|
|
8
|
+
type Id = Uint8Array | string | number | bigint;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Repository is a high level kv storage
|
|
12
|
+
* This abstract repository is designed in a way to store items with different prefixed
|
|
13
|
+
* Specially when those prefixed data is not available in the object to be stored
|
|
14
|
+
*
|
|
15
|
+
* By default, SSZ-encoded values,
|
|
16
|
+
*/
|
|
17
|
+
export abstract class PrefixedRepository<P, I extends Id, T> {
|
|
18
|
+
private readonly dbReqOpts: DbReqOpts;
|
|
19
|
+
/** Inclusive range for the minimum key for the bucket */
|
|
20
|
+
private readonly minKey: Uint8Array;
|
|
21
|
+
/** Exclusive range for the maximum key for the bucket */
|
|
22
|
+
private readonly maxKey: Uint8Array;
|
|
23
|
+
|
|
24
|
+
protected constructor(
|
|
25
|
+
protected config: ChainForkConfig,
|
|
26
|
+
protected db: Db,
|
|
27
|
+
protected bucket: number,
|
|
28
|
+
protected type: Type<T>,
|
|
29
|
+
private readonly bucketId: string
|
|
30
|
+
) {
|
|
31
|
+
this.dbReqOpts = {bucketId: this.bucketId};
|
|
32
|
+
this.minKey = encodeKey(bucket, Buffer.alloc(0));
|
|
33
|
+
this.maxKey = encodeKey(bucket + 1, Buffer.alloc(0));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
abstract encodeKeyRaw(prefix: P, id: I): Uint8Array;
|
|
37
|
+
abstract decodeKeyRaw(raw: Uint8Array): {prefix: P; id: I};
|
|
38
|
+
/**
|
|
39
|
+
* Max key is inclusive
|
|
40
|
+
* */
|
|
41
|
+
abstract getMaxKeyRaw(prefix: P): Uint8Array;
|
|
42
|
+
/**
|
|
43
|
+
* Min key is inclusive
|
|
44
|
+
* */
|
|
45
|
+
abstract getMinKeyRaw(prefix: P): Uint8Array;
|
|
46
|
+
|
|
47
|
+
protected encodeValue(value: T): Uint8Array {
|
|
48
|
+
return this.type.serialize(value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
protected decodeValue(data: Uint8Array): T {
|
|
52
|
+
return this.type.deserialize(data);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
protected wrapKey(raw: Uint8Array): Uint8Array {
|
|
56
|
+
return encodeKey(this.bucket, raw);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
protected unwrapKey(key: Uint8Array): Uint8Array {
|
|
60
|
+
return key.slice(BUCKET_LENGTH);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// The Id can be inferred from the value
|
|
64
|
+
getId(value: T): I {
|
|
65
|
+
return this.type.hashTreeRoot(value) as I;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async get(prefix: P, id: I): Promise<T | null> {
|
|
69
|
+
const key = this.wrapKey(this.encodeKeyRaw(prefix, id));
|
|
70
|
+
const v = await this.db.get(key, this.dbReqOpts);
|
|
71
|
+
return v ? this.decodeValue(v) : null;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async getMany(prefix: P, ids: I[]): Promise<(T | undefined)[]> {
|
|
75
|
+
const keys = [];
|
|
76
|
+
for (const id of ids) {
|
|
77
|
+
keys.push(this.wrapKey(this.encodeKeyRaw(prefix, id)));
|
|
78
|
+
}
|
|
79
|
+
const values = await this.db.getMany(keys, this.dbReqOpts);
|
|
80
|
+
|
|
81
|
+
const result = [];
|
|
82
|
+
for (const value of values) {
|
|
83
|
+
result.push(value ? this.decodeValue(value) : undefined);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async getManyBinary(prefix: P, ids: I[]): Promise<(Uint8Array | undefined)[]> {
|
|
90
|
+
const keys = [];
|
|
91
|
+
for (const id of ids) {
|
|
92
|
+
keys.push(this.wrapKey(this.encodeKeyRaw(prefix, id)));
|
|
93
|
+
}
|
|
94
|
+
return await this.db.getMany(keys, this.dbReqOpts);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async getBinary(prefix: P, id: I): Promise<Uint8Array | null> {
|
|
98
|
+
const key = this.wrapKey(this.encodeKeyRaw(prefix, id));
|
|
99
|
+
return await this.db.get(key, this.dbReqOpts);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async put(prefix: P, item: T): Promise<void> {
|
|
103
|
+
const id = this.getId(item);
|
|
104
|
+
const key = this.wrapKey(this.encodeKeyRaw(prefix, id));
|
|
105
|
+
await this.db.put(key, this.encodeValue(item), this.dbReqOpts);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async putMany(prefix: P, items: T[]): Promise<void> {
|
|
109
|
+
const batch: KeyValue<Uint8Array, Uint8Array>[] = [];
|
|
110
|
+
for (const item of items) {
|
|
111
|
+
const id = this.getId(item);
|
|
112
|
+
const key = this.wrapKey(this.encodeKeyRaw(prefix, id));
|
|
113
|
+
batch.push({key, value: this.encodeValue(item)});
|
|
114
|
+
}
|
|
115
|
+
await this.db.batchPut(batch, this.dbReqOpts);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async putBinary(prefix: P, id: I, bytes: Uint8Array): Promise<void> {
|
|
119
|
+
const key = this.wrapKey(this.encodeKeyRaw(prefix, id));
|
|
120
|
+
await this.db.put(key, bytes, this.dbReqOpts);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
async putManyBinary(prefix: P, items: KeyValue<I, Uint8Array>[]): Promise<void> {
|
|
124
|
+
const batch: KeyValue<Uint8Array, Uint8Array>[] = [];
|
|
125
|
+
for (const {key, value} of items) {
|
|
126
|
+
batch.push({key: this.wrapKey(this.encodeKeyRaw(prefix, key)), value: value});
|
|
127
|
+
}
|
|
128
|
+
await this.db.batchPut(batch, this.dbReqOpts);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async delete(prefix: P, id: I): Promise<void> {
|
|
132
|
+
const key = this.wrapKey(this.encodeKeyRaw(prefix, id));
|
|
133
|
+
await this.db.delete(key, this.dbReqOpts);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async deleteMany(prefix: P | P[]): Promise<void> {
|
|
137
|
+
const keys: Uint8Array[][] = [];
|
|
138
|
+
|
|
139
|
+
for (const p of Array.isArray(prefix) ? prefix : [prefix]) {
|
|
140
|
+
const prefixedKeys = await this.db.keys({
|
|
141
|
+
gte: this.wrapKey(this.getMinKeyRaw(p)),
|
|
142
|
+
lte: this.wrapKey(this.getMaxKeyRaw(p)),
|
|
143
|
+
bucketId: this.bucketId,
|
|
144
|
+
});
|
|
145
|
+
keys.push(prefixedKeys);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
await this.db.batchDelete(keys.flat(), this.dbReqOpts);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async *valuesStream(prefix: P | P[]): AsyncIterable<T> {
|
|
152
|
+
for (const p of Array.isArray(prefix) ? prefix : [prefix]) {
|
|
153
|
+
for await (const vb of this.db.valuesStream({
|
|
154
|
+
gte: this.wrapKey(this.getMinKeyRaw(p)),
|
|
155
|
+
lte: this.wrapKey(this.getMaxKeyRaw(p)),
|
|
156
|
+
bucketId: this.bucketId,
|
|
157
|
+
})) {
|
|
158
|
+
yield this.decodeValue(vb);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async *valuesStreamBinary(prefix: P | P[]): AsyncIterable<{prefix: P; id: I; value: Uint8Array}> {
|
|
164
|
+
for (const p of Array.isArray(prefix) ? prefix : [prefix]) {
|
|
165
|
+
for await (const {key, value} of this.db.entriesStream({
|
|
166
|
+
gte: this.wrapKey(this.getMinKeyRaw(p)),
|
|
167
|
+
lte: this.wrapKey(this.getMaxKeyRaw(p)),
|
|
168
|
+
bucketId: this.bucketId,
|
|
169
|
+
})) {
|
|
170
|
+
const {prefix, id} = this.decodeKeyRaw(this.unwrapKey(key));
|
|
171
|
+
|
|
172
|
+
yield {
|
|
173
|
+
prefix,
|
|
174
|
+
id,
|
|
175
|
+
value,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async *entriesStream(prefix: P | P[]): AsyncIterable<{prefix: P; id: I; value: T}> {
|
|
182
|
+
for (const v of Array.isArray(prefix) ? prefix : [prefix]) {
|
|
183
|
+
for await (const {key, value} of this.db.entriesStream({
|
|
184
|
+
gte: this.wrapKey(this.getMinKeyRaw(v)),
|
|
185
|
+
lte: this.wrapKey(this.getMaxKeyRaw(v)),
|
|
186
|
+
bucketId: this.bucketId,
|
|
187
|
+
})) {
|
|
188
|
+
const {prefix, id} = this.decodeKeyRaw(this.unwrapKey(key));
|
|
189
|
+
|
|
190
|
+
yield {
|
|
191
|
+
prefix,
|
|
192
|
+
id,
|
|
193
|
+
value: this.decodeValue(value),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async *entriesStreamBinary(prefix: P | P[]): AsyncIterable<{prefix: P; id: I; value: Uint8Array}> {
|
|
200
|
+
for (const v of Array.isArray(prefix) ? prefix : [prefix]) {
|
|
201
|
+
for await (const {key, value} of this.db.entriesStream({
|
|
202
|
+
gte: this.wrapKey(this.getMinKeyRaw(v)),
|
|
203
|
+
lte: this.wrapKey(this.getMaxKeyRaw(v)),
|
|
204
|
+
bucketId: this.bucketId,
|
|
205
|
+
})) {
|
|
206
|
+
const {prefix, id} = this.decodeKeyRaw(this.unwrapKey(key));
|
|
207
|
+
|
|
208
|
+
yield {
|
|
209
|
+
prefix,
|
|
210
|
+
id: id,
|
|
211
|
+
value,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async keys(opts?: FilterOptions<{prefix: P; id: I}>): Promise<{prefix: P; id: I}[]> {
|
|
218
|
+
const optsBuff: FilterOptions<Uint8Array> = {
|
|
219
|
+
bucketId: this.bucketId,
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
if (opts?.gte !== undefined) {
|
|
223
|
+
optsBuff.gte = this.wrapKey(this.encodeKeyRaw(opts.gte.prefix, opts.gte.id));
|
|
224
|
+
} else if (opts?.gt !== undefined) {
|
|
225
|
+
optsBuff.gt = this.wrapKey(this.encodeKeyRaw(opts.gt.prefix, opts.gt.id));
|
|
226
|
+
} else {
|
|
227
|
+
optsBuff.gte = this.minKey;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (opts?.lte !== undefined) {
|
|
231
|
+
optsBuff.lte = this.wrapKey(this.encodeKeyRaw(opts.lte.prefix, opts.lte.id));
|
|
232
|
+
} else if (opts?.lt !== undefined) {
|
|
233
|
+
optsBuff.lt = this.wrapKey(this.encodeKeyRaw(opts.lt.prefix, opts.lt.id));
|
|
234
|
+
} else {
|
|
235
|
+
optsBuff.lt = this.maxKey;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (opts?.reverse !== undefined) optsBuff.reverse = opts.reverse;
|
|
239
|
+
if (opts?.limit !== undefined) optsBuff.limit = opts.limit;
|
|
240
|
+
|
|
241
|
+
const data = await this.db.keys(optsBuff);
|
|
242
|
+
return (data ?? []).map((data) => this.decodeKeyRaw(this.unwrapKey(data)));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
import {Type} from "@chainsafe/ssz";
|
|
2
|
+
import {ChainForkConfig} from "@lodestar/config";
|
|
3
|
+
import {BUCKET_LENGTH} from "./const.js";
|
|
4
|
+
import {FilterOptions, KeyValue} from "./controller/index.js";
|
|
5
|
+
import {Db, DbReqOpts} from "./controller/interface.js";
|
|
6
|
+
import {encodeKey as _encodeKey} from "./util.js";
|
|
7
|
+
|
|
8
|
+
export type Id = Uint8Array | string | number | bigint;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Repository is a high level kv storage
|
|
12
|
+
* managing a Uint8Array to Uint8Array kv database
|
|
13
|
+
* It translates typed keys and values to Uint8Arrays required by the underlying database
|
|
14
|
+
*
|
|
15
|
+
* By default, SSZ-encoded values,
|
|
16
|
+
* indexed by root
|
|
17
|
+
*/
|
|
18
|
+
export abstract class Repository<I extends Id, T> {
|
|
19
|
+
private readonly dbReqOpts: DbReqOpts;
|
|
20
|
+
|
|
21
|
+
private readonly minKey: Uint8Array;
|
|
22
|
+
private readonly maxKey: Uint8Array;
|
|
23
|
+
|
|
24
|
+
protected constructor(
|
|
25
|
+
protected config: ChainForkConfig,
|
|
26
|
+
protected db: Db,
|
|
27
|
+
protected bucket: number,
|
|
28
|
+
protected type: Type<T>,
|
|
29
|
+
protected readonly bucketId: string
|
|
30
|
+
) {
|
|
31
|
+
this.dbReqOpts = {bucketId: this.bucketId};
|
|
32
|
+
this.minKey = _encodeKey(bucket, Buffer.alloc(0));
|
|
33
|
+
this.maxKey = _encodeKey(bucket + 1, Buffer.alloc(0));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
encodeValue(value: T): Uint8Array {
|
|
37
|
+
return this.type.serialize(value);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
decodeValue(data: Uint8Array): T {
|
|
41
|
+
return this.type.deserialize(data);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
encodeKey(id: I): Uint8Array {
|
|
45
|
+
return _encodeKey(this.bucket, id);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
decodeKey(key: Uint8Array): I {
|
|
49
|
+
return key.slice(BUCKET_LENGTH) as I;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async get(id: I): Promise<T | null> {
|
|
53
|
+
const value = await this.db.get(this.encodeKey(id), this.dbReqOpts);
|
|
54
|
+
if (!value) return null;
|
|
55
|
+
return this.decodeValue(value);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async getBinary(id: I): Promise<Uint8Array | null> {
|
|
59
|
+
const value = await this.db.get(this.encodeKey(id), this.dbReqOpts);
|
|
60
|
+
if (!value) return null;
|
|
61
|
+
return value;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async has(id: I): Promise<boolean> {
|
|
65
|
+
return (await this.get(id)) !== null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async put(id: I, value: T): Promise<void> {
|
|
69
|
+
await this.db.put(this.encodeKey(id), this.encodeValue(value), this.dbReqOpts);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async putBinary(id: I, value: Uint8Array): Promise<void> {
|
|
73
|
+
await this.db.put(this.encodeKey(id), value, this.dbReqOpts);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async delete(id: I): Promise<void> {
|
|
77
|
+
await this.db.delete(this.encodeKey(id), this.dbReqOpts);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// The Id can be inferred from the value
|
|
81
|
+
getId(value: T): I {
|
|
82
|
+
return this.type.hashTreeRoot(value) as I;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async add(value: T): Promise<void> {
|
|
86
|
+
await this.put(this.getId(value), value);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async remove(value: T): Promise<void> {
|
|
90
|
+
await this.delete(this.getId(value));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async batchPut(items: KeyValue<I, T>[]): Promise<void> {
|
|
94
|
+
if (items.length === 1) {
|
|
95
|
+
return this.put(items[0].key, items[0].value);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await this.db.batchPut(
|
|
99
|
+
Array.from({length: items.length}, (_, i) => ({
|
|
100
|
+
key: this.encodeKey(items[i].key),
|
|
101
|
+
value: this.encodeValue(items[i].value),
|
|
102
|
+
})),
|
|
103
|
+
this.dbReqOpts
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Similar to batchPut but we support value as Uint8Array
|
|
108
|
+
async batchPutBinary(items: KeyValue<I, Uint8Array>[]): Promise<void> {
|
|
109
|
+
if (items.length === 1) {
|
|
110
|
+
return this.db.put(this.encodeKey(items[0].key), items[0].value, this.dbReqOpts);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
await this.db.batchPut(
|
|
114
|
+
Array.from({length: items.length}, (_, i) => ({
|
|
115
|
+
key: this.encodeKey(items[i].key),
|
|
116
|
+
value: items[i].value,
|
|
117
|
+
})),
|
|
118
|
+
this.dbReqOpts
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async batchDelete(ids: I[]): Promise<void> {
|
|
123
|
+
if (ids.length === 1) {
|
|
124
|
+
return this.delete(ids[0]);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
await this.db.batchDelete(
|
|
128
|
+
Array.from({length: ids.length}, (_, i) => this.encodeKey(ids[i])),
|
|
129
|
+
this.dbReqOpts
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
async batchAdd(values: T[]): Promise<void> {
|
|
134
|
+
// handle single value in batchPut
|
|
135
|
+
await this.batchPut(
|
|
136
|
+
Array.from({length: values.length}, (_, i) => ({
|
|
137
|
+
key: this.getId(values[i]),
|
|
138
|
+
value: values[i],
|
|
139
|
+
}))
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async batchRemove(values: T[]): Promise<void> {
|
|
144
|
+
// handle single value in batchDelete
|
|
145
|
+
await this.batchDelete(Array.from({length: values.length}, (_ignored, i) => this.getId(values[i])));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async keys(opts?: FilterOptions<I>): Promise<I[]> {
|
|
149
|
+
const data = await this.db.keys(this.dbFilterOptions(opts));
|
|
150
|
+
return (data ?? []).map((data) => this.decodeKey(data));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
async *keysStream(opts?: FilterOptions<I>): AsyncIterable<I> {
|
|
154
|
+
const keysStream = this.db.keysStream(this.dbFilterOptions(opts));
|
|
155
|
+
const decodeKey = this.decodeKey.bind(this);
|
|
156
|
+
for await (const key of keysStream) {
|
|
157
|
+
yield decodeKey(key);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async values(opts?: FilterOptions<I>): Promise<T[]> {
|
|
162
|
+
const data = await this.db.values(this.dbFilterOptions(opts));
|
|
163
|
+
return (data ?? []).map((data) => this.decodeValue(data));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async *valuesStream(opts?: FilterOptions<I>): AsyncIterable<T> {
|
|
167
|
+
const valuesStream = this.db.valuesStream(this.dbFilterOptions(opts));
|
|
168
|
+
const decodeValue = this.decodeValue.bind(this);
|
|
169
|
+
for await (const value of valuesStream) {
|
|
170
|
+
yield decodeValue(value);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
async *binaryEntriesStream(opts?: FilterOptions<I>): AsyncIterable<KeyValue<Uint8Array, Uint8Array>> {
|
|
175
|
+
yield* this.db.entriesStream(this.dbFilterOptions(opts));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async entries(opts?: FilterOptions<I>): Promise<KeyValue<I, T>[]> {
|
|
179
|
+
const data = await this.db.entries(this.dbFilterOptions(opts));
|
|
180
|
+
return (data ?? []).map((data) => ({
|
|
181
|
+
key: this.decodeKey(data.key),
|
|
182
|
+
value: this.decodeValue(data.value),
|
|
183
|
+
}));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async *entriesStream(opts?: FilterOptions<I>): AsyncIterable<KeyValue<I, T>> {
|
|
187
|
+
const entriesStream = this.db.entriesStream(this.dbFilterOptions(opts));
|
|
188
|
+
const decodeKey = this.decodeKey.bind(this);
|
|
189
|
+
const decodeValue = this.decodeValue.bind(this);
|
|
190
|
+
for await (const entry of entriesStream) {
|
|
191
|
+
yield {
|
|
192
|
+
key: decodeKey(entry.key),
|
|
193
|
+
value: decodeValue(entry.value),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
async firstKey(): Promise<I | null> {
|
|
199
|
+
// Metrics accounted in this.keys()
|
|
200
|
+
const keys = await this.keys({limit: 1, bucketId: this.bucketId});
|
|
201
|
+
if (!keys.length) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
return keys[0];
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async lastKey(): Promise<I | null> {
|
|
208
|
+
// Metrics accounted in this.keys()
|
|
209
|
+
const keys = await this.keys({limit: 1, reverse: true, bucketId: this.bucketId});
|
|
210
|
+
if (!keys.length) {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
return keys[0];
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
async firstValue(): Promise<T | null> {
|
|
217
|
+
// Metrics accounted in this.values()
|
|
218
|
+
const values = await this.values({limit: 1, bucketId: this.bucketId});
|
|
219
|
+
if (!values.length) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
return values[0];
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async lastValue(): Promise<T | null> {
|
|
226
|
+
// Metrics accounted in this.values()
|
|
227
|
+
const values = await this.values({limit: 1, reverse: true, bucketId: this.bucketId});
|
|
228
|
+
if (!values.length) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
return values[0];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async firstEntry(): Promise<KeyValue<I, T> | null> {
|
|
235
|
+
// Metrics accounted in this.entries()
|
|
236
|
+
const entries = await this.entries({limit: 1, bucketId: this.bucketId});
|
|
237
|
+
if (!entries.length) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
return entries[0];
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
async lastEntry(): Promise<KeyValue<I, T> | null> {
|
|
244
|
+
// Metrics accounted in this.entries()
|
|
245
|
+
const entries = await this.entries({limit: 1, reverse: true, bucketId: this.bucketId});
|
|
246
|
+
if (!entries.length) {
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
return entries[0];
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Transforms opts from I to Uint8Array
|
|
254
|
+
*/
|
|
255
|
+
protected dbFilterOptions(opts?: FilterOptions<I>): FilterOptions<Uint8Array> {
|
|
256
|
+
const optsBuff: FilterOptions<Uint8Array> = {
|
|
257
|
+
bucketId: this.bucketId,
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
// Set at least one min key
|
|
261
|
+
if (opts?.lt !== undefined) {
|
|
262
|
+
optsBuff.lt = this.encodeKey(opts.lt);
|
|
263
|
+
} else if (opts?.lte !== undefined) {
|
|
264
|
+
optsBuff.lte = this.encodeKey(opts.lte);
|
|
265
|
+
} else {
|
|
266
|
+
optsBuff.lt = this.maxKey;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Set at least on max key
|
|
270
|
+
if (opts?.gt !== undefined) {
|
|
271
|
+
optsBuff.gt = this.encodeKey(opts.gt);
|
|
272
|
+
} else if (opts?.gte !== undefined) {
|
|
273
|
+
optsBuff.gte = this.encodeKey(opts.gte);
|
|
274
|
+
} else {
|
|
275
|
+
optsBuff.gte = this.minKey;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
if (opts?.reverse !== undefined) optsBuff.reverse = opts.reverse;
|
|
279
|
+
if (opts?.limit !== undefined) optsBuff.limit = opts.limit;
|
|
280
|
+
|
|
281
|
+
return optsBuff;
|
|
282
|
+
}
|
|
283
|
+
}
|
package/src/const.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import {LevelDbControllerMetrics} from "./metrics.js";
|
|
2
|
+
|
|
3
|
+
/** Shortcut for Uint8Array based DatabaseController */
|
|
4
|
+
export type Db = DatabaseController<Uint8Array, Uint8Array>;
|
|
5
|
+
|
|
6
|
+
export type DatabaseOptions = {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export interface FilterOptions<K> {
|
|
11
|
+
gt?: K;
|
|
12
|
+
gte?: K;
|
|
13
|
+
lt?: K;
|
|
14
|
+
lte?: K;
|
|
15
|
+
reverse?: boolean;
|
|
16
|
+
limit?: number;
|
|
17
|
+
/** For metrics */
|
|
18
|
+
bucketId?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type DbReqOpts = {
|
|
22
|
+
/** For metrics */
|
|
23
|
+
bucketId?: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export interface KeyValue<K, V> {
|
|
27
|
+
key: K;
|
|
28
|
+
value: V;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface DatabaseController<K, V> {
|
|
32
|
+
// service start / stop
|
|
33
|
+
|
|
34
|
+
close(): Promise<void>;
|
|
35
|
+
|
|
36
|
+
/** To inject metrics after CLI initialization */
|
|
37
|
+
setMetrics(metrics: LevelDbControllerMetrics): void;
|
|
38
|
+
|
|
39
|
+
// Core API
|
|
40
|
+
|
|
41
|
+
get(key: K, opts?: DbReqOpts): Promise<V | null>;
|
|
42
|
+
getMany(key: K[], opts?: DbReqOpts): Promise<(V | undefined)[]>;
|
|
43
|
+
|
|
44
|
+
put(key: K, value: V, opts?: DbReqOpts): Promise<void>;
|
|
45
|
+
delete(key: K, opts?: DbReqOpts): Promise<void>;
|
|
46
|
+
|
|
47
|
+
// Batch operations
|
|
48
|
+
|
|
49
|
+
batchPut(items: KeyValue<K, V>[], opts?: DbReqOpts): Promise<void>;
|
|
50
|
+
batchDelete(keys: K[], opts?: DbReqOpts): Promise<void>;
|
|
51
|
+
|
|
52
|
+
// Iterate over entries
|
|
53
|
+
|
|
54
|
+
keysStream(opts?: FilterOptions<K>): AsyncIterable<K>;
|
|
55
|
+
keys(opts?: FilterOptions<K>): Promise<K[]>;
|
|
56
|
+
|
|
57
|
+
valuesStream(opts?: FilterOptions<K>): AsyncIterable<V>;
|
|
58
|
+
values(opts?: FilterOptions<K>): Promise<V[]>;
|
|
59
|
+
|
|
60
|
+
entriesStream(opts?: FilterOptions<K>): AsyncIterable<KeyValue<K, V>>;
|
|
61
|
+
entries(opts?: FilterOptions<K>): Promise<KeyValue<K, V>[]>;
|
|
62
|
+
}
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import {ClassicLevel} from "classic-level";
|
|
2
|
+
import {Logger} from "@lodestar/utils";
|
|
3
|
+
import {DatabaseController, DatabaseOptions, DbReqOpts, FilterOptions, KeyValue} from "./interface.js";
|
|
4
|
+
import {LevelDbControllerMetrics} from "./metrics.js";
|
|
5
|
+
|
|
6
|
+
enum Status {
|
|
7
|
+
started = "started",
|
|
8
|
+
closed = "closed",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface LevelDBOptions extends DatabaseOptions {
|
|
12
|
+
db?: ClassicLevel<Uint8Array, Uint8Array>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type LevelDbControllerModules = {
|
|
16
|
+
logger: Logger;
|
|
17
|
+
metrics?: LevelDbControllerMetrics | null;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const BUCKET_ID_UNKNOWN = "unknown";
|
|
21
|
+
|
|
22
|
+
/** Time between capturing metric for db size, every few minutes is sufficient */
|
|
23
|
+
const DB_SIZE_METRIC_INTERVAL_MS = 5 * 60 * 1000;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* The LevelDB implementation of DB
|
|
27
|
+
*/
|
|
28
|
+
export class LevelDbController implements DatabaseController<Uint8Array, Uint8Array> {
|
|
29
|
+
private status = Status.started;
|
|
30
|
+
|
|
31
|
+
private dbSizeMetricInterval?: NodeJS.Timeout;
|
|
32
|
+
|
|
33
|
+
constructor(
|
|
34
|
+
private readonly logger: Logger,
|
|
35
|
+
private readonly db: ClassicLevel<Uint8Array, Uint8Array>,
|
|
36
|
+
private metrics: LevelDbControllerMetrics | null
|
|
37
|
+
) {
|
|
38
|
+
this.metrics = metrics ?? null;
|
|
39
|
+
|
|
40
|
+
if (this.metrics) {
|
|
41
|
+
this.collectDbSizeMetric();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
static async create(opts: LevelDBOptions, {metrics, logger}: LevelDbControllerModules): Promise<LevelDbController> {
|
|
46
|
+
const db =
|
|
47
|
+
opts.db ||
|
|
48
|
+
new ClassicLevel(opts.name || "beaconchain", {
|
|
49
|
+
keyEncoding: "binary",
|
|
50
|
+
valueEncoding: "binary",
|
|
51
|
+
multithreading: true,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
await db.open();
|
|
56
|
+
} catch (e) {
|
|
57
|
+
if ((e as LevelDbError).cause?.code === "LEVEL_LOCKED") {
|
|
58
|
+
throw new Error("Database already in use by another process");
|
|
59
|
+
}
|
|
60
|
+
throw e;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return new LevelDbController(logger, db, metrics ?? null);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async close(): Promise<void> {
|
|
67
|
+
if (this.status === Status.closed) return;
|
|
68
|
+
this.status = Status.closed;
|
|
69
|
+
|
|
70
|
+
if (this.dbSizeMetricInterval) {
|
|
71
|
+
clearInterval(this.dbSizeMetricInterval);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
await this.db.close();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** To inject metrics after CLI initialization */
|
|
78
|
+
setMetrics(metrics: LevelDbControllerMetrics): void {
|
|
79
|
+
if (this.metrics !== null) {
|
|
80
|
+
throw Error("metrics can only be set once");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.metrics = metrics;
|
|
84
|
+
if (this.status === Status.started) {
|
|
85
|
+
this.collectDbSizeMetric();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async clear(): Promise<void> {
|
|
90
|
+
await this.db.clear();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async get(key: Uint8Array, opts?: DbReqOpts): Promise<Uint8Array | null> {
|
|
94
|
+
try {
|
|
95
|
+
this.metrics?.dbReadReq.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, 1);
|
|
96
|
+
this.metrics?.dbReadItems.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, 1);
|
|
97
|
+
return (await this.db.get(key)) as Uint8Array | null;
|
|
98
|
+
} catch (e) {
|
|
99
|
+
if ((e as LevelDbError).code === "LEVEL_NOT_FOUND") {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
throw e;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Return the multiple items in the order of the given keys
|
|
108
|
+
* Will return `null` for the keys which does not exists
|
|
109
|
+
*
|
|
110
|
+
* https://github.com/Level/abstract-level?tab=readme-ov-file#dbgetmanykeys-options
|
|
111
|
+
*/
|
|
112
|
+
async getMany(keys: Uint8Array[], opts?: DbReqOpts): Promise<(Uint8Array | undefined)[]> {
|
|
113
|
+
this.metrics?.dbReadReq.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, 1);
|
|
114
|
+
this.metrics?.dbReadItems.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, keys.length);
|
|
115
|
+
return await this.db.getMany(keys);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
put(key: Uint8Array, value: Uint8Array, opts?: DbReqOpts): Promise<void> {
|
|
119
|
+
this.metrics?.dbWriteReq.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, 1);
|
|
120
|
+
this.metrics?.dbWriteItems.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, 1);
|
|
121
|
+
|
|
122
|
+
return this.db.put(key, value);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
delete(key: Uint8Array, opts?: DbReqOpts): Promise<void> {
|
|
126
|
+
this.metrics?.dbWriteReq.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, 1);
|
|
127
|
+
this.metrics?.dbWriteItems.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, 1);
|
|
128
|
+
|
|
129
|
+
return this.db.del(key);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
batchPut(items: KeyValue<Uint8Array, Uint8Array>[], opts?: DbReqOpts): Promise<void> {
|
|
133
|
+
this.metrics?.dbWriteReq.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, 1);
|
|
134
|
+
this.metrics?.dbWriteItems.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, items.length);
|
|
135
|
+
|
|
136
|
+
return this.db.batch(items.map((item) => ({type: "put", key: item.key, value: item.value})));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
batchDelete(keys: Uint8Array[], opts?: DbReqOpts): Promise<void> {
|
|
140
|
+
this.metrics?.dbWriteReq.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, 1);
|
|
141
|
+
this.metrics?.dbWriteItems.inc({bucket: opts?.bucketId ?? BUCKET_ID_UNKNOWN}, keys.length);
|
|
142
|
+
|
|
143
|
+
return this.db.batch(keys.map((key) => ({type: "del", key: key})));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
keysStream(opts: FilterOptions<Uint8Array> = {}): AsyncIterable<Uint8Array> {
|
|
147
|
+
return this.metricsIterator(this.db.keys(opts), (key) => key, opts.bucketId ?? BUCKET_ID_UNKNOWN);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
valuesStream(opts: FilterOptions<Uint8Array> = {}): AsyncIterable<Uint8Array> {
|
|
151
|
+
return this.metricsIterator(this.db.values(opts), (value) => value, opts.bucketId ?? BUCKET_ID_UNKNOWN);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
entriesStream(opts: FilterOptions<Uint8Array> = {}): AsyncIterable<KeyValue<Uint8Array, Uint8Array>> {
|
|
155
|
+
return this.metricsIterator(
|
|
156
|
+
this.db.iterator(opts),
|
|
157
|
+
(entry) => ({key: entry[0], value: entry[1]}),
|
|
158
|
+
opts.bucketId ?? BUCKET_ID_UNKNOWN
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
keys(opts: FilterOptions<Uint8Array> = {}): Promise<Uint8Array[]> {
|
|
163
|
+
return this.metricsAll(this.db.keys(opts).all(), opts.bucketId ?? BUCKET_ID_UNKNOWN);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
values(opts: FilterOptions<Uint8Array> = {}): Promise<Uint8Array[]> {
|
|
167
|
+
return this.metricsAll(this.db.values(opts).all(), opts.bucketId ?? BUCKET_ID_UNKNOWN);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async entries(opts: FilterOptions<Uint8Array> = {}): Promise<KeyValue<Uint8Array, Uint8Array>[]> {
|
|
171
|
+
const entries = await this.metricsAll(this.db.iterator(opts).all(), opts.bucketId ?? BUCKET_ID_UNKNOWN);
|
|
172
|
+
return entries.map((entry) => ({key: entry[0], value: entry[1]}));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Get the approximate number of bytes of file system space used by the range [start..end).
|
|
177
|
+
* The result might not include recently written data.
|
|
178
|
+
*/
|
|
179
|
+
approximateSize(start: Uint8Array, end: Uint8Array): Promise<number> {
|
|
180
|
+
return this.db.approximateSize(start, end);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Manually trigger a database compaction in the range [start..end].
|
|
185
|
+
*/
|
|
186
|
+
compactRange(start: Uint8Array, end: Uint8Array): Promise<void> {
|
|
187
|
+
return this.db.compactRange(start, end);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Capture metrics for db.iterator, db.keys, db.values .all() calls */
|
|
191
|
+
private async metricsAll<T>(promise: Promise<T[]>, bucket: string): Promise<T[]> {
|
|
192
|
+
this.metrics?.dbReadReq.inc({bucket}, 1);
|
|
193
|
+
const items = await promise;
|
|
194
|
+
this.metrics?.dbReadItems.inc({bucket}, items.length);
|
|
195
|
+
return items;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Capture metrics for db.iterator, db.keys, db.values AsyncIterable calls */
|
|
199
|
+
private async *metricsIterator<T, K>(
|
|
200
|
+
iterator: AsyncIterable<T>,
|
|
201
|
+
getValue: (item: T) => K,
|
|
202
|
+
bucket: string
|
|
203
|
+
): AsyncIterable<K> {
|
|
204
|
+
this.metrics?.dbReadReq.inc({bucket}, 1);
|
|
205
|
+
|
|
206
|
+
let itemsRead = 0;
|
|
207
|
+
|
|
208
|
+
for await (const item of iterator) {
|
|
209
|
+
// Count metrics after done condition
|
|
210
|
+
itemsRead++;
|
|
211
|
+
|
|
212
|
+
yield getValue(item);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
this.metrics?.dbReadItems.inc({bucket}, itemsRead);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/** Start interval to capture metric for db size */
|
|
219
|
+
private collectDbSizeMetric(): void {
|
|
220
|
+
this.dbSizeMetric();
|
|
221
|
+
this.dbSizeMetricInterval = setInterval(this.dbSizeMetric.bind(this), DB_SIZE_METRIC_INTERVAL_MS);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Capture metric for db size */
|
|
225
|
+
private dbSizeMetric(): void {
|
|
226
|
+
const timer = this.metrics?.dbApproximateSizeTime.startTimer();
|
|
227
|
+
const minKey = Buffer.from([0x00]);
|
|
228
|
+
const maxKey = Buffer.from([0xff]);
|
|
229
|
+
|
|
230
|
+
this.approximateSize(minKey, maxKey)
|
|
231
|
+
.then((dbSize) => {
|
|
232
|
+
this.metrics?.dbSizeTotal.set(dbSize);
|
|
233
|
+
})
|
|
234
|
+
.catch((e) => {
|
|
235
|
+
this.logger.debug("Error approximating db size", {}, e);
|
|
236
|
+
})
|
|
237
|
+
.finally(timer);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
static async destroy(location: string): Promise<void> {
|
|
241
|
+
return ClassicLevel.destroy(location);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/** From https://www.npmjs.com/package/level */
|
|
246
|
+
type LevelDbError = {code: "LEVEL_NOT_FOUND"; cause?: {code: "LEVEL_LOCKED"}};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {Counter, Gauge, Histogram} from "@lodestar/utils";
|
|
2
|
+
|
|
3
|
+
export type LevelDbControllerMetrics = {
|
|
4
|
+
dbReadReq: Counter<{bucket: string}>;
|
|
5
|
+
dbReadItems: Counter<{bucket: string}>;
|
|
6
|
+
dbWriteReq: Counter<{bucket: string}>;
|
|
7
|
+
dbWriteItems: Counter<{bucket: string}>;
|
|
8
|
+
dbSizeTotal: Gauge;
|
|
9
|
+
dbApproximateSizeTime: Histogram;
|
|
10
|
+
};
|
package/src/index.ts
ADDED
package/src/util.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {bytesToInt, intToBytes} from "@lodestar/utils";
|
|
2
|
+
import {BUCKET_LENGTH} from "./const.js";
|
|
3
|
+
|
|
4
|
+
export const uintLen = 8;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Encode a key for the db write/read, Prepend a bucket to a key
|
|
8
|
+
*
|
|
9
|
+
* The encoding of key is very important step that can cause failure of proper indexing and querying of data
|
|
10
|
+
*
|
|
11
|
+
* We are using LevelDB which have pluggable comparator support, so you can decide how to
|
|
12
|
+
* compare keys. But for NodeJS binding only default comparison algorithm is supported which
|
|
13
|
+
* uses lexicographical comparison of the raw bytes of the keys
|
|
14
|
+
*
|
|
15
|
+
* It is important to use **helpers implemented here** to encode db keys so that key comparison properly work.
|
|
16
|
+
*/
|
|
17
|
+
export function encodeKey(bucket: number, key: Uint8Array | string | number | bigint): Uint8Array {
|
|
18
|
+
let buf: Buffer;
|
|
19
|
+
const prefixLength = BUCKET_LENGTH;
|
|
20
|
+
//all keys are writen with prefixLength offet
|
|
21
|
+
if (typeof key === "string") {
|
|
22
|
+
buf = Buffer.alloc(key.length + prefixLength);
|
|
23
|
+
buf.write(key, prefixLength);
|
|
24
|
+
} else if (typeof key === "number" || typeof key === "bigint") {
|
|
25
|
+
buf = Buffer.alloc(uintLen + prefixLength);
|
|
26
|
+
intToBytes(BigInt(key), uintLen, "be").copy(buf, prefixLength);
|
|
27
|
+
} else {
|
|
28
|
+
buf = Buffer.alloc(key.length + prefixLength);
|
|
29
|
+
buf.set(key, prefixLength);
|
|
30
|
+
}
|
|
31
|
+
//bucket prefix on position 0
|
|
32
|
+
buf.set(intToBytes(bucket, BUCKET_LENGTH, "le"), 0);
|
|
33
|
+
return buf;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function encodeNumberForDbKey(value: number, byteSize: number): Uint8Array {
|
|
37
|
+
return intToBytes(value, byteSize, "be");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function decodeNumberForDbKey(value: Uint8Array, byteSize: number): number {
|
|
41
|
+
return bytesToInt(value.slice(0, byteSize), "be");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function encodeStringForDbKey(value: string): Uint8Array {
|
|
45
|
+
return Buffer.from(value, "utf-8");
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function decodeStringForDbKey(value: Uint8Array): string {
|
|
49
|
+
return Buffer.from(value).toString("utf8");
|
|
50
|
+
}
|