A global graph of async computations used by tenacious: each node normally corresponds to a single execution of a `memoize`: if `memoize`'s heart gets broken, we create a new node next time it's demanded.

There is an edge from `a` to `b` if computation `a` is waiting for result of computation `b`.

`module Node : sig ... end`
`module Dump : sig ... end`
`val root_until : node:Node.t ‑> 'a Async.Deferred.t ‑> 'a Async.Deferred.t`

Any created node that blocks no other node should be made a root, otherwise it doesn't participate in the cycle checking and dumping at all.

`val edge_until : Node.t ‑> blocked_on:Node.t ‑> 'a Async.Deferred.t ‑> 'a Async.Deferred.t`
`val look_for_a_cycle : unit ‑> ([ `Prefix of string list ] * [ `Cycle of string list ]) option`

Looks for a cycle in the graph.

If `Some (`Prefix ["a"; "b"], `Cycle ["c"; "d"]) = look_for_a_cycle ()`, it means the graph has a path "a; b; c; d; c; d; c; ...".