A claim is a lease#

_images/lease.svg

A claim with no expiry is a claim a crashed worker keeps. The node stays claimed with nobody on it, and because one assignee has at most one live node, that worker’s identity can never claim again either. One process dying takes a node and an identity with it for good. So a claim is a lease: release hands a claim back on purpose, moving the generation the way a reclaim does, so a holder that stops is not busy until the lease runs out. renew says the holder is alive, and going quiet past the lease returns the node to ready for somebody else. Chubby’s leases and ZooKeeper’s ephemeral nodes answer the same question the same way; the graph has one mutator and no way to ask whether a worker is alive, so the only evidence is whether it said so recently.

A generation is a fence#

The generation moves on every claim and every reclaim. A holder that stalled long enough to be reclaimed wakes up as if it still owned the node, and an assignee check alone does not stop it: a reclaim clears the assignee, and a cleared assignee is what lets anybody finish an unheld node. A holder that passes the generation it was given is refused exactly when the world moved underneath it. renew leaves the generation alone, because a renewal is not a change of ownership and moving it would invalidate the token the holder is about to complete with.

Readiness is derived#

A caller may ask for ready and the dependencies decide. If status could be asserted, it would lie to every reader who picks work from it, and the refusal at claim time would not help the one who believed it. The parent chain is checked for loops the same way a dependency edge is, so a node cannot be its own ancestor and a walk up the tree always ends.

Which ready node#

When several nodes are ready, the one with the longest chain of work waiting below it is the one to take first: finishing it frees the most. That is the critical-path rule for scheduling a partial order on identical machines (Hu, doi:10.1287/opre.9.6.841; Graham, doi:10.1137/0117039), and the heterogeneous earliest-finish-time heuristic (HEFT) extends it to workers of different speeds (doi:10.1109/71.993206). Computing the depth below every node is one pass over the graph and costs under a millisecond at four thousand nodes.

One mutator across processes#

Every command line and every server call that changes the graph takes an advisory lock on the graph directory, held from load to save. Two workers claiming at once serialise on it, so neither writes back a snapshot that lacks the other’s change; readers take no lock and read the last snapshot whole, since it is replaced by rename.

Outside the join#

The tracker knows what the work is and who agrees. The deed store knows what the work produced. The pack knows what was learned. claimdag knows only which session node is held and by whom, and it is deliberately not joined to the others by the accession: a session’s scheduling state should not outlive the session or leak into what is cited. Completing a node here does not close a ticket. The seat maps tracker ids onto nodes for convenience, and the mapping lives in the seat.