@aztec/kv-store 0.0.1-commit.f504929 → 0.0.1-commit.f5a9928
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 +10 -1
- package/dest/bench/shared_map_bench.d.ts +19 -0
- package/dest/bench/shared_map_bench.d.ts.map +1 -0
- package/dest/bench/shared_map_bench.js +91 -0
- package/dest/deprecated/indexeddb/array.d.ts +22 -0
- package/dest/deprecated/indexeddb/array.d.ts.map +1 -0
- package/dest/deprecated/indexeddb/index.d.ts +7 -0
- package/dest/deprecated/indexeddb/index.d.ts.map +1 -0
- package/dest/deprecated/indexeddb/index.js +8 -0
- package/dest/deprecated/indexeddb/map.d.ts +38 -0
- package/dest/deprecated/indexeddb/map.d.ts.map +1 -0
- package/dest/deprecated/indexeddb/multi_map.d.ts +14 -0
- package/dest/deprecated/indexeddb/multi_map.d.ts.map +1 -0
- package/dest/{indexeddb → deprecated/indexeddb}/multi_map.js +2 -1
- package/dest/deprecated/indexeddb/set.d.ts +17 -0
- package/dest/deprecated/indexeddb/set.d.ts.map +1 -0
- package/dest/deprecated/indexeddb/singleton.d.ts +17 -0
- package/dest/deprecated/indexeddb/singleton.d.ts.map +1 -0
- package/dest/deprecated/indexeddb/store.d.ts +98 -0
- package/dest/deprecated/indexeddb/store.d.ts.map +1 -0
- package/dest/{indexeddb → deprecated/indexeddb}/store.js +2 -0
- package/dest/interfaces/array_test_suite.d.ts +1 -1
- package/dest/interfaces/array_test_suite.d.ts.map +1 -1
- package/dest/interfaces/array_test_suite.js +33 -34
- package/dest/interfaces/index.d.ts +2 -2
- package/dest/interfaces/index.d.ts.map +1 -1
- package/dest/interfaces/map_test_suite.d.ts +1 -1
- package/dest/interfaces/map_test_suite.d.ts.map +1 -1
- package/dest/interfaces/map_test_suite.js +32 -33
- package/dest/interfaces/multi_map_test_suite.d.ts +1 -1
- package/dest/interfaces/multi_map_test_suite.d.ts.map +1 -1
- package/dest/interfaces/multi_map_test_suite.js +68 -69
- package/dest/interfaces/set_test_suite.d.ts +1 -1
- package/dest/interfaces/set_test_suite.d.ts.map +1 -1
- package/dest/interfaces/set_test_suite.js +13 -14
- package/dest/interfaces/singleton_test_suite.d.ts +1 -1
- package/dest/interfaces/singleton_test_suite.d.ts.map +1 -1
- package/dest/interfaces/singleton_test_suite.js +6 -7
- package/dest/lmdb/index.d.ts +2 -2
- package/dest/lmdb/index.d.ts.map +1 -1
- package/dest/lmdb/index.js +2 -2
- package/dest/lmdb/store.d.ts +3 -3
- package/dest/lmdb/store.d.ts.map +1 -1
- package/dest/lmdb/store.js +12 -8
- package/dest/lmdb-v2/factory.d.ts +30 -4
- package/dest/lmdb-v2/factory.d.ts.map +1 -1
- package/dest/lmdb-v2/factory.js +62 -10
- package/dest/lmdb-v2/read_transaction.js +21 -19
- package/dest/lmdb-v2/store.d.ts +2 -2
- package/dest/lmdb-v2/store.d.ts.map +1 -1
- package/dest/lmdb-v2/store.js +4 -4
- package/dest/sqlite-opfs/array.d.ts +21 -0
- package/dest/sqlite-opfs/array.d.ts.map +1 -0
- package/dest/sqlite-opfs/array.js +128 -0
- package/dest/sqlite-opfs/errors.d.ts +54 -0
- package/dest/sqlite-opfs/errors.d.ts.map +1 -0
- package/dest/sqlite-opfs/errors.js +77 -0
- package/dest/sqlite-opfs/index.d.ts +14 -0
- package/dest/sqlite-opfs/index.d.ts.map +1 -0
- package/dest/sqlite-opfs/index.js +16 -0
- package/dest/sqlite-opfs/internal/ordered-binary-browser.d.ts +32 -0
- package/dest/sqlite-opfs/internal/ordered-binary-browser.d.ts.map +1 -0
- package/dest/sqlite-opfs/internal/ordered-binary-browser.js +448 -0
- package/dest/sqlite-opfs/manage.d.ts +22 -0
- package/dest/sqlite-opfs/manage.d.ts.map +1 -0
- package/dest/sqlite-opfs/manage.js +38 -0
- package/dest/sqlite-opfs/map.d.ts +35 -0
- package/dest/sqlite-opfs/map.d.ts.map +1 -0
- package/dest/sqlite-opfs/map.js +163 -0
- package/dest/sqlite-opfs/messages.d.ts +66 -0
- package/dest/sqlite-opfs/messages.d.ts.map +1 -0
- package/dest/sqlite-opfs/messages.js +5 -0
- package/dest/sqlite-opfs/multi_map.d.ts +16 -0
- package/dest/sqlite-opfs/multi_map.d.ts.map +1 -0
- package/dest/sqlite-opfs/multi_map.js +67 -0
- package/dest/sqlite-opfs/pool_integrity.d.ts +20 -0
- package/dest/sqlite-opfs/pool_integrity.d.ts.map +1 -0
- package/dest/sqlite-opfs/pool_integrity.js +282 -0
- package/dest/sqlite-opfs/pool_lock.d.ts +8 -0
- package/dest/sqlite-opfs/pool_lock.d.ts.map +1 -0
- package/dest/sqlite-opfs/pool_lock.js +47 -0
- package/dest/sqlite-opfs/set.d.ts +13 -0
- package/dest/sqlite-opfs/set.d.ts.map +1 -0
- package/dest/sqlite-opfs/set.js +19 -0
- package/dest/sqlite-opfs/singleton.d.ts +13 -0
- package/dest/sqlite-opfs/singleton.d.ts.map +1 -0
- package/dest/sqlite-opfs/singleton.js +48 -0
- package/dest/sqlite-opfs/store.d.ts +84 -0
- package/dest/sqlite-opfs/store.d.ts.map +1 -0
- package/dest/sqlite-opfs/store.js +317 -0
- package/dest/sqlite-opfs/worker.d.ts +2 -0
- package/dest/sqlite-opfs/worker.d.ts.map +1 -0
- package/dest/sqlite-opfs/worker.js +275 -0
- package/dest/stores/l2_tips_store.d.ts +7 -13
- package/dest/stores/l2_tips_store.d.ts.map +1 -1
- package/dest/stores/l2_tips_store.js +24 -43
- package/package.json +24 -22
- package/src/bench/shared_map_bench.ts +111 -0
- package/src/{indexeddb → deprecated/indexeddb}/array.ts +2 -2
- package/src/deprecated/indexeddb/index.ts +12 -0
- package/src/{indexeddb → deprecated/indexeddb}/map.ts +2 -2
- package/src/{indexeddb → deprecated/indexeddb}/multi_map.ts +5 -3
- package/src/{indexeddb → deprecated/indexeddb}/set.ts +2 -2
- package/src/{indexeddb → deprecated/indexeddb}/singleton.ts +2 -2
- package/src/{indexeddb → deprecated/indexeddb}/store.ts +10 -9
- package/src/interfaces/array_test_suite.ts +33 -35
- package/src/interfaces/index.ts +1 -1
- package/src/interfaces/map_test_suite.ts +32 -34
- package/src/interfaces/multi_map_test_suite.ts +65 -67
- package/src/interfaces/set_test_suite.ts +13 -15
- package/src/interfaces/singleton_test_suite.ts +6 -8
- package/src/lmdb/index.ts +3 -3
- package/src/lmdb/store.ts +12 -8
- package/src/lmdb-v2/factory.ts +86 -10
- package/src/lmdb-v2/read_transaction.ts +23 -23
- package/src/lmdb-v2/store.ts +4 -2
- package/src/sqlite-opfs/array.ts +124 -0
- package/src/sqlite-opfs/errors.ts +94 -0
- package/src/sqlite-opfs/index.ts +27 -0
- package/src/sqlite-opfs/internal/ordered-binary-browser.js +465 -0
- package/src/sqlite-opfs/manage.ts +46 -0
- package/src/sqlite-opfs/map.ts +163 -0
- package/src/sqlite-opfs/messages.ts +39 -0
- package/src/sqlite-opfs/multi_map.ts +74 -0
- package/src/sqlite-opfs/pool_integrity.ts +327 -0
- package/src/sqlite-opfs/pool_lock.ts +62 -0
- package/src/sqlite-opfs/set.ts +29 -0
- package/src/sqlite-opfs/singleton.ts +48 -0
- package/src/sqlite-opfs/store.ts +330 -0
- package/src/sqlite-opfs/worker.ts +259 -0
- package/src/stores/l2_tips_store.ts +20 -41
- package/dest/config.d.ts +0 -17
- package/dest/config.d.ts.map +0 -1
- package/dest/config.js +0 -26
- package/dest/indexeddb/array.d.ts +0 -22
- package/dest/indexeddb/array.d.ts.map +0 -1
- package/dest/indexeddb/index.d.ts +0 -7
- package/dest/indexeddb/index.d.ts.map +0 -1
- package/dest/indexeddb/index.js +0 -16
- package/dest/indexeddb/map.d.ts +0 -38
- package/dest/indexeddb/map.d.ts.map +0 -1
- package/dest/indexeddb/multi_map.d.ts +0 -14
- package/dest/indexeddb/multi_map.d.ts.map +0 -1
- package/dest/indexeddb/set.d.ts +0 -17
- package/dest/indexeddb/set.d.ts.map +0 -1
- package/dest/indexeddb/singleton.d.ts +0 -17
- package/dest/indexeddb/singleton.d.ts.map +0 -1
- package/dest/indexeddb/store.d.ts +0 -96
- package/dest/indexeddb/store.d.ts.map +0 -1
- package/src/config.ts +0 -36
- package/src/indexeddb/index.ts +0 -31
- /package/dest/{indexeddb → deprecated/indexeddb}/array.js +0 -0
- /package/dest/{indexeddb → deprecated/indexeddb}/map.js +0 -0
- /package/dest/{indexeddb → deprecated/indexeddb}/set.js +0 -0
- /package/dest/{indexeddb → deprecated/indexeddb}/singleton.js +0 -0
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { toArray } from '@aztec/foundation/iterable';
|
|
2
2
|
|
|
3
|
-
import { expect } from 'chai';
|
|
4
|
-
|
|
5
3
|
import type { Key, Range } from './common.js';
|
|
6
4
|
import type { AztecAsyncMultiMap, AztecMultiMap } from './multi_map.js';
|
|
7
5
|
import type { AztecAsyncKVStore, AztecKVStore } from './store.js';
|
|
@@ -72,16 +70,16 @@ export function describeAztecMultiMap(
|
|
|
72
70
|
await multiMap.set('foo', 'bar');
|
|
73
71
|
await multiMap.set('baz', 'qux');
|
|
74
72
|
|
|
75
|
-
expect(await get('foo')).
|
|
76
|
-
expect(await get('baz')).
|
|
77
|
-
expect(await get('quux')).
|
|
73
|
+
expect(await get('foo')).toBe('bar');
|
|
74
|
+
expect(await get('baz')).toBe('qux');
|
|
75
|
+
expect(await get('quux')).toBe(undefined);
|
|
78
76
|
});
|
|
79
77
|
|
|
80
78
|
it('should be able to set values if they do not exist', async () => {
|
|
81
|
-
expect(await multiMap.setIfNotExists('foo', 'bar')).
|
|
82
|
-
expect(await multiMap.setIfNotExists('foo', 'baz')).
|
|
79
|
+
expect(await multiMap.setIfNotExists('foo', 'bar')).toBe(true);
|
|
80
|
+
expect(await multiMap.setIfNotExists('foo', 'baz')).toBe(false);
|
|
83
81
|
|
|
84
|
-
expect(await get('foo')).
|
|
82
|
+
expect(await get('foo')).toBe('bar');
|
|
85
83
|
});
|
|
86
84
|
|
|
87
85
|
it('should be able to delete values', async () => {
|
|
@@ -90,61 +88,61 @@ export function describeAztecMultiMap(
|
|
|
90
88
|
|
|
91
89
|
await multiMap.delete('foo');
|
|
92
90
|
|
|
93
|
-
expect(await get('foo')).
|
|
94
|
-
expect(await get('baz')).
|
|
91
|
+
expect(await get('foo')).toBe(undefined);
|
|
92
|
+
expect(await get('baz')).toBe('qux');
|
|
95
93
|
});
|
|
96
94
|
|
|
97
95
|
it('should be able to get size of the map', async () => {
|
|
98
96
|
await multiMap.set('foo', 'bar');
|
|
99
|
-
expect(await size()).
|
|
97
|
+
expect(await size()).toBe(1);
|
|
100
98
|
await multiMap.set('baz', 'qux');
|
|
101
|
-
expect(await size()).
|
|
99
|
+
expect(await size()).toBe(2);
|
|
102
100
|
|
|
103
101
|
await multiMap.delete('foo');
|
|
104
|
-
expect(await size()).
|
|
102
|
+
expect(await size()).toBe(1);
|
|
105
103
|
});
|
|
106
104
|
|
|
107
105
|
it('returns 0 for empty multimap size', async () => {
|
|
108
|
-
expect(await size()).
|
|
106
|
+
expect(await size()).toBe(0);
|
|
109
107
|
});
|
|
110
108
|
|
|
111
109
|
it('calculates size correctly with multiple values per key', async () => {
|
|
112
|
-
expect(await size()).
|
|
110
|
+
expect(await size()).toBe(0);
|
|
113
111
|
|
|
114
112
|
// Add multiple values for same key
|
|
115
113
|
await multiMap.set('key1', 'value1');
|
|
116
|
-
expect(await size()).
|
|
114
|
+
expect(await size()).toBe(1);
|
|
117
115
|
await multiMap.set('key1', 'value2');
|
|
118
|
-
expect(await size()).
|
|
116
|
+
expect(await size()).toBe(2);
|
|
119
117
|
await multiMap.set('key1', 'value3');
|
|
120
|
-
expect(await size()).
|
|
118
|
+
expect(await size()).toBe(3);
|
|
121
119
|
|
|
122
120
|
// Add values for different key
|
|
123
121
|
await multiMap.set('key2', 'value4');
|
|
124
|
-
expect(await size()).
|
|
122
|
+
expect(await size()).toBe(4);
|
|
125
123
|
|
|
126
124
|
// Delete one value from key1
|
|
127
125
|
await multiMap.deleteValue('key1', 'value2');
|
|
128
|
-
expect(await size()).
|
|
126
|
+
expect(await size()).toBe(3);
|
|
129
127
|
|
|
130
128
|
// Delete entire key
|
|
131
129
|
await multiMap.delete('key1');
|
|
132
|
-
expect(await size()).
|
|
130
|
+
expect(await size()).toBe(1);
|
|
133
131
|
|
|
134
132
|
// Delete last key
|
|
135
133
|
await multiMap.delete('key2');
|
|
136
|
-
expect(await size()).
|
|
134
|
+
expect(await size()).toBe(0);
|
|
137
135
|
});
|
|
138
136
|
|
|
139
137
|
it('should be able to iterate over entries when there are no keys', async () => {
|
|
140
|
-
expect(await entries()).
|
|
138
|
+
expect(await entries()).toEqual([]);
|
|
141
139
|
});
|
|
142
140
|
|
|
143
141
|
it('should be able to iterate over entries', async () => {
|
|
144
142
|
await multiMap.set('foo', 'bar');
|
|
145
143
|
await multiMap.set('baz', 'qux');
|
|
146
144
|
|
|
147
|
-
expect(await entries()).
|
|
145
|
+
expect(await entries()).toEqual([
|
|
148
146
|
['baz', 'qux'],
|
|
149
147
|
['foo', 'bar'],
|
|
150
148
|
]);
|
|
@@ -154,28 +152,28 @@ export function describeAztecMultiMap(
|
|
|
154
152
|
await multiMap.set('foo', 'bar');
|
|
155
153
|
await multiMap.set('baz', 'quux');
|
|
156
154
|
|
|
157
|
-
expect(await values()).
|
|
155
|
+
expect(await values()).toEqual(['quux', 'bar']);
|
|
158
156
|
});
|
|
159
157
|
|
|
160
158
|
it('should be able to iterate over keys', async () => {
|
|
161
159
|
await multiMap.set('foo', 'bar');
|
|
162
160
|
await multiMap.set('baz', 'qux');
|
|
163
161
|
|
|
164
|
-
expect(await keys()).
|
|
162
|
+
expect(await keys()).toEqual(['baz', 'foo']);
|
|
165
163
|
});
|
|
166
164
|
|
|
167
165
|
it('should be able to get multiple values for a single key', async () => {
|
|
168
166
|
await multiMap.set('foo', 'bar');
|
|
169
167
|
await multiMap.set('foo', 'baz');
|
|
170
168
|
|
|
171
|
-
expect(await getValues('foo')).
|
|
169
|
+
expect(await getValues('foo')).toEqual(['bar', 'baz']);
|
|
172
170
|
});
|
|
173
171
|
|
|
174
172
|
it('should ignore multiple identical values', async () => {
|
|
175
173
|
await multiMap.set('foo', 'bar');
|
|
176
174
|
await multiMap.set('foo', 'bar');
|
|
177
175
|
|
|
178
|
-
expect(await getValues('foo')).
|
|
176
|
+
expect(await getValues('foo')).toEqual(['bar']);
|
|
179
177
|
});
|
|
180
178
|
|
|
181
179
|
it('should be able to delete individual values for a single key', async () => {
|
|
@@ -185,22 +183,22 @@ export function describeAztecMultiMap(
|
|
|
185
183
|
|
|
186
184
|
await multiMap.deleteValue('foo', '2');
|
|
187
185
|
|
|
188
|
-
expect(await getValues('foo')).
|
|
186
|
+
expect(await getValues('foo')).toEqual(['1', '3']);
|
|
189
187
|
});
|
|
190
188
|
|
|
191
189
|
it('should be able to get size of the map with duplicate keys', async () => {
|
|
192
190
|
await multiMap.set('foo', '1');
|
|
193
191
|
await multiMap.set('foo', '2');
|
|
194
192
|
await multiMap.set('foo', '3');
|
|
195
|
-
expect(await size()).
|
|
193
|
+
expect(await size()).toBe(3);
|
|
196
194
|
|
|
197
195
|
await multiMap.set('bar', '1');
|
|
198
196
|
await multiMap.set('bar', '2');
|
|
199
197
|
await multiMap.set('bar', '3');
|
|
200
|
-
expect(await size()).
|
|
198
|
+
expect(await size()).toBe(6);
|
|
201
199
|
|
|
202
200
|
await multiMap.deleteValue('foo', '2');
|
|
203
|
-
expect(await size()).
|
|
201
|
+
expect(await size()).toBe(5);
|
|
204
202
|
});
|
|
205
203
|
|
|
206
204
|
it('should be able to delete the last and first values for a key', async () => {
|
|
@@ -210,11 +208,11 @@ export function describeAztecMultiMap(
|
|
|
210
208
|
|
|
211
209
|
await multiMap.deleteValue('foo', '1');
|
|
212
210
|
|
|
213
|
-
expect(await getValues('foo')).
|
|
211
|
+
expect(await getValues('foo')).toEqual(['2', '3']);
|
|
214
212
|
|
|
215
213
|
await multiMap.deleteValue('foo', '3');
|
|
216
214
|
|
|
217
|
-
expect(await getValues('foo')).
|
|
215
|
+
expect(await getValues('foo')).toEqual(['2']);
|
|
218
216
|
});
|
|
219
217
|
|
|
220
218
|
it('should be able to fully clear a key', async () => {
|
|
@@ -226,7 +224,7 @@ export function describeAztecMultiMap(
|
|
|
226
224
|
await multiMap.deleteValue('foo', '3');
|
|
227
225
|
await multiMap.deleteValue('foo', '2');
|
|
228
226
|
|
|
229
|
-
expect(await getValues('foo')).
|
|
227
|
+
expect(await getValues('foo')).toEqual([]);
|
|
230
228
|
});
|
|
231
229
|
|
|
232
230
|
it('should be able to insert after deletion', async () => {
|
|
@@ -237,12 +235,12 @@ export function describeAztecMultiMap(
|
|
|
237
235
|
await multiMap.deleteValue('foo', '2');
|
|
238
236
|
await multiMap.set('foo', 'bar');
|
|
239
237
|
|
|
240
|
-
expect(await getValues('foo')).
|
|
238
|
+
expect(await getValues('foo')).toEqual(['1', '3', 'bar']);
|
|
241
239
|
|
|
242
240
|
// Delete the just-added entry
|
|
243
241
|
await multiMap.deleteValue('foo', 'bar');
|
|
244
242
|
|
|
245
|
-
expect(await getValues('foo')).
|
|
243
|
+
expect(await getValues('foo')).toEqual(['1', '3']);
|
|
246
244
|
|
|
247
245
|
// Reinsert the initially deleted key
|
|
248
246
|
await multiMap.set('foo', '2');
|
|
@@ -250,7 +248,7 @@ export function describeAztecMultiMap(
|
|
|
250
248
|
// LMDB and IndexedDB behave differently here, the former ordering by value and the latter by insertion. This is
|
|
251
249
|
// fine because there is no expectation for values in a multimap to be ordered.
|
|
252
250
|
const values = (await getValues('foo')).sort((a, b) => a.localeCompare(b));
|
|
253
|
-
expect(values).
|
|
251
|
+
expect(values).toEqual(['1', '2', '3']);
|
|
254
252
|
|
|
255
253
|
// Fully clear the key
|
|
256
254
|
await multiMap.deleteValue('foo', '1');
|
|
@@ -260,7 +258,7 @@ export function describeAztecMultiMap(
|
|
|
260
258
|
// Insert some more
|
|
261
259
|
await multiMap.set('foo', 'baz');
|
|
262
260
|
await multiMap.set('foo', 'qux');
|
|
263
|
-
expect(await getValues('foo')).
|
|
261
|
+
expect(await getValues('foo')).toEqual(['baz', 'qux']);
|
|
264
262
|
});
|
|
265
263
|
|
|
266
264
|
it('supports range queries', async () => {
|
|
@@ -269,29 +267,29 @@ export function describeAztecMultiMap(
|
|
|
269
267
|
await multiMap.set('c', 'c');
|
|
270
268
|
await multiMap.set('d', 'd');
|
|
271
269
|
|
|
272
|
-
expect(await keys({ start: 'b', end: 'c' })).
|
|
273
|
-
expect(await keys({ start: 'b' })).
|
|
274
|
-
expect(await keys({ end: 'c' })).
|
|
275
|
-
expect(await keys({ start: 'b', end: 'c', reverse: true })).
|
|
276
|
-
expect(await keys({ start: 'b', limit: 1 })).
|
|
277
|
-
expect(await keys({ start: 'b', reverse: true })).
|
|
278
|
-
expect(await keys({ end: 'b', reverse: true })).
|
|
270
|
+
expect(await keys({ start: 'b', end: 'c' })).toEqual(['b']);
|
|
271
|
+
expect(await keys({ start: 'b' })).toEqual(['b', 'c', 'd']);
|
|
272
|
+
expect(await keys({ end: 'c' })).toEqual(['a', 'b']);
|
|
273
|
+
expect(await keys({ start: 'b', end: 'c', reverse: true })).toEqual(['c']);
|
|
274
|
+
expect(await keys({ start: 'b', limit: 1 })).toEqual(['b']);
|
|
275
|
+
expect(await keys({ start: 'b', reverse: true })).toEqual(['d', 'c']);
|
|
276
|
+
expect(await keys({ end: 'b', reverse: true })).toEqual(['b', 'a']);
|
|
279
277
|
});
|
|
280
278
|
|
|
281
279
|
it('returns 0 for missing key', async () => {
|
|
282
|
-
expect(await getValueCount('missing')).
|
|
280
|
+
expect(await getValueCount('missing')).toBe(0);
|
|
283
281
|
});
|
|
284
282
|
|
|
285
283
|
it('counts a single value', async () => {
|
|
286
284
|
await multiMap.set('foo', 'bar');
|
|
287
|
-
expect(await getValueCount('foo')).
|
|
285
|
+
expect(await getValueCount('foo')).toBe(1);
|
|
288
286
|
});
|
|
289
287
|
|
|
290
288
|
it('counts multiple distinct values for same key', async () => {
|
|
291
289
|
await multiMap.set('foo', 'bar');
|
|
292
290
|
await multiMap.set('foo', 'baz');
|
|
293
291
|
await multiMap.set('foo', 'qux');
|
|
294
|
-
expect(await getValueCount('foo')).
|
|
292
|
+
expect(await getValueCount('foo')).toBe(3);
|
|
295
293
|
});
|
|
296
294
|
|
|
297
295
|
it('does not increase count for duplicate inserts', async () => {
|
|
@@ -299,42 +297,42 @@ export function describeAztecMultiMap(
|
|
|
299
297
|
await multiMap.set('foo', 'bar');
|
|
300
298
|
await multiMap.set('foo', 'baz');
|
|
301
299
|
await multiMap.set('foo', 'baz');
|
|
302
|
-
expect(await getValueCount('foo')).
|
|
303
|
-
expect(await getValues('foo')).
|
|
300
|
+
expect(await getValueCount('foo')).toBe(2);
|
|
301
|
+
expect((await getValues('foo')).sort()).toEqual(['bar', 'baz'].sort());
|
|
304
302
|
});
|
|
305
303
|
|
|
306
304
|
it('decrements when deleting a single value', async () => {
|
|
307
305
|
await multiMap.set('foo', '1');
|
|
308
306
|
await multiMap.set('foo', '2');
|
|
309
307
|
await multiMap.set('foo', '3');
|
|
310
|
-
expect(await getValueCount('foo')).
|
|
308
|
+
expect(await getValueCount('foo')).toBe(3);
|
|
311
309
|
await multiMap.deleteValue('foo', '2');
|
|
312
|
-
expect(await getValueCount('foo')).
|
|
313
|
-
expect(await getValues('foo')).
|
|
310
|
+
expect(await getValueCount('foo')).toBe(2);
|
|
311
|
+
expect((await getValues('foo')).sort()).toEqual(['1', '3'].sort());
|
|
314
312
|
});
|
|
315
313
|
|
|
316
314
|
it('does not change count when deleting a non-existent value', async () => {
|
|
317
315
|
await multiMap.set('foo', '1');
|
|
318
316
|
await multiMap.set('foo', '3');
|
|
319
|
-
expect(await getValueCount('foo')).
|
|
317
|
+
expect(await getValueCount('foo')).toBe(2);
|
|
320
318
|
await multiMap.deleteValue('foo', '2');
|
|
321
|
-
expect(await getValueCount('foo')).
|
|
319
|
+
expect(await getValueCount('foo')).toBe(2);
|
|
322
320
|
});
|
|
323
321
|
|
|
324
322
|
it('clears all values when deleting a key', async () => {
|
|
325
323
|
await multiMap.set('foo', 'bar');
|
|
326
324
|
await multiMap.set('foo', 'baz');
|
|
327
|
-
expect(await getValueCount('foo')).
|
|
325
|
+
expect(await getValueCount('foo')).toBe(2);
|
|
328
326
|
await multiMap.delete('foo');
|
|
329
|
-
expect(await getValueCount('foo')).
|
|
330
|
-
expect(await getValues('foo')).
|
|
327
|
+
expect(await getValueCount('foo')).toBe(0);
|
|
328
|
+
expect(await getValues('foo')).toEqual([]);
|
|
331
329
|
});
|
|
332
330
|
|
|
333
331
|
it('count equals enumerated values length', async () => {
|
|
334
332
|
await multiMap.set('foo', '1');
|
|
335
333
|
await multiMap.set('foo', '2');
|
|
336
334
|
const vals = await getValues('foo');
|
|
337
|
-
expect(await getValueCount('foo')).
|
|
335
|
+
expect(await getValueCount('foo')).toBe(vals.length);
|
|
338
336
|
});
|
|
339
337
|
|
|
340
338
|
it('sum of per-key counts equals total size', async () => {
|
|
@@ -348,27 +346,27 @@ export function describeAztecMultiMap(
|
|
|
348
346
|
const uniqueKeys = Array.from(new Set(allKeys));
|
|
349
347
|
const counts = await Promise.all(uniqueKeys.map(k => getValueCount(k)));
|
|
350
348
|
const sum = counts.reduce((s, n) => s + n, 0);
|
|
351
|
-
expect(sum).
|
|
349
|
+
expect(sum).toBe(await size());
|
|
352
350
|
});
|
|
353
351
|
|
|
354
352
|
it('supports sparse slots: delete middle, reinsert new, count remains correct', async () => {
|
|
355
353
|
await multiMap.set('foo', '1');
|
|
356
354
|
await multiMap.set('foo', '2');
|
|
357
355
|
await multiMap.set('foo', '3');
|
|
358
|
-
expect(await getValueCount('foo')).
|
|
356
|
+
expect(await getValueCount('foo')).toBe(3);
|
|
359
357
|
await multiMap.deleteValue('foo', '2');
|
|
360
|
-
expect(await getValueCount('foo')).
|
|
358
|
+
expect(await getValueCount('foo')).toBe(2);
|
|
361
359
|
await multiMap.set('foo', '4');
|
|
362
|
-
expect(await getValueCount('foo')).
|
|
363
|
-
expect(await getValues('foo')).
|
|
360
|
+
expect(await getValueCount('foo')).toBe(3);
|
|
361
|
+
expect((await getValues('foo')).sort()).toEqual(['1', '3', '4'].sort());
|
|
364
362
|
});
|
|
365
363
|
|
|
366
364
|
it('multiple keys are independent', async () => {
|
|
367
365
|
await multiMap.set('foo', '1');
|
|
368
366
|
await multiMap.set('foo', '2');
|
|
369
367
|
await multiMap.set('bar', '3');
|
|
370
|
-
expect(await getValueCount('foo')).
|
|
371
|
-
expect(await getValueCount('bar')).
|
|
368
|
+
expect(await getValueCount('foo')).toBe(2);
|
|
369
|
+
expect(await getValueCount('bar')).toBe(1);
|
|
372
370
|
});
|
|
373
371
|
});
|
|
374
372
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { toArray } from '@aztec/foundation/iterable';
|
|
2
2
|
|
|
3
|
-
import { expect } from 'chai';
|
|
4
|
-
|
|
5
3
|
import type { Range } from './common.js';
|
|
6
4
|
import type { AztecAsyncSet, AztecSet } from './set.js';
|
|
7
5
|
import type { AztecAsyncKVStore, AztecKVStore } from './store.js';
|
|
@@ -41,9 +39,9 @@ export function describeAztecSet(
|
|
|
41
39
|
await set.add('foo');
|
|
42
40
|
await set.add('baz');
|
|
43
41
|
|
|
44
|
-
expect(await has('foo')).
|
|
45
|
-
expect(await has('baz')).
|
|
46
|
-
expect(await has('bar')).
|
|
42
|
+
expect(await has('foo')).toBe(true);
|
|
43
|
+
expect(await has('baz')).toBe(true);
|
|
44
|
+
expect(await has('bar')).toBe(false);
|
|
47
45
|
});
|
|
48
46
|
|
|
49
47
|
it('should be able to delete values', async () => {
|
|
@@ -52,15 +50,15 @@ export function describeAztecSet(
|
|
|
52
50
|
|
|
53
51
|
await set.delete('foo');
|
|
54
52
|
|
|
55
|
-
expect(await has('foo')).
|
|
56
|
-
expect(await has('baz')).
|
|
53
|
+
expect(await has('foo')).toBe(false);
|
|
54
|
+
expect(await has('baz')).toBe(true);
|
|
57
55
|
});
|
|
58
56
|
|
|
59
57
|
it('should be able to iterate over entries', async () => {
|
|
60
58
|
await set.add('baz');
|
|
61
59
|
await set.add('foo');
|
|
62
60
|
|
|
63
|
-
expect(await entries()).
|
|
61
|
+
expect(await entries()).toEqual(['baz', 'foo']);
|
|
64
62
|
});
|
|
65
63
|
|
|
66
64
|
it('supports range queries', async () => {
|
|
@@ -69,13 +67,13 @@ export function describeAztecSet(
|
|
|
69
67
|
await set.add('c');
|
|
70
68
|
await set.add('d');
|
|
71
69
|
|
|
72
|
-
expect(await entries({ start: 'b', end: 'c' })).
|
|
73
|
-
expect(await entries({ start: 'b' })).
|
|
74
|
-
expect(await entries({ end: 'c' })).
|
|
75
|
-
expect(await entries({ start: 'b', end: 'c', reverse: true })).
|
|
76
|
-
expect(await entries({ start: 'b', limit: 1 })).
|
|
77
|
-
expect(await entries({ start: 'b', reverse: true })).
|
|
78
|
-
expect(await entries({ end: 'b', reverse: true })).
|
|
70
|
+
expect(await entries({ start: 'b', end: 'c' })).toEqual(['b']);
|
|
71
|
+
expect(await entries({ start: 'b' })).toEqual(['b', 'c', 'd']);
|
|
72
|
+
expect(await entries({ end: 'c' })).toEqual(['a', 'b']);
|
|
73
|
+
expect(await entries({ start: 'b', end: 'c', reverse: true })).toEqual(['c']);
|
|
74
|
+
expect(await entries({ start: 'b', limit: 1 })).toEqual(['b']);
|
|
75
|
+
expect(await entries({ start: 'b', reverse: true })).toEqual(['d', 'c']);
|
|
76
|
+
expect(await entries({ end: 'b', reverse: true })).toEqual(['b', 'a']);
|
|
79
77
|
});
|
|
80
78
|
});
|
|
81
79
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { expect } from 'chai';
|
|
2
|
-
|
|
3
1
|
import type { AztecAsyncSingleton, AztecSingleton } from './singleton.js';
|
|
4
2
|
import type { AztecAsyncKVStore, AztecKVStore } from './store.js';
|
|
5
3
|
import { isSyncStore } from './utils.js';
|
|
@@ -29,18 +27,18 @@ export function describeAztecSingleton(
|
|
|
29
27
|
}
|
|
30
28
|
|
|
31
29
|
it('returns undefined if the value is not set', async () => {
|
|
32
|
-
expect(await get()).
|
|
30
|
+
expect(await get()).toBe(undefined);
|
|
33
31
|
});
|
|
34
32
|
|
|
35
33
|
it('should be able to set and get values', async () => {
|
|
36
|
-
expect(await singleton.set('foo')).
|
|
37
|
-
expect(await get()).
|
|
34
|
+
expect(await singleton.set('foo')).toBe(true);
|
|
35
|
+
expect(await get()).toBe('foo');
|
|
38
36
|
});
|
|
39
37
|
|
|
40
38
|
it('overwrites the value if it is set again', async () => {
|
|
41
|
-
expect(await singleton.set('foo')).
|
|
42
|
-
expect(await singleton.set('bar')).
|
|
43
|
-
expect(await get()).
|
|
39
|
+
expect(await singleton.set('foo')).toBe(true);
|
|
40
|
+
expect(await singleton.set('bar')).toBe(true);
|
|
41
|
+
expect(await get()).toBe('bar');
|
|
44
42
|
});
|
|
45
43
|
});
|
|
46
44
|
}
|
package/src/lmdb/index.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
2
|
+
import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
|
|
2
3
|
|
|
3
4
|
import { join } from 'path';
|
|
4
5
|
|
|
5
|
-
import type { DataStoreConfig } from '../config.js';
|
|
6
6
|
import { initStoreForRollupAndSchemaVersion } from '../utils.js';
|
|
7
7
|
import { AztecLmdbStore } from './store.js';
|
|
8
8
|
|
|
@@ -26,8 +26,8 @@ export function createStore(
|
|
|
26
26
|
);
|
|
27
27
|
|
|
28
28
|
const store = AztecLmdbStore.open(dataDirectory, config.dataStoreMapSizeKb, false);
|
|
29
|
-
if (config.
|
|
30
|
-
return initStoreForRollupAndSchemaVersion(store, schemaVersion, config.
|
|
29
|
+
if (config.rollupAddress) {
|
|
30
|
+
return initStoreForRollupAndSchemaVersion(store, schemaVersion, config.rollupAddress, log);
|
|
31
31
|
}
|
|
32
32
|
return store;
|
|
33
33
|
}
|
package/src/lmdb/store.ts
CHANGED
|
@@ -147,21 +147,25 @@ export class AztecLmdbStore implements AztecKVStore, AztecAsyncKVStore {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
/**
|
|
150
|
-
* Clears all entries in the store & sub DBs.
|
|
150
|
+
* Clears all entries in the store & sub DBs atomically within a single transaction.
|
|
151
151
|
*/
|
|
152
152
|
async clear() {
|
|
153
|
-
await this.#
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
await this.#rootDb.transaction(async () => {
|
|
154
|
+
await this.#data.clearAsync();
|
|
155
|
+
await this.#multiMapData.clearAsync();
|
|
156
|
+
await this.#rootDb.clearAsync();
|
|
157
|
+
});
|
|
156
158
|
}
|
|
157
159
|
|
|
158
160
|
/**
|
|
159
|
-
* Drops the database & sub DBs.
|
|
161
|
+
* Drops the database & sub DBs atomically within a single transaction.
|
|
160
162
|
*/
|
|
161
163
|
async drop() {
|
|
162
|
-
await this.#
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
await this.#rootDb.transaction(async () => {
|
|
165
|
+
await this.#data.drop();
|
|
166
|
+
await this.#multiMapData.drop();
|
|
167
|
+
await this.#rootDb.drop();
|
|
168
|
+
});
|
|
165
169
|
}
|
|
166
170
|
|
|
167
171
|
/**
|
package/src/lmdb-v2/factory.ts
CHANGED
|
@@ -1,24 +1,36 @@
|
|
|
1
1
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
2
|
import { type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
DatabaseVersionManager,
|
|
5
|
+
type SchemaVersionMismatchPolicy,
|
|
6
|
+
type VersionFileReadFailurePolicy,
|
|
7
|
+
} from '@aztec/stdlib/database-version/manager';
|
|
8
|
+
import type { DataStoreConfig } from '@aztec/stdlib/kv-store';
|
|
4
9
|
|
|
5
|
-
import { mkdir, mkdtemp, rm } from 'fs/promises';
|
|
10
|
+
import { copyFile, mkdir, mkdtemp, rm } from 'fs/promises';
|
|
6
11
|
import { tmpdir } from 'os';
|
|
7
12
|
import { join } from 'path';
|
|
8
13
|
|
|
9
|
-
import type { DataStoreConfig } from '../config.js';
|
|
10
14
|
import { AztecLMDBStoreV2 } from './store.js';
|
|
11
15
|
|
|
12
16
|
const MAX_READERS = 16;
|
|
13
17
|
|
|
18
|
+
/** Optional versioning hooks for persistent LMDB stores. */
|
|
19
|
+
export type CreateStoreOptions = {
|
|
20
|
+
onUpgrade?: (dataDir: string, currentVersion: number, latestVersion: number) => Promise<void>;
|
|
21
|
+
schemaVersionMismatchPolicy?: SchemaVersionMismatchPolicy;
|
|
22
|
+
versionFileReadFailurePolicy?: VersionFileReadFailurePolicy;
|
|
23
|
+
};
|
|
24
|
+
|
|
14
25
|
export async function createStore(
|
|
15
26
|
name: string,
|
|
16
27
|
schemaVersion: number,
|
|
17
28
|
config: DataStoreConfig,
|
|
18
29
|
bindings?: LoggerBindings,
|
|
30
|
+
options: CreateStoreOptions = {},
|
|
19
31
|
): Promise<AztecLMDBStoreV2> {
|
|
20
32
|
const log = createLogger('kv-store:lmdb-v2:' + name, bindings);
|
|
21
|
-
const { dataDirectory,
|
|
33
|
+
const { dataDirectory, rollupAddress: rollupFromConfig } = config;
|
|
22
34
|
|
|
23
35
|
let store: AztecLMDBStoreV2;
|
|
24
36
|
if (typeof dataDirectory !== 'undefined') {
|
|
@@ -26,7 +38,7 @@ export async function createStore(
|
|
|
26
38
|
const subDir = join(dataDirectory, name);
|
|
27
39
|
await mkdir(subDir, { recursive: true });
|
|
28
40
|
|
|
29
|
-
const rollupAddress =
|
|
41
|
+
const rollupAddress = rollupFromConfig ?? EthAddress.ZERO;
|
|
30
42
|
|
|
31
43
|
// Create a version manager
|
|
32
44
|
const versionManager = new DatabaseVersionManager({
|
|
@@ -35,6 +47,9 @@ export async function createStore(
|
|
|
35
47
|
dataDirectory: subDir,
|
|
36
48
|
onOpen: dbDirectory =>
|
|
37
49
|
AztecLMDBStoreV2.new(dbDirectory, config.dataStoreMapSizeKb, MAX_READERS, () => Promise.resolve(), bindings),
|
|
50
|
+
onUpgrade: options.onUpgrade,
|
|
51
|
+
schemaVersionMismatchPolicy: options.schemaVersionMismatchPolicy,
|
|
52
|
+
versionFileReadFailurePolicy: options.versionFileReadFailurePolicy,
|
|
38
53
|
});
|
|
39
54
|
|
|
40
55
|
log.info(
|
|
@@ -48,9 +63,14 @@ export async function createStore(
|
|
|
48
63
|
return store;
|
|
49
64
|
}
|
|
50
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Open a persistent on-disk store rooted in OS tmpdir. Caller chooses whether to
|
|
68
|
+
* auto-remove the directory on close. Uses standard durable LMDB flags (fsync on
|
|
69
|
+
* every commit) — for full in-memory / NOSYNC semantics use `openEphemeralStore`.
|
|
70
|
+
*/
|
|
51
71
|
export async function openTmpStore(
|
|
52
72
|
name: string,
|
|
53
|
-
|
|
73
|
+
cleanupTmpDir: boolean = true,
|
|
54
74
|
dbMapSizeKb = 10 * 1_024 * 1_024, // 10GB
|
|
55
75
|
maxReaders = MAX_READERS,
|
|
56
76
|
bindings?: LoggerBindings,
|
|
@@ -61,7 +81,7 @@ export async function openTmpStore(
|
|
|
61
81
|
|
|
62
82
|
// pass a cleanup callback because process.on('beforeExit', cleanup) does not work under Jest
|
|
63
83
|
const cleanup = async () => {
|
|
64
|
-
if (
|
|
84
|
+
if (cleanupTmpDir) {
|
|
65
85
|
try {
|
|
66
86
|
await rm(dataDir, { recursive: true, force: true, maxRetries: 3 });
|
|
67
87
|
log.debug(`Deleted temporary data store: ${dataDir}`);
|
|
@@ -73,9 +93,35 @@ export async function openTmpStore(
|
|
|
73
93
|
}
|
|
74
94
|
};
|
|
75
95
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
96
|
+
return AztecLMDBStoreV2.new(dataDir, dbMapSizeKb, maxReaders, cleanup, bindings, false);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Open a fully-ephemeral store: a fresh tmpdir backing file, LMDB opened with
|
|
101
|
+
* MDB_NOSYNC | MDB_NOMETASYNC (no fsync, kernel-only writeback), and the directory
|
|
102
|
+
* unconditionally removed on close. Intended for tests and worker-local scratch
|
|
103
|
+
* stores where durability is explicitly not desired.
|
|
104
|
+
*/
|
|
105
|
+
export async function openEphemeralStore(
|
|
106
|
+
name: string,
|
|
107
|
+
dbMapSizeKb = 10 * 1_024 * 1_024, // 10GB
|
|
108
|
+
maxReaders = MAX_READERS,
|
|
109
|
+
bindings?: LoggerBindings,
|
|
110
|
+
): Promise<AztecLMDBStoreV2> {
|
|
111
|
+
const log = createLogger('kv-store:lmdb-v2:' + name, bindings);
|
|
112
|
+
const dataDir = await mkdtemp(join(tmpdir(), name + '-'));
|
|
113
|
+
log.debug(`Created ephemeral data store at: ${dataDir} with size: ${dbMapSizeKb} KB (LMDB v2)`);
|
|
114
|
+
|
|
115
|
+
const cleanup = async () => {
|
|
116
|
+
try {
|
|
117
|
+
await rm(dataDir, { recursive: true, force: true, maxRetries: 3 });
|
|
118
|
+
log.debug(`Deleted ephemeral data store: ${dataDir}`);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
log.warn(`Failed to delete ephemeral data directory (LMDB v2) ${dataDir}: ${err}`);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
return AztecLMDBStoreV2.new(dataDir, dbMapSizeKb, maxReaders, cleanup, bindings, true);
|
|
79
125
|
}
|
|
80
126
|
|
|
81
127
|
export async function openStoreAt(
|
|
@@ -89,6 +135,36 @@ export async function openStoreAt(
|
|
|
89
135
|
return await AztecLMDBStoreV2.new(dataDir, dbMapSizeKb, maxReaders, undefined, bindings);
|
|
90
136
|
}
|
|
91
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Open a fully-ephemeral store seeded from an existing `data.mdb` file. Creates a fresh tmpdir,
|
|
140
|
+
* copies `srcDataMdbPath` into it as `data.mdb`, opens with MDB_NOSYNC | MDB_NOMETASYNC, and
|
|
141
|
+
* removes the tmpdir on close. Intended for worker clones of a main-thread-built store — the
|
|
142
|
+
* source file is never written to.
|
|
143
|
+
*/
|
|
144
|
+
export async function cloneEphemeralStoreFrom(
|
|
145
|
+
srcDataMdbPath: string,
|
|
146
|
+
name: string,
|
|
147
|
+
dbMapSizeKb = 10 * 1_024 * 1_024, // 10GB
|
|
148
|
+
maxReaders = MAX_READERS,
|
|
149
|
+
bindings?: LoggerBindings,
|
|
150
|
+
): Promise<AztecLMDBStoreV2> {
|
|
151
|
+
const log = createLogger('kv-store:lmdb-v2:' + name, bindings);
|
|
152
|
+
const dataDir = await mkdtemp(join(tmpdir(), name + '-'));
|
|
153
|
+
await copyFile(srcDataMdbPath, join(dataDir, 'data.mdb'));
|
|
154
|
+
log.debug(`Cloned ephemeral data store at: ${dataDir} from ${srcDataMdbPath} (LMDB v2)`);
|
|
155
|
+
|
|
156
|
+
const cleanup = async () => {
|
|
157
|
+
try {
|
|
158
|
+
await rm(dataDir, { recursive: true, force: true, maxRetries: 3 });
|
|
159
|
+
log.debug(`Deleted ephemeral data store: ${dataDir}`);
|
|
160
|
+
} catch (err) {
|
|
161
|
+
log.warn(`Failed to delete ephemeral data directory (LMDB v2) ${dataDir}: ${err}`);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
return AztecLMDBStoreV2.new(dataDir, dbMapSizeKb, maxReaders, cleanup, bindings, true);
|
|
166
|
+
}
|
|
167
|
+
|
|
92
168
|
export async function openVersionedStoreAt(
|
|
93
169
|
dataDirectory: string,
|
|
94
170
|
schemaVersion: number,
|