burner-redis #
an embedded, in-process redis-compatible store for zig, ported from the engine in prefectlabs/burner-redis (rust). zig callers use the store directly: there is no server and no wire protocol. the design, command set and semantics are the rust original's.
install #
requires zig 0.17.
zig fetch --save https://tangled.org/zzstoatzz.io/burner-redis/archive/v0.0.5.tar.gz
then in build.zig:
const burner = b.dependency("burner_redis_zig", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("burner_redis", burner.module("burner_redis"));
use #
store — keys, strings, hashes, sets, sorted sets, lists, streams
const burner = @import("burner_redis");
var store = burner.Store.init(allocator, io);
defer store.deinit();
_ = try store.zadd("queue", &.{.{ .score = 1, .member = "task" }}, .{});
const score = try store.zscore("queue", "task"); // ?f64
one method per redis command. which commands, and where they answer differently from redis-server, is in docs/redis-compatibility.md.
scripts — lua 5.1 with redis.call, as EVAL runs it
var lua = burner.scripting.LuaEngine.init(allocator, &store);
defer lua.deinit();
const reply = try lua.eval(arena, "return redis.call('ZCARD', KEYS[1])", &.{"queue"}, &.{});
a script runs with nothing else in between, as in redis. eval leaves its scratch allocations to the allocator it is given: pass an arena.
snapshots — save the keyspace to one file and load it back
try store.save("burner.brdb");
const found = try store.load("burner.brdb"); // false when there is no file
a damaged file is refused with an error and the store left as it was.
pub/sub — channels and patterns, delivered to callbacks
subscribe, psubscribe and publish on Store, in the process only.
design #
- embedded, not served — callers that would otherwise run a redis next to themselves get its data model as a library, with no socket and no serialization.
- one lock for the whole store — redis's single-threaded model, so a
*Storecan be shared between threads and a script holds the lock from its first line to its last. - the same lua a real redis runs — a consumer can send identical scripts to redis-server or to this store and get the same effects.
- the wall clock — deadlines, stream ids and idle times read
std.Io's clock, as redis reads its own.
develop #
zig build test # unit tests
property tests #
the store is checked against a real redis-server: generated histories of commands and of docket's lua scripts are sent to both, and every reply compared. the harness runs on libhegel through hegel-zig, and lives on the pbt/discovery branch so that zig build test needs neither.
git switch pbt/discovery
zig build pbt -Dhegel -Doptimize=ReleaseSafe # needs redis-server, and cargo the first time
a run prints what it exercised by rule, and counts the divergences from redis it already knows by name. the method is written up in hegel-zig's docs.
docs #
docs/ holds the store's layout, its redis compatibility, and its benchmarks against the rust original.
used by #
- docket — its memory backend, running the same lua scripts it sends to redis