@peerbit/log
Advanced tools
Comparing version 4.0.21 to 4.0.22
import { AnyBlockStore } from "@peerbit/blocks"; | ||
import { Ed25519Keypair } from "@peerbit/crypto"; | ||
import { create } from "@peerbit/indexer-sqlite3"; | ||
import B from "benchmark"; | ||
import * as B from "tinybench"; | ||
import { Log } from "../src/log.js"; | ||
@@ -10,3 +10,7 @@ // Run with "node --loader ts-node/esm ./benchmark/append.ts" | ||
const key = await Ed25519Keypair.create(); | ||
const close = () => { | ||
return log?.close(); | ||
}; | ||
const reset = async () => { | ||
await close(); | ||
log = new Log(); | ||
@@ -17,26 +21,13 @@ store = new AnyBlockStore(); | ||
await reset(); | ||
const suite = new B.Suite({ delay: 100 }); | ||
suite | ||
.add("chain", { | ||
fn: async (deferred) => { | ||
await log.append(new Uint8Array([1, 2, 3])); | ||
deferred.resolve(); | ||
}, | ||
defer: true, | ||
const suite = new B.Bench({ warmupIterations: 1000, setup: reset }); | ||
await suite | ||
.add("chain", async () => { | ||
await log.append(new Uint8Array([1, 2, 3])); | ||
}) | ||
.add("no-next", { | ||
fn: async (deferred) => { | ||
await log.append(new Uint8Array([1, 2, 3]), { meta: { next: [] } }); | ||
deferred.resolve(); | ||
}, | ||
defer: true, | ||
.add("no-next", async () => { | ||
await log.append(new Uint8Array([1, 2, 3]), { meta: { next: [] } }); | ||
}) | ||
.on("cycle", async (event) => { | ||
console.log(String(event.target)); | ||
await reset(); | ||
}) | ||
.on("error", (err) => { | ||
throw err; | ||
}) | ||
.run(); | ||
await close(); | ||
console.table(suite.table()); | ||
//# sourceMappingURL=append.js.map |
@@ -71,3 +71,3 @@ import { type Blocks } from "@peerbit/blocks-interface"; | ||
}): Promise<void>; | ||
delete(k: string, shallow?: ShallowEntry | undefined): Promise<ShallowEntry | undefined>; | ||
delete(k: string, from?: Entry<any> | ShallowEntry): Promise<ShallowEntry | Entry<any> | undefined>; | ||
getMemoryUsage(): Promise<number | bigint>; | ||
@@ -74,0 +74,0 @@ private privateUpdateNextHeadProperty; |
@@ -85,2 +85,9 @@ import { deserialize, serialize } from "@dao-xyz/borsh"; | ||
const results = await iterator.next(amount); | ||
return coerce(results); | ||
}; | ||
const all = async () => { | ||
const results = await iterator.all(); | ||
return coerce(results); | ||
}; | ||
const coerce = async (results) => { | ||
if (resolveInFull) { | ||
@@ -98,12 +105,3 @@ const maybeResolved = await Promise.all(results.map((x) => this.resolve(x.value.hash, resolveInFullOptions))); | ||
next, | ||
all: async () => { | ||
const results = []; | ||
while (!iterator.done()) { | ||
for (const element of await next(100)) { | ||
results.push(element); | ||
} | ||
} | ||
await iterator.close(); | ||
return results; | ||
}, | ||
all, | ||
}; | ||
@@ -142,2 +140,6 @@ } | ||
async has(k) { | ||
let mem = this.cache.get(k); | ||
if (mem) { | ||
return true; | ||
} | ||
const result = await this.properties.index.get(toId(k), { | ||
@@ -179,6 +181,7 @@ shape: { hash: true }, | ||
const fn = async () => { | ||
this.cache.add(entry.hash, entry); | ||
if (properties.unique === true || !(await this.has(entry.hash))) { | ||
this._length++; | ||
} | ||
// add cache after .has check before .has uses the cache | ||
this.cache.add(entry.hash, entry); | ||
await this.properties.index.put(entry.toShallow(properties.isHead)); | ||
@@ -225,9 +228,9 @@ // check if gids has been shadowed, by query all nexts that have a different gid | ||
} | ||
async delete(k, shallow = undefined) { | ||
async delete(k, from) { | ||
this.cache.del(k); | ||
if (shallow && shallow.hash !== k) { | ||
if (from && from.hash !== k) { | ||
throw new Error("Shallow hash doesn't match the key"); | ||
} | ||
shallow = shallow || (await this.getShallow(k))?.value; | ||
if (!shallow) { | ||
from = from || (await this.getShallow(k))?.value; | ||
if (!from) { | ||
return; // already deleted | ||
@@ -240,4 +243,4 @@ } | ||
// mark all next entries as new heads | ||
await this.privateUpdateNextHeadProperty(shallow, true); | ||
return shallow; | ||
await this.privateUpdateNextHeadProperty(from, true); | ||
return from; | ||
} | ||
@@ -299,18 +302,18 @@ } | ||
let coercedOptions = typeof options === "object" ? options : undefined; | ||
if (await this.has(k)) { | ||
let mem = this.cache.get(k); | ||
if (mem === undefined) { | ||
mem = await this.resolveFromStore(k, coercedOptions); | ||
if (mem) { | ||
this.properties.init(mem); | ||
mem.hash = k; | ||
} | ||
else if (coercedOptions?.ignoreMissing !== true) { | ||
throw new Error("Failed to load entry from head with hash: " + k); | ||
} | ||
this.cache.add(k, mem ?? undefined); | ||
/* if (await this.has(k)) { */ | ||
let mem = this.cache.get(k); | ||
if (mem === undefined) { | ||
mem = await this.resolveFromStore(k, coercedOptions); | ||
if (mem) { | ||
this.properties.init(mem); | ||
mem.hash = k; | ||
} | ||
return mem ? mem : undefined; | ||
else if (coercedOptions?.ignoreMissing !== true) { | ||
throw new Error("Failed to load entry from head with hash: " + k); | ||
} | ||
this.cache.add(k, mem ?? undefined); | ||
} | ||
return undefined; | ||
return mem ? mem : undefined; | ||
/* } | ||
return undefined; */ | ||
} | ||
@@ -317,0 +320,0 @@ async resolveFromStore(k, options) { |
@@ -100,3 +100,3 @@ import { type Blocks } from "@peerbit/blocks-interface"; | ||
delete(store: Blocks): Promise<void>; | ||
static createGid(seed?: Uint8Array): Promise<string>; | ||
static createGid(seed?: Uint8Array): Promise<string> | string; | ||
static create<T>(properties: { | ||
@@ -103,0 +103,0 @@ store: Blocks; |
@@ -13,3 +13,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
import {} from "@peerbit/blocks-interface"; | ||
import { AccessError, DecryptedThing, Ed25519PublicKey, MaybeEncrypted, PublicSignKey, SignatureWithKey, X25519Keypair, X25519PublicKey, randomBytes, sha256Base64, } from "@peerbit/crypto"; | ||
import { AccessError, DecryptedThing, Ed25519PublicKey, MaybeEncrypted, PublicSignKey, SignatureWithKey, X25519Keypair, X25519PublicKey, randomBytes, sha256Base64, toBase64, } from "@peerbit/crypto"; | ||
import { verify } from "@peerbit/crypto"; | ||
@@ -300,3 +300,3 @@ import {} from "@peerbit/keychain"; | ||
static createGid(seed) { | ||
return sha256Base64(seed || randomBytes(32)); | ||
return seed ? sha256Base64(seed) : toBase64(randomBytes(32)); | ||
} | ||
@@ -303,0 +303,0 @@ static async create(properties) { |
@@ -74,2 +74,6 @@ import { type AnyStore } from "@peerbit/any-store"; | ||
}; | ||
type PendingDelete<T> = { | ||
entry: ShallowOrFullEntry<T>; | ||
fn: () => Promise<ShallowEntry | undefined>; | ||
}; | ||
export declare class Log<T> { | ||
@@ -226,10 +230,4 @@ private _id; | ||
}; | ||
}[], skipFirst?: boolean): Promise<{ | ||
entry: ShallowOrFullEntry<T>; | ||
fn: () => Promise<ShallowEntry | undefined>; | ||
}[]>; | ||
prepareDelete(hash: string): Promise<{ | ||
entry: ShallowEntry; | ||
fn: () => Promise<ShallowEntry | undefined>; | ||
} | { | ||
}[], skipFirst?: boolean): Promise<PendingDelete<T>[]>; | ||
prepareDelete(hash: string): Promise<PendingDelete<T> | { | ||
entry: undefined; | ||
@@ -236,0 +234,0 @@ }>; |
@@ -390,3 +390,3 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { | ||
}); | ||
const removed = await this.processEntry(entry); | ||
const pendingDeletes = await this.processEntry(entry); | ||
entry.init({ encoding: this._encoding, keychain: this._keychain }); | ||
@@ -396,5 +396,6 @@ const trimmed = await this.trim(options?.trim); | ||
for (const entry of trimmed) { | ||
removed.push(entry); | ||
pendingDeletes.push({ entry, fn: undefined }); | ||
} | ||
} | ||
const removed = pendingDeletes.map((x) => x.entry); | ||
const changes = { | ||
@@ -405,2 +406,3 @@ added: [{ head: true, entry }], | ||
await (options?.onChange || this._onChange)?.(changes); | ||
await Promise.all(pendingDeletes.map((x) => x.fn?.())); | ||
return { entry, removed }; | ||
@@ -605,9 +607,10 @@ } | ||
}); | ||
const removed = await this.processEntry(entry); | ||
const pendingDeletes = await this.processEntry(entry); | ||
const trimmed = await this.trim(options?.trim); | ||
if (trimmed) { | ||
for (const entry of trimmed) { | ||
removed.push(entry); | ||
pendingDeletes.push({ entry, fn: undefined }); | ||
} | ||
} | ||
const removed = pendingDeletes.map((x) => x.entry); | ||
await options?.onChange?.({ | ||
@@ -621,2 +624,3 @@ added: [{ head: options.isHead, entry }], | ||
}); | ||
await Promise.all(pendingDeletes.map((x) => x.fn?.())); | ||
return true; | ||
@@ -626,3 +630,3 @@ } | ||
if (entry.meta.type === EntryType.CUT) { | ||
return this.deleteRecursively(entry, true); | ||
return this.prepareDeleteRecursively(entry, true); | ||
} | ||
@@ -684,3 +688,3 @@ return []; | ||
await this._trim.deleteFromCache(hash); | ||
const removedEntry = await this._entryIndex.delete(hash, entry.value); | ||
const removedEntry = (await this._entryIndex.delete(hash, entry.value)); | ||
return removedEntry; | ||
@@ -687,0 +691,0 @@ }, |
{ | ||
"name": "@peerbit/log", | ||
"version": "4.0.21", | ||
"version": "4.0.22", | ||
"description": "Append-only log CRDT", | ||
@@ -65,7 +65,7 @@ "author": "dao.xyz", | ||
"@peerbit/cache": "2.1.0", | ||
"@peerbit/blocks-interface": "^1.3.7", | ||
"@peerbit/blocks-interface": "^1.3.8", | ||
"@peerbit/crypto": "2.3.2", | ||
"@peerbit/logger": "1.0.3", | ||
"@peerbit/time": "2.0.7", | ||
"libp2p": "^2.2.1", | ||
"libp2p": "^2.3.1", | ||
"p-queue": "^8.0.1", | ||
@@ -75,6 +75,6 @@ "path-browserify": "^1.0.1", | ||
"@peerbit/indexer-interface": "^2.0.1", | ||
"@peerbit/indexer-simple": "^1.1.3" | ||
"@peerbit/indexer-simple": "^1.1.4" | ||
}, | ||
"devDependencies": { | ||
"@peerbit/test-utils": "2.1.9", | ||
"@peerbit/test-utils": "2.1.10", | ||
"@types/yallist": "^4.0.4", | ||
@@ -81,0 +81,0 @@ "assert": "^2.0.0", |
@@ -8,2 +8,3 @@ import { deserialize, serialize } from "@dao-xyz/borsh"; | ||
type Index, | ||
type IndexedResults, | ||
Not, | ||
@@ -33,3 +34,2 @@ Or, | ||
const ENTRY_CACHE_MAX_SIZE = 10; // TODO as param for log | ||
type ResolveFullyOptions = | ||
@@ -179,2 +179,15 @@ | true | ||
const results = await iterator.next(amount); | ||
return coerce(results); | ||
}; | ||
const all = async (): Promise<ReturnTypeFromResolveOptions<R, T>[]> => { | ||
const results = await iterator.all(); | ||
return coerce(results); | ||
}; | ||
const coerce = async ( | ||
results: IndexedResults<{ | ||
[x: string]: any; | ||
}>, | ||
): Promise<ReturnTypeFromResolveOptions<R, T>[]> => { | ||
if (resolveInFull) { | ||
@@ -200,12 +213,3 @@ const maybeResolved = await Promise.all( | ||
next, | ||
all: async () => { | ||
const results: ReturnTypeFromResolveOptions<R, T>[] = []; | ||
while (!iterator.done()) { | ||
for (const element of await next(100)) { | ||
results.push(element); | ||
} | ||
} | ||
await iterator.close(); | ||
return results; | ||
}, | ||
all, | ||
}; | ||
@@ -271,2 +275,6 @@ } | ||
async has(k: string) { | ||
let mem = this.cache.get(k); | ||
if (mem) { | ||
return true; | ||
} | ||
const result = await this.properties.index.get(toId(k), { | ||
@@ -309,4 +317,2 @@ shape: { hash: true }, | ||
const fn = async () => { | ||
this.cache.add(entry.hash, entry); | ||
if (properties.unique === true || !(await this.has(entry.hash))) { | ||
@@ -316,2 +322,5 @@ this._length++; | ||
// add cache after .has check before .has uses the cache | ||
this.cache.add(entry.hash, entry); | ||
await this.properties.index.put(entry.toShallow(properties.isHead)); | ||
@@ -375,11 +384,11 @@ | ||
async delete(k: string, shallow: ShallowEntry | undefined = undefined) { | ||
async delete(k: string, from?: Entry<any> | ShallowEntry) { | ||
this.cache.del(k); | ||
if (shallow && shallow.hash !== k) { | ||
if (from && from.hash !== k) { | ||
throw new Error("Shallow hash doesn't match the key"); | ||
} | ||
shallow = shallow || (await this.getShallow(k))?.value; | ||
if (!shallow) { | ||
from = from || (await this.getShallow(k))?.value; | ||
if (!from) { | ||
return; // already deleted | ||
@@ -395,4 +404,4 @@ } | ||
// mark all next entries as new heads | ||
await this.privateUpdateNextHeadProperty(shallow, true); | ||
return shallow; | ||
await this.privateUpdateNextHeadProperty(from, true); | ||
return from; | ||
} | ||
@@ -468,17 +477,17 @@ } | ||
let coercedOptions = typeof options === "object" ? options : undefined; | ||
if (await this.has(k)) { | ||
let mem = this.cache.get(k); | ||
if (mem === undefined) { | ||
mem = await this.resolveFromStore(k, coercedOptions); | ||
if (mem) { | ||
this.properties.init(mem); | ||
mem.hash = k; | ||
} else if (coercedOptions?.ignoreMissing !== true) { | ||
throw new Error("Failed to load entry from head with hash: " + k); | ||
} | ||
this.cache.add(k, mem ?? undefined); | ||
/* if (await this.has(k)) { */ | ||
let mem = this.cache.get(k); | ||
if (mem === undefined) { | ||
mem = await this.resolveFromStore(k, coercedOptions); | ||
if (mem) { | ||
this.properties.init(mem); | ||
mem.hash = k; | ||
} else if (coercedOptions?.ignoreMissing !== true) { | ||
throw new Error("Failed to load entry from head with hash: " + k); | ||
} | ||
return mem ? mem : undefined; | ||
this.cache.add(k, mem ?? undefined); | ||
} | ||
return undefined; | ||
return mem ? mem : undefined; | ||
/* } | ||
return undefined; */ | ||
} | ||
@@ -485,0 +494,0 @@ |
@@ -22,2 +22,3 @@ import { | ||
sha256Base64, | ||
toBase64, | ||
} from "@peerbit/crypto"; | ||
@@ -391,4 +392,4 @@ import { verify } from "@peerbit/crypto"; | ||
static createGid(seed?: Uint8Array): Promise<string> { | ||
return sha256Base64(seed || randomBytes(32)); | ||
static createGid(seed?: Uint8Array): Promise<string> | string { | ||
return seed ? sha256Base64(seed) : toBase64(randomBytes(32)); | ||
} | ||
@@ -395,0 +396,0 @@ |
@@ -107,2 +107,7 @@ import { deserialize, field, fixedArray, variant } from "@dao-xyz/borsh"; | ||
type PendingDelete<T> = { | ||
entry: ShallowOrFullEntry<T>; | ||
fn: () => Promise<ShallowEntry | undefined>; | ||
}; | ||
@variant(0) | ||
@@ -540,3 +545,6 @@ export class Log<T> { | ||
const removed: ShallowOrFullEntry<T>[] = await this.processEntry(entry); | ||
const pendingDeletes: ( | ||
| PendingDelete<T> | ||
| { entry: Entry<T>; fn: undefined } | ||
)[] = await this.processEntry(entry); | ||
@@ -549,6 +557,6 @@ entry.init({ encoding: this._encoding, keychain: this._keychain }); | ||
for (const entry of trimmed) { | ||
removed.push(entry); | ||
pendingDeletes.push({ entry, fn: undefined }); | ||
} | ||
} | ||
const removed = pendingDeletes.map((x) => x.entry); | ||
const changes: Change<T> = { | ||
@@ -560,2 +568,3 @@ added: [{ head: true, entry }], | ||
await (options?.onChange || this._onChange)?.(changes); | ||
await Promise.all(pendingDeletes.map((x) => x.fn?.())); | ||
return { entry, removed }; | ||
@@ -799,3 +808,2 @@ } | ||
})); | ||
if (!nested) { | ||
@@ -831,3 +839,6 @@ throw new Error("Missing entry in joinRecursively: " + a); | ||
const removed: ShallowOrFullEntry<T>[] = await this.processEntry(entry); | ||
const pendingDeletes: ( | ||
| PendingDelete<T> | ||
| { entry: Entry<T>; fn: undefined } | ||
)[] = await this.processEntry(entry); | ||
const trimmed = await this.trim(options?.trim); | ||
@@ -837,6 +848,8 @@ | ||
for (const entry of trimmed) { | ||
removed.push(entry); | ||
pendingDeletes.push({ entry, fn: undefined }); | ||
} | ||
} | ||
const removed = pendingDeletes.map((x) => x.entry); | ||
await options?.onChange?.({ | ||
@@ -851,8 +864,14 @@ added: [{ head: options.isHead, entry }], | ||
await Promise.all(pendingDeletes.map((x) => x.fn?.())); | ||
return true; | ||
} | ||
private async processEntry(entry: Entry<T>): Promise<ShallowEntry[]> { | ||
private async processEntry(entry: Entry<T>): Promise< | ||
{ | ||
entry: ShallowOrFullEntry<T>; | ||
fn: () => Promise<ShallowEntry | undefined>; | ||
}[] | ||
> { | ||
if (entry.meta.type === EntryType.CUT) { | ||
return this.deleteRecursively(entry, true); | ||
return this.prepareDeleteRecursively(entry, true); | ||
} | ||
@@ -891,6 +910,3 @@ return []; | ||
let counter = 0; | ||
const toDelete: { | ||
entry: ShallowOrFullEntry<T>; | ||
fn: () => Promise<ShallowEntry | undefined>; | ||
}[] = []; | ||
const toDelete: PendingDelete<T>[] = []; | ||
@@ -930,6 +946,3 @@ while (stack.length > 0) { | ||
hash: string, | ||
): Promise< | ||
| { entry: ShallowEntry; fn: () => Promise<ShallowEntry | undefined> } | ||
| { entry: undefined } | ||
> { | ||
): Promise<PendingDelete<T> | { entry: undefined }> { | ||
let entry = await this._entryIndex.getShallow(hash); | ||
@@ -943,3 +956,6 @@ if (!entry) { | ||
await this._trim.deleteFromCache(hash); | ||
const removedEntry = await this._entryIndex.delete(hash, entry.value); | ||
const removedEntry = (await this._entryIndex.delete( | ||
hash, | ||
entry.value, | ||
)) as ShallowEntry; | ||
return removedEntry; | ||
@@ -946,0 +962,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
393620
7710
208
34
53
142
Updatedlibp2p@^2.3.1