UNPKG

@jawis/shared-buffer-store

Version:

Store for variable sized buffers to use in concurrent programs.

102 lines (101 loc) 3.71 kB
import { BufferStore } from "^shared-algs"; import { HeaderUtil, HeaderUtilDeps, MetaData, MetaDataDeps } from "./internal"; export type AppendOnlyBufferStoreDeps = { sharedArray: Uint8Array; byteSize: number; direction: "left" | "right"; } & MetaDataDeps & HeaderUtilDeps; /** * - Delete is only logically. Deleted nodes will still take space in memory. * - Can store the heap in left or right direction. Meaning the heap grows from a fix point in either * left or right direction. * * memory layout (from fix point) * meta data (from left) * 4 bytes buffer count * 4 bytes used bytes * buffers (repeated) * * right buffers layout (from fix point) * header (from left) * 1 byte header length * 1 byte memory alignment (1, 2, 4 or 8) * 1 byte version (for integrity) * 4 bytes buffer length * x bytes padding * data (from left) * n bytes * * structure of reference (heighest bits first) * 28 bits buffer index * 4 bits integrity version * * impl * - Free pointer points at the first unused byte. * - Index is the position of the header in the array. In left direction, the data is to the left and * the header is to the right. In right direction, both data and header is to the right of the index. * - Left and right direction will not yield symmetric memory layout. * - The reason a symmetry isn't desirable is the header is used to align the data's left edge. But we don't * know if the sharedArray has 8-byte aligned right edge. It's also too burdensome to write the data in reverse * direction, and without benefit. Also there's no benefit of writing the header in reverse direction. * - In left direction, the header and data section are ordered the same seen from left. As the right is seen from right. * But the data within the two sections is still stored from left to right. * * * notes * - Only supports Uint8Array. But support for other sizes is started. * * todo * - There is only need for a lock when adding, because only this operation needs to update meta data. * - But what about delete and get? They interfere * * notes on resize * - To keep it simple resize is not possible. In order to support resize, a map: `ref => index` is needed. * So references returned to user can be remapped to new indexes on resize. * - Would it be possible to return indexes to the user instead, and then have a cut of, where indexes above * are remapped. This way it's a single operation to determine if a value is remapped, and * the remapping could be partial: `invalid index => valid index`. Compaction would not be possible in * this design, or at least more complex. * */ export declare class AppendOnlyBufferStore implements BufferStore { deps: AppendOnlyBufferStoreDeps; metaData: MetaData; headerUtil: HeaderUtil; /** * */ constructor(deps: AppendOnlyBufferStoreDeps); /** * partial */ pack: () => { direction: "left" | "right"; byteSize: number; sharedArray: Uint8Array; initialized: true; }; /** * */ get count(): number; /** * */ get: (ref: number) => Uint8Array; /** * */ add: (buffer: Uint8Array) => number; /** * Throws when reference is unknown or already deleted. */ delete: (ref: number) => void; /** * * notes * - it's not possible to have count as just an atomic variable, because free pointer * can't be updated atomically. But we could update free pointer optimistically with retry. */ private _allocHelper; }