Trafikist · module 05
TRA and native values
The module’s second family: two metadata commands, four bitmap commands on ordinary strings, a versioned C table for other modules and three bundled Lua sources. A bitmap lives in a string; no native value type is registered.
trafikey registers two families from one table.
EMQ.* carries the job core and the bus's three writes and runs the command grammar;
TRA.*
is the other six rows, and it runs a grammar of its own: no numkeys, no fence, no brand read. Two
TRA commands report the module’s metadata, and four read and write the bits of one
ordinary string key, the high bit of byte 0 first. Of the six, TRA.SETBIT is the only
one that writes a key, and it replicates the command itself, where every EMQ write
replicates as its effects. Beside the commands the module exports a versioned C table that hands other modules
the bundled Lua sources, and installing those sources stays an explicit act. A native bitmap value type does
not exist: the default build registers no module data type, and the one data type in the source is a
persistence probe behind a feature that is off by default. Pick a command to read its arguments, its reply and
what it writes.
The second family
The six TRA rows follow the EMQ rows in
registry::TABLE and register the same way: one row, one command, with its flags,
its key-spec and its ACL categories. The
registration table reads the rows. What runs inside differs. A TRA handler takes
no numkeys, reads no {emq}:version, runs no fence and calls no
begin_writes: the server checks the arity, the handler parses its arguments, and a
bitmap command opens its one key. The two metadata commands open no key at all.
The six TRA commands · pick one
key: reads one ordinary string; a missing key reads as empty
writes: writes that string in place, grown with zero bytes when the bit lies past the end; an unchanged bit inside the string writes nothing
reply: the previous bit, 0 or 1
refusals: ERR TRA invalid-offset · ERR TRA invalid-argument · ERR TRA limit · WRONGTYPE
replicated: the command itself, verbatim, with a setbit keyspace event, whenever it writes
grammar: no numkeys, no fence, no brand read
Six commands, one string key at most, and no fence: TRA shares the
module’s table and loader, not its grammar.
Two metadata commands
TRA.CAPABILITIES and TRA.INFO take no argument and read no
key. Each answers a map built in insertion order: a RESP3 map, or on a RESP2 connection the same pairs as one
flat array. TRA.CAPABILITIES reports eight pairs: the module’s name, the
TRA metadata version string, a stage, the shared API version, the bitmap command
count, and three facts about the shared API and the bundled Lua. The bitmap count is
not a constant. It is counted from the registered TRA rows that carry the
bitmap token, so a build without one of the four rows reports three.
TRA.INFO, flagged admin, reports the name, the same version
string and two call counters.
// trafikey — tra::capabilities and tra::info, the two metadata commands, with the counter they bump fn increment(value: &AtomicU64) { // Counters saturate rather than wrapping to an apparently fresh observation. let _ = value.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |old| { Some(old.saturating_add(1)) }); } // … pub(crate) fn capabilities(ctx: &Context, _: Vec<ValkeyString>) -> ValkeyResult { increment(&CAPS_CALLS); // Derived from the registration table: only registered bitmap rows are counted. let bitmap_commands = registry::capabilities(Family::Tra, |name| registry::registered(ctx, name)) .filter(|token| *token == "bitmap") .count() as i64; reply_pairs( ctx, &[ (b"module", Field::Text(b"trafikey")), (b"version", Field::Text(b"0.1.0-tra1")), (b"stage", Field::Text(b"abi-lua-preview")), (b"api_version", Field::Int(1)), (b"bitmap_commands", Field::Int(bitmap_commands)), (b"shared_api", Field::Int(1)), (b"bundled_lua", Field::Int(1)), (b"lua_scripts", Field::Int(3)), ], ) } pub(crate) fn info(ctx: &Context, _: Vec<ValkeyString>) -> ValkeyResult { increment(&INFO_CALLS); reply_pairs( ctx, &[ (b"module", Field::Text(b"trafikey")), (b"version", Field::Text(b"0.1.0-tra1")), ( b"capabilities_calls", Field::Int(bounded_count(&CAPS_CALLS)), ), (b"info_calls", Field::Int(bounded_count(&INFO_CALLS))), ], ) }
The counters are two atomics in process memory: they start at zero in each server
process and stop at the top of their range instead of wrapping to a value that would read as fresh. The
version string these two commands report belongs to TRA alone; it is neither the
version in the module declaration nor the crate version EMQ.VERSION reports. On the
stand’s module node TRA.CAPABILITIES answers those eight pairs in the order
above, and TRA.CAPABILITIES x gets the server’s own
ERR wrong number of arguments reply.
The metadata commands describe the module without touching the keyspace, and even the bitmap count is read from the table.
One write, replicated verbatim
TRA.SETBIT is the only TRA command that writes a key. When
it changes a bit, or grows the string to reach one, it writes the string’s bytes in place, raises a
setbit keyspace event in the string class, and has the server replicate the
command verbatim: the AOF and the replicas receive TRA.SETBIT with the arguments the
client sent. A call that leaves a bit inside the string as it was writes nothing and replicates nothing.
// trafikey — tra::bitmap::setbit, its two exits // Equal bit without growth is not a logical mutation: no write, no replication, no WATCH touch. if !grows && previous == bit { return Ok(ValkeyValue::Integer(i64::from(previous))); } // … the string reopened for writing, grown when needed, the bit set or cleared raw::close_key(key); ctx.notify_keyspace_event(NotifyEvent::STRING, "setbit", name); ctx.replicate_verbatim(); Ok(ValkeyValue::Integer(i64::from(previous)))
Every EMQ write goes the other way. An
EMQ handler calls the server itself with the ! flag, so each
write it makes, an HSET, a ZADD, a
ZREM, reaches the AOF and the replicas as that write, and the writes of one command
arrive inside one MULTI/EXEC. An EMQ
handler never replicates its own command. One
guard, then effects reads that path.
The AOF of a TRA.SETBIT holds TRA.SETBIT; the AOF
of an EMQ write holds the writes it made.
A C table and three sources
The library carries three Lua files compiled into it: a capabilities wrapper, a bounded bitmap count over an
ordinary string, and a Function library that holds both. The last step of init
exports one C getter, trafikey_get_api_v1, under that name. Another module in the
same server requests it by name, negotiates a version and a size, and receives a read-only table whose
functions hand back the source bytes by id. Nothing in the module loads a script or a library into the
server: an authorized caller does that with SCRIPT LOAD or
FUNCTION LOAD. The second dive reads the table and the three sources.
The module ships its Lua as bytes; putting a script into the server is someone else’s authorized step.
No native value type
Every TRA bitmap is an ordinary string the server owns. The module declaration
registers no data type and lists no commands of its own; every command arrives through the table. The only
module data type in the source, traprobe1, compiles under the
probe-type feature, which the crate does not turn on by default. It exists to prove
that a module type with RDB save and load and AOF rewrite survives a restart, and it is never part of a
shipped artifact.
// trafikey — the module declaration: no data types, no commands of its own
valkey_module! {
name: "trafikey",
version: 100,
allocator: (ValkeyAlloc, ValkeyAlloc),
data_types: [],
preload: preload,
init: init,
commands: [],
}
Today a TRA bitmap is a string the server stores and saves like any
other; the module owns the commands, not the value.
The dives
Three dives read the family in the real trafikey sources: the bitmap commands, the
C table with the Lua it hands out, and the value type that is not there.
Bitmaps on strings
TRA.SETBIT, GETBIT, STRLEN and BITCOUNT over string keys, high bit first; every key type but a string answers WRONGTYPE, classified from the raw type value so a Valkey 9.2 key cannot abort the server.
The shared ABI and bundled Lua
A versioned C table hands other modules the three bundled Lua sources by id; installing them stays an explicit SCRIPT LOAD or FUNCTION LOAD.
The native value type
A probe type behind an off-by-default feature proves RDB and AOF persistence; the bitmap value type is designed, not built.
Pattern & implementation
Where Redis Patterns Applied teaches a bitmap as one string with a flag per bit, this module reads the module commands that work on exactly such a string.
A bitmap is one string whose bit N is the flag for entity N, set and read in place and counted without enumerating the entities. Bitmaps teaches it.
Four TRA commands over that ordinary string, high bit first, with their own
parsers and refusals and the one write replicated verbatim; two metadata commands; a C table and three Lua
sources beside them; and no native value type.
Take the dives in order. After the third, the part closes with the workshop, which runs one transition on both executors.
References
Sources
- Valkey — SETBIT — the built-in bit write over a string, the twin of the one TRA write.
- Valkey — GETBIT — the built-in bit read.
- Valkey — BITCOUNT — the built-in population count the bundled Lua calls.
- Valkey — Modules introduction — native code the server loads, which registers commands.
- Valkey — Modules API reference — verbatim replication, keyspace events, shared APIs and module data types.
- Valkey — Replication — what a replica receives from its primary.
Related in this course
- Trafikist — the part this module belongs to.
- The registration table — the six TRA rows and the bitmap count they feed.
- The closed error registry — the EMQ texts, and TRA’s own grammar beside them.
- One guard, then effects — EMQ’s writes replicated as their effects.
- The native module — the Protocol’s bridge into this part.
- redis-patterns · Bitmaps — the near side of the door.