The Protocol Buffers (PBC) side of the fake Riak endpoint.
Every message is framed as <<length::32-big, msg_code::8, payload>> where
length counts the code byte plus the protobuf payload. Supported messages:
| Code | Request | Reply |
|---|---|---|
| 1 | RpbPingReq | 2 RpbPingResp |
| 3 | RpbGetClientIdReq | 4 RpbGetClientIdResp (static id) |
| 5 | RpbSetClientIdReq | 6 RpbSetClientIdResp (ignored) |
| 7 | RpbGetServerInfoReq | 8 RpbGetServerInfoResp |
| 9 | RpbGetReq | 10 RpbGetResp (empty when absent) |
| 11 | RpbPutReq | 12 RpbPutResp |
| 13 | RpbDelReq | 14 RpbDelResp (always succeeds) |
| 15 | RpbListBucketsReq | 16 RpbListBucketsResp (single frame) |
| 17 | RpbListKeysReq | 18 RpbListKeysResp (single frame) |
| 19 | RpbGetBucketReq | 20 RpbGetBucketResp (static props) |
| 21 | RpbSetBucketReq | 22 RpbSetBucketResp (ignored) |
| 25 | RpbIndexReq | 26 RpbIndexResp (single frame) |
| 29 | RpbResetBucketReq | 30 RpbResetBucketResp (ignored) |
| 31 | RpbGetBucketTypeReq | 20 RpbGetBucketResp (static props) |
| 32 | RpbSetBucketTypeReq | 22 RpbSetBucketResp (ignored) |
| 50 | RpbCounterUpdateReq | 51 RpbCounterUpdateResp |
| 52 | RpbCounterGetReq | 53 RpbCounterGetResp |
| 80 | DtFetchReq | 81 DtFetchResp |
| 82 | DtUpdateReq | 83 DtUpdateResp |
| 253 | RpbAuthReq | 254 RpbAuthResp (always succeeds) |
| 255 | RpbStartTls | 255, then a TLS handshake |
Any other code gets an RpbErrorResp (0) and the connection stays open.
There is no real security model: RpbAuthReq accepts any username and
password (or none) and always replies with success, so clients configured
for auth against a real Riak cluster still work against the fake one.
Bucket properties are not modelled: RpbSetBucketReq and friends are
accepted and ignored, and RpbGetBucketReq reports a fixed set of props that
happen to describe how the fake actually behaves — a default n_val with
allow_mult true, since vclock-less puts accumulate as siblings. The client
id is cosmetic too: the vclock is a static opaque token that never depends on
an actor id, so RpbSetClientIdReq is ignored and RpbGetClientIdReq returns
a fixed id.
Objects are stored as their raw RpbContent.value in the same bucketed
FakeRiak.SimpleStore space the HTTP API uses, so the two APIs see each
other's writes. Each key holds a list of siblings: an RpbPutReq without a
vclock (field 3) is a blind write that appends a new sibling, while one that
carries a vclock resolves the key down to the single value it sends. An
RpbGetResp returns every sibling as a repeated RpbContent in field 1.
Vector clocks are a static opaque token: clients only ever echo them back, so
it is their presence on a put — not their content — that signals resolution.
Legacy counters (RpbCounterUpdateReq/RpbCounterGetReq) are Riak's pre-CRDT
counters. They live in a separate signed-integer keyspace in SimpleStore,
not the object space above: an update adds a signed sint64 amount to the
current value (0 if unset), and a get of a counter that was never updated
yields an empty response, the way real Riak reports an unset counter.
Secondary indexes (2i) are PBC-only here — the HTTP side does not implement
them. Indexes ride along on the object: an RpbPutReq carries them as field
10 of its RpbContent (a repeated RpbPair of index name and term), and the
put path stashes them per (bucket, key) in SimpleStore, following the
put's own merge mode (a vclock-resolving put overwrites the entries, a blind
sibling put unions them). Deleting the key drops its entries. RpbIndexReq
answers eq and range queries as a single done-framed RpbIndexResp (the
degenerate stream clients accept); index names ending in _int compare
numerically, everything else lexicographically. return_terms adds the
matching {term, key} pairs as results; the paging options
(max_results/continuation/term_regex/…) are not honored.
CRDT data types (DtFetchReq/DtUpdateReq) cover counter, set and gset;
map and hll are out of scope and their update ops return an error. A real
Riak learns a key's datatype from the bucket-type config, which the fake does
not have, so an update infers it from the op present (counter_op/set_op/
gset_op) and stores the tag so a fetch reports the right type. Data is
keyed by (bucket-type, bucket, key) in a separate SimpleStore keyspace.
The context is a static opaque token like the vclock — clients only echo it
back — so set removes are best-effort (they apply directly, with no real
causal context), and a gset only grows. A fetch of a key that was never
updated is a "not found" reported as the default COUNTER type with no value.
This module is not wired to a listener itself: FakeRiak.Riak detects PBC
framing on the first byte of a connection and delegates here, passing its
own dispatch state through untouched (requests are independent, so no state
of our own is needed).
Summary
Functions
Wrap a message code and protobuf payload in a PBC frame.