on master help sign in
remove outdated clay docs and cleanup links
commita5a5bbbfd1df0ca1aa7c0b9561a31868473650b1 authortinnus-napbus <admin@tinnus-napbus.xyz> dateFri 7 May 2021, 21:00 (5 years ago) parentcf2f1d5
6 files changed−1473
arvo/clay/_index.md−13 arvo/clay/clay.md−12 arvo/clay/foreign.md−412 arvo/clay/local-reads.md−783 arvo/clay/local-sub.md−249 arvo/clay/using.md−4
arvo/clay/_index.md−13
@@ -22,16 +22,3 @@ reading and subscribing, syncing to Unix, and merging.
2222[Data Types](@/docs/arvo/clay/data-types.md)
2323
2424Explanations of the many data types found throughout Clay.
25−
26−[Local Reads and Writes](@/docs/arvo/clay/local-reads.md)
27−
28−How local reads and writes work.
29−
30−[Local Subscriptions](@/docs/arvo/clay/local-sub.md)
31−
32−How local subscriptions work.
33−
34−[Foreign Requests](@/docs/arvo/clay/foreign.md)
35−
36−How foreign reads and subscriptions work.
37−
arvo/clay/clay.md−12
@@ -51,15 +51,3 @@ reading and subscribing, syncing to Unix, and merging. (Up to date as of April 2
5151[Data Types](@/docs/arvo/clay/data-types.md)
5252
5353Explanations of the many data types found throughout Clay. (Up to date as of April 2021)
54−
55−[Local Reads and Writes](@/docs/arvo/clay/local-reads.md)
56−
57−How local reads and writes work.
58−
59−[Local Subscriptions](@/docs/arvo/clay/local-sub.md)
60−
61−How local subscriptions work.
62−
63−[Foreign Requests](@/docs/arvo/clay/foreign.md)
64−
65−How foreign reads and subscriptions work.
arvo/clay/foreign.mddeleted−412
@@ -1,412 +0,0 @@
1−+++
2−title = "Foreign Requests"
3−weight = 7
4−template = "doc.html"
5−+++
6−
7−Parts of this document may be out of date as of March 2021.
8−
9−Foreign reads and subscriptions are handled in much the same way as
10−local ones. The interface is the same -- a vane or app sends a `%warp`
11−kiss with the request. The difference is simply that the `sock` refers
12−to the foreign ship.
13−
14−Thus, we start in the same place -- in `++call`, handling `%warp`.
15−However, since the two side of the `sock` are different, we follow a
16−different path.
17−
18−```hoon
19− =+ wex=(do now p.q.hic p.q.q.hic ruf)
20− =+ ^= woo
21− ?~ q.q.q.hic
22− abet:(ease:wex hen)
23− abet:(eave:wex hen u.q.q.q.hic)
24− [-.woo (posh q.p.q.hic p.q.q.hic +.woo ruf)]
25−```
26−
27−If we compare this to how the local case was handled, we see that it's
28−not all that different. We use `++do` rather than `++un` and `++de` to
29−set up the core for the foreign ship. This gives us a `++de` core, so we
30−either cancel or begin the request by calling `++ease` or `++eave`,
31−exactly as in the local case. In either case, we call `++abet:de` to
32−resolve our various types of output into actual moves, as described in
33−the local case. Finally, we call `++posh` to update our raft, putting
34−the modified rung into the raft.
35−
36−We'll first trace through `++do`.
37−
38−```hoon
39− ++ do
40− |= [now=@da [who=ship him=ship] syd=@tas ruf=raft]
41− =+ ^= rug ^- rung
42− =+ rug=(~(get by hoy.ruf) him)
43− ?^(rug u.rug *rung)
44− =+ ^= red ^- rede
45− =+ yit=(~(get by rus.rug) syd)
46− ?^(yit u.yit `rede`[~2000.1.1 ~ [~ *rind] *dome])
47− ((de now ~ ~) [who him] syd red ran.ruf)
48−```
49−
50−If we already have a rung for this foreign ship, then we use that.
51−Otherwise, we create a new blank one. If we already have a rede in this
52−rung, then we use that, otherwise we create a blank one. An important
53−point to note here is that we let `ref` in the rede be `[~ *rind]`.
54−Recall, for domestic desks `ref` is null. We use this to distinguish
55−between foreign and domestic desks in `++de`.
56−
57−With this information, we create a `++de` core as usual.
58−
59−Although we've already covered `++ease` and `++eave`, we'll go through
60−them quickly again, highlighting the case of foreign request.
61−
62−```hoon
63− ++ ease :: release request
64− |= hen=duct
65− ^+ +>
66− ?~ ref +>
67− =+ rov=(~(got by qyx) hen)
68− =. qyx (~(del by qyx) hen)
69− (mabe rov (cury best hen))
70− =. qyx (~(del by qyx) hen)
71− |- ^+ +>+.$
72− =+ nux=(~(get by fod.u.ref) hen)
73− ?~ nux +>+.$
74− %= +>+.$
75− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
76− fod.u.ref (~(del by fod.u.ref) hen)
77− bom.u.ref (~(del by bom.u.ref) u.nux)
78− ==
79−```
80−
81−Here, we still remove the duct from our cult (we maintain a cult even
82−for foreign desks), but we also need to tell the foreign desk to cancel
83−our subscription. We do this by sending a request (by appending to
84−`say`, which gets resolved in `++abet:de` to a `%want` kiss to ames) to
85−the foreign ship to cancel the subscription. Since we don't anymore
86−expect a response on this duct, we remove it from `fod` and `bom`, which
87−are the maps between ducts, raves, and request sequence numbers.
88−Basically, we remove every trace of the subscription from our request
89−manager.
90−
91−In the case of `++eave`, where we're creating a new request, everything
92−is exactly identical to the case of the local request except `++duce`.
93−We said that `++duce` simply puts the request into our cult. This is
94−true for a domestic request, but distinctly untrue for foreign requests.
95−
96−```hoon
97− ++ duce :: produce request
98− |= [hen=duct rov=rove]
99− ^+ +>
100− =. qyx (~(put by qyx) hen rov)
101− ?~ ref +>.$
102− |- ^+ +>+.$ :: XX why?
103− =+ rav=(reve rov)
104− =+ ^= vaw ^- rave
105− ?. ?=([%& %v *] rav) rav
106− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
107− =+ inx=nix.u.ref
108− %= +>+.$
109− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
110− nix.u.ref +(nix.u.ref)
111− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
112− fod.u.ref (~(put by fod.u.ref) hen inx)
113− ==
114−```
115−
116−If we have a request manager (i.e. this is a foreign desk), then we do
117−the approximate inverse of `++ease`. We create a rave out of the given
118−request and send it off to the foreign desk by putting it in `say`. Note
119−that the rave is created to request the information starting at the next
120−revision number. Since this is a new request, we put it into `fod` and
121−`bom` to associate the request with its duct and its sequence number.
122−Since we're using another sequence number, we must increment `nix`,
123−which represents the next available sequence number.
124−
125−And that's really it for this side of the request. Requesting foreign
126−information isn't that hard. Let's see what it looks like on the other
127−side. When we get a request from another ship for information on our
128−ship, that comes to us in the form of a `%wart` from ames.
129−
130−We handle a `%wart` in `++call`, right next to where we handle the
131−`%warp` case.
132−
133−```hoon
134− %wart
135− ?> ?=(%re q.q.hic)
136− =+ ryf=((hard riff) s.q.hic)
137− :_ ..^$
138− :~ :- hen
139− :^ %pass [(scot %p p.p.q.hic) (scot %p q.p.q.hic) r.q.hic]
140− %c
141− [%warp [p.p.q.hic p.p.q.hic] ryf]
142− ==
143−```
144−
145−Every request we receive should be of type `riff`, so we coerce it into
146−that type. We just convert this into a new `%warp` kiss that we pass to
147−ourself. This gets handled like normal, as a local request. When the
148−request produces a value, it does so like normal as a `%writ`, which is
149−returned to `++take` along the path we just sent it on.
150−
151−```hoon
152− %writ
153− ?> ?=([@ @ *] tea)
154− =+ our=(need (slaw %p i.tea))
155− =+ him=(need (slaw %p i.t.tea))
156− :_ ..^$
157− :~ :- hen
158− [%pass ~ %a [%want [our him] [%r %re %c t.t.tea] p.+.q.hin]]
159− ==
160−```
161−
162−Since we encoded the ship we need to respond to in the path, we can just
163−pass our `%want` back to ames, so that we tell the requesting ship about
164−the new data.
165−
166−This comes back to the original ship as a `%waft` from ames, which comes
167−into `++take`, right next to where we handled `%writ`.
168−
169−```hoon
170− %waft
171− ?> ?=([@ @ ~] tea)
172− =+ syd=(need (slaw %tas i.tea))
173− =+ inx=(need (slaw %ud i.t.tea))
174− =+ ^= zat
175− =< wake
176− (knit:(do now p.+.q.hin syd ruf) [inx ((hard riot) q.+.q.hin)])
177− =^ mos ruf
178− =+ zot=abet.zat
179− [-.zot (posh q.p.+.q.hin syd +.zot ruf)]
180− [mos ..^$(ran.ruf ran.zat)] :: merge in new obj
181−```
182−
183−This gets the desk and sequence number from the path the request was
184−sent over. This determines exactly which request is being responded to.
185−We call `++knit:de` to apply the changes to our local desk, and we call
186−`++wake` to update our subscribers. Then we call `++abet:de` and
187−`++posh` as normal (like in `++eave`).
188−
189−We'll examine `++knit` and `++wake`, in that order.
190−
191−```hoon
192− ++ knit :: external change
193− |= [inx=@ud rot=riot]
194− ^+ +>
195− ?> ?=(^ ref)
196− |- ^+ +>+.$
197− =+ ruv=(~(get by bom.u.ref) inx)
198− ?~ ruv +>+.$
199− => ?. |(?=(~ rot) ?=(& -.q.u.ruv)) .
200− %_ .
201− bom.u.ref (~(del by bom.u.ref) inx)
202− fod.u.ref (~(del by fod.u.ref) p.u.ruv)
203− ==
204− ?~ rot
205− =+ rav=`rave`q.u.ruv
206− %= +>+.$
207− lim
208− ?.(&(?=(| -.rav) ?=(%da -.q.p.rav)) lim `@da`p.q.p.rav)
209− ::
210− haw.u.ref
211− ?. ?=(& -.rav) haw.u.ref
212− (~(put by haw.u.ref) p.rav ~)
213− ==
214− ?< ?=(%v p.p.u.rot)
215− =. haw.u.ref
216− (~(put by haw.u.ref) [p.p.u.rot q.p.u.rot q.u.rot] ~ r.u.rot)
217− ?. ?=(%w p.p.u.rot) +>+.$
218− |- ^+ +>+.^$
219− =+ nez=[%w [%ud let.dom] ~]
220− =+ nex=(~(get by haw.u.ref) nez)
221− ?~ nex +>+.^$
222− ?~ u.nex +>+.^$ :: should never happen
223− =. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
224− ?>(?=(^ ref.roo) roo)
225− %= $
226− haw.u.ref (~(del by haw.u.ref) nez)
227− ==
228−```
229−
230−This is kind of a long [gate](/docs/glossary/gate/), but don't worry, it's not bad at all.
231−
232−First, we assert that we're not a domestic desk. That wouldn't make any
233−sense at all.
234−
235−Since we have the sequence number of the request, we can get the duct
236−and rave from `bom` in our request manager. If we didn't actually
237−request this data (or the request was canceled before we got it), then
238−we do nothing.
239−
240−Else, we remove the request from `bom` and `fod` unless this was a
241−subscription request and we didn't receive a null riot (which would
242−indicate the last message on the subscription).
243−
244−Now, if we received a null riot, then if this was a subscription request
245−by date, then we update `lim` in our request manager (representing the
246−latest time at which we have complete information for this desk) to the
247−date that was requested. If this was a single read request, then we put
248−the result in our simple cache `haw` to make future requests faster.
249−Then we're done.
250−
251−If we received actual data, then we put it into our cache `haw`. Unless
252−it's a `%w` request, we're done.
253−
254−If it is a `%w` request, then we try to get the `%w` at our current head
255−from the cache. In general, that should be the thing we just put in a
256−moment ago, but that is not guaranteed. The most common case where this
257−is different is when we receive desk updates out of order. At any rate,
258−since we now have new information, we need to apply it to our local copy
259−of the desk. We do so in `++edis`, and then we remove the stuff we just
260−applied from the cache, since it's not really a true "single read", like
261−what should really be in the cache.
262−
263−```hoon
264− ++ edis :: apply subscription
265− |= nak=nako
266− ^+ +>
267− %= +>
268− hit.dom (~(uni by hit.dom) gar.nak)
269− let.dom let.nak
270− lat.ran %+ roll (~(tap in bar.nak) ~)
271− =< .(yeb lat.ran)
272− |= [sar=blob yeb=(map lobe blob)]
273− =+ zax=(blob-to-lobe sar)
274− %+ ~(put by yeb) zax sar
275− hut.ran %+ roll (~(tap in lar.nak) ~)
276− =< .(yeb hut.ran)
277− |= [sar=yaki yeb=(map tako yaki)]
278− %+ ~(put by yeb) r.sar sar
279− ==
280−```
281−
282−This shows, of course, exactly why nako is defined the way it is. To
283−become completely up to date with the foreign desk, we need to merge
284−`hit` with the foreign one so that we have all the revision numbers. We
285−update `let` so that we know which revision is the head.
286−
287−We merge the new blobs in `lat`, keying them by their hash, which we get
288−from a call to `++blob-to-lobe`. Recall that the hash is stored in the
289−actual blob itself. We do the same thing to the new yakis, putting them
290−in `hut`, keyed by their hash.
291−
292−Now, our local dome should be exactly the same as the foreign one.
293−
294−This concludes our discussion of `++knit`. Now the changes have been
295−applied to our local copy of the desk, and we just need to update our
296−subscribers. We do so in `++wake:de`.
297−
298−```hoon
299− ++ wake :: update subscribers
300− ^+ .
301− =+ xiq=(~(tap by qyx) ~)
302− =| xaq=(list ,[p=duct q=rove])
303− |- ^+ ..wake
304− ?~ xiq
305− ..wake(qyx (~(gas by *cult) xaq))
306− ?- -.q.i.xiq
307− &
308− =+ cas=?~(ref ~ (~(get by haw.u.ref) `mood`p.q.i.xiq))
309− ?^ cas
310− %= $
311− xiq t.xiq
312− ..wake ?~ u.cas (blub p.i.xiq)
313− (blab p.i.xiq p.q.i.xiq u.u.cas)
314− ==
315− =+ nao=(~(case-to-aeon ze lim dom ran) q.p.q.i.xiq)
316− ?~ nao $(xiq t.xiq, xaq [i.xiq xaq])
317− $(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq))
318− ::
319− |
320− =+ mot=`moot`p.q.i.xiq
321− =+ nab=(~(case-to-aeon ze lim dom ran) p.mot)
322− ?~ nab
323− $(xiq t.xiq, xaq [i.xiq xaq])
324− =+ huy=(~(case-to-aeon ze lim dom ran) q.mot)
325− ?~ huy
326− =+ ptr=[%ud +(let.dom)]
327− %= $
328− xiq t.xiq
329− xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq]
330− ..wake =+ ^= ear
331− (~(lobes-at-path ze lim dom ran) let.dom r.p.q.i.xiq)
332− ?: =(s.p.q.i.xiq ear) ..wake
333− =+ fud=(~(make-nako ze lim dom ran) u.nab let.dom)
334− (bleb p.i.xiq let.dom fud)
335− ==
336− %= $
337− xiq t.xiq
338− ..wake =- (blub:- p.i.xiq)
339− =+ ^= ear
340− (~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
341− ?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
342− =+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
343− (bleb p.i.xiq +(u.nab) fud)
344− ==
345− ==
346− --
347−```
348−
349−This is even longer than `++knit`, but it's pretty similar to `++eave`.
350−We loop through each of our subscribers `xiq`, processing each in turn.
351−When we're done, we just put the remaining subscribers back in our
352−subscriber list.
353−
354−If the subscriber is a single read, then, if this is a foreign desk
355−(note that `++wake` is called from other arms, and not only on foreign
356−desks). Obviously, if we find an identical request there, then we can
357−produce the result immediately. Referential transparency for the win. We
358−produce the result with a call to `++blab`. If this is a foreign desk
359−but the result is not in the cache, then we produce `++blub` (canceled
360−subscription with no data) for reasons entirely opaque to me. Seriously,
361−it seems like we should wait until we get an actual response to the
362−request. If someone figures out why this is, let me know. At any rate,
363−it seems to work.
364−
365−If this is a domestic desk, then we check to see if the case exists yet.
366−If it doesn't, then we simply move on to the next subscriber, consing
367−this one onto `xaq` so that we can check again the next time around. If
368−it does exist, then we call `++balk` to fulfill the request and produce
369−it.
370−
371−`++balk` is very simple, so we'll describe it here before we get to the
372−subscription case.
373−
374−```hoon
375− ++ balk :: read and send
376− |= [hen=duct oan=@ud mun=mood]
377− ^+ +>
378− =+ vid=(~(read-at-aeon ze lim dom ran) oan mun)
379− ?~ vid (blub hen) (blab hen mun u.vid)
380−```
381−
382−We call `++read-at-aeon` on the given request and aeon. If you recall,
383−this processes a `mood` at a particular aeon and produces the result, if
384−there is one. If there is data at the requested location, then we
385−produce it with `++blab`. Else, we call `++blub` to notify the
386−subscriber that no data can ever come over this subscriptioin since it
387−is now impossible for there to ever be data for the given request.
388−Because referential transparency.
389−
390−At any rate, back to `++wake`. If the given rave is a subscription
391−request, then we proceed similarly to how we do in `++eave`. We first
392−try to get the aeon referred to by the starting case. If it doesn't
393−exist yet, then we can't do anything interesting with this subscription,
394−so we move on to the next one.
395−
396−Otherwise, we try to get the aeon referred to by the ending case. If it
397−doesn't exist yet, then we produce all the information we can. We call
398−`++lobes-at-path` at the given aeon and path to see if the requested
399−path has actually changed. If it hasn't, then we don't produce anything;
400−else, we produce the correct nako by calling `++bleb` on the result of
401−`++make-nako`, as in `++eave`. At any rate, we move on to the next
402−subscription, putting back into our cult the current subscription with a
403−new start case of the next aeon after the present.
404−
405−If the aeon referred to by the ending case does exist, then we drop this
406−subscriber from our cult and satisfy its request immediately. This is
407−the same as before -- we check to see if the data at the path has
408−actually changed, producing it if it has; else, we call `++blub` since
409−no more data can be produced over this subscription.
410−
411−This concludes our discussion of foreign requests.
412−
arvo/clay/local-reads.mddeleted−783
@@ -1,783 +0,0 @@
1−+++
2−title = "Local Reads and Writes"
3−weight = 5
4−template = "doc.html"
5−+++
6−
7−Parts of this document may be out of date as of March 2021.
8−
9−There are two real types of interaction with a filesystem: you can read,
10−and you can write. We'll describe each process, detailing both the flow
11−of control followed by the kernel and the algorithms involved. The
12−simpler case is that of the read, so we'll begin with that.
13−
14−When a vane or an application wishes to read a file from the filesystem,
15−it sends a `%warp` kiss, as described above. Of course, you may request
16−a file on another ship and, being a global filesystem, clay will happily
17−produce it for you. That code pathway will be described in another
18−section; here, we will restrict ourselves to examining the case of a
19−read from a ship on our own pier.
20−
21−The kiss can request either a single version of a file node or a range
22−of versions of a desk. Here, we'll deal only with a request for a single
23−version.
24−
25−As in all vanes, a kiss enters clay via a call to `++call`. Scanning
26−through the arm, we quickly see where `%warp` is handled.
27−
28−```hoon
29− ?: =(p.p.q.hic q.p.q.hic)
30− =+ une=(un p.p.q.hic now ruf)
31− =+ wex=(di:une p.q.q.hic)
32− =+ ^= wao
33− ?~ q.q.q.hic
34− (ease:wex hen)
35− (eave:wex hen u.q.q.q.hic)
36− =+ ^= woo
37− abet:wao
38− [-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)]
39−```
40−
41−We're following the familar patern of producing a list of moves and an
42−updated state. In this case, the state is `++raft`.
43−
44−We first check to see if the sending and receiving ships are the same.
45−If they're not, then this is a request for data on another ship. We
46−describe that process later. Here, we discuss only the case of a local
47−read.
48−
49−At a high level, the call to `++un` sets up the core for the domestic
50−ship that contains the files we're looking for. The call to `++di` sets
51−up the core for the particular desk we're referring to.
52−
53−After this, we perform the actual request. If there is no rave in the
54−riff, then that means we are cancelling a request, so we call
55−`++ease:de`. Otherwise, we start a subscription with `++eave:de`. We
56−call `++abet:de` to resolve our various types of output into actual
57−moves. We produce the moves we found above and the `++un` core resolved
58−with `++pish:un` (putting the modified desk in the room) and `++abet:un`
59−(putting the modified room in the raft).
60−
61−Much of this is fairly straightforward, so we'll only describe `++ease`,
62−`++eave`, and `++abet:de`. Feel free to look up the code to the other
63−steps -- it should be easy to follow.
64−
65−Although it's called last, it's usually worth examining `++abet` first,
66−since it defines in what ways we can cause side effects. Let's do that,
67−and also a few of the lines at the beginning of `++de`.
68−
69−```hoon
70− =| yel=(list ,[p=duct q=gift])
71− =| byn=(list ,[p=duct q=riot])
72− =| vag=(list ,[p=duct q=gift])
73− =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]])
74− =| tag=(list ,[p=duct q=path c=note])
75− |%
76− ++ abet
77− ^- [(list move) rede]
78− :_ red
79− ;: weld
80− %+ turn (flop yel)
81− |=([a=duct b=gift] [hun %give b])
82− ::
83− %+ turn (flop byn)
84− |=([a=duct b=riot] [a %give [%writ b]])
85− ::
86− %+ turn (flop vag)
87− |=([a=duct b=gift] [a %give b])
88− ::
89− %+ turn (flop say)
90− |= [a=duct b=path c=ship d=[p=@ud q=riff]]
91− :- a
92− [%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d]
93− ::
94− %+ turn (flop tag)
95− |=([a=duct b=path c=note] [a %pass b c])
96− ==
97−```
98−
99−This is very simple code. We see there are exactly five different kinds
100−of side effects we can generate.
101−
102−In `yel` we put gifts that we wish to be sent along the `hun:room` duct
103−to dill. See the documentation for `++room` above. This is how we
104−display messages to the terminal.
105−
106−In `byn` we put riots that we wish returned to subscribers. Recall that
107−a riot is a response to a subscription. These are returned to our
108−subscribers in the form of a `%writ` gift.
109−
110−In `vag` we put gifts along with the ducts on which to send them. This
111−allows us to produce arbitrary gifts, but in practice this is only used
112−to produce `%ergo` gifts.
113−
114−In `say` we put messages we wish to pass to ames. These messages are
115−used to request information from clay on other piers. We must provide
116−not only the duct and the request (the riff), but also the return path,
117−the other ship to talk to, and the sequence number of the request.
118−
119−In `tag` we put arbitrary notes we wish to pass to other vanes. For now,
120−the only notes we pass here are `%wait` and `%rest` to the timer vane.
121−
122−Now that we know what kinds of side effects we may have, we can jump
123−into the handling of requests.
124−
125−```hoon
126− ++ ease :: release request
127− |= hen=duct
128− ^+ +>
129− ?~ ref +>
130− =+ rov=(~(got by qyx) hen)
131− =. qyx (~(del by qyx) hen)
132− (mabe rov (cury best hen))
133− =. qyx (~(del by qyx) hen)
134− |- ^+ +>+.$
135− =+ nux=(~(get by fod.u.ref) hen)
136− ?~ nux +>+.$
137− %= +>+.$
138− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
139− fod.u.ref (~(del by fod.u.ref) hen)
140− bom.u.ref (~(del by bom.u.ref) u.nux)
141− ==
142−```
143−
144−This is called when we're cancelling a subscription. For domestic desks,
145−`ref` is null, so we're going to cancel any timer we might have created.
146−We first delete the duct from our map of requests, and then we call
147−`++mabe` with `++best` to send a `%rest` kiss to the timer vane if we
148−have started a timer. We'll describe `++best` and `++mabe` momentarily.
149−
150−Although we said we're not going to talk about foreign requests yet,
151−it's easy to see that for foreign desks, we cancel any outstanding
152−requests for this duct and send a message over ames to the other ship
153−telling them to cancel the subscription.
154−
155−```hoon
156− ++ best
157− |= [hen=duct tym=@da]
158− %_(+> tag :_(tag [hen /tyme %t %rest tym]))
159−```
160−
161−This simply pushes a `%rest` note onto `tag`, from where it will be
162−passed back to arvo to be handled. This cancels the timer at the given
163−duct (with the given time).
164−
165−```hoon
166− ++ mabe :: maybe fire function
167− |* [rov=rove fun=$+(@da _+>.^$)]
168− ^+ +>.$
169− %- fall :_ +>.$
170− %- bind :_ fun
171− ^- (unit ,@da)
172− ?- -.rov
173− %&
174− ?. ?=(%da -.q.p.rov) ~
175− `p.q.p.rov
176− %|
177− =* mot p.rov
178− %+ hunt
179− ?. ?=(%da -.p.mot) ~
180− ?.((lth now p.p.mot) ~ [~ p.p.mot])
181− ?. ?=(%da -.q.mot) ~
182− ?.((lth now p.q.mot) [~ now] [~ p.q.mot])
183− ==
184−```
185−
186−This decides whether the given request can only be satsified in the
187−future. In that case, we call the given function with the time in the
188−future when we expect to have an update to give to this request. This is
189−called with `++best` to cancel timers and with `++bait` to start them.
190−
191−For single requests, we have a time if the request is for a particular
192−time (which is assumed to be in the future). For ranges of requests, we
193−check both the start and end cases to see if they are time cases. If so,
194−we choose the earlier time.
195−
196−If any of those give us a time, then we call the given funciton with the
197−smallest time.
198−
199−The more interesting case is, of course, when we're not cancelling a
200−subscription but starting one.
201−
202−```hoon
203− ++ eave :: subscribe
204− |= [hen=duct rav=rave]
205− ^+ +>
206− ?- -.rav
207− &
208− ?: &(=(p.p.rav %u) !=(p.q.p.rav now))
209− ~& [%clay-fail p.q.p.rav %now now]
210− !!
211− =+ ver=(aver p.rav)
212− ?~ ver
213− (duce hen rav)
214− ?~ u.ver
215− (blub hen)
216− (blab hen p.rav u.u.ver)
217−```
218−
219−There are two types of subscriptions -- either we're requesting a single
220−file or we're requesting a range of versions of a desk. We'll dicuss the
221−simpler case first.
222−
223−First, we check that we're not requesting the `rang` from any time other
224−than the present. Since we don't store that information for any other
225−time, we can't produce it in a referentially transparent manner for any
226−time other than the present.
227−
228−Then, we try to read the requested `mood:clay` `p.rav`. If we can't access
229−the request data right now, we call `++duce` to put the request in our
230−queue to be satisfied when the information becomes available.
231−
232−This case occurs when we make a request for a case whose (1) date is
233−after the current date, (2) number is after the current number, or (3)
234−label is not yet used.
235−
236−```hoon
237− ++ duce :: produce request
238− |= [hen=duct rov=rove]
239− ^+ +>
240− =. qyx (~(put by qyx) hen rov)
241− ?~ ref
242− (mabe rov (cury bait hen))
243− |- ^+ +>+.$ :: XX why?
244− =+ rav=(reve rov)
245− =+ ^= vaw ^- rave
246− ?. ?=([%& %v *] rav) rav
247− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
248− =+ inx=nix.u.ref
249− %= +>+.$
250− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
251− nix.u.ref +(nix.u.ref)
252− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
253− fod.u.ref (~(put by fod.u.ref) hen inx)
254− ==
255−```
256−
257−The code for `++duce` is nearly the exact inverse of `++ease`, which in
258−the case of a domestic desk is very simple -- we simply put the duct and
259−rave into `qyx` and possibly start a timer with `++mabe` and `++bait`.
260−Recall that `ref` is null for domestic desks and that `++mabe` fires the
261−given function with the time we need to be woken up at, if we need to be
262−woken up at a particular time.
263−
264−```hoon
265− ++ bait
266− |= [hen=duct tym=@da]
267− %_(+> tag :_(tag [hen /tyme %t %wait tym]))
268−```
269−
270−This sets an alarm by sending a `%wait` card with the given time to the
271−timer vane.
272−
273−Back in `++eave`, if `++aver` returned `[~ ~]`, then we cancel the
274−subscription. This occurs when we make (1) a `%x` request for a file
275−that does not exist, (2) a `%w` request with a case that is not a
276−number, or (3) a `%w` request with a nonempty path. The `++blub` is
277−exactly what you would expect it to be.
278−
279−```hoon
280− ++ blub :: ship stop
281− |= hen=duct
282− %_(+> byn [[hen ~] byn])
283−```
284−
285−We notify the duct that we're cancelling their subscription since it
286−isn't satisfiable.
287−
288−Otherwise, we have received the desired information, so we send it on to
289−the subscriber with `++blab`.
290−
291−```hoon
292− ++ blab :: ship result
293− |= [hen=duct mun=mood dat=*]
294− ^+ +>
295− +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn])
296−```
297−
298−The most interesting arm called in `++eave` is, of course, `++aver`,
299−where we actually try to read the data.
300−
301−```hoon
302− ++ aver :: read
303− |= mun=mood
304− ^- (unit (unit ,*))
305− ?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things
306− ~& [%clay-fail p.q.mun %now now]
307− !!
308− =+ ezy=?~(ref ~ (~(get by haw.u.ref) mun))
309− ?^ ezy ezy
310− =+ nao=(~(case-to-aeon ze lim dom ran) q.mun)
311− ?~(nao ~ [~ (~(read-at-aeon ze lim dom ran) u.nao mun)])
312−```
313−
314−We check immediately that we're not requesting the `rang` for any time
315−other than the present.
316−
317−If this is a foreign desk, then we check our cache for the specific
318−request. If either this is a domestic desk or we don't have the request
319−in our cache, then we have to actually go read the data from our dome.
320−
321−We need to do two things. First, we try to find the number of the commit
322−specified by the given case, and then we try to get the data there.
323−
324−Here, we jump into `arvo/zuse.hoon`, which is where much of the
325−algorithmic code is stored, as opposed to the clay interface, which is
326−stored in `arvo/clay.hoon`. We examine `++case-to-aeon:ze`.
327−
328−```hoon
329− ++ case-to-aeon :: case-to-aeon:ze
330− |= lok=case :: act count through
331− ^- (unit aeon)
332− ?- -.lok
333− %da
334− ?: (gth p.lok lim) ~
335− |- ^- (unit aeon)
336− ?: =(0 let) [~ 0] :: avoid underflow
337− ?: %+ gte p.lok
338− =< t
339− %- tako-to-yaki
340− %- aeon-to-tako
341− let
342− [~ let]
343− $(let (dec let))
344− ::
345− %tas (~(get by lab) p.lok)
346− %ud ?:((gth p.lok let) ~ [~ p.lok])
347− ==
348−```
349−
350−We handle each type of `case:clay` differently. The latter two types are
351−easy.
352−
353−If we're requesting a revision by label, then we simply look up the
354−requested label in `lab` from the given dome. If it exists, that is our
355−aeon; else we produce null, indicating the requested revision does not
356−yet exist.
357−
358−If we're requesting a revision by number, we check if we've yet reached
359−that number. If so, we produce the number; else we produce null.
360−
361−If we're requesting a revision by date, we check first if the date is in
362−the future, returning null if so. Else we start from the most recent
363−revision and scan backwards until we find the first revision committed
364−before that date, and we produce that. If we requested a date before any
365−revisions were committed, we produce `0`.
366−
367−The definitions of `++aeon-to-tako` and `++tako-to-yaki` are trivial.
368−
369−```hoon
370− ++ aeon-to-tako ~(got by hit)
371−
372− ++ tako-to-yaki ~(got by hut) :: grab yaki
373−```
374−
375−We simply look up the aeon or tako in their respective maps (`hit` and
376−`hut`).
377−
378−Assuming we got a valid version number, `++aver` calls
379−`++read-at-aeon:ze`, which reads the requested data at the given
380−revision.
381−
382−```hoon
383− ++ read-at-aeon :: read-at-aeon:ze
384− |= [oan=aeon mun=mood] :: seek and read
385− ^- (unit)
386− ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed
387− ?^(r.mun ~ [~ oan])
388− (read:(rewind oan) mun)
389−```
390−
391−If we're requesting the revision number with a case other than by
392−number, then we go ahead and just produce the number we were given.
393−Otherwise, we call `++rewind` to rewind our state to the given revision,
394−and then we call `++read` to get the requested information.
395−
396−```hoon
397− ++ rewind :: rewind:ze
398− |= oan=aeon :: rewind to aeon
399− ^+ +>
400− ?: =(let oan) +>
401− ?: (gth oan let) !! :: don't have version
402− +>(ank (checkout-ankh q:(tako-to-yaki (aeon-to-tako oan))), let oan)
403−```
404−
405−If we're already at the requested version, we do nothing. If we're
406−requesting a version later than our head, we are unable to comply.
407−
408−Otherwise, we get the hash of the commit at the number, and from that we
409−get the commit itself (the yaki), which has the map of path to lobe that
410−represents a version of the filesystem. We call `++checkout-ankh` to
411−checkout the commit, and we replace `ank` in our context with the
412−result.
413−
414−```hoon
415− ++ checkout-ankh :: checkout-ankh:ze
416− |= hat=(map path lobe) :: checkout commit
417− ^- ankh
418− %- cosh
419− %+ roll (~(tap by hat) ~)
420− |= [[pat=path bar=lobe] ank=ankh]
421− ^- ankh
422− %- cosh
423− ?~ pat
424− =+ zar=(lobe-to-noun bar)
425− ank(q [~ (sham zar) zar])
426− =+ nak=(~(get by r.ank) i.pat)
427− %= ank
428− r %+ ~(put by r.ank) i.pat
429− $(pat t.pat, ank (fall nak _ankh))
430− ==
431−```
432−
433−Twice we call `++cosh`, which hashes a commit, updating `p` in an
434−`ankh`. Let's jump into that algorithm before we describe
435−`++checkout-ankh`.
436−
437−```hoon
438− ++ cosh :: locally rehash
439− |= ank=ankh :: NB v/unix.c
440− ank(p rehash:(zu ank))
441−```
442−
443−We simply replace `p` in the hash with the `cash` we get from a call to
444−`++rehash:zu`.
445−
446−```hoon
447− ++ zu !: :: filesystem
448− |= ank=ankh :: filesystem state
449− =| myz=(list ,[p=path q=miso]) :: changes in reverse
450− =| ram=path :: reverse path into
451− |%
452− ++ rehash :: local rehash
453− ^- cash
454− %+ mix ?~(q.ank 0 p.u.q.ank)
455− =+ axe=1
456− |- ^- cash
457− ?~ r.ank _@
458− ;: mix
459− (shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank))))
460− $(r.ank l.r.ank, axe (peg axe 2))
461− $(r.ank r.r.ank, axe (peg axe 3))
462− ==
463−```
464−
465−`++zu` is a core we set up with a particular filesystem node to traverse
466−a checkout of the filesystem and access the actual data inside it. One
467−of the things we can do with it is to create a recursive hash of the
468−node.
469−
470−In `++rehash`, if this node is a file, then we xor the remainder of the
471−hash with the hash of the contents of the file. The remainder of the
472−hash is `0` if we have no children, else we descend into our children.
473−Basically, we do a half SHA-256 of the xor of the axis of this child and
474−the half SHA-256 of the xor of the name of the child and the hash of the
475−child. This is done for each child and all the results are xored
476−together.
477−
478−Now we return to our discussion of `++checkout-ankh`.
479−
480−We fold over every path in this version of the filesystem and create a
481−great ankh out of them. First, we call `++lobe-to-noun` to get the raw
482−data referred to be each lobe.
483−
484−```hoon
485− ++ lobe-to-noun :: grab blob
486− |= p=lobe :: ^- *
487− %- blob-to-noun
488− (lobe-to-blob p)
489−```
490−
491−This converts a lobe into the raw data it refers to by first getting the
492−blob with `++lobe-to-blob` and converting that into data with
493−`++blob-to-noun`.
494−
495−```hoon
496− ++ lobe-to-blob ~(got by lat) :: grab blob
497−```
498−
499−This just grabs the blob that the lobe refers to.
500−
501−```hoon
502− ++ blob-to-noun :: grab blob
503− |= p=blob
504− ?- -.p
505− %delta (lump r.p (lobe-to-noun q.p))
506− %direct q.p
507− %indirect q.p
508− ==
509−```
510−
511−If we have either a direct or an indirect blob, then the data is stored
512−right in the blob. Otherwise, we have to reconstruct it from the diffs.
513−We do this by calling `++lump` on the diff in the blob with the data
514−obtained by recursively calling the parent of this blob.
515−
516−```hoon
517− ++ lump :: apply patch
518− |= [don=udon src=*]
519− ^- *
520− ?+ p.don ~|(%unsupported !!)
521− %a
522− ?+ -.q.don ~|(%unsupported !!)
523− %a q.q.don
524− %c (lurk ((hard (list)) src) p.q.don)
525− %d (lure src p.q.don)
526− ==
527− ::
528− %c
529− =+ dst=(lore ((hard ,@) src))
530− %- roly
531− ?+ -.q.don ~|(%unsupported !!)
532− %a ((hard (list ,@t)) q.q.don)
533− %c (lurk dst p.q.don)
534− ==
535− ==
536−```
537−
538−This is defined in `arvo/hoon.hoon` for historical reasons which are
539−likely no longer applicable. Since the `++umph` structure will likely
540−change we convert clay to be a typed filesystem, we'll only give a
541−high-level description of this process. If we have a `%a` udon, then
542−we're performing a trivial replace, so we produce simply `q.q.don`. If
543−we have a `%c` udon, then we're performing a list merge (as in, for
544−example, lines of text). The merge is performed by `++lurk`.
545−
546−```hoon
547− ++ lurk :: apply list patch
548− |* [hel=(list) rug=(urge)]
549− ^+ hel
550− =+ war=`_hel`~
551− |- ^+ hel
552− ?~ rug (flop war)
553− ?- -.i.rug
554− &
555− %= $
556− rug t.rug
557− hel (slag p.i.rug hel)
558− war (weld (flop (scag p.i.rug hel)) war)
559− ==
560− ::
561− |
562− %= $
563− rug t.rug
564− hel =+ gur=(flop p.i.rug)
565− |- ^+ hel
566− ?~ gur hel
567− ?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur))
568− war (weld q.i.rug war)
569− ==
570− ==
571−```
572−
573−We accumulate our final result in `war`. If there's nothing more in our
574−list of merge instructions (unces), we just reverse `war` and produce
575−it. Otherwise, we process another unce. If the unce is of type `&`, then
576−we have `p.i.rug` lines of no changes, so we just copy them over from
577−`hel` to `war`. If the unice is of type `|`, then we verify that the
578−source lines (in `hel`) are what we expect them to be (`p.i.rug`),
579−crashing on failure. If they're good, then we append the new lines in
580−`q.i.rug` onto `war`.
581−
582−And that's really it. List merges are pretty easy. Anyway, if you
583−recall, we were discussing `++checkout-ankh`.
584−
585−```hoon
586− ++ checkout-ankh :: checkout-ankh:ze
587− |= hat=(map path lobe) :: checkout commit
588− ^- ankh
589− %- cosh
590− %+ roll (~(tap by hat) ~)
591− |= [[pat=path bar=lobe] ank=ankh]
592− ^- ankh
593− %- cosh
594− ?~ pat
595− =+ zar=(lobe-to-noun bar)
596− ank(q [~ (sham zar) zar])
597− =+ nak=(~(get by r.ank) i.pat)
598− %= ank
599− r %+ ~(put by r.ank) i.pat
600− $(pat t.pat, ank (fall nak _ankh))
601− ==
602−```
603−
604−If the path is null, then we calculate `zar`, the raw data at the path
605−`pat` in this version. We produce the given ankh with the correct data.
606−
607−Otherwise, we try to get the child we're looking at from our parent
608−ankh. If it's already been created, this succeeds; otherwise, we simply
609−create a default blank ankh. We place ourselves in our parent after
610−recursively computing our children.
611−
612−This algorithm really isn't that complicated, but it may not be
613−immediately obvious why it works. An example should clear everything up.
614−
615−Suppose `hat` is a map of the following information.
616−
617−```
618− /greeting --> "customary upon meeting"
619− /greeting/english --> "hello"
620− /greeting/spanish --> "hola"
621− /greeting/russian/short --> "привет"
622− /greeting/russian/long --> "Здравствуйте"
623− /farewell/russian --> "до свидания"
624−```
625−
626−Furthermore, let's say that we process them in this order:
627−
628−```
629− /greeting/english
630− /greeting/russian/short
631− /greeting/russian/long
632− /greeting
633− /greeting/spanish
634− /farewell/russian
635−```
636−
637−Then, the first path we process is `/greeting/english` . Since our path
638−is not null, we try to get `nak`, but because our ankh is blank at this
639−point it doesn't find anything. Thus, update our blank top-level ankh
640−with a child `%greeting`. and recurse with the blank `nak` to create the
641−ankh of the new child.
642−
643−In the recursion, we our path is `/english` and our ankh is again blank.
644−We try to get the `english` child of our ankh, but this of course fails.
645−Thus, we update our blank `/greeting` ankh with a child `english`
646−produced by recursing.
647−
648−Now our path is null, so we call `++lobe-to-noun` to get the actual
649−data, and we place it in the brand-new ankh.
650−
651−Next, we process `/greeting/russian/short`. Since our path is not null,
652−we try to get the child named `%greeting`, which does exist since we
653−created it earlier. We put modify this child by recursing on it. Our
654−path is now `/russian/short`, so we look for a `%russian` child in our
655−`/greeting` ankh. This doesn't exist, so we add it by recursing. Our
656−path is now `/short`, so we look for a `%short` child in our
657−`/greeting/russian` ankh. This doesn't exist, so we add it by recursing.
658−Now our path is null, so we set the contents of this node to `"привет"`,
659−and we're done processing this path.
660−
661−Next, we process `/greeting/russian/long`. This proceeds similarly to
662−the previous except that now the ankh for `/greeting/russian` already
663−exists, so we simply reuse it rather than creating a new one. Of course,
664−we still must create a new `/greeting/russian/long` ankh.
665−
666−Next, we process `/greeting`. This ankh already exists, so after we've
667−recursed once, our path is null, and our ankh is not blank -- it already
668−has two children (and two grandchildren). We don't touch those, though,
669−since a node may be both a file and a directory. We just add the
670−contents of the file -- "customary upon meeting" -- to the existing
671−ankh.
672−
673−Next, we process `/greeting/spanish`. Of course, the `/greeting` ankh
674−already exists, but it doesn't have a `%spanish` child, so we create
675−that, taking care not to disturb the contents of the `/greeting` file.
676−We put "hola" into the ankh and call it good.
677−
678−Finally, we process `/farewell/russian`. Here, the `/farewell` ankh
679−doesn't exist, so we create it. Clearly the newly-created ankh doesn't
680−have any children, so we have to add a `%russian` child, and in this
681−child we put our last content -- "до свидания".
682−
683−We hope it's fairly obvious that the order we process the paths doesn't
684−affect the final ankh tree. The tree will be constructed in a very
685−different order depending on what order the paths come in, but the
686−resulting tree is independent of order.
687−
688−At any rate, we were talking about something important, weren't we? If
689−you recall, that concludes our discussion of `++rewind`, which was
690−called from `++read-at-aeon`. In summary, `++rewind` returns a context
691−in which our current state is (very nearly) as it was when the specified
692−version of the desk was the head. This allows `++read-at-aeon` to call
693−`++read` to read the requested information.
694−
695−```hoon
696− ++ read :: read:ze
697− |= mun=mood :: read at point
698− ^- (unit)
699− ?: ?=(%v p.mun)
700− [~ `dome`+<+<.read]
701− ?: &(?=(%w p.mun) !?=(%ud -.q.mun))
702− ?^(r.mun ~ [~ let])
703− ?: ?=(%w p.mun)
704− =+ ^= yak
705− %- tako-to-yaki
706− %- aeon-to-tako
707− let
708− ?^(r.mun ~ [~ [t.yak (forge-nori yak)]])
709− ::?> ?=(^ hit) ?^(r.mun ~ [~ i.hit]) :: what do?? need [@da nori]
710− (query(ank ank:(descend-path:(zu ank) r.mun)) p.mun)
711−```
712−
713−If we're requesting the dome, then we just return that immediately.
714−
715−If we're requesting the revision number of the desk and we're not
716−requesting it by number, then we just return the current number of this
717−desk. Note of course that this was really already handled in
718−`++read-at-aeon`.
719−
720−If we're requesting a `%w` with a specific revision number, then we do
721−something or other with the commit there. It's kind of weird, and it
722−doesn't seem to work, so we'll ignore this case.
723−
724−Otherwise, we descend into the ankh tree to the given path with
725−`++descend-path:zu`, and then we handle specific request in `++query`.
726−
727−```hoon
728− ++ descend-path :: descend recursively
729− |= way=path
730− ^+ +>
731− ?~(way +> $(way t.way, +> (descend i.way)))
732−```
733−
734−This is simple recursion down into the ankh tree. `++descend` descends
735−one level, so this will eventually get us down to the path we want.
736−
737−```hoon
738− ++ descend :: descend
739− |= lol=@ta
740− ^+ +>
741− =+ you=(~(get by r.ank) lol)
742− +>.$(ram [lol ram], ank ?~(you [*cash ~ ~] u.you))
743−```
744−
745−`ram` is the path that we're at, so to descend one level we push the
746−name of this level onto that path. We update the ankh with the correct
747−one at that path if it exists; else we create a blank one.
748−
749−Once we've decscended to the correct level, we need to actually deal
750−with the request.
751−
752−```hoon
753− ++ query :: query:ze
754− |= ren=?(%u %v %x %y %z) :: endpoint query
755− ^- (unit ,*)
756− ?- ren
757− %u [~ `rang`+<+>.query]
758− %v [~ `dome`+<+<.query]
759− %x ?~(q.ank ~ [~ q.u.q.ank])
760− %y [~ as-arch]
761− %z [~ ank]
762− ==
763−```
764−
765−Now that everything's set up, it's really easy. If they're requesting
766−the rang, dome, or ankh, we give it to them. If the contents of a file,
767−we give it to them if it is in fact a file. If the `arch`, then we
768−calculate it with `++as-arch`.
769−
770−```hoon
771− ++ as-arch :: as-arch:ze
772− ^- arch :: arch report
773− :+ p.ank
774− ?~(q.ank ~ [~ p.u.q.ank])
775− |- ^- (map ,@ta ,~)
776− ?~ r.ank ~
777− [[p.n.r.ank ~] $(r.ank l.r.ank) $(r.ank r.r.ank)]
778−```
779−
780−This very simply strips out all the "real" data and returns just our own
781−hash, the hash of the file contents (if we're a file), and a map of the
782−names of our immediate children.
783−
arvo/clay/local-sub.mddeleted−249
@@ -1,249 +0,0 @@
1−+++
2−title = "Local Subscriptions"
3−weight = 6
4−template = "doc.html"
5−+++
6−
7−Parts of this document may be out of date as of March 2021.
8−
9−A subscription to a range of revisions of a desk initially follows the
10−same path that a single read does. In `++aver`, we checked the head of
11−the given rave. If the head was `&`, then it was a single request, so we
12−handled it above. If `|`, then we handle it with the following code.
13−
14−```hoon
15− =+ nab=(~(case-to-aeon ze lim dom ran) p.p.rav)
16− ?~ nab
17− ?> =(~ (~(case-to-aeon ze lim dom ran) q.p.rav))
18− (duce hen (rive rav))
19− =+ huy=(~(case-to-aeon ze lim dom ran) q.p.rav)
20− ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab))))
21− (blub hen)
22− =+ top=?~(huy let.dom u.huy)
23− =+ sar=(~(lobes-at-path ze lim dom ran) u.nab r.p.rav)
24− =+ ear=(~(lobes-at-path ze lim dom ran) top r.p.rav)
25− =. +>.$
26− ?: =(sar ear) +>.$
27− =+ fud=(~(make-nako ze lim dom ran) u.nab top)
28− (bleb hen u.nab fud)
29− ?^ huy
30− (blub hen)
31− =+ ^= ptr ^- case
32− [%ud +(let.dom)]
33− (duce hen `rove`[%| ptr q.p.rav r.p.rav ear])
34− ==
35−```
36−
37−Recall that `++case-to-aeon:ze` produces the revision number that a case
38−corresponds to, if it corresponds to any. If it doesn't yet correspond
39−to a revision, then it produces null.
40−
41−Thus, we first check to see if we've even gotten to the beginning of the
42−range of revisions requested. If not, then we assert that we haven't yet
43−gotten to the end of the range either, because that would be really
44−strange. If not, then we immediately call `++duce`, which, if you
45−recall, for a local request, simply puts this duct and rove into our
46−cult `qyx`, so that we know who to respond to when the revision does
47−appear.
48−
49−If we've already gotten to the first revision, then we can produce some
50−content immediately. If we've also gotten to the final revision, and
51−that revision is earlier than the start revision, then it's a bad
52−request and we call `++blub`, which tells the subscriber that his
53−subscription will not be satisfied.
54−
55−Otherwise, we find the data at the given path at the beginning of the
56−subscription and at the last available revision in the subscription. If
57−they're the same, then we don't send a notification. Otherwise, we call
58−`++gack`, which creates the `++nako` we need to produce. We call
59−`++bleb` to actually produce the information.
60−
61−If we already have the last requested revision, then we also tell the
62−subscriber with `++blub` that the subscription will receive no further
63−updates.
64−
65−If there will be more revisions in the subscription, then we call
66−`++duce`, adding the duct to our subscribers. We modify the rove to
67−start at the next revision since we've already handled all the revisions
68−up to the present.
69−
70−We glossed over the calls to `++lobes-at-path`, `++make-nako`, and
71−`++bleb`, so we'll get back to those right now. `++bleb` is simple, so
72−we'll start with that.
73−
74−```hoon
75− ++ bleb :: ship sequence
76− |= [hen=duct ins=@ud hip=nako]
77− ^+ +>
78− (blab hen [%w [%ud ins] ~] hip)
79−```
80−
81−We're given a duct, the beginning revision number, and the nako that
82−contains the updates since that revision. We use `++blab` to produce
83−this result to the subscriber. The case is `%w` with a revision number
84−of the beginning of the subscription, and the data is the nako itself.
85−
86−We call `++lobes-at-path:ze` to get the data at the particular path.
87−
88−```hoon
89− ++ lobes-at-path :: lobes-at-path:ze
90− |= [oan=aeon pax=path] :: data at path
91− ^- (map path lobe)
92− ?: =(0 oan) ~
93− %- mo
94− %+ skim
95− %. ~
96− %~ tap by
97− =< q
98− %- tako-to-yaki
99− %- aeon-to-tako
100− oan
101− |= [p=path q=lobe]
102− ?| ?=(~ pax)
103− ?& !?=(~ p)
104− =(-.pax -.p)
105− $(p +.p, pax +.pax)
106− == ==
107−```
108−
109−At revision zero, the theoretical common revision between all
110−repositories, there is no data, so we produce null.
111−
112−We get the list of paths (paired with their lobe) in the revision
113−referred to by the given number and we keep only those paths which begin
114−with `pax`. Converting to a map, we now have a map from the subpaths at
115−the given path to the hash of their data. This is simple and efficient
116−to calculate and compare to later revisions. This allows us to easily
117−tell if a node or its children have changed.
118−
119−Finally, we will describe `++make-nako:ze`.
120−
121−```hoon
122− ++ make-nako :: gack a through b
123− |= [a=aeon b=aeon]
124− ^- [(map aeon tako) aeon (set yaki) (set blob)]
125− :_ :- b
126− =- [(takos-to-yakis -<) (lobes-to-blobs ->)]
127− %+ reachable-between-takos
128− (~(get by hit) a) :: if a not found, a=0
129− (aeon-to-tako b)
130− ^- (map aeon tako)
131− %- mo %+ skim (~(tap by hit) ~)
132− |= [p=aeon *]
133− &((gth p a) (lte p b))
134−```
135−
136−We need to produce four things -- the numbers of the new commits, the
137−number of the latest commit, the new commits themselves, and the new
138−data itself.
139−
140−The first is fairly easy to produce. We simply go over our map of
141−numbered commits and produce all those numbered greater than `a` and not
142−greater than `b`.
143−
144−The second is even easier to produce -- `b` is clearly our most recent
145−commit.
146−
147−The third and fourth are slightly more interesting, though not too
148−terribly difficult. First, we call `++reachable-between-takos`.
149−
150−```hoon
151− ++ reachable-between-takos
152− |= [a=(unit tako) b=tako] :: pack a through b
153− ^- [(set tako) (set lobe)]
154− =+ ^= sar
155− ?~ a ~
156− (reachable-takos r:(tako-to-yaki u.a))
157− =+ yak=`yaki`(tako-to-yaki b)
158− %+ new-lobes-takos (new-lobes ~ sar) :: get lobes
159− |- ^- (set tako) :: walk onto sar
160− ?: (~(has in sar) r.yak)
161− ~
162− =+ ber=`(set tako)`(~(put in `(set tako)`~) `tako`r.yak)
163− %- ~(uni in ber)
164− ^- (set tako)
165− %+ roll p.yak
166− |= [yek=tako bar=(set tako)]
167− ^- (set tako)
168− ?: (~(has in bar) yek) :: save some time
169− bar
170− %- ~(uni in bar)
171− ^$(yak (tako-to-yaki yek))
172−```
173−
174−We take a possible starting commit and a definite ending commit, and we
175−produce the set of commits and the set of data between them.
176−
177−We let `sar` be the set of commits reachable from `a`. If `a` is null,
178−then obviously no commits are reachable. Otherwise, we call
179−`++reachable-takos` to calculate this.
180−
181−```hoon
182− ++ reachable-takos :: reachable
183− |= p=tako :: XX slow
184− ^- (set tako)
185− =+ y=(tako-to-yaki p)
186− =+ t=(~(put in _(set tako)) p)
187− %+ roll p.y
188− |= [q=tako s=_t]
189− ?: (~(has in s) q) :: already done
190− s :: hence skip
191− (~(uni in s) ^$(p q)) :: otherwise traverse
192−```
193−
194−We very simply produce the set of the given tako plus its parents,
195−recursively.
196−
197−Back in `++reachable-between-takos`, we let `yak` be the yaki of `b`,
198−the ending commit. With this, we create a set that is the union of `sar`
199−and all takos reachable from `b`.
200−
201−We pass `sar` into `++new-lobes` to get all the lobes referenced by any
202−tako referenced by `a`. The result is passed into `++new-lobes-takos` to
203−do the same, but not recomputing those in already calculated last
204−sentence. This produces the sets of takos and lobes we need.
205−
206−```hoon
207− ++ new-lobes :: object hash set
208− |= [b=(set lobe) a=(set tako)] :: that aren't in b
209− ^- (set lobe)
210− %+ roll (~(tap in a) ~)
211− |= [tak=tako bar=(set lobe)]
212− ^- (set lobe)
213− =+ yak=(tako-to-yaki tak)
214− %+ roll (~(tap by q.yak) ~)
215− |= [[path lob=lobe] far=_bar]
216− ^- (set lobe)
217− ?~ (~(has in b) lob) :: don't need
218− far
219− =+ gar=(lobe-to-blob lob)
220− ?- -.gar
221− %direct (~(put in far) lob)
222− %delta (~(put in $(lob q.gar)) lob)
223− %indirect (~(put in $(lob s.gar)) lob)
224− ==
225−```
226−
227−Here, we're creating a set of lobes referenced in a commit in `a`. We
228−start out with `b` as the initial set of lobes, so we don't need to
229−recompute any of the lobes referenced in there.
230−
231−The algorithm is pretty simple, so we won't bore you with the details.
232−We simply traverse every commit in `a`, looking at every blob referenced
233−there, and, if it's not already in `b`, we add it to `b`. In the case of
234−a direct blob, we're done. For a delta or an indirect blob, we
235−recursively add every blob referenced within the blob.
236−
237−```hoon
238− ++ new-lobes-takos :: garg & repack
239− |= [b=(set lobe) a=(set tako)]
240− ^- [(set tako) (set lobe)]
241− [a (new-lobes b a)]
242−```
243−
244−Here, we just update the set of lobes we're given with the commits we're
245−given and produce both sets.
246−
247−This concludes our discussion of a local subscription.
248−
249−
arvo/clay/using.md−4
@@ -49,10 +49,6 @@ from the start to the end triggers a response. Since a `%many`
4949request doesn't ask for any particular data, there aren't `%u`,
5050`%x`, and `%y` versions for it.
5151
52−For further information, see [Local Reads](@/docs/arvo/clay/local-reads.md),
53−[Local Subscriptions](@/docs/arvo/clay/local-sub.md), and [Foreign
54−Requests](@/docs/arvo/clay/foreign.md)
55−
5652### Unix sync
5753
5854Usage: