refactor blockstore

This commit is contained in:
dholms 2022-08-10 16:26:26 -05:00
parent 26cb3a35eb
commit 4e03fba102
10 changed files with 76 additions and 111 deletions

@ -0,0 +1,3 @@
export * from './ipld-store'
export * from './memory-blockstore'
export * from './persistent-blockstore'

@ -4,11 +4,8 @@ import { sha256 as blockHasher } from 'multiformats/hashes/sha2'
import * as blockCodec from '@ipld/dag-cbor'
import { BlockWriter } from '@ipld/car/writer'
import MemoryBlockstore from './memory-blockstore'
import * as check from '../common/check'
import * as util from '../common/util'
import { BlockstoreI } from './types'
import { PersistentBlockstore } from './persistent-blockstore'
import { BlockReader } from '@ipld/car/api'
import CidSet from '../repo/cid-set'
@ -18,20 +15,11 @@ export type AllowedIpldVal =
| AllowedIpldRecordVal
| Record<string, AllowedIpldRecordVal>
export class IpldStore {
rawBlockstore: BlockstoreI
constructor(rawBlockstore: BlockstoreI) {
this.rawBlockstore = rawBlockstore
}
static createInMemory(): IpldStore {
return new IpldStore(new MemoryBlockstore())
}
static createPersistent(location = 'blockstore'): IpldStore {
return new IpldStore(new PersistentBlockstore(location))
}
export abstract class IpldStore {
abstract has(cid: CID): Promise<boolean>
abstract getBytes(cid: CID): Promise<Uint8Array>
abstract putBytes(cid: CID, bytes: Uint8Array): Promise<void>
abstract destroy(): Promise<void>
async put(
value: Record<string, AllowedIpldVal> | AllowedIpldVal,
@ -67,10 +55,6 @@ export class IpldStore {
return block.value
}
async has(cid: CID): Promise<boolean> {
return this.rawBlockstore.has(cid)
}
async isMissing(cid: CID): Promise<boolean> {
const has = await this.has(cid)
return !has
@ -83,18 +67,6 @@ export class IpldStore {
return new CidSet(missing)
}
async getBytes(cid: CID): Promise<Uint8Array> {
return this.rawBlockstore.get(cid)
}
async putBytes(cid: CID, bytes: Uint8Array): Promise<void> {
return this.rawBlockstore.put(cid, bytes)
}
async destroy(): Promise<void> {
return this.rawBlockstore.destroy()
}
async addToCar(car: BlockWriter, cid: CID) {
car.put({ cid, bytes: await this.getBytes(cid) })
}

@ -1,20 +1,21 @@
import { CID } from 'multiformats/cid'
import { BlockstoreI } from './types'
import IpldStore from './ipld-store'
export class MemoryBlockstore implements BlockstoreI {
export class MemoryBlockstore extends IpldStore {
map: Map<string, Uint8Array>
constructor() {
super()
this.map = new Map()
}
async get(k: CID): Promise<Uint8Array> {
async getBytes(k: CID): Promise<Uint8Array> {
const v = this.map.get(k.toString())
if (!v) throw new Error(`Not found: ${k.toString()}`)
return v
}
async put(k: CID, v: Uint8Array): Promise<void> {
async putBytes(k: CID, v: Uint8Array): Promise<void> {
this.map.set(k.toString(), v)
}

@ -1,29 +1,29 @@
import level from 'level'
import { CID } from 'multiformats/cid'
import IpldStore from './ipld-store'
import { BlockstoreI } from './types'
export class PersistentBlockstore implements BlockstoreI {
export class PersistentBlockstore extends IpldStore {
store: level.Level
constructor(location = 'blockstore') {
super()
this.store = new level.Level(location, {
valueEncoding: 'view',
compression: false,
})
}
async get(cid: CID): Promise<Uint8Array> {
async getBytes(cid: CID): Promise<Uint8Array> {
return this.store.get(cid.toString(), { valueEncoding: 'view' })
}
async put(cid: CID, bytes: Uint8Array): Promise<void> {
async putBytes(cid: CID, bytes: Uint8Array): Promise<void> {
await this.store.put(cid.toString(), bytes, { valueEncoding: 'view' })
}
async has(cid: CID): Promise<boolean> {
try {
await this.get(cid)
await this.getBytes(cid)
return true
} catch (_) {
return false

@ -1,8 +0,0 @@
import { CID } from 'multiformats/cid'
export interface BlockstoreI {
get(cid: CID): Promise<Uint8Array>
put(cid: CID, bytes: Uint8Array): Promise<void>
has(cid: CID): Promise<boolean>
destroy(): Promise<void>
}

@ -1,7 +1,4 @@
export * from './blockstore/ipld-store'
export * from './blockstore/memory-blockstore'
export * from './blockstore/persistent-blockstore'
export * from './blockstore'
export * from './repo'
export * from './microblog/index'

@ -1,14 +1,12 @@
import { CID } from 'multiformats'
import IpldStore from '../src/blockstore/ipld-store'
import TID from '../src/repo/tid'
import { Follow, IdMapping, schema } from '../src/repo/types'
import { DID } from '../src/common/types'
// import SSTable from '../src/repo/ss-table'
import { IdMapping } from '../src/repo/types'
import { Repo } from '../src/repo'
import { MST } from '../src'
import { MemoryBlockstore, MST } from '../src'
import fs from 'fs'
const fakeStore = IpldStore.createInMemory()
const fakeStore = new MemoryBlockstore()
export const randomCid = async (store: IpldStore = fakeStore): Promise<CID> => {
const str = randomStr(50)
@ -65,7 +63,7 @@ export const shuffle = <T>(arr: T[]): T[] => {
export const generateObject = (): Record<string, string> => {
return {
name: randomStr(50),
name: randomStr(100),
}
}

@ -6,19 +6,19 @@ import {
DataDelete,
} from '../src/repo/mst'
import { IpldStore } from '../src/blockstore/ipld-store'
import { MemoryBlockstore } from '../src/blockstore'
import * as util from './_util'
import { CID } from 'multiformats'
describe('Merkle Search Tree', () => {
let blockstore: IpldStore
let blockstore: MemoryBlockstore
let mst: MST
let mapping: Record<string, CID>
let shuffled: [string, CID][]
beforeAll(async () => {
blockstore = IpldStore.createInMemory()
blockstore = new MemoryBlockstore()
mst = await MST.create(blockstore)
mapping = await util.generateBulkTidMapping(1000, blockstore)
shuffled = util.shuffle(Object.entries(mapping))

@ -1,17 +1,17 @@
import * as auth from '@adxp/auth'
import { Repo } from '../src/repo'
import IpldStore from '../src/blockstore/ipld-store'
import { MemoryBlockstore } from '../src/blockstore'
import * as util from './_util'
describe('Repo', () => {
let blockstore: IpldStore
let blockstore: MemoryBlockstore
let authStore: auth.AuthStore
let repo: Repo
let repoData: util.RepoData
it('creates repo', async () => {
blockstore = IpldStore.createInMemory()
blockstore = new MemoryBlockstore()
authStore = await auth.MemoryStore.load()
await authStore.claimFull()
repo = await Repo.create(blockstore, await authStore.did(), authStore)

@ -1,52 +1,54 @@
import * as auth from '@adxp/auth'
import { Repo } from '../src/repo'
import IpldStore from '../src/blockstore/ipld-store'
import { MemoryBlockstore } from '../src/blockstore'
import * as util from './_util'
describe('Sync', () => {
let aliceBlockstore, bobBlockstore: IpldStore
let aliceRepo: Repo
let repoData: util.RepoData
for (let i = 0; i < 1; i++) {
describe('Sync', () => {
let aliceBlockstore, bobBlockstore: MemoryBlockstore
let aliceRepo: Repo
let repoData: util.RepoData
beforeAll(async () => {
aliceBlockstore = IpldStore.createInMemory()
const authStore = await auth.MemoryStore.load()
await authStore.claimFull()
aliceRepo = await Repo.create(
aliceBlockstore,
await authStore.did(),
authStore,
)
bobBlockstore = IpldStore.createInMemory()
})
it('syncs an empty repo', async () => {
const car = await aliceRepo.getFullHistory()
const repoBob = await Repo.fromCarFile(car, bobBlockstore)
const data = await repoBob.data.list('', 10)
expect(data.length).toBe(0)
})
let bobRepo: Repo
it('syncs a repo that is starting from scratch', async () => {
repoData = await util.fillRepo(aliceRepo, 100)
const car = await aliceRepo.getFullHistory()
bobRepo = await Repo.fromCarFile(car, bobBlockstore)
// const diff = await bobRepo.verifySetOfUpdates(null, bobRepo.cid)
await util.checkRepo(bobRepo, repoData)
})
it('syncs a repo that is behind', async () => {
// add more to alice's repo & have bob catch up
repoData = await util.editRepo(aliceRepo, repoData, {
adds: 20,
updates: 20,
deletes: 20,
beforeAll(async () => {
aliceBlockstore = new MemoryBlockstore()
const authStore = await auth.MemoryStore.load()
await authStore.claimFull()
aliceRepo = await Repo.create(
aliceBlockstore,
await authStore.did(),
authStore,
)
bobBlockstore = new MemoryBlockstore()
})
const diffCar = await aliceRepo.getDiffCar(bobRepo.cid)
// const diff = await bobRepo.loadAndVerifyDiff(diffCar)
await util.checkRepo(bobRepo, repoData)
it('syncs an empty repo', async () => {
const car = await aliceRepo.getFullHistory()
const repoBob = await Repo.fromCarFile(car, bobBlockstore)
const data = await repoBob.data.list('', 10)
expect(data.length).toBe(0)
})
let bobRepo: Repo
it('syncs a repo that is starting from scratch', async () => {
repoData = await util.fillRepo(aliceRepo, 500)
const car = await aliceRepo.getFullHistory()
bobRepo = await Repo.fromCarFile(car, bobBlockstore)
// const diff = await bobRepo.verifySetOfUpdates(null, bobRepo.cid)
await util.checkRepo(bobRepo, repoData)
})
// it('syncs a repo that is behind', async () => {
// // add more to alice's repo & have bob catch up
// repoData = await util.editRepo(aliceRepo, repoData, {
// adds: 20,
// updates: 20,
// deletes: 20,
// })
// const diffCar = await aliceRepo.getDiffCar(bobRepo.cid)
// // const diff = await bobRepo.loadAndVerifyDiff(diffCar)
// await util.checkRepo(bobRepo, repoData)
// })
})
})
}