From 7599b99051d8eff4221deac94578330272482640 Mon Sep 17 00:00:00 2001 From: haad Date: Wed, 17 Apr 2024 14:52:11 +0300 Subject: [PATCH] Change how heads are stored, add migrations --- benchmarks/orbitdb-documents.js | 110 ++++++++++-------- src/oplog/heads.js | 53 ++++++--- src/oplog/log.js | 8 +- src/storage/ipfs-block.js | 13 ++- src/sync.js | 2 +- test/database-replication.test.js | 8 +- test/database.test.js | 10 +- test/databases/replication/documents.test.js | 4 +- test/databases/replication/events.test.js | 4 +- .../replication/keyvalue-indexed.test.js | 4 +- test/databases/replication/keyvalue.test.js | 4 +- .../fixtures/pre-2.5.0/ipfs/blocks/000003.log | Bin 0 -> 79430 bytes test/fixtures/pre-2.5.0/ipfs/blocks/CURRENT | 1 + test/fixtures/pre-2.5.0/ipfs/blocks/LOCK | 0 test/fixtures/pre-2.5.0/ipfs/blocks/LOG | 1 + .../pre-2.5.0/ipfs/blocks/MANIFEST-000002 | Bin 0 -> 50 bytes .../pre-2.5.0/orbitdb/keystore/000003.log | Bin 0 -> 195 bytes .../pre-2.5.0/orbitdb/keystore/CURRENT | 1 + test/fixtures/pre-2.5.0/orbitdb/keystore/LOCK | 0 test/fixtures/pre-2.5.0/orbitdb/keystore/LOG | 1 + .../orbitdb/keystore/MANIFEST-000002 | Bin 0 -> 50 bytes .../log/_heads/000003.log | Bin 0 -> 86453 bytes .../log/_heads/CURRENT | 1 + .../log/_heads/LOCK | 0 .../log/_heads/LOG | 1 + .../log/_heads/MANIFEST-000002 | Bin 0 -> 50 bytes .../log/_index/000003.log | Bin 0 -> 9675 bytes .../log/_index/CURRENT | 1 + .../log/_index/LOCK | 0 .../log/_index/LOG | 1 + .../log/_index/MANIFEST-000002 | Bin 0 -> 50 bytes test/heads-migration.test.js | 52 +++++++++ test/oplog/join.test.js | 2 +- test/orbitdb-replication.test.js | 11 +- 34 files changed, 200 insertions(+), 93 deletions(-) create mode 100644 test/fixtures/pre-2.5.0/ipfs/blocks/000003.log create mode 100644 test/fixtures/pre-2.5.0/ipfs/blocks/CURRENT create mode 100644 test/fixtures/pre-2.5.0/ipfs/blocks/LOCK create mode 100644 test/fixtures/pre-2.5.0/ipfs/blocks/LOG create mode 100644 test/fixtures/pre-2.5.0/ipfs/blocks/MANIFEST-000002 create mode 100644 test/fixtures/pre-2.5.0/orbitdb/keystore/000003.log create mode 100644 test/fixtures/pre-2.5.0/orbitdb/keystore/CURRENT create mode 100644 test/fixtures/pre-2.5.0/orbitdb/keystore/LOCK create mode 100644 test/fixtures/pre-2.5.0/orbitdb/keystore/LOG create mode 100644 test/fixtures/pre-2.5.0/orbitdb/keystore/MANIFEST-000002 create mode 100644 test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/000003.log create mode 100644 test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/CURRENT create mode 100644 test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/LOCK create mode 100644 test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/LOG create mode 100644 test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/MANIFEST-000002 create mode 100644 test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_index/000003.log create mode 100644 test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_index/CURRENT create mode 100644 test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_index/LOCK create mode 100644 test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_index/LOG create mode 100644 test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_index/MANIFEST-000002 create mode 100644 test/heads-migration.test.js diff --git a/benchmarks/orbitdb-documents.js b/benchmarks/orbitdb-documents.js index 110b441..9612f07 100644 --- a/benchmarks/orbitdb-documents.js +++ b/benchmarks/orbitdb-documents.js @@ -1,68 +1,86 @@ import { createOrbitDB } from '../src/index.js' -// import { createOrbitDB, MemoryStorage } from '../src/index.js' -import { rimraf as rmrf } from 'rimraf' import createHelia from '../test/utils/create-helia.js' +// import { MemoryStorage, LevelStorage, LRUStorage } from '../src/storage/index.js' +import { rimraf as rmrf } from 'rimraf' -import { EventEmitter } from 'events' -EventEmitter.defaultMaxListeners = 10000 +let db +let interval + +// Metrics +let totalQueries = 0 +let seconds = 0 +let queriesPerSecond = 0 +let lastTenSeconds = 0 + +// Settings +const benchmarkDuration = 20 // seconds + +const queryLoop = async () => { + const doc = { _id: 'id-' + totalQueries, content: 'hello ' + totalQueries } + // await db.put(totalQueries.toString(), { referencesCount: 0 }) + await db.put(doc) + totalQueries++ + lastTenSeconds++ + queriesPerSecond++ + if (interval) { + setImmediate(queryLoop) + } +} ;(async () => { console.log('Starting benchmark...') - const entryCount = 1000 + console.log('Benchmark duration is ' + benchmarkDuration + ' seconds') - await rmrf('./ipfs') await rmrf('./orbitdb') + // const identities = await Identities() + // const testIdentity = await identities.createIdentity({ id: 'userA' }) + const ipfs = await createHelia() const orbitdb = await createOrbitDB({ ipfs }) - console.log(`Insert ${entryCount} documents`) - + // MemoryStorage is the default storage for Log but defining them here + // in case we want to benchmark different storage modules // const entryStorage = await MemoryStorage() // const headsStorage = await MemoryStorage() // const indexStorage = await MemoryStorage() + // Test LRUStorage + // const entryStorage = await LRUStorage() + // const headsStorage = await LRUStorage() + // const indexStorage = await LRUStorage() + // Test LevelStorage + // const entryStorage = await LevelStorage({ path: './logA/entries' }) + // const headsStorage = await LevelStorage({ path: './orbitdb/benchmark-documents-2/heads', valueEncoding: 'json' }) + // const headsStorage = await LevelStorage({ path: './orbitdb/benchmark-documents-2/heads' }) + // const indexStorage = await LevelStorage({ path: './logA/index' }) - // const db1 = await orbitdb.open('benchmark-documents', { type: 'documents', referencesCount: 16, entryStorage, headsStorage, indexStorage }) + // db = await orbitdb.open('benchmark-documents-2', { type: 'documents', entryStorage, headsStorage, indexStorage }) + db = await orbitdb.open('benchmark-documents-2', { type: 'documents' }) - const db1 = await orbitdb.open('benchmark-documents', { type: 'documents' }) + // Output metrics at 1 second interval + interval = setInterval(async () => { + seconds++ + console.log(`${queriesPerSecond} queries per second, ${totalQueries} queries in ${seconds} seconds`) + queriesPerSecond = 0 - const startTime1 = new Date().getTime() + if (seconds % 10 === 0) { + console.log(`--> Average of ${lastTenSeconds / 10} q/s in the last 10 seconds`) + if (lastTenSeconds === 0) throw new Error('Problems!') + lastTenSeconds = 0 + } - for (let i = 0; i < entryCount; i++) { - const doc = { _id: i.toString(), message: 'hello ' + i } - await db1.put(doc) - } + if (seconds >= benchmarkDuration) { + clearInterval(interval) + interval = null + process.nextTick(async () => { + await db.close() + await orbitdb.stop() + await rmrf('./orbitdb') + process.exit(0) + }, 1000) + } + }, 1000) - const endTime1 = new Date().getTime() - const duration1 = endTime1 - startTime1 - const operationsPerSecond1 = Math.floor(entryCount / (duration1 / 1000)) - const millisecondsPerOp1 = duration1 / entryCount - console.log(`Inserting ${entryCount} documents took ${duration1} ms, ${operationsPerSecond1} ops/s, ${millisecondsPerOp1} ms/op`) - - console.log(`Query ${entryCount} documents`) - const startTime2 = new Date().getTime() - - const all = [] - for await (const { key, value } of db1.iterator()) { - all.unshift({ key, value }) - } - - const endTime2 = new Date().getTime() - const duration2 = endTime2 - startTime2 - const operationsPerSecond2 = Math.floor(entryCount / (duration2 / 1000)) - const millisecondsPerOp2 = duration2 / entryCount - - console.log(`Querying ${all.length} documents took ${duration2} ms, ${operationsPerSecond2} ops/s, ${millisecondsPerOp2} ms/op`) - - await db1.drop() - await db1.close() - - await orbitdb.stop() - await ipfs.stop() - - await rmrf('./ipfs') - await rmrf('./orbitdb') - - process.exit(0) + setImmediate(queryLoop) })() diff --git a/src/oplog/heads.js b/src/oplog/heads.js index cf34b7c..23405ea 100644 --- a/src/oplog/heads.js +++ b/src/oplog/heads.js @@ -9,19 +9,13 @@ import MemoryStorage from '../storage/memory.js' const DefaultStorage = MemoryStorage -const Heads = async ({ storage, heads }) => { +const Heads = async ({ storage, heads, entryStorage }) => { storage = storage || await DefaultStorage() const put = async (heads) => { heads = findHeads(heads) - for (const head of heads) { - await storage.put(head.hash, head.bytes) - } - } - - const set = async (heads) => { - await storage.clear() - await put(heads) + const headHashes = heads.map(e => e.hash) + await storage.put('heads', JSON.stringify(headHashes)) } const add = async (head) => { @@ -30,7 +24,7 @@ const Heads = async ({ storage, heads }) => { return } const newHeads = findHeads([...currentHeads, head]) - await set(newHeads) + await put(newHeads) return newHeads } @@ -38,14 +32,18 @@ const Heads = async ({ storage, heads }) => { const remove = async (hash) => { const currentHeads = await all() const newHeads = currentHeads.filter(e => e.hash !== hash) - await set(newHeads) + await put(newHeads) } const iterator = async function * () { - const it = storage.iterator() - for await (const [, bytes] of it) { - const head = await Entry.decode(bytes) - yield head + const e = await storage.get('heads') + const headHashes = e ? JSON.parse(e) : [] + for (const hash of headHashes) { + const entry = await entryStorage.get(hash) + if (entry) { + const head = await Entry.decode(entry) + yield head + } } } @@ -66,11 +64,32 @@ const Heads = async ({ storage, heads }) => { } // Initialize the heads if given as parameter - await put(heads || []) + if (heads) { + await put(heads) + } + + // Migrate from 2.4.3 -> 2.5.0 + const migrate1 = async () => { + const it_ = storage.iterator() + const values = [] + for await (const [hash] of it_) { + if (hash !== 'heads') { + values.push(hash) + } + } + if (values.length > 0) { + console.log('Migrate pre v2.5.0 heads database') + console.log('Heads:', values) + await storage.clear() + await storage.put('heads', JSON.stringify(values)) + } + } + + await migrate1() return { put, - set, + set: put, add, remove, iterator, diff --git a/src/oplog/log.js b/src/oplog/log.js index dd76c8c..bfeaf0f 100644 --- a/src/oplog/log.js +++ b/src/oplog/log.js @@ -79,7 +79,7 @@ const Log = async (identity, { logId, logHeads, access, entryStorage, headsStora // Heads storage headsStorage = headsStorage || await DefaultStorage() // Add heads to the state storage, ie. init the log state - const _heads = await Heads({ storage: headsStorage, heads: logHeads }) + const _heads = await Heads({ storage: headsStorage, heads: logHeads, entryStorage: _entries }) // Conflict-resolution sorting function sortFn = NoZeroes(sortFn || LastWriteWins) // Internal queues for processing appends and joins in their call-order @@ -184,10 +184,10 @@ const Log = async (identity, { logId, logHeads, access, entryStorage, headsStora throw new Error(`Could not append entry:\nKey "${identity.hash}" is not allowed to write to the log`) } - // The appended entry is now the latest head - await _heads.set([entry]) // Add entry to the entry storage await _entries.put(entry.hash, entry.bytes) + // The appended entry is now the latest head + await _heads.set([entry]) // Add entry to the entry index await _index.put(entry.hash, true) // Return the appended entry @@ -315,7 +315,7 @@ const Log = async (identity, { logId, logHeads, access, entryStorage, headsStora /* 6. Add new entry to entries (for pinning) */ await _entries.put(entry.hash, entry.bytes) - /* 6. Add the new entry to heads (=union with current heads) */ + /* 7. Add the new entry to heads (=union with current heads) */ await _heads.add(entry) return true diff --git a/src/storage/ipfs-block.js b/src/storage/ipfs-block.js index a1c4acc..806b1cd 100644 --- a/src/storage/ipfs-block.js +++ b/src/storage/ipfs-block.js @@ -9,7 +9,7 @@ import { base58btc } from 'multiformats/bases/base58' import { TimeoutController } from 'timeout-abort-controller' import drain from 'it-drain' -const DefaultTimeout = 30000 // 30 seconds +const DefaultTimeout = 10000 // 30 seconds /** * Creates an instance of IPFSBlockStorage. @@ -28,6 +28,8 @@ const DefaultTimeout = 30000 // 30 seconds const IPFSBlockStorage = async ({ ipfs, pin, timeout } = {}) => { if (!ipfs) throw new Error('An instance of ipfs is required.') + const signals = new Set() + /** * Puts data to an IPFS block. * @function @@ -59,7 +61,9 @@ const IPFSBlockStorage = async ({ ipfs, pin, timeout } = {}) => { const get = async (hash) => { const cid = CID.parse(hash, base58btc) const { signal } = new TimeoutController(timeout || DefaultTimeout) + signals.add(signal) const block = await ipfs.blockstore.get(cid, { signal }) + signals.delete(signal) if (block) { return block } @@ -71,7 +75,12 @@ const IPFSBlockStorage = async ({ ipfs, pin, timeout } = {}) => { const clear = async () => {} - const close = async () => {} + const close = async () => { + for (const s in signals) { + s.abort() + } + signals.clear() + } return { put, diff --git a/src/sync.js b/src/sync.js index e4005ee..79255ab 100644 --- a/src/sync.js +++ b/src/sync.js @@ -228,7 +228,7 @@ const Sync = async ({ ipfs, log, events, onSynced, start, timeout }) => { } if (topic === address) { - queue.add(task) + await queue.add(task) } } diff --git a/test/database-replication.test.js b/test/database-replication.test.js index 3d029f4..138ad56 100644 --- a/test/database-replication.test.js +++ b/test/database-replication.test.js @@ -30,7 +30,7 @@ describe('Database - Replication', function () { } beforeEach(async () => { - [ipfs1, ipfs2] = await Promise.all([createHelia(), createHelia()]) + [ipfs1, ipfs2] = await Promise.all([createHelia({ directory: './ipfs1' }), createHelia({ directory: './ipfs2' })]) await connectPeers(ipfs1, ipfs2) await copy(testKeysPath, keysPath) @@ -42,23 +42,21 @@ describe('Database - Replication', function () { afterEach(async () => { if (db1) { - await db1.drop() await db1.close() - await rimraf('./orbitdb1') } if (db2) { - await db2.drop() await db2.close() - await rimraf('./orbitdb2') } if (ipfs1) { + await ipfs1.blockstore.child.child.child.close() await ipfs1.stop() } if (ipfs2) { + await ipfs2.blockstore.child.child.child.close() await ipfs2.stop() } diff --git a/test/database.test.js b/test/database.test.js index 5677b58..c96d97c 100644 --- a/test/database.test.js +++ b/test/database.test.js @@ -77,9 +77,9 @@ describe('Database', function () { await db.close() - const headsStorage = await LevelStorage({ path: headsPath }) + const headsStorage = await LevelStorage({ path: headsPath, valueEncoding: 'json' }) - deepStrictEqual((await Entry.decode(await headsStorage.get(hash))).payload, op) + deepStrictEqual(await headsStorage.get('heads'), [hash]) await headsStorage.close() @@ -97,9 +97,9 @@ describe('Database', function () { await db.close() - const headsStorage = await LevelStorage({ path: headsPath }) + const headsStorage = await LevelStorage({ path: headsPath, valueEncoding: 'json' }) - deepStrictEqual((await Entry.decode(await headsStorage.get(hash))).payload, op) + deepStrictEqual(await headsStorage.get('heads'), [hash]) await headsStorage.close() @@ -113,7 +113,7 @@ describe('Database', function () { const op = { op: 'PUT', key: 1, value: 'record 1 on db 1' } const hash = await db.addOperation(op) - deepStrictEqual((await Entry.decode(await headsStorage.get(hash))).payload, op) + deepStrictEqual(JSON.parse(await headsStorage.get('heads')), [hash]) await db.close() }) diff --git a/test/databases/replication/documents.test.js b/test/databases/replication/documents.test.js index 4c167cd..aa2577f 100644 --- a/test/databases/replication/documents.test.js +++ b/test/databases/replication/documents.test.js @@ -30,7 +30,7 @@ describe('Documents Database Replication', function () { } before(async () => { - [ipfs1, ipfs2] = await Promise.all([createHelia(), createHelia()]) + [ipfs1, ipfs2] = await Promise.all([createHelia({ directory: './ipfs1' }), createHelia({ directory: './ipfs2' })]) await connectPeers(ipfs1, ipfs2) await copy(testKeysPath, keysPath) @@ -42,10 +42,12 @@ describe('Documents Database Replication', function () { after(async () => { if (ipfs1) { + await ipfs1.blockstore.child.child.child.close() await ipfs1.stop() } if (ipfs2) { + await ipfs2.blockstore.child.child.child.close() await ipfs2.stop() } diff --git a/test/databases/replication/events.test.js b/test/databases/replication/events.test.js index c956582..5962fa6 100644 --- a/test/databases/replication/events.test.js +++ b/test/databases/replication/events.test.js @@ -40,7 +40,7 @@ describe('Events Database Replication', function () { ] before(async () => { - [ipfs1, ipfs2] = await Promise.all([createHelia(), createHelia()]) + [ipfs1, ipfs2] = await Promise.all([createHelia({ directory: './ipfs1' }), createHelia({ directory: './ipfs2' })]) await connectPeers(ipfs1, ipfs2) await copy(testKeysPath, keysPath) @@ -52,10 +52,12 @@ describe('Events Database Replication', function () { after(async () => { if (ipfs1) { + await ipfs1.blockstore.child.child.child.close() await ipfs1.stop() } if (ipfs2) { + await ipfs2.blockstore.child.child.child.close() await ipfs2.stop() } diff --git a/test/databases/replication/keyvalue-indexed.test.js b/test/databases/replication/keyvalue-indexed.test.js index 590bf68..5718632 100644 --- a/test/databases/replication/keyvalue-indexed.test.js +++ b/test/databases/replication/keyvalue-indexed.test.js @@ -29,7 +29,7 @@ describe('KeyValueIndexed Database Replication', function () { } before(async () => { - [ipfs1, ipfs2] = await Promise.all([createHelia(), createHelia()]) + [ipfs1, ipfs2] = await Promise.all([createHelia({ directory: './ipfs1' }), createHelia({ directory: './ipfs2' })]) await connectPeers(ipfs1, ipfs2) await rimraf(keysPath) @@ -47,10 +47,12 @@ describe('KeyValueIndexed Database Replication', function () { after(async () => { if (ipfs1) { + await ipfs1.blockstore.child.child.child.close() await ipfs1.stop() } if (ipfs2) { + await ipfs2.blockstore.child.child.child.close() await ipfs2.stop() } diff --git a/test/databases/replication/keyvalue.test.js b/test/databases/replication/keyvalue.test.js index b12114d..2bbce2b 100644 --- a/test/databases/replication/keyvalue.test.js +++ b/test/databases/replication/keyvalue.test.js @@ -29,7 +29,7 @@ describe('KeyValue Database Replication', function () { } before(async () => { - [ipfs1, ipfs2] = await Promise.all([createHelia(), createHelia()]) + [ipfs1, ipfs2] = await Promise.all([createHelia({ directory: './ipfs1' }), createHelia({ directory: './ipfs2' })]) await connectPeers(ipfs1, ipfs2) await copy(testKeysPath, keysPath) @@ -41,10 +41,12 @@ describe('KeyValue Database Replication', function () { after(async () => { if (ipfs1) { + await ipfs1.blockstore.child.child.child.close() await ipfs1.stop() } if (ipfs2) { + await ipfs2.blockstore.child.child.child.close() await ipfs2.stop() } diff --git a/test/fixtures/pre-2.5.0/ipfs/blocks/000003.log b/test/fixtures/pre-2.5.0/ipfs/blocks/000003.log new file mode 100644 index 0000000000000000000000000000000000000000..57550c8b8f61ad050159dc87fd0624415da8f109 GIT binary patch literal 79430 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/pre-2.5.0/ipfs/blocks/CURRENT b/test/fixtures/pre-2.5.0/ipfs/blocks/CURRENT new file mode 100644 index 0000000..1a84852 --- /dev/null +++ b/test/fixtures/pre-2.5.0/ipfs/blocks/CURRENT @@ -0,0 +1 @@ +MANIFEST-000002 diff --git a/test/fixtures/pre-2.5.0/ipfs/blocks/LOCK b/test/fixtures/pre-2.5.0/ipfs/blocks/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/pre-2.5.0/ipfs/blocks/LOG b/test/fixtures/pre-2.5.0/ipfs/blocks/LOG new file mode 100644 index 0000000..0b0087e --- /dev/null +++ b/test/fixtures/pre-2.5.0/ipfs/blocks/LOG @@ -0,0 +1 @@ +2024/11/29-11:58:49.407658 172883000 Delete type=3 #1 diff --git a/test/fixtures/pre-2.5.0/ipfs/blocks/MANIFEST-000002 b/test/fixtures/pre-2.5.0/ipfs/blocks/MANIFEST-000002 new file mode 100644 index 0000000000000000000000000000000000000000..bbbc585686bcbcc33686059c69d80b7b4e1291cd GIT binary patch literal 50 zcmWIhx#Ncn10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAe$kRS-TOEg7@3$k8JJmE F7y#sj5K{mE literal 0 HcmV?d00001 diff --git a/test/fixtures/pre-2.5.0/orbitdb/keystore/000003.log b/test/fixtures/pre-2.5.0/orbitdb/keystore/000003.log new file mode 100644 index 0000000000000000000000000000000000000000..5fb1175757e06c4d888bebb2547b5a7d1c093cd7 GIT binary patch literal 195 zcmb14O-r?5U}R)~01(Z{TTql)mROP+Us{}6WT>EWze)eSMft5G`(JM7W8J8g%Ara*2*EqWu}t?vm(Rx&U$AsgWZGs3_)In~0<*uXH^G&RN4&@?U0$k;H&(!eO$ zFv;97%`DZ_%+ey&!aO-KF)7g~*&@l*(8R(ZF*(I7$uuR^BGE8a;kq$d btJbdea82BJ(CQLj4$t$&8EZe^(%TCFCk{Wq literal 0 HcmV?d00001 diff --git a/test/fixtures/pre-2.5.0/orbitdb/keystore/CURRENT b/test/fixtures/pre-2.5.0/orbitdb/keystore/CURRENT new file mode 100644 index 0000000..1a84852 --- /dev/null +++ b/test/fixtures/pre-2.5.0/orbitdb/keystore/CURRENT @@ -0,0 +1 @@ +MANIFEST-000002 diff --git a/test/fixtures/pre-2.5.0/orbitdb/keystore/LOCK b/test/fixtures/pre-2.5.0/orbitdb/keystore/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/pre-2.5.0/orbitdb/keystore/LOG b/test/fixtures/pre-2.5.0/orbitdb/keystore/LOG new file mode 100644 index 0000000..ea5ff68 --- /dev/null +++ b/test/fixtures/pre-2.5.0/orbitdb/keystore/LOG @@ -0,0 +1 @@ +2024/11/29-11:58:49.433589 172883000 Delete type=3 #1 diff --git a/test/fixtures/pre-2.5.0/orbitdb/keystore/MANIFEST-000002 b/test/fixtures/pre-2.5.0/orbitdb/keystore/MANIFEST-000002 new file mode 100644 index 0000000000000000000000000000000000000000..bbbc585686bcbcc33686059c69d80b7b4e1291cd GIT binary patch literal 50 zcmWIhx#Ncn10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAe$kRS-TOEg7@3$k8JJmE F7y#sj5K{mE literal 0 HcmV?d00001 diff --git a/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/000003.log b/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/000003.log new file mode 100644 index 0000000000000000000000000000000000000000..7fc21a6dfd338f0891e8d6ac530f95b2013d5a2b GIT binary patch literal 86453 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

e2o*W{ejF_cZqyfBQC+&SXtNehR~ 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/CURRENT b/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/CURRENT new file mode 100644 index 0000000..1a84852 --- /dev/null +++ b/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/CURRENT @@ -0,0 +1 @@ +MANIFEST-000002 diff --git a/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/LOCK b/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/LOG b/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/LOG new file mode 100644 index 0000000..25e0ef7 --- /dev/null +++ b/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/LOG @@ -0,0 +1 @@ +2024/11/29-11:58:49.466751 172077000 Delete type=3 #1 diff --git a/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/MANIFEST-000002 b/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_heads/MANIFEST-000002 new file mode 100644 index 0000000000000000000000000000000000000000..bbbc585686bcbcc33686059c69d80b7b4e1291cd GIT binary patch literal 50 zcmWIhx#Ncn10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAe$kRS-TOEg7@3$k8JJmE F7y#sj5K{mE literal 0 HcmV?d00001 diff --git a/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_index/000003.log b/test/fixtures/pre-2.5.0/orbitdb/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES/log/_index/000003.log new file mode 100644 index 0000000000000000000000000000000000000000..9ef96f5ad20c40404bd756a799a614106f4e689c GIT binary patch literal 9675 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 { + await copy(fixturesPath, testDir) + ipfs = await createHelia({ directory: `${testDir}/ipfs` }) + orbitdb = await createOrbitDB({ ipfs, id: 'user1', directory: `${testDir}/orbitdb` }) + }) + + after(async () => { + await orbitdb.stop() + await ipfs.blockstore.child.child.child.close() + await ipfs.stop() + await rimraf(testDir) + }) + + it('migrates the heads database from pre 2.5.0 to 2.5.0 format', async () => { + const db = await orbitdb.open('/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES') + + const res = [] + + for await (const event of db.iterator()) { + res.unshift(event) + } + + deepStrictEqual(res.length, 129) + }) + + it('can read the database after migration to 2.5.0 format', async () => { + const db = await orbitdb.open('/orbitdb/zdpuAoE5P3f5zsPGkNDVgK4XF61oyE5c5JY6Yz5d74oWFCYES') + + const res = [] + + for await (const event of db.iterator()) { + res.unshift(event) + } + + deepStrictEqual(res.length, 129) + }) +}) diff --git a/test/oplog/join.test.js b/test/oplog/join.test.js index 7c313c9..2d040c6 100644 --- a/test/oplog/join.test.js +++ b/test/oplog/join.test.js @@ -760,7 +760,7 @@ describe('Log - Join', async function () { await log1.storage.merge(log0.storage) - await headsStorage1.put(e0.hash, e0.bytes) + await headsStorage1.put('heads', JSON.stringify([e0.hash])) await log1.append('hello1') await log1.append('hello2') diff --git a/test/orbitdb-replication.test.js b/test/orbitdb-replication.test.js index 916854a..a9983a1 100644 --- a/test/orbitdb-replication.test.js +++ b/test/orbitdb-replication.test.js @@ -14,8 +14,7 @@ describe('Replicating databases', function () { let orbitdb1, orbitdb2 before(async () => { - ipfs1 = await createHelia({ directory: './ipfs1' }) - ipfs2 = await createHelia({ directory: './ipfs2' }) + [ipfs1, ipfs2] = await Promise.all([createHelia({ directory: './ipfs1' }), createHelia({ directory: './ipfs2' })]) await connectPeers(ipfs1, ipfs2) orbitdb1 = await createOrbitDB({ ipfs: ipfs1, id: 'user1', directory: './orbitdb1' }) @@ -138,10 +137,6 @@ describe('Replicating databases', function () { await orbitdb1.stop() await orbitdb2.stop() - // TODO: Strange issue with ClassicLevel. Causes subsequent Helia - // instantiations to error with db closed. Explicitly closing the - // nested ClassicLevel db seems to resolve the issue. Requires further - // investigation. await ipfs1.blockstore.child.child.child.close() await ipfs2.blockstore.child.child.child.close() await ipfs1.stop() @@ -153,10 +148,8 @@ describe('Replicating databases', function () { await connectPeers(ipfs1, ipfs2) orbitdb1 = await createOrbitDB({ ipfs: ipfs1, id: 'user1', directory: './orbitdb1' }) - orbitdb2 = await createOrbitDB({ ipfs: ipfs2, id: 'user2', directory: './orbitdb2' }) db1 = await orbitdb1.open('helloworld', { referencesCount: 0 }) - db2 = await orbitdb2.open(db1.address) console.time('query 2') const eventsFromDb1 = [] @@ -180,6 +173,8 @@ describe('Replicating databases', function () { replicated = true } + orbitdb2 = await createOrbitDB({ ipfs: ipfs2, id: 'user2', directory: './orbitdb2' }) + const db2 = await orbitdb2.open(db1.address) db2.events.on('join', onJoin)