deno.land / x / replicache@v10.0.0-beta.0 / persist / fixup-transformer.test.ts
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798import {assert} from '@esm-bundle/chai';import * as dag from '../dag/mod';import * as db from '../db/mod';import {fakeHash, makeNewTempHashFunction, parse as parseHash} from '../hash';import {BTreeWrite} from '../btree/write';import {FixupTransformer} from './fixup-transformer';import type {ReadonlyJSONValue} from '../json';
test('fixup of a single snapshot commit with empty btree', async () => { const memdag = new dag.TestStore( undefined, makeNewTempHashFunction(), () => undefined, );
const [headHash, valueHash] = await memdag.withWrite(async dagWrite => { const tree = new BTreeWrite(dagWrite); const valueHash = await tree.flush(); const c = db.newSnapshot( dagWrite.createChunk, null, 0, null, valueHash, [], ); await dagWrite.putChunk(c.chunk); await dagWrite.setHead('test', c.chunk.hash); await dagWrite.commit(); return [c.chunk.hash, valueHash]; });
const snapshot = memdag.kvStore.snapshot();
assert.deepEqual(snapshot, { 'c/t/000000000000000000000000000000/d': [0, []], 'c/t/000000000000000000000000000001/d': { meta: {type: 3, basisHash: null, lastMutationID: 0, cookieJSON: null}, valueHash: 't/000000000000000000000000000000', indexes: [], }, 'c/t/000000000000000000000000000001/m': [ 't/000000000000000000000000000000', ], 'h/test': 't/000000000000000000000000000001', 'c/t/000000000000000000000000000000/r': 1, 'c/t/000000000000000000000000000001/r': 1, });
const mappings = new Map([ [headHash, fakeHash('head')], [valueHash, fakeHash('value')], ]);
const newHeadHash = await memdag.withWrite(async dagWrite => { const transformer = new FixupTransformer(dagWrite, mappings); const newHeadHash = await transformer.transformCommit(headHash);
await dagWrite.setHead('test', newHeadHash); await dagWrite.commit(); return newHeadHash; });
assert.equal(newHeadHash, fakeHash('head'));
assert.deepEqual(memdag.kvStore.snapshot(), { 'h/test': 'fake000000000000000000000000head', 'c/fake00000000000000000000000value/d': [0, []], 'c/fake000000000000000000000000head/d': { meta: {type: 3, basisHash: null, lastMutationID: 0, cookieJSON: null}, valueHash: 'fake00000000000000000000000value', indexes: [], }, 'c/fake000000000000000000000000head/m': [ 'fake00000000000000000000000value', ], 'c/fake00000000000000000000000value/r': 1, 'c/fake000000000000000000000000head/r': 1, });
// Now add a local commit on top of the snapshot commit. { const headHash = await memdag.withWrite(async dagWrite => { const c = db.newLocal( dagWrite.createChunk, newHeadHash, 1, 'test', {v: 42}, null, fakeHash('value'), [], 42, ); await dagWrite.putChunk(c.chunk); await dagWrite.setHead('test', c.chunk.hash); await dagWrite.commit(); return c.chunk.hash; });
assert.deepEqual(memdag.kvStore.snapshot(), { 'c/fake000000000000000000000000head/d': { indexes: [], meta: { basisHash: null, cookieJSON: null, lastMutationID: 0, type: 3, }, valueHash: 'fake00000000000000000000000value', }, 'c/fake000000000000000000000000head/m': [ 'fake00000000000000000000000value', ], 'c/fake000000000000000000000000head/r': 1, 'c/fake00000000000000000000000value/d': [0, []], 'c/fake00000000000000000000000value/r': 2, 'c/t/000000000000000000000000000002/d': { indexes: [], meta: { basisHash: 'fake000000000000000000000000head', mutationID: 1, mutatorArgsJSON: { v: 42, }, mutatorName: 'test', originalHash: null, timestamp: 42, type: 2, }, valueHash: 'fake00000000000000000000000value', }, 'c/t/000000000000000000000000000002/m': [ 'fake00000000000000000000000value', 'fake000000000000000000000000head', ], 'c/t/000000000000000000000000000002/r': 1, 'h/test': 't/000000000000000000000000000002', });
const mappings = new Map([[headHash, fakeHash('head2')]]);
const newHeadHash2 = await memdag.withWrite(async dagWrite => { const transformer = new FixupTransformer(dagWrite, mappings); const newHeadHash = await transformer.transformCommit(headHash);
await dagWrite.setHead('test', newHeadHash); await dagWrite.commit(); return newHeadHash; });
assert.deepEqual(memdag.kvStore.snapshot(), { 'c/fake000000000000000000000000head/d': { indexes: [], meta: { basisHash: null, cookieJSON: null, lastMutationID: 0, type: 3, }, valueHash: 'fake00000000000000000000000value', }, 'c/fake000000000000000000000000head/m': [ 'fake00000000000000000000000value', ], 'c/fake000000000000000000000000head/r': 1, 'c/fake00000000000000000000000head2/d': { indexes: [], meta: { basisHash: 'fake000000000000000000000000head', mutationID: 1, mutatorArgsJSON: { v: 42, }, mutatorName: 'test', originalHash: null, timestamp: 42, type: 2, }, valueHash: 'fake00000000000000000000000value', }, 'c/fake00000000000000000000000head2/m': [ 'fake00000000000000000000000value', 'fake000000000000000000000000head', ], 'c/fake00000000000000000000000head2/r': 1, 'c/fake00000000000000000000000value/d': [0, []], 'c/fake00000000000000000000000value/r': 2, 'h/test': 'fake00000000000000000000000head2', }); assert.equal(newHeadHash2, fakeHash('head2')); }});
test('fixup base snapshot when there is a local commit on top of it', async () => { const memdag = new dag.TestStore( undefined, makeNewTempHashFunction(), () => undefined, );
const [snapshotCommit, localCommit, valueHash] = await memdag.withWrite( async dagWrite => { const tree = new BTreeWrite(dagWrite); const valueHash = await tree.flush(); const snapshotCommit = db.newSnapshot( dagWrite.createChunk, null, 0, null, valueHash, [], ); await dagWrite.putChunk(snapshotCommit.chunk);
const localCommit = db.newLocal( dagWrite.createChunk, snapshotCommit.chunk.hash, 1, 'test', {v: 42}, null, fakeHash('value'), [], 42, ); await dagWrite.putChunk(localCommit.chunk);
await dagWrite.setHead('test', localCommit.chunk.hash); await dagWrite.commit(); return [snapshotCommit, localCommit, valueHash]; }, );
assert.deepEqual(memdag.kvStore.snapshot(), { 'c/fake00000000000000000000000value/r': 1, 'c/t/000000000000000000000000000000/d': [0, []], 'c/t/000000000000000000000000000000/r': 1, 'c/t/000000000000000000000000000001/d': { indexes: [], meta: { basisHash: null, cookieJSON: null, lastMutationID: 0, type: 3, }, valueHash: 't/000000000000000000000000000000', }, 'c/t/000000000000000000000000000001/m': [ 't/000000000000000000000000000000', ], 'c/t/000000000000000000000000000001/r': 1, 'c/t/000000000000000000000000000002/d': { indexes: [], meta: { basisHash: 't/000000000000000000000000000001', mutationID: 1, mutatorArgsJSON: { v: 42, }, mutatorName: 'test', originalHash: null, timestamp: 42, type: 2, }, valueHash: 'fake00000000000000000000000value', }, 'c/t/000000000000000000000000000002/m': [ 'fake00000000000000000000000value', 't/000000000000000000000000000001', ], 'c/t/000000000000000000000000000002/r': 1, 'h/test': 't/000000000000000000000000000002', });
// These mappings do not contain the local commit. This is simulating that a // local commit happened after we got the result back from the perdag persist // part. const mappings = new Map([ [snapshotCommit.chunk.hash, fakeHash('snapshot')], [valueHash, fakeHash('value')], ]);
const newLocalCommitHash = await memdag.withWrite(async dagWrite => { const transformer = new FixupTransformer(dagWrite, mappings); const newLocalCommitHash = await transformer.transformCommit( localCommit.chunk.hash, );
await dagWrite.setHead('test', newLocalCommitHash); await dagWrite.commit(); return newLocalCommitHash; });
assert.notEqual(newLocalCommitHash, localCommit.chunk.hash);
assert.deepEqual(memdag.kvStore.snapshot(), { 'c/fake00000000000000000000000value/d': [0, []], 'c/fake00000000000000000000000value/r': 2, 'c/fake00000000000000000000snapshot/d': { indexes: [], meta: { basisHash: null, cookieJSON: null, lastMutationID: 0, type: 3, }, valueHash: 'fake00000000000000000000000value', }, 'c/fake00000000000000000000snapshot/m': [ 'fake00000000000000000000000value', ], 'c/fake00000000000000000000snapshot/r': 1, 'c/t/000000000000000000000000000003/d': { indexes: [], meta: { basisHash: 'fake00000000000000000000snapshot', mutationID: 1, mutatorArgsJSON: { v: 42, }, mutatorName: 'test', originalHash: null, timestamp: 42, type: 2, }, valueHash: 'fake00000000000000000000000value', }, 'c/t/000000000000000000000000000003/m': [ 'fake00000000000000000000000value', 'fake00000000000000000000snapshot', ], 'c/t/000000000000000000000000000003/r': 1, 'h/test': 't/000000000000000000000000000003', });});
async function makeBTree( dagWrite: dag.Write, entries: [string, ReadonlyJSONValue][],): Promise<BTreeWrite> { const tree = new BTreeWrite(dagWrite, undefined, 2, 4, () => 1, 0); for (const [k, v] of entries) { await tree.put(k, v); } return tree;}
test('fixup of a single snapshot commit with a btree with internal nodes', async () => { const memdag = new dag.TestStore( undefined, makeNewTempHashFunction(), () => undefined, );
const entries = Object.entries({ a: 0, b: 1, c: 2, d: 3, e: 4, f: 5, });
const [headHash, valueHash] = await memdag.withWrite(async dagWrite => { const tree = await makeBTree(dagWrite, entries);
const valueHash = await tree.flush(); const c = db.newSnapshot( dagWrite.createChunk, null, 0, null, valueHash, [], ); await dagWrite.putChunk(c.chunk); await dagWrite.setHead('test', c.chunk.hash); await dagWrite.commit(); return [c.chunk.hash, valueHash]; });
assert.deepEqual( memdag.kvStore.snapshot(),
{ 'c/t/000000000000000000000000000000/d': [ 0, [ ['a', 0], ['b', 1], ], ], 'c/t/000000000000000000000000000001/d': [ 0, [ ['c', 2], ['d', 3], ['e', 4], ['f', 5], ], ], 'c/t/000000000000000000000000000002/d': [ 1, [ ['b', 't/000000000000000000000000000000'], ['f', 't/000000000000000000000000000001'], ], ], 'c/t/000000000000000000000000000002/m': [ 't/000000000000000000000000000000', 't/000000000000000000000000000001', ], 'c/t/000000000000000000000000000003/d': { meta: { type: 3, basisHash: null, lastMutationID: 0, cookieJSON: null, }, valueHash: 't/000000000000000000000000000002', indexes: [], }, 'c/t/000000000000000000000000000003/m': [ 't/000000000000000000000000000002', ], 'h/test': 't/000000000000000000000000000003', 'c/t/000000000000000000000000000000/r': 1, 'c/t/000000000000000000000000000001/r': 1, 'c/t/000000000000000000000000000002/r': 1, 'c/t/000000000000000000000000000003/r': 1, }, );
const mappings = new Map([ [headHash, fakeHash('head')], [valueHash, fakeHash('value')], [parseHash('t/000000000000000000000000000000'), fakeHash('data0')], [parseHash('t/000000000000000000000000000001'), fakeHash('data1')], ]);
const newHeadHash = await memdag.withWrite(async dagWrite => { const transformer = new FixupTransformer(dagWrite, mappings); const newHeadHash = await transformer.transformCommit(headHash);
await dagWrite.setHead('test', newHeadHash); await dagWrite.commit(); return newHeadHash; });
assert.equal(newHeadHash, fakeHash('head'));
assert.deepEqual( memdag.kvStore.snapshot(),
{ 'h/test': 'fake000000000000000000000000head', 'c/fake00000000000000000000000data0/d': [ 0, [ ['a', 0], ['b', 1], ], ], 'c/fake00000000000000000000000data1/d': [ 0, [ ['c', 2], ['d', 3], ['e', 4], ['f', 5], ], ], 'c/fake00000000000000000000000value/d': [ 1, [ ['b', 'fake00000000000000000000000data0'], ['f', 'fake00000000000000000000000data1'], ], ], 'c/fake00000000000000000000000value/m': [ 'fake00000000000000000000000data0', 'fake00000000000000000000000data1', ], 'c/fake000000000000000000000000head/d': { meta: { type: 3, basisHash: null, lastMutationID: 0, cookieJSON: null, }, valueHash: 'fake00000000000000000000000value', indexes: [], }, 'c/fake000000000000000000000000head/m': [ 'fake00000000000000000000000value', ], 'c/fake00000000000000000000000data0/r': 1, 'c/fake00000000000000000000000data1/r': 1, 'c/fake00000000000000000000000value/r': 1, 'c/fake000000000000000000000000head/r': 1, }, );});
test('fixup of a base snapshot with an index', async () => { const memdag = new dag.TestStore( undefined, makeNewTempHashFunction(), () => undefined, );
const entries = Object.entries({ a: {a: '0'}, b: {a: '1'}, c: {a: '2'}, d: {a: '3'}, e: {a: '4'}, f: {b: '5'}, });
const indexEntries: [string, ReadonlyJSONValue][] = [ [db.encodeIndexKey(['0', 'a']), {a: '0'}], [db.encodeIndexKey(['1', 'b']), {a: '1'}], [db.encodeIndexKey(['2', 'c']), {a: '2'}], [db.encodeIndexKey(['3', 'd']), {a: '3'}], [db.encodeIndexKey(['4', 'e']), {a: '4'}], ];
const [headHash, valueHash, indexHash] = await memdag.withWrite( async dagWrite => { const tree = await makeBTree(dagWrite, entries); const valueHash = await tree.flush();
const indexTree = await makeBTree(dagWrite, indexEntries); const indexHash = await indexTree.flush();
const c = db.newSnapshot(dagWrite.createChunk, null, 0, null, valueHash, [ { definition: { jsonPointer: '/a', keyPrefix: '', name: 'idx', }, valueHash: indexHash, }, ]); await dagWrite.putChunk(c.chunk); await dagWrite.setHead('test', c.chunk.hash); await dagWrite.commit(); return [c.chunk.hash, valueHash, indexHash]; }, );
const snapshot = memdag.kvStore.snapshot();
assert.deepEqual(snapshot, { 'c/t/000000000000000000000000000000/d': [ 0, [ ['a', {a: '0'}], ['b', {a: '1'}], ], ], 'c/t/000000000000000000000000000001/d': [ 0, [ ['c', {a: '2'}], ['d', {a: '3'}], ['e', {a: '4'}], ['f', {b: '5'}], ], ], 'c/t/000000000000000000000000000002/d': [ 1, [ ['b', 't/000000000000000000000000000000'], ['f', 't/000000000000000000000000000001'], ], ], 'c/t/000000000000000000000000000002/m': [ 't/000000000000000000000000000000', 't/000000000000000000000000000001', ], 'c/t/000000000000000000000000000003/d': [ 0, [ ['\u00000\u0000a', {a: '0'}], ['\u00001\u0000b', {a: '1'}], ], ], 'c/t/000000000000000000000000000004/d': [ 0, [ ['\u00002\u0000c', {a: '2'}], ['\u00003\u0000d', {a: '3'}], ['\u00004\u0000e', {a: '4'}], ], ], 'c/t/000000000000000000000000000005/d': [ 1, [ ['\u00001\u0000b', 't/000000000000000000000000000003'], ['\u00004\u0000e', 't/000000000000000000000000000004'], ], ], 'c/t/000000000000000000000000000005/m': [ 't/000000000000000000000000000003', 't/000000000000000000000000000004', ], 'c/t/000000000000000000000000000006/d': { meta: {type: 3, basisHash: null, lastMutationID: 0, cookieJSON: null}, valueHash: 't/000000000000000000000000000002', indexes: [ { definition: {jsonPointer: '/a', keyPrefix: '', name: 'idx'}, valueHash: 't/000000000000000000000000000005', }, ], }, 'c/t/000000000000000000000000000006/m': [ 't/000000000000000000000000000002', 't/000000000000000000000000000005', ], 'h/test': 't/000000000000000000000000000006', 'c/t/000000000000000000000000000000/r': 1, 'c/t/000000000000000000000000000001/r': 1, 'c/t/000000000000000000000000000003/r': 1, 'c/t/000000000000000000000000000004/r': 1, 'c/t/000000000000000000000000000002/r': 1, 'c/t/000000000000000000000000000005/r': 1, 'c/t/000000000000000000000000000006/r': 1, });
const mappings = new Map([ [headHash, fakeHash('head')], [valueHash, fakeHash('value')], [indexHash, fakeHash('indecs')], [parseHash('t/000000000000000000000000000000'), fakeHash('data0')], [parseHash('t/000000000000000000000000000001'), fakeHash('data1')], [parseHash('t/000000000000000000000000000003'), fakeHash('data3')], [parseHash('t/000000000000000000000000000004'), fakeHash('data4')], ]);
const newHeadHash = await memdag.withWrite(async dagWrite => { const transformer = new FixupTransformer(dagWrite, mappings); const newHeadHash = await transformer.transformCommit(headHash);
await dagWrite.setHead('test', newHeadHash); await dagWrite.commit(); return newHeadHash; });
assert.equal(newHeadHash, fakeHash('head'));
assert.deepEqual(memdag.kvStore.snapshot(), { 'c/fake000000000000000000000000head/d': { indexes: [ { definition: { jsonPointer: '/a', keyPrefix: '', name: 'idx', }, valueHash: 'fake0000000000000000000000indecs', }, ], meta: { basisHash: null, cookieJSON: null, lastMutationID: 0, type: 3, }, valueHash: 'fake00000000000000000000000value', }, 'c/fake000000000000000000000000head/m': [ 'fake00000000000000000000000value', 'fake0000000000000000000000indecs', ], 'c/fake000000000000000000000000head/r': 1, 'c/fake00000000000000000000000data0/d': [ 0, [ [ 'a', { a: '0', }, ], [ 'b', { a: '1', }, ], ], ], 'c/fake00000000000000000000000data0/r': 1, 'c/fake00000000000000000000000data1/d': [ 0, [ [ 'c', { a: '2', }, ], [ 'd', { a: '3', }, ], [ 'e', { a: '4', }, ], [ 'f', { b: '5', }, ], ], ], 'c/fake00000000000000000000000data1/r': 1, 'c/fake00000000000000000000000data3/d': [ 0, [ [ '\u00000\u0000a', { a: '0', }, ], [ '\u00001\u0000b', { a: '1', }, ], ], ], 'c/fake00000000000000000000000data3/r': 1, 'c/fake00000000000000000000000data4/d': [ 0, [ [ '\u00002\u0000c', { a: '2', }, ], [ '\u00003\u0000d', { a: '3', }, ], [ '\u00004\u0000e', { a: '4', }, ], ], ], 'c/fake00000000000000000000000data4/r': 1, 'c/fake0000000000000000000000indecs/d': [ 1, [ ['\u00001\u0000b', 'fake00000000000000000000000data3'], ['\u00004\u0000e', 'fake00000000000000000000000data4'], ], ], 'c/fake0000000000000000000000indecs/m': [ 'fake00000000000000000000000data3', 'fake00000000000000000000000data4', ], 'c/fake0000000000000000000000indecs/r': 1, 'c/fake00000000000000000000000value/d': [ 1, [ ['b', 'fake00000000000000000000000data0'], ['f', 'fake00000000000000000000000data1'], ], ], 'c/fake00000000000000000000000value/m': [ 'fake00000000000000000000000data0', 'fake00000000000000000000000data1', ], 'c/fake00000000000000000000000value/r': 1, 'h/test': 'fake000000000000000000000000head', });});
Version Info