Multi-threaded 64bit memory cache database inspired by redis-like features
npm install ram64ram64:
Map key requirements that exceed the 2^24 limits of V8
ram64:
Map
10us (0.010ms)
50us.
ram64.
npm run bench for a comprehensive look at throughput on your hardware,
ram64 instance is only permitted on the main thread, and is
import { startup } from 'ram64';
const ram64 = await startup();
`
Of course we can perform any operation from the main instance, but for
best performance you'll want to spawn your own workers and connect to the
main instance like so:
`
// main.js
import { Worker } from 'worker_threads';
import { startup } from 'ram64';
const ram64 = await startup();
const worker = ram64.spawnWorker('./worker.js', {
onMessage: msg => {
if (msg?.status === 'done') worker.terminate(); // test complete!
}
});
// optionally you can spawn your own worker and
// invoke ram64.registerWorker(worker) instead
`
`
// worker.js
const { workerData, parentPort } = require('worker_threads');
const { connect } = require('ram64');
connect(workerData.connectKey).then(async ram64 => {
await ram64.set('hello', 'world');
const world = await ram64.get('hello');
parentPort.postMessage({ status: 'done' });
});
`
Exports
* startup(StartupOptions): Promise - Create a new RAM64 instance.
* StartupOptions.threadCount: number (default: CPU_CORES) - Number of dedicated
cache workers to spread load/shards over. Tunable based on your usage, but
default should generally suffice.
* StartupOptions.shardCount: number (default 100000) - The default is typically
sufficient to handle any memory requirements of 2TB and beyond.
* StartupOptions.maxMemory: number - By default LRU Eviction
is not enabled. You must specify a maxMemory threshold (in bytes) in
order for LRU Eviction to maintain the desired memory usage across
the entire process.
* StartupOptions.concurrency: number (default: 50) - Concurrent operations
per client instance. Anything higher will be queued.
* connect(connectKey: string, ConnectOptions): Promise - Connect to an existing
RAM64 instance from a worker thread.
* connectKey: string - Required to connect to an existing RAM64 instance.
* ConnectOptions.concurrency (default: 50) - Concurrent operations
per client instance. Anything higher will be queued.
* isRAM64Message(msg): boolean - Useful if you need to distinguish between
Worker messages from RAM64 and your own custom messages.
* RAMFunction - See RAMFunction API.
RAM64 API
Methods and properties of the RAM64 class. All operations are atomic.
* connectKey: string - Key required by connect.
* shutdown(): Promise - Shutdown the RAM64 instance and cleanup resources.
* save(dirPath: string): Promise - Save data to disk. One file will be created
for every shard, defined by shardCount. While it's safe to perform a save
while reads/writes are in progress, it's not recommended if you can avoid it as
the impact to performance/throughput will be considerable for large datasets.
* load(dirPath: string): Promise - Load shards from disk. To avoid data loss,
it's critical that you only load data from a dataset that was configured with
the same shardCount. Safe to load while actively reading/writing to cache,
at the cost to performance. Key collisions are also safe, and last write wins.
* spawnWorker(workerPath: string, options: RegisterWorkerOptions = {}): Worker -
Spawn your own worker process that you want to connect from. This will
automatically handle registering the worker, so do not invoke registerWorker again.
* RegisterWorkerOptions.onMessage: (msg: any) => void - Optionally register to
receive worker messages. More convenient than registering yourself as it
routes ram64 events internally and only forwards your own events to you.
* registerWorker(worker: Worker, options: RegisterWorkerOptions = {}): void - If
you spawn your own worker but would like to connect to a RAM64 instance, use this
function to wireup the parent to the worker.
* RegisterWorkerOptions.onMessage: (msg: any) => void - Optionally register to
receive worker messages. More convenient than registering yourself as it
routes ram64 events internally and only forwards your own events to you.
* registerFunction(fn: RAMFunction): Promise - Register
a dynamic function that can be executed by operations that support
it. See RAMFunction API for more details.
* exists(key: string): Promise - Returns true if the key exists.
* get(key: string): Promise - Get the value by key.
* getKeyCount(): Promise - Return the total number of keys across all shards.
* getMany(keys: string[]): Promise - Get many values by keys.
* getAndSet(key: string, staleFn: (obj: CacheObject) => Promise - Get the current value, and if the value is
stale invoke the stale function to lazily update the cache.
* getSet(key: string, value: any): Promise - Set the value on a key and return the old value.
* getWithOptions(key: string): Promise - Get the entire
cache object, value and options.
* touch(key: string): Promise - Bring the cache object
to the front to prevent LRU eviction, and return the cache object.
* set(key: string, value: any): Promise - Set the cache value.
* setIfValue(key: string, expectedValue: any, value: any): Promise -
Overwrite the current cache value only if the value has unchanged.
* setFn(key: string, fn: RAMFunction, params: any): Promise - Set
the value of the cache via a dynamic RAMFunction. This allows for conditional
updates, patching, or other custom logic of your choosing.
* setMany(sets: [string, any][]): Promise - Same as set, but
for many cache entries (that can span many shards/threads).
* setOptions(key: string, options: CacheOptions): Promise - Only set the
options on the cache object, not it's value.
* setWithOptions(key: string, value: CacheObject): Promise - Set the
value and options of the cache object.
* insert(key: string, value: any): Promise - Insert the cache value only
if it doesn't already exist.
* del(key: string): Promise - Delete a cache object and return true
if there was an object to remove.
* deleteAll(): Promise - Delete all cache objects across all shards.
* strAppend(key: string, value: string): Promise - Append a string to
the existing string value. Defaults to empty string if existing value
is not a string.
* strPrepend(key: string, value: string): Promise - Prepend a string to
the existing string value. Defaults to empty string if existing value
is not a string.
* strLength(key: string): Promise - Return the length of the cache value.
Defaults to empty string if existing value is not a string.
* strSetRange(key: string, offset: number, value: string): Promise -
Insert a string at the desired location. Defaults to empty string if existing value is not a string.
* strGetRange(key: string, start: number, end: number): Promise - Get
the value of a string between the start and end indexes. Defaults to empty string if existing value is not a string.
* strReplace(key: string, replace: string|RegExp, value: string): Promise
- Replace part of the current value (using string or expression) with the new
value. Defaults to empty string if existing value is not a string.
* numAdd(key: string, value: number, defaultValue: number = 0): Promise -
Add number to the existing value. If the value is not a number or doesn't
exist, will use the defaultValue.
* numSub(key: string, value: number, defaultValue: number = 0): Promise -
Subtract number to the existing value. If the value is not a number or doesn't
exist, will use the defaultValue.
* numMult(key: string, value: number, defaultValue: number = 0): Promise -
Multiply number to the existing value. If the value is not a number or doesn't
exist, will use the defaultValue.
* numDiv(key: string, value: number, defaultValue: number = 0): Promise -
Divide number to the existing value. If the value is not a number or doesn't
exist, will use the defaultValue.
* setGetMembers(key: string): Promise - Return the
entire Set.
* setAddMembers(key: string, members: (number|string)[]): Promise - Add one
or more members to the Set, ignoring duplicates. Will default to an empty
Set if not already.
* setRemoveMembers(key: string, members: (number|string)[]): Promise - Remove
members from the Set. Will default to an empty Set if not already.
* setGetMemberCount(key: string): Promise - Return the number of
members in the Set, or undefined if it does not exist.
* setHasMembers(key: string, members: (number|string)[]): Promise - Returns
the number of matched members.
* mapGetKeys(key: string): Promise - Return only the
keys from the Map.
* mapGetValues(key: string, keys: string[]): Promise - Return the values of
the requested keys.
* mapGetFields(key: string): Promise