xitdb 0.9.0 → 0.11.0
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 +31 -12
- package/dist/database.d.ts +1 -0
- package/dist/index.js +301 -56
- package/dist/read-array-list.d.ts +1 -0
- package/dist/read-counted-hash-map.d.ts +1 -2
- package/dist/read-counted-hash-set.d.ts +1 -2
- package/dist/read-hash-map.d.ts +2 -2
- package/dist/read-hash-set.d.ts +2 -2
- package/dist/read-linked-array-list.d.ts +1 -0
- package/dist/write-array-list.d.ts +1 -1
- package/dist/write-linked-array-list.d.ts +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -3,19 +3,22 @@
|
|
|
3
3
|
<br/>
|
|
4
4
|
<br/>
|
|
5
5
|
<b>Choose your flavor:</b>
|
|
6
|
-
<a href="https://github.com/
|
|
7
|
-
<a href="https://github.com/
|
|
6
|
+
<a href="https://github.com/xit-vcs/xitdb">Zig</a> |
|
|
7
|
+
<a href="https://github.com/xit-vcs/xitdb-java">Java</a> |
|
|
8
8
|
<a href="https://github.com/codeboost/xitdb-clj">Clojure</a> |
|
|
9
|
-
<a href="https://github.com/
|
|
9
|
+
<a href="https://github.com/xit-vcs/xitdb-ts">TypeScript</a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
-
* Each transaction efficiently creates a new "copy" of the database, and past copies can still be read from.
|
|
13
|
-
*
|
|
12
|
+
* Each transaction efficiently creates a new "copy" of the database, and past copies can still be read from and reverted to.
|
|
13
|
+
* Supports storing in a single file as well as purely in-memory use.
|
|
14
|
+
* Runs as a library (embedded in process).
|
|
15
|
+
* Incrementally reads and writes, so file-based databases can contain larger-than-memory datasets.
|
|
16
|
+
* Reads never block writes, and a database can be read from multiple threads/processes without locks.
|
|
14
17
|
* No query engine of any kind. You just write data structures (primarily an `ArrayList` and `HashMap`) that can be nested arbitrarily.
|
|
15
18
|
* No dependencies besides the JavaScript standard library.
|
|
16
|
-
*
|
|
19
|
+
* Available [on npm](https://www.npmjs.com/package/xitdb).
|
|
17
20
|
|
|
18
|
-
This database was originally made for the [xit version control system](https://github.com/
|
|
21
|
+
This database was originally made for the [xit version control system](https://github.com/xit-vcs/xit), but I bet it has a lot of potential for other projects. The combination of being immutable and having an API similar to in-memory data structures is pretty powerful. Consider using it [instead of SQLite](https://gist.github.com/radarroark/03a0724484e1111ef4c05d72a935c42c) for your TypeScript projects: it's simpler, it's pure TypeScript, and it creates no impedance mismatch with your program the way SQL databases do.
|
|
19
22
|
|
|
20
23
|
* [Example](#example)
|
|
21
24
|
* [Initializing a Database](#initializing-a-database)
|
|
@@ -24,6 +27,7 @@ This database was originally made for the [xit version control system](https://g
|
|
|
24
27
|
* [Large Byte Arrays](#large-byte-arrays)
|
|
25
28
|
* [Iterators](#iterators)
|
|
26
29
|
* [Hashing](#hashing)
|
|
30
|
+
* [Compaction](#compaction)
|
|
27
31
|
|
|
28
32
|
## Example
|
|
29
33
|
|
|
@@ -85,7 +89,7 @@ await history.appendContext(await history.getSlot(-1), async (cursor) => {
|
|
|
85
89
|
// get the most recent copy of the database, like a moment
|
|
86
90
|
// in time. the -1 index will return the last index in the list.
|
|
87
91
|
const momentCursor = await history.getCursor(-1);
|
|
88
|
-
const moment =
|
|
92
|
+
const moment = new ReadHashMap(momentCursor!);
|
|
89
93
|
|
|
90
94
|
// we can read the value of "foo" from the map by getting
|
|
91
95
|
// the cursor to "foo" and then calling readBytes on it
|
|
@@ -180,7 +184,7 @@ await history.appendContext(await history.getSlot(-1), async (cursor) => {
|
|
|
180
184
|
});
|
|
181
185
|
|
|
182
186
|
const momentCursor = await history.getCursor(-1);
|
|
183
|
-
const moment =
|
|
187
|
+
const moment = new ReadHashMap(momentCursor!);
|
|
184
188
|
|
|
185
189
|
// the food list includes the fruits
|
|
186
190
|
const foodCursor = await moment.getCursor('food');
|
|
@@ -221,7 +225,7 @@ await history.appendContext(await history.getSlot(-1), async (cursor) => {
|
|
|
221
225
|
});
|
|
222
226
|
|
|
223
227
|
const momentCursor = await history.getCursor(-1);
|
|
224
|
-
const moment =
|
|
228
|
+
const moment = new ReadHashMap(momentCursor!);
|
|
225
229
|
|
|
226
230
|
// the cities list contains all four
|
|
227
231
|
const citiesCursor = await moment.getCursor('cities');
|
|
@@ -267,7 +271,7 @@ await history.appendContext(await history.getSlot(-1), async (cursor) => {
|
|
|
267
271
|
});
|
|
268
272
|
|
|
269
273
|
const momentCursor = await history.getCursor(-1);
|
|
270
|
-
const moment =
|
|
274
|
+
const moment = new ReadHashMap(momentCursor!);
|
|
271
275
|
|
|
272
276
|
// the cities list contains all four
|
|
273
277
|
const citiesCursor = await moment.getCursor('cities');
|
|
@@ -323,7 +327,7 @@ const people = new ReadArrayList(peopleCursor!);
|
|
|
323
327
|
const peopleIter = await people.iterator();
|
|
324
328
|
while (await peopleIter.hasNext()) {
|
|
325
329
|
const personCursor = await peopleIter.next();
|
|
326
|
-
const person =
|
|
330
|
+
const person = new ReadHashMap(personCursor!);
|
|
327
331
|
const personIter = await person.iterator();
|
|
328
332
|
while (await personIter.hasNext()) {
|
|
329
333
|
const kvPairCursor = await personIter.next();
|
|
@@ -414,3 +418,18 @@ switch (hashIdStr) {
|
|
|
414
418
|
throw new Error('Invalid hash algorithm');
|
|
415
419
|
}
|
|
416
420
|
```
|
|
421
|
+
|
|
422
|
+
## Compaction
|
|
423
|
+
|
|
424
|
+
Normally, an immutable database grows forever, because old data is never deleted. To reclaim disk space and clear the history, xitdb supports compaction. This involves completely rebuilding the database file to only contain the data accessible from the latest copy (i.e., "moment") of the database.
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
// create the file and core for the new database
|
|
428
|
+
using compactCore = await CoreBufferedFile.create('compact.db');
|
|
429
|
+
|
|
430
|
+
const compactDb = await db.compact(compactCore);
|
|
431
|
+
|
|
432
|
+
// read from the new compacted db
|
|
433
|
+
const history = new ReadArrayList(compactDb.rootCursor());
|
|
434
|
+
expect(await history.count()).toBe(1);
|
|
435
|
+
```
|
package/dist/database.d.ts
CHANGED
|
@@ -223,6 +223,7 @@ export declare class Database {
|
|
|
223
223
|
static create(core: Core, hasher: Hasher): Promise<Database>;
|
|
224
224
|
rootCursor(): WriteCursor;
|
|
225
225
|
freeze(): Promise<void>;
|
|
226
|
+
compact(targetCore: Core): Promise<Database>;
|
|
226
227
|
truncate(): Promise<void>;
|
|
227
228
|
checkHashBytes(hash: Uint8Array): Uint8Array;
|
|
228
229
|
checkHash(target: HashMapGetTarget): Uint8Array;
|
package/dist/index.js
CHANGED
|
@@ -2317,6 +2317,43 @@ class Database3 {
|
|
|
2317
2317
|
throw new ExpectedTxStartException;
|
|
2318
2318
|
}
|
|
2319
2319
|
}
|
|
2320
|
+
async compact(targetCore) {
|
|
2321
|
+
const offsetMap = new Map;
|
|
2322
|
+
const hasher = new Hasher(this.hasher.algorithm, this.header.hashId);
|
|
2323
|
+
const target = await Database3.create(targetCore, hasher);
|
|
2324
|
+
if (this.header.tag === 0 /* NONE */)
|
|
2325
|
+
return target;
|
|
2326
|
+
if (this.header.tag !== 2 /* ARRAY_LIST */)
|
|
2327
|
+
throw new UnexpectedTagException;
|
|
2328
|
+
await this.core.seek(Header.LENGTH);
|
|
2329
|
+
const sourceReader = this.core.reader();
|
|
2330
|
+
const headerBytes = new Uint8Array(ArrayListHeader.LENGTH);
|
|
2331
|
+
await sourceReader.readFully(headerBytes);
|
|
2332
|
+
const sourceHeader = ArrayListHeader.fromBytes(headerBytes);
|
|
2333
|
+
if (sourceHeader.size === 0)
|
|
2334
|
+
return target;
|
|
2335
|
+
const lastKey = sourceHeader.size - 1;
|
|
2336
|
+
const shift = lastKey < SLOT_COUNT ? 0 : Math.floor(Math.log(lastKey) / Math.log(SLOT_COUNT));
|
|
2337
|
+
const lastSlotPtr = await this.readArrayListSlot(sourceHeader.ptr, lastKey, shift, 0 /* READ_ONLY */, true);
|
|
2338
|
+
const momentSlot = lastSlotPtr.slot;
|
|
2339
|
+
const targetWriter = targetCore.writer();
|
|
2340
|
+
await targetCore.seek(Header.LENGTH);
|
|
2341
|
+
const targetArrayListPtr = Header.LENGTH + TopLevelArrayListHeader.LENGTH;
|
|
2342
|
+
await targetWriter.write(new TopLevelArrayListHeader(0, new ArrayListHeader(targetArrayListPtr, 1)).toBytes());
|
|
2343
|
+
await targetWriter.write(new Uint8Array(INDEX_BLOCK_SIZE));
|
|
2344
|
+
const remappedMoment = await remapSlot(this.core, targetCore, this.header.hashSize, offsetMap, momentSlot);
|
|
2345
|
+
await targetCore.seek(targetArrayListPtr);
|
|
2346
|
+
await targetWriter.write(remappedMoment.toBytes());
|
|
2347
|
+
target.header = target.header.withTag(2 /* ARRAY_LIST */);
|
|
2348
|
+
await targetCore.seek(0);
|
|
2349
|
+
await target.header.write(targetCore);
|
|
2350
|
+
await targetCore.flush();
|
|
2351
|
+
const fileSize = await targetCore.length();
|
|
2352
|
+
await targetCore.seek(Header.LENGTH + ArrayListHeader.LENGTH);
|
|
2353
|
+
await targetWriter.writeLong(fileSize);
|
|
2354
|
+
await targetCore.flush();
|
|
2355
|
+
return target;
|
|
2356
|
+
}
|
|
2320
2357
|
async truncate() {
|
|
2321
2358
|
if (this.header.tag !== 2 /* ARRAY_LIST */)
|
|
2322
2359
|
return;
|
|
@@ -3141,17 +3178,229 @@ class Database3 {
|
|
|
3141
3178
|
return new LinkedArrayListHeader(nextShift, rootPtr, headerA.size + headerB.size);
|
|
3142
3179
|
}
|
|
3143
3180
|
}
|
|
3181
|
+
async function remapSlot(sourceCore, targetCore, hashSize, offsetMap, slot) {
|
|
3182
|
+
switch (slot.tag) {
|
|
3183
|
+
case 0 /* NONE */:
|
|
3184
|
+
case 8 /* UINT */:
|
|
3185
|
+
case 9 /* INT */:
|
|
3186
|
+
case 10 /* FLOAT */:
|
|
3187
|
+
case 7 /* SHORT_BYTES */:
|
|
3188
|
+
return slot;
|
|
3189
|
+
case 6 /* BYTES */: {
|
|
3190
|
+
const mapped = offsetMap.get(Number(slot.value));
|
|
3191
|
+
if (mapped !== undefined)
|
|
3192
|
+
return new Slot(mapped, slot.tag, slot.full);
|
|
3193
|
+
const newOffset = await remapBytes(sourceCore, targetCore, slot);
|
|
3194
|
+
offsetMap.set(Number(slot.value), newOffset);
|
|
3195
|
+
return new Slot(newOffset, slot.tag, slot.full);
|
|
3196
|
+
}
|
|
3197
|
+
case 1 /* INDEX */: {
|
|
3198
|
+
const mapped = offsetMap.get(Number(slot.value));
|
|
3199
|
+
if (mapped !== undefined)
|
|
3200
|
+
return new Slot(mapped, slot.tag, slot.full);
|
|
3201
|
+
const newOffset = await remapIndex(sourceCore, targetCore, hashSize, offsetMap, slot);
|
|
3202
|
+
offsetMap.set(Number(slot.value), newOffset);
|
|
3203
|
+
return new Slot(newOffset, slot.tag, slot.full);
|
|
3204
|
+
}
|
|
3205
|
+
case 2 /* ARRAY_LIST */: {
|
|
3206
|
+
const mapped = offsetMap.get(Number(slot.value));
|
|
3207
|
+
if (mapped !== undefined)
|
|
3208
|
+
return new Slot(mapped, slot.tag, slot.full);
|
|
3209
|
+
const newOffset = await remapArrayList(sourceCore, targetCore, hashSize, offsetMap, slot);
|
|
3210
|
+
offsetMap.set(Number(slot.value), newOffset);
|
|
3211
|
+
return new Slot(newOffset, slot.tag, slot.full);
|
|
3212
|
+
}
|
|
3213
|
+
case 3 /* LINKED_ARRAY_LIST */: {
|
|
3214
|
+
const mapped = offsetMap.get(Number(slot.value));
|
|
3215
|
+
if (mapped !== undefined)
|
|
3216
|
+
return new Slot(mapped, slot.tag, slot.full);
|
|
3217
|
+
const newOffset = await remapLinkedArrayList(sourceCore, targetCore, hashSize, offsetMap, slot);
|
|
3218
|
+
offsetMap.set(Number(slot.value), newOffset);
|
|
3219
|
+
return new Slot(newOffset, slot.tag, slot.full);
|
|
3220
|
+
}
|
|
3221
|
+
case 4 /* HASH_MAP */:
|
|
3222
|
+
case 11 /* HASH_SET */: {
|
|
3223
|
+
const mapped = offsetMap.get(Number(slot.value));
|
|
3224
|
+
if (mapped !== undefined)
|
|
3225
|
+
return new Slot(mapped, slot.tag, slot.full);
|
|
3226
|
+
const newOffset = await remapHashMapOrSet(sourceCore, targetCore, hashSize, offsetMap, slot, false);
|
|
3227
|
+
offsetMap.set(Number(slot.value), newOffset);
|
|
3228
|
+
return new Slot(newOffset, slot.tag, slot.full);
|
|
3229
|
+
}
|
|
3230
|
+
case 12 /* COUNTED_HASH_MAP */:
|
|
3231
|
+
case 13 /* COUNTED_HASH_SET */: {
|
|
3232
|
+
const mapped = offsetMap.get(Number(slot.value));
|
|
3233
|
+
if (mapped !== undefined)
|
|
3234
|
+
return new Slot(mapped, slot.tag, slot.full);
|
|
3235
|
+
const newOffset = await remapHashMapOrSet(sourceCore, targetCore, hashSize, offsetMap, slot, true);
|
|
3236
|
+
offsetMap.set(Number(slot.value), newOffset);
|
|
3237
|
+
return new Slot(newOffset, slot.tag, slot.full);
|
|
3238
|
+
}
|
|
3239
|
+
case 5 /* KV_PAIR */: {
|
|
3240
|
+
const mapped = offsetMap.get(Number(slot.value));
|
|
3241
|
+
if (mapped !== undefined)
|
|
3242
|
+
return new Slot(mapped, slot.tag, slot.full);
|
|
3243
|
+
const newOffset = await remapKvPair(sourceCore, targetCore, hashSize, offsetMap, slot);
|
|
3244
|
+
offsetMap.set(Number(slot.value), newOffset);
|
|
3245
|
+
return new Slot(newOffset, slot.tag, slot.full);
|
|
3246
|
+
}
|
|
3247
|
+
default:
|
|
3248
|
+
throw new UnexpectedTagException;
|
|
3249
|
+
}
|
|
3250
|
+
}
|
|
3251
|
+
async function remapBytes(sourceCore, targetCore, slot) {
|
|
3252
|
+
await sourceCore.seek(Number(slot.value));
|
|
3253
|
+
const sourceReader = sourceCore.reader();
|
|
3254
|
+
const length = await sourceReader.readLong();
|
|
3255
|
+
const formatTagSize = slot.full ? 2 : 0;
|
|
3256
|
+
const totalPayload = length + formatTagSize;
|
|
3257
|
+
const newOffset = await targetCore.length();
|
|
3258
|
+
await targetCore.seek(newOffset);
|
|
3259
|
+
const targetWriter = targetCore.writer();
|
|
3260
|
+
await targetWriter.writeLong(length);
|
|
3261
|
+
let remaining = totalPayload;
|
|
3262
|
+
while (remaining > 0) {
|
|
3263
|
+
const chunk = Math.min(remaining, 4096);
|
|
3264
|
+
const buf = new Uint8Array(chunk);
|
|
3265
|
+
await sourceReader.readFully(buf);
|
|
3266
|
+
await targetWriter.write(buf);
|
|
3267
|
+
remaining -= chunk;
|
|
3268
|
+
}
|
|
3269
|
+
return newOffset;
|
|
3270
|
+
}
|
|
3271
|
+
async function remapIndex(sourceCore, targetCore, hashSize, offsetMap, slot) {
|
|
3272
|
+
await sourceCore.seek(Number(slot.value));
|
|
3273
|
+
const sourceReader = sourceCore.reader();
|
|
3274
|
+
const blockBytes = new Uint8Array(INDEX_BLOCK_SIZE);
|
|
3275
|
+
await sourceReader.readFully(blockBytes);
|
|
3276
|
+
const remappedSlots = [];
|
|
3277
|
+
for (let i = 0;i < SLOT_COUNT; i++) {
|
|
3278
|
+
const slotBytes = blockBytes.slice(i * Slot.LENGTH, (i + 1) * Slot.LENGTH);
|
|
3279
|
+
const childSlot = Slot.fromBytes(slotBytes);
|
|
3280
|
+
remappedSlots.push(await remapSlot(sourceCore, targetCore, hashSize, offsetMap, childSlot));
|
|
3281
|
+
}
|
|
3282
|
+
const newOffset = await targetCore.length();
|
|
3283
|
+
await targetCore.seek(newOffset);
|
|
3284
|
+
const targetWriter = targetCore.writer();
|
|
3285
|
+
for (const s of remappedSlots) {
|
|
3286
|
+
await targetWriter.write(s.toBytes());
|
|
3287
|
+
}
|
|
3288
|
+
return newOffset;
|
|
3289
|
+
}
|
|
3290
|
+
async function remapArrayList(sourceCore, targetCore, hashSize, offsetMap, slot) {
|
|
3291
|
+
await sourceCore.seek(Number(slot.value));
|
|
3292
|
+
const sourceReader = sourceCore.reader();
|
|
3293
|
+
const headerBytes = new Uint8Array(ArrayListHeader.LENGTH);
|
|
3294
|
+
await sourceReader.readFully(headerBytes);
|
|
3295
|
+
const header = ArrayListHeader.fromBytes(headerBytes);
|
|
3296
|
+
const indexSlot = new Slot(header.ptr, 1 /* INDEX */);
|
|
3297
|
+
const remappedIndex = await remapSlot(sourceCore, targetCore, hashSize, offsetMap, indexSlot);
|
|
3298
|
+
const newOffset = await targetCore.length();
|
|
3299
|
+
await targetCore.seek(newOffset);
|
|
3300
|
+
const targetWriter = targetCore.writer();
|
|
3301
|
+
await targetWriter.write(new ArrayListHeader(Number(remappedIndex.value), header.size).toBytes());
|
|
3302
|
+
return newOffset;
|
|
3303
|
+
}
|
|
3304
|
+
async function remapLinkedArrayList(sourceCore, targetCore, hashSize, offsetMap, slot) {
|
|
3305
|
+
await sourceCore.seek(Number(slot.value));
|
|
3306
|
+
const sourceReader = sourceCore.reader();
|
|
3307
|
+
const headerBytes = new Uint8Array(LinkedArrayListHeader.LENGTH);
|
|
3308
|
+
await sourceReader.readFully(headerBytes);
|
|
3309
|
+
const header = LinkedArrayListHeader.fromBytes(headerBytes);
|
|
3310
|
+
const remappedPtr = await remapLinkedArrayListBlock(sourceCore, targetCore, hashSize, offsetMap, header.ptr);
|
|
3311
|
+
const newOffset = await targetCore.length();
|
|
3312
|
+
await targetCore.seek(newOffset);
|
|
3313
|
+
const targetWriter = targetCore.writer();
|
|
3314
|
+
await targetWriter.write(new LinkedArrayListHeader(header.shift, remappedPtr, header.size).toBytes());
|
|
3315
|
+
return newOffset;
|
|
3316
|
+
}
|
|
3317
|
+
async function remapLinkedArrayListBlock(sourceCore, targetCore, hashSize, offsetMap, blockOffset) {
|
|
3318
|
+
const mapped = offsetMap.get(blockOffset);
|
|
3319
|
+
if (mapped !== undefined)
|
|
3320
|
+
return mapped;
|
|
3321
|
+
await sourceCore.seek(blockOffset);
|
|
3322
|
+
const sourceReader = sourceCore.reader();
|
|
3323
|
+
const blockBytes = new Uint8Array(LINKED_ARRAY_LIST_INDEX_BLOCK_SIZE);
|
|
3324
|
+
await sourceReader.readFully(blockBytes);
|
|
3325
|
+
const slots = [];
|
|
3326
|
+
for (let i = 0;i < SLOT_COUNT; i++) {
|
|
3327
|
+
const slotBytes = blockBytes.slice(i * LinkedArrayListSlot2.LENGTH, (i + 1) * LinkedArrayListSlot2.LENGTH);
|
|
3328
|
+
slots.push(LinkedArrayListSlot2.fromBytes(slotBytes));
|
|
3329
|
+
}
|
|
3330
|
+
const remappedSlots = [];
|
|
3331
|
+
for (const s of slots) {
|
|
3332
|
+
if (s.slot.tag === 1 /* INDEX */) {
|
|
3333
|
+
const remappedPtr = await remapLinkedArrayListBlock(sourceCore, targetCore, hashSize, offsetMap, Number(s.slot.value));
|
|
3334
|
+
remappedSlots.push(new LinkedArrayListSlot2(s.size, new Slot(remappedPtr, 1 /* INDEX */, s.slot.full)));
|
|
3335
|
+
} else if (s.slot.empty()) {
|
|
3336
|
+
remappedSlots.push(s);
|
|
3337
|
+
} else {
|
|
3338
|
+
const remapped = await remapSlot(sourceCore, targetCore, hashSize, offsetMap, s.slot);
|
|
3339
|
+
remappedSlots.push(new LinkedArrayListSlot2(s.size, remapped));
|
|
3340
|
+
}
|
|
3341
|
+
}
|
|
3342
|
+
const newOffset = await targetCore.length();
|
|
3343
|
+
await targetCore.seek(newOffset);
|
|
3344
|
+
const targetWriter = targetCore.writer();
|
|
3345
|
+
for (const s of remappedSlots) {
|
|
3346
|
+
await targetWriter.write(s.toBytes());
|
|
3347
|
+
}
|
|
3348
|
+
offsetMap.set(blockOffset, newOffset);
|
|
3349
|
+
return newOffset;
|
|
3350
|
+
}
|
|
3351
|
+
async function remapHashMapOrSet(sourceCore, targetCore, hashSize, offsetMap, slot, counted) {
|
|
3352
|
+
await sourceCore.seek(Number(slot.value));
|
|
3353
|
+
const sourceReader = sourceCore.reader();
|
|
3354
|
+
let countValue = -1;
|
|
3355
|
+
if (counted) {
|
|
3356
|
+
countValue = await sourceReader.readLong();
|
|
3357
|
+
}
|
|
3358
|
+
const blockBytes = new Uint8Array(INDEX_BLOCK_SIZE);
|
|
3359
|
+
await sourceReader.readFully(blockBytes);
|
|
3360
|
+
const remappedSlots = [];
|
|
3361
|
+
for (let i = 0;i < SLOT_COUNT; i++) {
|
|
3362
|
+
const slotBytes = blockBytes.slice(i * Slot.LENGTH, (i + 1) * Slot.LENGTH);
|
|
3363
|
+
const childSlot = Slot.fromBytes(slotBytes);
|
|
3364
|
+
remappedSlots.push(await remapSlot(sourceCore, targetCore, hashSize, offsetMap, childSlot));
|
|
3365
|
+
}
|
|
3366
|
+
const newOffset = await targetCore.length();
|
|
3367
|
+
await targetCore.seek(newOffset);
|
|
3368
|
+
const targetWriter = targetCore.writer();
|
|
3369
|
+
if (counted) {
|
|
3370
|
+
await targetWriter.writeLong(countValue);
|
|
3371
|
+
}
|
|
3372
|
+
for (const s of remappedSlots) {
|
|
3373
|
+
await targetWriter.write(s.toBytes());
|
|
3374
|
+
}
|
|
3375
|
+
return newOffset;
|
|
3376
|
+
}
|
|
3377
|
+
async function remapKvPair(sourceCore, targetCore, hashSize, offsetMap, slot) {
|
|
3378
|
+
await sourceCore.seek(Number(slot.value));
|
|
3379
|
+
const sourceReader = sourceCore.reader();
|
|
3380
|
+
const kvPairBytes = new Uint8Array(KeyValuePair.length(hashSize));
|
|
3381
|
+
await sourceReader.readFully(kvPairBytes);
|
|
3382
|
+
const kvPair = KeyValuePair.fromBytes(kvPairBytes, hashSize);
|
|
3383
|
+
const remappedKey = await remapSlot(sourceCore, targetCore, hashSize, offsetMap, kvPair.keySlot);
|
|
3384
|
+
const remappedValue = await remapSlot(sourceCore, targetCore, hashSize, offsetMap, kvPair.valueSlot);
|
|
3385
|
+
const newOffset = await targetCore.length();
|
|
3386
|
+
await targetCore.seek(newOffset);
|
|
3387
|
+
const targetWriter = targetCore.writer();
|
|
3388
|
+
await targetWriter.write(new KeyValuePair(remappedValue, remappedKey, kvPair.hash).toBytes());
|
|
3389
|
+
return newOffset;
|
|
3390
|
+
}
|
|
3144
3391
|
// src/read-array-list.ts
|
|
3145
3392
|
class ReadArrayList {
|
|
3146
3393
|
cursor;
|
|
3147
3394
|
constructor(cursor) {
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3395
|
+
if (cursor) {
|
|
3396
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3397
|
+
case 0 /* NONE */:
|
|
3398
|
+
case 2 /* ARRAY_LIST */:
|
|
3399
|
+
this.cursor = cursor;
|
|
3400
|
+
break;
|
|
3401
|
+
default:
|
|
3402
|
+
throw new UnexpectedTagException;
|
|
3403
|
+
}
|
|
3155
3404
|
}
|
|
3156
3405
|
}
|
|
3157
3406
|
slot() {
|
|
@@ -3175,12 +3424,14 @@ class ReadArrayList {
|
|
|
3175
3424
|
}
|
|
3176
3425
|
// src/write-array-list.ts
|
|
3177
3426
|
class WriteArrayList extends ReadArrayList {
|
|
3178
|
-
constructor(
|
|
3179
|
-
super(
|
|
3427
|
+
constructor() {
|
|
3428
|
+
super();
|
|
3180
3429
|
}
|
|
3181
3430
|
static async create(cursor) {
|
|
3431
|
+
const list = new WriteArrayList;
|
|
3182
3432
|
const newCursor = await cursor.writePath([new ArrayListInit]);
|
|
3183
|
-
|
|
3433
|
+
list.cursor = newCursor;
|
|
3434
|
+
return list;
|
|
3184
3435
|
}
|
|
3185
3436
|
async iterator() {
|
|
3186
3437
|
return this.cursor.iterator();
|
|
@@ -3220,19 +3471,18 @@ class WriteArrayList extends ReadArrayList {
|
|
|
3220
3471
|
// src/read-hash-map.ts
|
|
3221
3472
|
class ReadHashMap {
|
|
3222
3473
|
cursor;
|
|
3223
|
-
constructor() {
|
|
3224
|
-
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3474
|
+
constructor(cursor) {
|
|
3475
|
+
if (cursor) {
|
|
3476
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3477
|
+
case 0 /* NONE */:
|
|
3478
|
+
case 4 /* HASH_MAP */:
|
|
3479
|
+
case 11 /* HASH_SET */:
|
|
3480
|
+
this.cursor = cursor;
|
|
3481
|
+
break;
|
|
3482
|
+
default:
|
|
3483
|
+
throw new UnexpectedTagException;
|
|
3484
|
+
}
|
|
3234
3485
|
}
|
|
3235
|
-
return map;
|
|
3236
3486
|
}
|
|
3237
3487
|
slot() {
|
|
3238
3488
|
return this.cursor.slot();
|
|
@@ -3367,19 +3617,18 @@ class WriteHashMap extends ReadHashMap {
|
|
|
3367
3617
|
// src/read-hash-set.ts
|
|
3368
3618
|
class ReadHashSet {
|
|
3369
3619
|
cursor;
|
|
3370
|
-
constructor() {
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3620
|
+
constructor(cursor) {
|
|
3621
|
+
if (cursor) {
|
|
3622
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3623
|
+
case 0 /* NONE */:
|
|
3624
|
+
case 4 /* HASH_MAP */:
|
|
3625
|
+
case 11 /* HASH_SET */:
|
|
3626
|
+
this.cursor = cursor;
|
|
3627
|
+
break;
|
|
3628
|
+
default:
|
|
3629
|
+
throw new UnexpectedTagException;
|
|
3630
|
+
}
|
|
3381
3631
|
}
|
|
3382
|
-
return set;
|
|
3383
3632
|
}
|
|
3384
3633
|
slot() {
|
|
3385
3634
|
return this.cursor.slot();
|
|
@@ -3469,13 +3718,15 @@ class WriteHashSet extends ReadHashSet {
|
|
|
3469
3718
|
class ReadLinkedArrayList {
|
|
3470
3719
|
cursor;
|
|
3471
3720
|
constructor(cursor) {
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3721
|
+
if (cursor) {
|
|
3722
|
+
switch (cursor.slotPtr.slot.tag) {
|
|
3723
|
+
case 0 /* NONE */:
|
|
3724
|
+
case 3 /* LINKED_ARRAY_LIST */:
|
|
3725
|
+
this.cursor = cursor;
|
|
3726
|
+
break;
|
|
3727
|
+
default:
|
|
3728
|
+
throw new UnexpectedTagException;
|
|
3729
|
+
}
|
|
3479
3730
|
}
|
|
3480
3731
|
}
|
|
3481
3732
|
slot() {
|
|
@@ -3499,12 +3750,14 @@ class ReadLinkedArrayList {
|
|
|
3499
3750
|
}
|
|
3500
3751
|
// src/write-linked-array-list.ts
|
|
3501
3752
|
class WriteLinkedArrayList extends ReadLinkedArrayList {
|
|
3502
|
-
constructor(
|
|
3503
|
-
super(
|
|
3753
|
+
constructor() {
|
|
3754
|
+
super();
|
|
3504
3755
|
}
|
|
3505
3756
|
static async create(cursor) {
|
|
3757
|
+
const list = new WriteLinkedArrayList;
|
|
3506
3758
|
const newCursor = await cursor.writePath([new LinkedArrayListInit]);
|
|
3507
|
-
|
|
3759
|
+
list.cursor = newCursor;
|
|
3760
|
+
return list;
|
|
3508
3761
|
}
|
|
3509
3762
|
async iterator() {
|
|
3510
3763
|
return this.cursor.iterator();
|
|
@@ -3553,21 +3806,17 @@ class WriteLinkedArrayList extends ReadLinkedArrayList {
|
|
|
3553
3806
|
}
|
|
3554
3807
|
// src/read-counted-hash-map.ts
|
|
3555
3808
|
class ReadCountedHashMap extends ReadHashMap {
|
|
3556
|
-
constructor() {
|
|
3809
|
+
constructor(cursor) {
|
|
3557
3810
|
super();
|
|
3558
|
-
}
|
|
3559
|
-
static async create(cursor) {
|
|
3560
|
-
const map = new ReadCountedHashMap;
|
|
3561
3811
|
switch (cursor.slotPtr.slot.tag) {
|
|
3562
3812
|
case 0 /* NONE */:
|
|
3563
3813
|
case 12 /* COUNTED_HASH_MAP */:
|
|
3564
3814
|
case 13 /* COUNTED_HASH_SET */:
|
|
3565
|
-
|
|
3815
|
+
this.cursor = cursor;
|
|
3566
3816
|
break;
|
|
3567
3817
|
default:
|
|
3568
3818
|
throw new UnexpectedTagException;
|
|
3569
3819
|
}
|
|
3570
|
-
return map;
|
|
3571
3820
|
}
|
|
3572
3821
|
async count() {
|
|
3573
3822
|
return this.cursor.count();
|
|
@@ -3599,21 +3848,17 @@ class WriteCountedHashMap extends WriteHashMap {
|
|
|
3599
3848
|
}
|
|
3600
3849
|
// src/read-counted-hash-set.ts
|
|
3601
3850
|
class ReadCountedHashSet extends ReadHashSet {
|
|
3602
|
-
constructor() {
|
|
3851
|
+
constructor(cursor) {
|
|
3603
3852
|
super();
|
|
3604
|
-
}
|
|
3605
|
-
static async create(cursor) {
|
|
3606
|
-
const set = new ReadCountedHashSet;
|
|
3607
3853
|
switch (cursor.slotPtr.slot.tag) {
|
|
3608
3854
|
case 0 /* NONE */:
|
|
3609
3855
|
case 12 /* COUNTED_HASH_MAP */:
|
|
3610
3856
|
case 13 /* COUNTED_HASH_SET */:
|
|
3611
|
-
|
|
3857
|
+
this.cursor = cursor;
|
|
3612
3858
|
break;
|
|
3613
3859
|
default:
|
|
3614
3860
|
throw new UnexpectedTagException;
|
|
3615
3861
|
}
|
|
3616
|
-
return set;
|
|
3617
3862
|
}
|
|
3618
3863
|
async count() {
|
|
3619
3864
|
return this.cursor.count();
|
|
@@ -3,6 +3,7 @@ import type { Slotted } from './slotted';
|
|
|
3
3
|
import { ReadCursor, CursorIterator } from './read-cursor';
|
|
4
4
|
export declare class ReadArrayList implements Slotted {
|
|
5
5
|
cursor: ReadCursor;
|
|
6
|
+
constructor();
|
|
6
7
|
constructor(cursor: ReadCursor);
|
|
7
8
|
slot(): Slot;
|
|
8
9
|
count(): Promise<number>;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ReadHashMap } from './read-hash-map';
|
|
2
2
|
import { ReadCursor } from './read-cursor';
|
|
3
3
|
export declare class ReadCountedHashMap extends ReadHashMap {
|
|
4
|
-
|
|
5
|
-
static create(cursor: ReadCursor): Promise<ReadCountedHashMap>;
|
|
4
|
+
constructor(cursor: ReadCursor);
|
|
6
5
|
count(): Promise<number>;
|
|
7
6
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ReadHashSet } from './read-hash-set';
|
|
2
2
|
import { ReadCursor } from './read-cursor';
|
|
3
3
|
export declare class ReadCountedHashSet extends ReadHashSet {
|
|
4
|
-
|
|
5
|
-
static create(cursor: ReadCursor): Promise<ReadCountedHashSet>;
|
|
4
|
+
constructor(cursor: ReadCursor);
|
|
6
5
|
count(): Promise<number>;
|
|
7
6
|
}
|
package/dist/read-hash-map.d.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { ReadCursor, CursorIterator, KeyValuePairCursor } from './read-cursor';
|
|
|
4
4
|
import { Bytes } from './writeable-data';
|
|
5
5
|
export declare class ReadHashMap implements Slotted {
|
|
6
6
|
cursor: ReadCursor;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
constructor();
|
|
8
|
+
constructor(cursor: ReadCursor);
|
|
9
9
|
slot(): Slot;
|
|
10
10
|
iterator(): Promise<CursorIterator>;
|
|
11
11
|
[Symbol.asyncIterator](): AsyncIterator<ReadCursor>;
|
package/dist/read-hash-set.d.ts
CHANGED
|
@@ -4,8 +4,8 @@ import { ReadCursor, CursorIterator } from './read-cursor';
|
|
|
4
4
|
import { Bytes } from './writeable-data';
|
|
5
5
|
export declare class ReadHashSet implements Slotted {
|
|
6
6
|
cursor: ReadCursor;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
constructor();
|
|
8
|
+
constructor(cursor: ReadCursor);
|
|
9
9
|
slot(): Slot;
|
|
10
10
|
iterator(): Promise<CursorIterator>;
|
|
11
11
|
[Symbol.asyncIterator](): AsyncIterator<ReadCursor>;
|
|
@@ -3,6 +3,7 @@ import type { Slotted } from './slotted';
|
|
|
3
3
|
import { ReadCursor, CursorIterator } from './read-cursor';
|
|
4
4
|
export declare class ReadLinkedArrayList implements Slotted {
|
|
5
5
|
cursor: ReadCursor;
|
|
6
|
+
constructor();
|
|
6
7
|
constructor(cursor: ReadCursor);
|
|
7
8
|
slot(): Slot;
|
|
8
9
|
count(): Promise<number>;
|
|
@@ -3,7 +3,7 @@ import { WriteCursor, WriteCursorIterator } from './write-cursor';
|
|
|
3
3
|
import { type ContextFunction } from './database';
|
|
4
4
|
import type { WriteableData } from './writeable-data';
|
|
5
5
|
export declare class WriteArrayList extends ReadArrayList {
|
|
6
|
-
constructor(
|
|
6
|
+
protected constructor();
|
|
7
7
|
static create(cursor: WriteCursor): Promise<WriteArrayList>;
|
|
8
8
|
iterator(): Promise<WriteCursorIterator>;
|
|
9
9
|
[Symbol.asyncIterator](): AsyncIterator<WriteCursor>;
|
|
@@ -3,7 +3,7 @@ import { ReadLinkedArrayList } from './read-linked-array-list';
|
|
|
3
3
|
import { WriteCursor, WriteCursorIterator } from './write-cursor';
|
|
4
4
|
import type { WriteableData } from './writeable-data';
|
|
5
5
|
export declare class WriteLinkedArrayList extends ReadLinkedArrayList {
|
|
6
|
-
constructor(
|
|
6
|
+
protected constructor();
|
|
7
7
|
static create(cursor: WriteCursor): Promise<WriteLinkedArrayList>;
|
|
8
8
|
iterator(): Promise<WriteCursorIterator>;
|
|
9
9
|
[Symbol.asyncIterator](): AsyncIterator<WriteCursor>;
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xitdb",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "An immutable database",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/
|
|
8
|
+
"url": "https://github.com/xit-vcs/xitdb-ts.git"
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
11
|
"main": "dist/index.js",
|