Using Multiple Storages
How to write to multiple storages and repair on read.
Register multiple storages when combining, for example, a fast backend with a durable one.
Register Multiple Storages
Calling persist() multiple times writes to every backend in parallel. Reads check backends in registration order and return the value from the first backend that has it.
import { Memory } from "@unikvs/memory";
import { NodeFs } from "@unikvs/fs.node";
import * as unikvs from "unikvs";
const kvs = new unikvs.Builder<{
profile: unikvs.PlainValue<Uint8Array>;
}>()
.persist(new Memory())
.persist(new NodeFs(".unikvs"))
.build();
In this example, writes go to both memory and files, while reads check memory first.
copy() and move() also apply to every backend where the source exists. If the source exists in only some backends, only those backends are updated. If it exists in none, the operation throws KeyNotFoundError.
Repair on Read
get() and stream() accept repair: true to write values found in later backends back to earlier ones. The default is false.
const bytes = await kvs.get("profile", { repair: true });
To control repair, use @unikvs/allow-repair. On branches that disallow repair, reads still succeed and a warning is logged. To fail reads when repair is denied, pass throwOnRepairDenied: true.
import { AllowRepair } from "@unikvs/allow-repair";
const noRepair = new AllowRepair();
noRepair.disable();
const kvs = new unikvs.Builder<{
profile: unikvs.PlainValue<Uint8Array>;
}>()
.persist(new Memory())
.fork(new unikvs.Branch().use(noRepair).persist(new NodeFs(".unikvs")))
.build();
Vary Transformations per Storage
Use fork() when each branch needs a different middleware combination. Each backend uses a snapshot of the pipeline taken at the time persist() is called. Middleware added after registration therefore does not affect already-registered backends.
import { Json } from "@unikvs/json";
import { Memory } from "@unikvs/memory";
import { NodeFs } from "@unikvs/fs.node";
import * as unikvs from "unikvs";
const kvs = new unikvs.Builder<{
settings: unikvs.PlainValue<Uint8Array>;
}>()
.fork(new unikvs.Branch().use(new Json()).persist(new Memory()))
.persist(new NodeFs(".unikvs"))
.build();
In this example, JSON transformation applies only to the memory side; the file side stores raw bytes.
Related
- For the background, see Architecture.
- For choosing a backend, see Storage Comparison.
- For package-specific notes, see each package reference.