UNPKG

@lodestar/beacon-node

Version:

A Typescript implementation of the beacon chain

96 lines (84 loc) 2.65 kB
import {Metrics} from "../metrics/metrics.js"; /** * If consumer wants more memory than available, we grow the buffer by this ratio. */ const GROW_RATIO = 1.1; export enum AllocSource { PERSISTENT_CHECKPOINTS_CACHE_VALIDATORS = "persistent_checkpoints_cache_validators", PERSISTENT_CHECKPOINTS_CACHE_STATE = "persistent_checkpoints_cache_state", ARCHIVE_STATE = "archive_state", } /** * A simple implementation to manage a single buffer. * This is initially used for state serialization at every epoch and for state reload. * We can enhance and use this for other purposes in the future. */ export class BufferPool { private buffer: Uint8Array; private inUse = false; private currentKey: number; private readonly metrics: Metrics["bufferPool"] | null = null; constructor(size: number, metrics: Metrics | null = null) { this.buffer = new Uint8Array(Math.floor(size * GROW_RATIO)); this.currentKey = 0; if (metrics) { this.metrics = metrics.bufferPool; metrics.bufferPool.length.addCollect(() => { metrics.bufferPool.length.set(this.buffer.length); }); } } get length(): number { return this.buffer.length; } /** * Returns a buffer of the given size with all 0. * If the buffer is already in use, return null. * Grow the buffer if the requested size is larger than the current buffer. */ alloc(size: number, source: AllocSource): BufferWithKey | null { return this.doAlloc(size, source, false); } /** * Same to alloc() but the buffer is not zeroed. */ allocUnsafe(size: number, source: AllocSource): BufferWithKey | null { return this.doAlloc(size, source, true); } private doAlloc(size: number, source: AllocSource, isUnsafe = false): BufferWithKey | null { if (this.inUse) { this.metrics?.misses.inc({source}); return null; } this.inUse = true; this.metrics?.hits.inc({source}); this.currentKey += 1; if (size > this.buffer.length) { this.metrics?.grows.inc(); this.buffer = new Uint8Array(Math.floor(size * GROW_RATIO)); } const bytes = this.buffer.subarray(0, size); if (!isUnsafe) { bytes.fill(0); } return new BufferWithKey(bytes, this.currentKey, this); } /** * Marks the buffer as free. */ free(key: number): void { if (key === this.currentKey) { this.inUse = false; } } } export class BufferWithKey implements Disposable { constructor( readonly buffer: Uint8Array, private readonly key: number, private readonly pool: BufferPool ) {} [Symbol.dispose](): void { this.pool.free(this.key); } }