Expand description
The stateless render farm: an indexed pool-draw stream, and the off-engine unit of work it hands out.
§Why the draw stream is indexed
The pool used to be filled from one advancing rand::Rng: draw, render,
dedupe, push, repeat. That makes the n-th tree a function of how many
draws happened before it, which is fine while one loop owns the RNG and
fatal the moment renders are farmed out to workers — a lost job, a
speculative draw past the stop point, or simply a different number of
renders in flight all shift the stream.
Here draw i is instead sampled from a fresh
StdRng::seed_from_u64(draw_seed(fill_seed, i)). Three properties follow,
and together they are what makes the farm’s determinism structural rather
than argued:
- Re-issue is stateless. A worker that dies mid-job costs nothing but
the render: the job is
(fill_seed, i), so any other worker can redo it with no retained state on either side. - Over-issue is free. Work dispatched past the point the pool fills is simply discarded; it cannot desynchronize a stream it never advanced.
- Width is invisible. The pool is the fold of indices
0, 1, 2, …in order — dedupe and vetting applied at absorption time — so the result depends on(fill_seed, pool_size)alone, at any farm width including zero.
The consequence, stated plainly: fixed-seed pools re-baselined when this
landed. That is invisible to the app (the browser seeds from
Math.random(), and saved sessions store trees rather than seeds) but any
test asserting exact pool contents from a fixed seed had to move with it.
Structs§
- Draw
- One unit of farm work: an index of the draw stream and the term it names.
- PreFeaturized
- A candidate whose render, vetting and featurization already happened — in a farm worker, or on the way back from transport.
Functions§
- draw_
seed - splitmix64 over
(base, index)— the pool draw stream’s index function.