Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Publishing independent outputs

The tutorial’s output example extends the text analyzer to produce words and their byte locations in one analyze(file) call. Its return value is a set of output handles naming words and locations; the handles do not contain those payloads.

This separates the cost of producing data from the decision to load or depend on each part.

Emission remains local until completion

Db::output derives a slot address from the running producer and the supplied name or name/key pair. It puts the typed value in that producer’s frame and returns an Output<T> handle.

The #[ajika::output] constructor is a convenience wrapper around these calls. It does not register another kind of query or write a storage row itself.

The function can pass handles back in its return value, but must finish before other queries can read its new outputs. Reading its own pending handle would require that unfinished producer to complete, so it is rejected.

If the function fails, its frame and pending outputs are discarded. If it succeeds, the evaluator compares all outputs and publishes their versions, values, and replacement dependency record together. Waiting callers can then read the completed set.

One record, several versions

For the initial text, the record might look like:

analyze("notes.txt")
  reads: File::text("notes.txt") at S1
  outputs:
    <return>    version H1   (the set of output handles)
    words       version W1
    locations   version L1

After inserting a space, the new input stamp is S2. The handles still contain the same addresses, words are equal, and locations differ:

reads:   S1 → S2
versions: H1, W1, L2

A consumer of words can stay valid. A consumer of locations must recheck its answer. Both depend on versions in the same producer’s output metadata.

All these outputs share the execution’s dependency list, durability, and lifetime. Independent versions do not imply independent execution or retention policies.

Reading a retained handle

A retained words handle already identifies analyze(file) and its words slot. Reading it does not require loading the producer’s returned set of handles just to find that same slot again.

output_value uses replay to establish the producer’s current versions without requesting its primary return value, just as dependency validation does. It then selects the slot and loads that payload if needed.

The read records the chosen slot’s version on the calling query’s frame. The operation and frame can then share that acquired Arc with repeated callers.

If the producer needs to execute, it still executes in full. If the selected slot is gone afterward, a direct handle read fails. In dependency validation, that same absence instead requires the parent to execute again, so it can discover which outputs the new inputs call for.

The returned set records membership

For dynamically keyed outputs, the returned handles also describe which slots exist. A code analyzer might emit one output per function body. If an edit deletes function B, a producer that previously returned body handles A and B should now return only A. Consumers observe that membership change before requesting individual bodies.

Keeping B’s old handle does not establish that B still exists. Handles name slots under the active input view; they are not historical snapshots.

Omitting a formerly emitted slot removes it from the new output metadata. Checkpointing then removes its durable location or masks the durable slot with the session producer’s new metadata. Old file bytes may remain until storage maintenance, but query readers can no longer observe them through that slot.

When adding a new output-producing abstraction, preserve these two boundaries: the producer owns publication, and every consumer records its own selected read. An accessor that hides either boundary can accidentally make the whole returned set a dependency or lose a dependency altogether.