barrel_channel (barrel_docdb v1.1.1)

View Source

Write-time channels: named subsets of a database materialized into per-channel change feeds (prefix 0x1E) as documents are written, so partial sync reads one bounded range scan instead of filtering the global feed.

A channel is a set of MQTT-style patterns over the document's ars topics (field/value, + matches one segment, a trailing # matches the rest). Channels are db create-time config: channels => #{Name => [Pattern]}, compiled at init into persistent_term {barrel_channels, DbName}. Immutable in v1; only writes made after creation are indexed.

Feed semantics: one member row per doc per channel, moved to the doc's current change HLC on every write (the forget-time cleanup relies on row HLC == doc COL_HLC). Deletes land member rows carrying the tombstone in the channels the doc was in. A doc that stops matching gets a leave row (an event, swept by retention); readers skip leave rows unless asked, and replicas simply stop receiving the departed doc (no target-side delete).

Summary

Functions

The configured channels of a database (empty when none).

Validate and compile a channels config map.

Fold one channel's feed since an HLC (exclusive), returning change maps in feed order. Leave rows are skipped unless include_leaves is set (they surface tagged left => true); the returned LastHlc is the last VISITED row, so pagination never re-reads skipped leaves. Options: limit, include_leaves.

Publish a compiled config for a database.

Channels whose pattern set matches any of the given topics.

Batch ops moving a doc's channel rows from OldHlc to NewHlc without recomputing membership: point-read each configured channel at OldHlc and rewrite what exists. This is the concurrent-loser path, where the winner's feed row moves but its body (possibly a tombstone, whose membership cannot be derived) is unchanged. Member rows are re-encoded from DocInfo (fresh rev and conflict count); leave rows move verbatim.

The ars topics of a document body ([] for tombstones).

Batch ops for one applied write. DocInfo carries id, rev, deleted, num_conflicts. Old rows (at OldHlc) are deleted for ALL configured channels: deleting an absent key is a RocksDB no-op, and it removes any old-membership bookkeeping.

Pure variant of write_ops/6: the compiled channel set and the key name are explicit arguments (no persistent_term reads), so it is callable before a database is registered (timeline rewind).

Types

compiled/0

-type compiled() :: #{binary() => [pattern_segments()]}.

config/0

-type config() :: #{binary() => [binary()]}.

pattern_segments/0

-type pattern_segments() :: [binary() | plus | hash].

row/0

-type row() ::
          #{flag := member | leave,
            id := binary(),
            rev := binary(),
            deleted := boolean(),
            num_conflicts := non_neg_integer()}.

Functions

channels(DbName)

-spec channels(binary()) -> compiled().

The configured channels of a database (empty when none).

compile(Config)

-spec compile(term()) -> {ok, compiled()} | {error, term()}.

Validate and compile a channels config map.

decode_row(_)

-spec decode_row(binary()) -> row().

encode_row(Flag, DocInfo)

-spec encode_row(member | leave, map()) -> binary().

fold(StoreRef, DbName0, Channel, Since, Opts)

-spec fold(barrel_store_rocksdb:db_ref(), binary(), binary(), barrel_hlc:timestamp() | first, map()) ->
              {ok, [map()], barrel_hlc:timestamp()}.

Fold one channel's feed since an HLC (exclusive), returning change maps in feed order. Leave rows are skipped unless include_leaves is set (they surface tagged left => true); the returned LastHlc is the last VISITED row, so pagination never re-reads skipped leaves. Options: limit, include_leaves.

install(DbName, Compiled)

-spec install(binary(), compiled()) -> ok.

Publish a compiled config for a database.

match(Compiled, Topics)

-spec match(compiled(), [binary()]) -> [binary()].

Channels whose pattern set matches any of the given topics.

move_ops(Get, DbName, OldHlc, NewHlc, DocInfo)

-spec move_ops(fun((binary()) -> {ok, binary()} | not_found | {error, term()}),
               binary(),
               barrel_hlc:timestamp(),
               barrel_hlc:timestamp(),
               map()) ->
                  [term()].

Batch ops moving a doc's channel rows from OldHlc to NewHlc without recomputing membership: point-read each configured channel at OldHlc and rewrite what exists. This is the concurrent-loser path, where the winner's feed row moves but its body (possibly a tombstone, whose membership cannot be derived) is unchanged. Member rows are re-encoded from DocInfo (fresh rev and conflict count); leave rows move verbatim.

names(DbName)

-spec names(binary()) -> [binary()].

topics(Body)

-spec topics(map() | undefined) -> [binary()].

The ars topics of a document body ([] for tombstones).

uninstall(DbName)

-spec uninstall(binary()) -> ok.

write_ops(DbName, NewHlc, DocInfo, NewTopics, OldHlc, OldTopics)

-spec write_ops(binary(),
                barrel_hlc:timestamp(),
                map(),
                [binary()],
                barrel_hlc:timestamp() | undefined,
                [binary()]) ->
                   [term()].

Batch ops for one applied write. DocInfo carries id, rev, deleted, num_conflicts. Old rows (at OldHlc) are deleted for ALL configured channels: deleting an absent key is a RocksDB no-op, and it removes any old-membership bookkeeping.

write_ops_compiled(Compiled0, Ks, NewHlc, DocInfo, NewTopics, OldHlc, OldTopics)

-spec write_ops_compiled(compiled(),
                         binary(),
                         barrel_hlc:timestamp(),
                         map(),
                         [binary()],
                         barrel_hlc:timestamp() | undefined,
                         [binary()]) ->
                            [term()].

Pure variant of write_ops/6: the compiled channel set and the key name are explicit arguments (no persistent_term reads), so it is callable before a database is registered (timeline rewind).