Skip to content

Commit 0804cd5

Browse files
committed
readme: explain the async lookup
The script surface, the eventfd suspend/resume mechanics, the transparent sync fallbacks, why the blocking form can reply-starve under a miss storm, and the bounded forced-re-ask exception.
1 parent 4a300b0 commit 0804cd5

1 file changed

Lines changed: 42 additions & 0 deletions

File tree

‎README.md‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,48 @@ sequenceDiagram
9191
N2-->>N3: value (passive copy)
9292
```
9393

94+
## The async lookup
95+
96+
The registrar exports `lookup()` as an asynchronous command, so the script
97+
form is just:
98+
99+
```
100+
async(lookup("location"), lookup_resume);
101+
```
102+
103+
What happens underneath:
104+
105+
* If a live local record answers the request — the common case once a node
106+
has converged — the lookup completes inline: no suspension, no extra
107+
cost over the plain synchronous `lookup()`.
108+
* On a miss, usrloc starts a cluster pull (owner-hinted when an expired
109+
local copy names the last owner) and hands the async framework the
110+
pull's **eventfd**. The SIP transaction suspends; **no worker is held**.
111+
The eventfd exists per pull slot and is created before the fork, which
112+
is what lets the reply land in whichever process the transport picked
113+
and still wake the one that asked.
114+
* When the answer (or the `pull_timeout_ms` deadline) fires, a worker
115+
resumes the transaction: it collects the pull, absorbs the record into
116+
local memory, and runs the normal lookup. The resume route replies —
117+
guard with `t_check_trans()` as in the example above.
118+
* Everything that cannot suspend falls back to the synchronous path
119+
transparently — other cluster modes, branch-AoR lookups, a pull that
120+
cannot start — so the script never needs a second code path.
121+
122+
Why it matters: a *blocking* pull occupies a worker for up to
123+
`pull_timeout_ms`, and pull replies themselves need a worker to be
124+
processed. Under a miss storm every worker can end up blocked in a wait
125+
whose answer is stuck behind it in the queue — the classic reply-starvation
126+
collapse. The async form removes that coupling entirely; combined with the
127+
rule that **REGISTER never pulls** (a registration is stored locally and
128+
never consults the cluster), the bench filled 1M contacts at 5,000
129+
REGISTER/s with pulls enabled everywhere and lost nothing.
130+
131+
One deliberate exception: the held-only *forced re-ask* (previous section)
132+
runs inside the resuming worker, blocking it for at most one more
133+
`pull_timeout_ms` — a bounded price paid only when a record's owner is
134+
gone, against a holder that proved alive milliseconds earlier.
135+
94136
## Minimal configuration
95137

96138
```

0 commit comments

Comments
 (0)