@@ -1,2625 +0,0 @@
1−+++
2−title = "Clay"
3−weight = 3
4−template = "doc.html"
5−+++
6−Our filesystem.
7−
8−`%clay` is version-controlled, referentially-transparent, and global.
9−While this filesystem is stored in `%clay`, it is mirrored to Unix for
10−convenience. Unix tells `%clay`s whenever a file changes in the Unix
11−copy of the filesystem so that the change may be applied. `%clay` tells
12−unix whenever an app or vane changes the filesystem so that the change
13−can be effected in Unix. Apps and vanes may use `%clay` to write to the
14−filesystem, query it, and subscribe to changes in it. Ford and gall use
15−`%clay` to serve up apps and web pages.
16−
17−`%clay` includes three components. First is the filesystem/version
18−control algorithms, which are mostly defined in `++ze` and `++zu` in
19−zuse. Second is the write, query, and subscription logic. Finally, there
20−is the logic for communicating requests to, and receiving requests from,
21−foreign ships.
22−
23−## Architecture
24−
25−Clay is the primary filesystem for the arvo operating system,
26−which is the core of an urbit. The architecture of clay is
27−intrinsically connected with arvo, but we assume no knowledge of
28−either arvo or urbit. We will point out only those features of
29−arvo that are necessary for an understanding of clay, and we will
30−do so only when they arise.
31−
32−The first relevant feature of arvo is that it is a deterministic
33−system where input and output are defined as a series of events
34−and effects. The state of arvo is simply a function of its event
35−log. None of the effects from an event are emitted until the
36−event is entered in the log and persisted, either to disk or
37−another trusted source of persistence, such as a Kafka cluster.
38−Consequently, arvo is a single-level store: everything in its
39−state is persistent.
40−
41−In a more traditional OS, everything in RAM can be erased at any
42−time by power failure, and is always erased on reboot. Thus, a
43−primary purpose of a filesystem is to ensure files persist across
44−power failures and reboots. In arvo, both power failures and
45−reboots are special cases of suspending computation, which is
46−done safely since our event log is already persistent. Therefore,
47−clay is not needed in arvo for persistence. Why, then, do we have a
48−filesystem? There are two answers to this question.
49−
50−First, clay provides a filesystem tree, which is a convenient
51−user interface for some applications. Unix has the useful concept
52−of virtual filesystems, which are used for everything from direct
53−access to devices, to random number generators, to the /proc
54−tree. It is easy and intuitive to read from and write to a
55−filesystem tree.
56−
57−Second, clay has a distributed revision-control system baked into
58−it. Traditional filesystems are not revision controlled, so
59−userspace software -- such as git -- is written on top of them to
60−do so. clay natively provides the same functionality as modern
61−DVCSes, and more.
62−
63−clay has two other unique properties that we'll cover later on:
64−it supports typed data and is referentially transparent.
65−
66−### Revision Control
67−
68−Every urbit has one or more "desks", which are independently
69−revision-controlled branches. Each desk contains its own mark
70−definitions, apps, doc, and so forth.
71−
72−Traditionally, an urbit has at least a base and a home desk. The
73−base desk has all the system software from the distribution. the
74−home desk is a fork of base with all the stuff specific to the
75−user of the urbit.
76−
77−A desk is a series of numbered commits, the most recent of which
78−represents the current state of the desk. A commit is composed of
79−(1) an absolute time when it was created, (2) a list of zero or
80−more parents, and (3) a map from paths to data.
81−
82−Most commits have exactly one parent, but the initial commit on a
83−desk may have zero parents, and merge commits have more than one
84−parent.
85−
86−The non-meta data is stored in the map of paths to data. It's
87−worth noting that no constraints are put on this map, so, for
88−example, both /a/b and /a/b/c could have data. This is impossible
89−in a traditional Unix filesystem since it means that /a/b is both
90−a file and a directory. Conventionally, the final element in the
91−path is its mark -- much like a filename extension in Unix. Thus,
92−/doc/readme.md in Unix is stored as /doc/readme/md in urbit.
93−
94−The data is not stored directly in the map; rather, a hash of the
95−data is stored, and we maintain a master blob store. Thus, if the
96−same data is referred to in multiple commits (as, for example,
97−when a file doesn't change between commits), only the hash is
98−duplicated.
99−
100−In the master blob store, we either store the data directly, or
101−else we store a diff against another blob. The hash is dependent
102−only on the data within and not on whether or not it's stored
103−directly, so we may on occasion rearrange the contents of the
104−blob store for performance reasons.
105−
106−Recall that a desk is a series of numbered commits. Not every
107−commit in a desk must be numbered. For example, if the base desk
108−has had 50 commits since home was forked from it, then a merge
109−from base to home will only add a single revision number to home,
110−although the full commit history will be accessible by traversing
111−the parentage of the individual commits.
112−
113−We do guarantee that the first commit is numbered 1, commits are
114−numbered consecutively after that (i.e. there are no "holes"),
115−the topmost commit is always numbered, and every numbered commit
116−is an ancestor of every later numbered commit.
117−
118−There are three ways to refer to particular commits in the
119−revision history. Firstly, one can use the revision number.
120−Secondly, one can use any absolute time between the one numbered
121−commit and the next (inclusive of the first, exclusive of the
122−second). Thirdly, every desk has a map of labels to revision
123−numbers. These labels may be used to refer to specific commits.
124−
125−Additionally, clay is a global filesystem, so data on other urbit
126−is easily accessible the same way as data on our local urbit. In
127−general, the path to a particular revision of a desk is
128−/~urbit-name/desk-name/revision. Thus, to get /try/readme/md
129−from revision 5 of the home desk on ~sampel-sipnym, we refer to
130−/~sampel-sipnym/home/5/try/readme/md. Clay's namespace is thus
131−global and referentially transparent.
132−
133−XXX reactivity here?
134−
135−### A Typed Filesystem
136−
137−Since clay is a general filesystem for storing data of arbitrary
138−types, in order to revision control correctly it needs to be
139−aware of types all the way through. Traditional revision control
140−does an excellent job of handling source code, so for source code
141−we act very similar to traditional revision control. The
142−challenge is to handle other data similarly well.
143−
144−For example, modern VCSs generally support "binary files", which
145−are files for which the standard textual diffing, patching, and
146−merging algorithms are not helpful. A "diff" of two binary files
147−is just a pair of the files, "patching" this diff is just
148−replacing the old file with the new one, and "merging"
149−non-identical diffs is always a conflict, which can't even be
150−helpfully annotated. Without knowing anything about the structure
151−of a blob of data, this is the best we can do.
152−
153−Often, though, "binary" files have some internal structure, and
154−it is possible to create diff, patch, and merge algorithms that
155−take advantage of this structure. An image may be the result of a
156−base image with some set of operations applied. With algorithms
157−aware of this set of operations, not only can revision control
158−software save space by not having to save every revision of the
159−image individually, these transformations can be made on parallel
160−branches and merged at will.
161−
162−Suppose Alice is tasked with touching up a picture, improving the
163−color balance, adjusting the contrast, and so forth, while Bob
164−has the job of cropping the picture to fit where it's needed and
165−adding textual overlay. Without type-aware revision control,
166−these changes must be made serially, requiring Alice and Bob to
167−explicitly coordinate their efforts. With type-aware revision
168−control, these operations may be performed in parallel, and then
169−the two changesets can be merged programmatically.
170−
171−Of course, even some kinds of text files may be better served by
172−diff, patch, and merge algorithms aware of the structure of the
173−files. Consider a file containing a pretty-printed JSON object.
174−Small changes in the JSON object may result in rather significant
175−changes in how the object is pretty-printed (for example, by
176−addding an indentation level, splitting a single line into
177−multiple lines).
178−
179−A text file wrapped at 80 columns also reacts suboptimally with
180−unadorned Hunt-McIlroy diffs. A single word inserted in a
181−paragraph may push the final word or two of the line onto the
182−next line, and the entire rest of the paragraph may be flagged as
183−a change. Two diffs consisting of a single added word to
184−different sentences may be flagged as a conflict. In general,
185−prose should be diffed by sentence, not by line.
186−
187−As far as the author is aware, clay is the first generalized,
188−type-aware revision control system. We'll go into the workings
189−of this system in some detail.
190−
191−### Marks
192−
193−Central to a typed filesystem is the idea of types. In clay, we
194−call these "marks". A mark is a file that defines a type,
195−conversion routines to and from the mark, and diff, patch, and
196−merge routines.
197−
198−For example, a `%txt` mark may be a list of lines of text, and it
199−may include conversions to `%mime` to allow it to be serialized
200−and sent to a browswer or to the unix filesystem. It will also
201−include Hunt-McIlroy diff, patch, and merge algorithms.
202−
203−A `%json` mark would be defined as a json object in the code, and
204−it would have a parser to convert from `%txt` and a printer to
205−convert back to `%txt`. The diff, patch, and merge algorithms are
206−fairly straightforward for json, though they're very different
207−from the text ones.
208−
209−More formally, a mark is a core with three arms, `++grab`,
210−`++grow`, and `++grad`. In `++grab` is a series of functions to
211−convert from other marks to the given mark. In `++grow` is a
212−series of functions to convert from the given mark to other
213−marks. In `++grad` is `++diff`, `++pact`, `++join`, and `++mash`.
214−
215−The types are as follows, in an informal pseudocode:
216−
217−```
218− ++ grab:
219− ++ mime: <mime> -> <mark-type>
220− ++ txt: <txt> -> <mark-type>
221− ...
222− ++ grow:
223− ++ mime: <mark-type> -> <mime>
224− ++ txt: <mark-type> -> <txt>
225− ...
226− ++ grad
227− ++ diff: (<mark-type>, <mark-type>) -> <diff-type>
228− ++ pact: (<mark-type>, <diff-type>) -> <mark-type>
229− ++ join: (<diff-type>, <diff-type>) -> <diff-type> or NULL
230− ++ mash: (<diff-type>, <diff-type>) -> <diff-type>
231−```
232−
233−These types are basically what you would expect. Not every mark
234−has each of these functions defined -- all of them are optional
235−in the general case.
236−
237−In general, for a particular mark, the `++grab` and `++grow` entries
238−(if they exist) should be inverses of each other.
239−
240−In `++grad`, `++diff` takes two instances of a mark and produces
241−a diff of them. `++pact` takes an instance of a mark and patches
242−it with the given diff. `++join` takes two diffs and attempts to
243−merge them into a single diff. If there are conflicts, it
244−produces null. `++mash` takes two diffs and forces a merge,
245−annotating any conflicts.
246−
247−In general, if `++diff` called with A and B produces diff D, then
248−`++pact` called with A and D should produce B. Also, if `++join`
249−of two diffs does not produce null, then `++mash` of the same
250−diffs should produce the same result.
251−
252−Alternately, instead of `++diff`, `++pact`, `++join`, and
253−`++mash`, a mark can provide the same functionality by defining
254−`++sted` to be the name of another mark to which we wish to
255−delegate the revision control responsibilities. Then, before
256−running any of those functions, clay will convert to the other
257−mark, and convert back afterward. For example, the `%hoon` mark
258−is revision-controlled in the same way as `%txt`, so its `++grad`
259−is simply `++sted %txt`. Of course, `++txt` must be defined in
260−`++grow` and `++grab` as well.
261−
262−Every file in clay has a mark, and that mark must have a
263−fully-functioning `++grad`. Marks are used for more than just
264−clay, and other marks don't need a `++grad`, but if a piece of
265−data is to be saved to clay, we must know how to revision-control
266−it.
267−
268−Additionally, if a file is to be synced out to unix, then it must
269−have conversion routines to and from the `%mime` mark.
270−
271−## Using clay
272−
273−### Reading and Subscribing
274−
275−When reading from Clay, there are three types of requests. A
276−`%sing` request asks for data at single revsion. A `%next`
277−request asks to be notified the next time there's a change to
278−given file. A `%many` request asks to be notified on every
279−change in a desk for a range of changes.
280−
281−For `%sing` and `%next`, there are generally three things to be
282−queried. A `%u` request simply checks for the existence of a
283−file at a path. A `%x` request gets the data in the file at a
284−path. A `%y` request gets a hash of the data in the file at the
285−path combined with all its children and their data. Thus, `%y`
286−of a node changes if it or any of its children change.
287−
288−A `%sing` request is fulfilled immediately if possible. If the
289−requested revision is in the future, or is on another ship for
290−which we don't have the result cached, we don't respond
291−immediately. If the requested revision is in the future, we wait
292−until the revision happens before we respond to the request. If
293−the request is for data on another ship, we pass on the request
294−to the other ship. In general, Clay subscriptions, like most
295−things in Urbit, aren't guaranteed to return immediately.
296−They'll return when they can, and they'll do so in a
297−referentially transparent manner.
298−
299−A `%next` request checks query at the given revision, and it
300−produces the result of the query the next time it changes, along
301−with the revsion number when it changes. Thus, a `%next` of a
302−`%u` is triggered when a file is added or deleted, a `%next` of a
303−`%x` is triggered when a file is added, deleted, or changed, and
304−a `%next` of a `%y` is triggered when a file or any of its
305−children is added, deleted, or changed.
306−
307−A `%many` request is triggered every time the given desk has a
308−new revision. Unlike a `%next`, a `%many` has both a start and
309−an end revsion, after which it stops returning. For `%next`, a
310−single change is reported, and if the caller wishes to hear of
311−the next change, it must resubscribe. For `%many`, every revsion
312−from the start to the end triggers a response. Since a `%many`
313−request doesn't ask for any particular data, there aren't `%u`,
314−`%x`, and `%y` versions for it.
315−
316−### Unix sync
317−
318−One of the primary functions of clay is as a convenient user
319−interface. While tools exist to use clay from within urbit, it's
320−often useful to be able to treat clay like any other filesystem
321−from the Unix perspective -- to "mount" it, as it were.
322−
323−From urbit, you can run `|mount /path/to/directory %mount-point`,
324−and this will mount the given clay directory to the mount-point
325−directory in Unix. Every file is converted to `%mime` before it's
326−written to Unix, and converted back when read from Unix. The
327−entire directory is watched (a la Dropbox), and every change is
328−committed once you run `|commit %mount-point`.
329−
330−### Merging
331−
332−Merging is a fundamental operation for a distributed revision
333−control system. At their root, clay's merges are similar to
334−git's, but with some additions to accomodate typed data. There
335−are seven different merge strategies.
336−
337−Throughout our discussion, we'll say that the merge is from
338−Alice's desk to Bob's. Recall that a commit is a date (for all
339−new commits this will be the current date), a list of parents,
340−and the data itself.
341−
342−A `%init` merge should be used iff it's the first commit to a
343−desk. The head of Alice's desk is used as the number 1 commit to
344−Bob's desk. Obviously, the ancestry remains intact through
345−traversing the parentage of the commit even though previous
346−commits are not numbered for Bob's desk.
347−
348−A `%this` merge means to keep what's in Bob's desk, but join the
349−ancestry. Thus, the new commit has the head of each desk as
350−parents, but the data is exactly what's in Bob's desk. For those
351−following along in git, this is the 'ours' merge strategy, not
352−the '--ours' option to the 'recursive' merge strategy. In other
353−words, even if Alice makes a change that does not conflict with
354−Bob, we throw it away. It's Bob's way or the highway.
355−
356−A `%that` merge means to take what's in Alice's desk, but join
357−the ancestry. This is the reverse of `%this`.
358−
359−A `%fine` merge is a "fast-forward" merge. This succeeds iff one
360−head is in the ancestry of the other. In this case, we use the
361−descendant as our new head.
362−
363−For `%meet`, `%mate`, and `%meld` merges, we first find the most
364−recent common ancestor to use as our merge base. If we have no
365−common ancestors, then we fail. If we have more than one most
366−recent common ancestor, then we have a criss-cross situation,
367−which should be handled delicately. At present, we delicately
368−throw up our hands and give up, but something akin to git's
369−'recursive' strategy should be implemented in the future.
370−
371−There's a functional inclusion ordering on `%fine`, `%meet`,
372−`%mate`, and `%meld` such that if an earlier strategy would have
373−succeeded, then every later strategy will produce the same
374−result. Put another way, every earlier strategy is the same as
375−every later strategy except with a restricted domain.
376−
377−A `%meet` merge only succeeds if the changes from the merge base
378−to Alice's head (hereafter, "Alice's changes") are in different
379−files than Bob's changes. In this case, the parents are both
380−Alice's and Bob's heads, and the data is the merge base plus
381−Alice's changed files plus Bob's changed files.
382−
383−A `%mate` merge attempts to merge changes to the same file when
384−both Alice and bob change it. If the merge is clean, we use it;
385−otherwise, we fail. A merge between different types of changes --
386−for example, deleting a file vs changing it -- is always a
387−conflict. If we succeed, the parents are both Alice's and Bob's
388−heads, and the data is the merge base plus Alice's changed files
389−plus Bob's changed files plus the merged files.
390−
391−A `%meld` merge will succeed even if there are conflicts. If
392−there are conflicts in a file, then we use the merge base's
393−version of that file, and we produce a set of files with
394−conflicts. The parents are both Alice's and Bob's heads, and the
395−data is the merge base plus Alice's changed files plus Bob's
396−changed files plus the successfully merged files plus the merge
397−base's version of the conflicting files.
398−
399−That's the extent of the merge options in clay proper. In
400−userspace there's a final option `%auto`, which is the most
401−common. `%auto` checks to see if Bob's desk exists, and if it
402−doesn't we use a `%init` merge. Otherwise, we progressively try
403−`%fine`, `%meet`, and `%mate` until one succeeds.
404−
405−If none succeed, we merge Bob's desk into a scratch desk. Then,
406−we merge Alice's desk into the scratch desk with the `%meld`
407−option to force the merge. For each file in the produced set of
408−conflicting files, we call the `++mash` function for the
409−appropriate mark, which annotates the conflicts if we know how.
410−
411−Finally, we display a message to the user informing them of the
412−scratch desk's existence, which files have annotated conflicts,
413−and which files have unannotated conflicts. When the user has
414−resolved the conflicts, they can merge the scratch desk back into
415−Bob's desk. This will be a `%fine` merge since Bob's head is in
416−the ancestry of the scratch desk.
417−
418−### Autosync
419−
420−Tracking and staying in sync with another desk is another
421−fundamental operation. We call this "autosync". This doesn't mean
422−simply mirroring a desk, since that wouldn't allow local changes.
423−We simply want to apply changes as they are made upstream, as
424−long as there are no conflicts with local changes.
425−
426−This is implemented by watching the other desk, and, when it has
427−changes, merging these changes into our desk with the usual merge
428−strategies.
429−
430−Note that it's quite reasonable for two desks to be autosynced to
431−each other. This results in any change on one desk being mirrored
432−to the other and vice versa.
433−
434−Additionally, it's fine to set up an autosync even if one desk,
435−the other desk, or both desks do not exist. The sync will be
436−activated when the upstream desk comes into existence and will
437−create the downstream desk if needed.
438−
439−## Commentary
440−
441−The first part of this section will be reference documentation for the data
442−types used by our filesystem. In fact, as a general guide, we recommend
443−reading and attempting to understand the data structures used in any
444−Hoon code before you try to read the code itself. Although complete
445−understanding of the data structures is impossible without seeing them
446−used in the code, an 80% understanding greatly clarifies the code. As
447−another general guide, when reading Hoon, it rarely pays off to
448−understand every line of code when it appears. Try to get the gist of
449−it, and then move on. The next time you come back to it, it'll likely
450−make a lot more sense.
451−
452−After a description of the data models, we'll give an overview of the
453−interface that vanes and applications can use to interact with the
454−filesystem.
455−
456−Finally, we'll dive into the code and the algorithms themselves. You
457−know, the fun part.
458−
459−### Data Models
460−
461−As you're reading through this section, remember you can always come
462−back to this when you run into these types later on. You're not going to
463−remember everything the first time through, but it is worth reading, or
464−at least skimming, this so that you get a rough idea of how our state is
465−organized.
466−
467−The types that are certainly worth reading are `++raft`, `++room`,
468−`++dome:clay`, `++ankh:clay`, `++rung:clay`, `++rang:clay`, `++blob:clay`, `++yaki:clay`, and `++nori:clay`
469−(possibly in that order). All in all, though, this section isn't too
470−long, so many readers may wish to quickly read through all of it. If you
471−get bored, though, just skip to the next section. You can always come
472−back when you need to.
473−
474−### `++raft`, formal state
475−
476−```hoon
477− ++ raft :: filesystem
478− $: fat=(map ship room) :: domestic
479− hoy=(map ship rung) :: foreign
480− ran=rang :: hashes
481− == ::
482−```
483−
484−This is the state of our vane. Anything that must be remembered between
485−calls to clay is stored in this state.
486−
487−`fat` is the set of domestic servers. This stores all the information
488−that is specfic to a particular ship on this pier. The keys to this map
489−are the ships on the current pier. all the information that is specific
490−to a particular foreign ship. The keys to this map are all the ships
491−whose filesystems we have attempted to access through clay.
492−
493−`ran` is the store of all commits and deltas, keyed by hash. The is
494−where all the "real" data we know is stored; the rest is "just
495−bookkeeping".
496−
497−#### `++room`, filesystem per domestic ship
498−
499−```hoon
500− ++ room :: fs per ship
501− $: hun=duct :: terminal duct
502− hez=(unit duct) :: sync duch
503− dos=(map desk dojo) :: native desk
504− == ::
505−```
506−
507−This is the representation of the filesystem of a ship on our pier.
508−
509−`hun` is the duct we use to send messages to dill to display
510−notifications of filesystem changes. Only `%note` gifts should be
511−produced along this duct. This is set by the `%init` kiss.
512−
513−`hez`, if present, is the duct we use to send sync messages to unix so
514−that they end up in the pier unix directory. Only `%ergo` gifts should
515−be producd along this duct. This is set by `%into` and `%invo` kisses.
516−
517−`dos` is a well-known operating system released in 1981. It is also the
518−set of desks on this ship, mapped to their data.
519−
520−#### `++desk`, filesystem branch
521−
522−```hoon
523− ++ desk ,@tas :: ship desk case spur
524−```
525−
526−This is the name of a branch of the filesystem. The default desks are
527−"arvo", "main", and "try". More may be created by simply referencing
528−them. Desks have independent histories and states, and they may be
529−merged into each other.
530−
531−### `++dojo`, domestic desk state
532−
533−```hoon
534− ++ dojo ,[p=cult q=dome] :: domestic desk state
535−```
536−
537−This is the all the data that is specific to a particular desk on a
538−domestic ship. `p` is the set of subscribers to this desk and `q` is the
539−data in the desk.
540−
541−#### `++cult`, subscriptions
542−
543−```hoon
544− ++ cult (map duct rave) :: subscriptions
545−```
546−
547−This is the set of subscriptions to a particular desk. The keys are the
548−ducts from where the subscriptions requests came. The results will be
549−produced along these ducts. The values are a description of the
550−requested information.
551−
552−#### `++rave:clay`, general subscription request
553−
554−```hoon
555− ++ rave :: general request
556− $% [& p=mood] :: single request
557− [| p=moat] :: change range
558− == ::
559−```
560−
561−This represents a subscription request for a desk. The request can be
562−for either a single item in the desk or else for a range of changes on
563−the desk.
564−
565−### `++rove`, stored general subscription request
566−
567−```hoon
568− ++ rove (each mood moot) :: stored request
569−```
570−
571−When we store a request, we store subscriptions with a little extra
572−information so that we can determine whether new versions actually
573−affect the path we're subscribed to.
574−
575−#### `++mood:clay`, single subscription request
576−
577−```hoon
578− ++ mood ,[p=care q=case r=path] :: request in desk
579−```
580−
581−This represents a request for the state of the desk at a particular
582−commit, specfied by `q`. `p` specifies what kind of information is
583−desired, and `r` specifies the path we are requesting.
584−
585−#### `++moat:clay`, range subscription request
586−
587−```hoon
588− ++ moat ,[p=case q=case r=path] :: change range
589−```
590−
591−This represents a request for all changes between `p` and `q` on path
592−`r`. You will be notified when a change is made to the node referenced
593−by the path or to any of its children.
594−
595−### `++moot`, stored range subscription request
596−
597−```hoon
598− ++ moot ,[p=case q=case r=path s=(map path lobe)] ::
599−```
600−
601−This is just a `++moat:clay` plus a map of paths to lobes. This map
602−represents the data at the node referenced by the path at case `p`, if
603−we've gotten to that case (else null). We only send a notification along
604−the subscription if the data at a new revision is different than it was.
605−
606−### `++care:clay`, clay submode
607−
608−```hoon
609− ++ care ?(%u %v %w %x %y %z) :: clay submode
610−```
611−
612−This specifies what type of information is requested in a subscription
613−or a scry.
614−
615−`%u` requests the `++rang:clay` at the current moment. Because this
616−information is not stored for any moment other than the present, we
617−crash if the `++case:clay` is not a `%da` for now.
618−
619−`%v` requests the `++dome:clay` at the specified commit.
620−
621−`%w` requests the revsion number of the desk.
622−
623−`%x` requests the file at a specified path at the specified commit. If
624−there is no node at that path or if the node has no contents (that is,
625−if `q:ankh` is null), then this produces null.
626−
627−`%y` requests a `++arch` of the specfied commit at the specified path.
628−
629−`%z` requests the `++ankh` of the specified commit at the specfied path.
630−
631−### `++arch`, shallow filesystem node
632−
633−```hoon
634− ++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node
635−```
636−
637−This is analogous to `++ankh:clay` except that the we have neither our
638−contents nor the ankhs of our children. The other fields are exactly the
639−same, so `p` is a hash of the associated ankh, `u.q`, if it exists, is a
640−hash of the contents of this node, and the keys of `r` are the names of
641−our children. `r` is a map to null rather than a set so that the
642−ordering of the map will be equivalent to that of `r:ankh`, allowing
643−efficient conversion.
644−
645−#### `++case:clay`, specifying a commit
646−
647−```hoon
648− ++ case :: ship desk case spur
649− $% [%da p=@da] :: date
650− [%tas p=@tas] :: label
651− [%ud p=@ud] :: number
652− == ::
653−```
654−
655−A commit can be referred to in three ways: `%da` refers to the commit
656−that was at the head on date `p`, `%tas` refers to the commit labeled
657−`p`, and `%ud` refers to the commit numbered `p`. Note that since these
658−all can be reduced down to a `%ud`, only numbered commits may be
659−referenced with a `++case:clay`.
660−
661−#### `++dome:clay`, desk data
662−
663−```hoon
664− ++ dome :: project state
665− $: ang=agon :: pedigree
666− ank=ankh :: state
667− let=@ud :: top id
668− hit=(map ,@ud tako) :: changes by id
669− lab=(map ,@tas ,@ud) :: labels
670− == ::
671−```
672−
673−This is the data that is actually stored in a desk.
674−
675−`ang` is unused and should be removed.
676−
677−`ank` is the current state of the desk. Thus, it is the state of the
678−filesystem at revison `let`. The head of a desk is always a numbered
679−commit.
680−
681−`let` is the number of the most recently numbered commit. This is also
682−the total number of numbered commits.
683−
684−`hit` is a map of numerical ids to hashes of commits. These hashes are
685−mapped into their associated commits in `hut:rang:clay`. In general, the keys
686−of this map are exactly the numbers from 1 to `let`, with no gaps. Of
687−course, when there are no numbered commits, `let` is 0, so `hit` is
688−null. Additionally, each of the commits is an ancestor of every commit
689−numbered greater than this one. Thus, each is a descendant of every
690−commit numbered less than this one. Since it is true that the date in
691−each commit (`t:yaki`) is no earlier than that of each of its parents,
692−the numbered commits are totally ordered in the same way by both
693−pedigree and date. Of course, not every commit is numbered. If that
694−sounds too complicated to you, don't worry about it. It basically
695−behaves exactly as you would expect.
696−
697−`lab` is a map of textual labels to numbered commits. Note that labels
698−can only be applied to numbered commits. Labels must be unique across a
699−desk.
700−
701−#### `++ankh`, filesystem node
702−
703−```hoon
704− ++ ankh :: fs node (new)
705− $: p=cash :: recursive hash
706− q=(unit ,[p=cash q=*]) :: file
707− r=(map ,@ta ankh) :: folders
708− == ::
709−```
710−
711−This is a single node in the filesystem. This may be file or a directory
712−or both. In earth filesystems, a node is a file xor a directory. On
713−mars, we're inclusive, so a node is a file ior a directory.
714−
715−`p` is a recursive hash that depends on the contents of the this file or
716−directory and on any children.
717−
718−`q` is the contents of this file, if any. `p.q` is a hash of the
719−contents while `q.q` is the data itself.
720−
721−`r` is the set of children of this node. In the case of a pure file,
722−this is empty. The keys are the names of the children and the values
723−are, recursively, the nodes themselves.
724−
725−#### `++cash`, ankh hash
726−
727−```hoon
728− ++ cash ,@uvH :: ankh hash
729−```
730−
731−This is a 128-bit hash of an ankh. These are mostly stored within ankhs
732−themselves, and they are used to check for changes in possibly-deep
733−hierarchies.
734−
735−#### `++rung`, filesystem per neighbor ship
736−
737−```hoon
738− ++ rung $: rus=(map desk rede) :: neighbor desks
739− == ::
740−```
741−
742−This is the filesystem of a neighbor ship. The keys to this map are all
743−the desks we know about on their ship.
744−
745−#### `++rede`, desk state
746−
747−```hoon
748− ++ rede :: universal project
749− $: lim=@da :: complete to
750− qyx=cult :: subscribers
751− ref=(unit rind) :: outgoing requests
752− dom=dome :: revision state
753− == ::
754−```
755−
756−This is our knowledge of the state of a desk, either foreign or
757−domestic.
758−
759−`lim` is the date of the last full update. We only respond to requests
760−for stuff before this time.
761−
762−`qyx` is the list of subscribers to this desk. For domestic desks, this
763−is simply `p:dojo`, all subscribers to the desk, while in foreign desks
764−this is all the subscribers from our ship to the foreign desk.
765−
766−`ref` is the request manager for the desk. For domestic desks, this is
767−null since we handle requests ourselves.
768−
769−`dom` is the actual data in the desk.
770−
771−#### `++rind`, request manager
772−
773−```hoon
774− ++ rind :: request manager
775− $: nix=@ud :: request index
776− bom=(map ,@ud ,[p=duct q=rave]) :: outstanding
777− fod=(map duct ,@ud) :: current requests
778− haw=(map mood (unit)) :: simple cache
779− == ::
780−```
781−
782−This is the request manager for a foreign desk.
783−
784−`nix` is one more than the index of the most recent request. Thus, it is
785−the next available request number.
786−
787−`bom` is the set of outstanding requests. The keys of this map are some
788−subset of the numbers between 0 and one less than `nix`. The members of
789−the map are exactly those requests that have not yet been fully
790−satisfied.
791−
792−`fod` is the same set as `bom`, but from a different perspective. In
793−particular, the values of `fod` are the same as the values of `bom`, and
794−the `p` out of the values of `bom` are the same as the keys of `fod`.
795−Thus, we can map ducts to their associated request number and `++rave:clay`,
796−and we can map numbers to their associated duct and `++rave:clay`.
797−
798−`haw` is a map from simple requests to their values. This acts as a
799−cache for requests that have already been made. Thus, the second request
800−for a particular `++mood:clay` is nearly instantaneous.
801−
802−#### `++rang:clay`, data store
803−
804−```hoon
805− ++ rang $: hut=(map tako yaki) ::
806− lat=(map lobe blob) ::
807− == ::
808−```
809−
810−This is a set of data keyed by hash. Thus, this is where the "real" data
811−is stored, but it is only meaningful if we know the hash of what we're
812−looking for.
813−
814−`hut` is a map from hashes to commits. We often get the hashes from
815−`hit:dome:clay`, which keys them by logical id. Not every commit has an id.
816−
817−`lat` is a map from hashes to the actual data. We often get the hashes
818−from a `++yaki`, a commit, which references this map to get the data.
819−There is no `++blob:clay` in any `++yaki:clay`. They are only accessible through
820−this map.
821−
822−#### `++tako:clay`, commit reference
823−
824−```hoon
825− ++ tako ,@ :: yaki ref
826−```
827−
828−This is a hash of a `++yaki:clay`, a commit. These are most notably used as
829−the keys in `hut:rang:clay`, where they are associated with the actual
830−`++yaki:clay`, and as the values in `hit:dome:clay`, where sequential ids are
831−associated with these.
832−
833−#### `++yaki:clay`, commit
834−
835−```hoon
836− ++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit
837−```
838−
839−This is a single commit.
840−
841−`p` is a list of the hashes of the parents of this commit. In most
842−cases, this will be a single commit, but in a merge there may be more
843−parents. In theory, there may be an arbitrary number of parents, but in
844−practice merges have exactly two parents. This may change in the future.
845−For commit 1, there is no parent.
846−
847−`q` is a map of the paths on a desk to the data at that location. If you
848−understand what a `++lobe:clay` and a `++blob:clay` is, then the type signature
849−here tells the whole story.
850−
851−`r` is the hash associated with this commit.
852−
853−`t` is the date at which this commit was made.
854−
855−#### `++lobe:clay`, data reference
856−
857−```hoon
858− ++ lobe ,@ :: blob ref
859−```
860−
861−This is a hash of a `++blob:clay`. These are most notably used in `lat:rang:clay`,
862−where they are associated with the actual `++blob:clay`, and as the values in
863−`q:yaki:clay`, where paths are associated with their data in a commit.
864−
865−#### `++blob:clay`, data
866−
867−```hoon
868− ++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q
869− [%direct p=lobe q=* r=umph] ::
870− [%indirect p=lobe q=* r=udon s=lobe] ::
871− == ::
872−```
873−
874−This is a node of data. In every case, `p` is the hash of the blob.
875−
876−`%delta` is the case where we define the data by a delta on other data.
877−In practice, the other data is always the previous commit, but nothing
878−depends on this. `q` is the hash of the parent blob, and `r` is the
879−delta.
880−
881−`%direct` is the case where we simply have the data directly. `q` is the
882−data itself, and `r` is any preprocessing instructions. These almost
883−always come from the creation of a file.
884−
885−`%indirect` is both of the preceding cases at once. `q` is the direct
886−data, `r` is the delta, and `s` is the parent blob. It should always be
887−the case that applying `r` to `s` gives the same data as `q` directly
888−(with the prepreprocessor instructions in `p.r`). This exists purely for
889−performance reasons. This is unused, at the moment, but in general these
890−should be created when there are a long line of changes so that we do
891−not have to traverse the delta chain back to the creation of the file.
892−
893−#### `++udon`, abstract delta
894−
895−```hoon
896− ++ udon :: abstract delta
897− $: p=umph :: preprocessor
898− $= q :: patch
899− $% [%a p=* q=*] :: trivial replace
900− [%b p=udal] :: atomic indel
901− [%c p=(urge)] :: list indel
902− [%d p=upas q=upas] :: tree edit
903− == ::
904− == ::
905−```
906−
907−This is an abstract change to a file. This is a superset of what would
908−normally be called diffs. Diffs usually refer to changes in lines of
909−text while we have the ability to do more interesting deltas on
910−arbitrary data structures.
911−
912−`p` is any preprocessor instructions.
913−
914−`%a` refers to the trival delta of a complete replace of old data with
915−new data.
916−
917−`%b` refers to changes in an opaque atom on the block level. This has
918−very limited usefulness, and is not used at the moment.
919−
920−`%c` refers to changes in a list of data. This is often lines of text,
921−which is your classic diff. We, however, will work on any list of data.
922−
923−`%d` refers to changes in a tree of data. This is general enough to
924−describe changes to any hoon noun, but often more special-purpose delta
925−should be created for different content types. This is not used at the
926−moment, and may in fact be unimplemented.
927−
928−#### `++urge`, list change
929−
930−```hoon
931− ++ urge |*(a=_,* (list (unce a))) :: list change
932−```
933−
934−This is a parametrized type for list changes. For example, `(urge ,@t)`
935−is a list change for lines of text.
936−
937−#### `++unce`, change part of a list.
938−
939−```hoon
940− ++ unce |* a=_,* :: change part
941− $% [%& p=@ud] :: skip[copy]
942− [%| p=(list a) q=(list a)] :: p -> q[chunk]
943− == ::
944−```
945−
946−This is a single change in a list of elements of type `a`. For example,
947−`(unce ,@t)` is a single change in a lines of text.
948−
949−`%&` means the next `p` lines are unchanged.
950−
951−`%|` means the lines `p` have changed to `q`.
952−
953−#### `++umph`, preprocessing information
954−
955−```hoon
956− ++ umph :: change filter
957− $| $? %a :: no filter
958− %b :: jamfile
959− %c :: LF text
960− == ::
961− $% [%d p=@ud] :: blocklist
962− == ::
963−```
964−
965−This space intentionally left undocumented. This stuff will change once
966−we get a well-typed clay.
967−
968−#### `++upas`, tree change
969−
970−```hoon
971− ++ upas :: tree change (%d)
972− $& [p=upas q=upas] :: cell
973− $% [%0 p=axis] :: copy old
974− [%1 p=*] :: insert new
975− [%2 p=axis q=udon] :: mutate!
976− == ::
977−```
978−
979−This space intentionally left undocumented. This stuff is not known to
980−work, and will likely change when we get a well-typed clay. Also, this
981−is not a complicated type; it is not difficult to work out the meaning.
982−
983−#### `++nori:clay`, repository action
984−
985−```hoon
986− ++ nori :: repository action
987− $% [& q=soba] :: delta
988− [| p=@tas] :: label
989− == ::
990−```
991−
992−This describes a change that we are asking clay to make to the desk.
993−There are two kinds of changes that may be made: we can modify files or
994−we can apply a label to a commit.
995−
996−In the `|` case, we will simply label the current commit with the given
997−label. In the `&` case, we will apply the given changes.
998−
999−#### `++soba:clay`, delta
1000−
1001−```hoon
1002− ++ soba ,[p=cart q=(list ,[p=path q=miso])] :: delta
1003−```
1004−
1005−This describes a set of changes to make to a desk. The `cart` is simply
1006−a pair of the old hash and the new hash of the desk. The list is a list
1007−of changes keyed by the file they're changing. Thus, the paths are paths
1008−to files to be changed while `miso` is a description of the change
1009−itself.
1010−
1011−#### `++miso:clay`, ankh delta
1012−
1013−```hoon
1014− ++ miso :: ankh delta
1015− $% [%del p=*] :: delete
1016− [%ins p=*] :: insert
1017− [%mut p=udon] :: mutate
1018− == ::
1019−```
1020−
1021−There are three kinds of changes that may be made to a node in a desk.
1022−We can insert a file, in which case `p` is the contents of the new file.
1023−We can delete a file, in which case `p` is the contents of the old file.
1024−Finally, we can mutate that file, in which case the `udon` describes the
1025−changes we are applying to the file.
1026−
1027−#### `++mizu:clay`, merged state
1028−
1029−```hoon
1030− ++ mizu ,[p=@u q=(map ,@ud tako) r=rang] :: new state
1031−```
1032−
1033−This is the input to the `%merg` kiss, which allows us to perform a
1034−merge. The `p` is the number of the new head commit. The `q` is a map
1035−from numbers to commit hashes. This is all the new numbered commits that
1036−are to be inserted. The keys to this should always be the numbers from
1037−`let.dom` plus one to `p`, inclusive. The `r` is the maps of all the new
1038−commits and data. Since these are merged into the current state, no old
1039−commits or data need be here.
1040−
1041−#### `++riff:clay`, request/desist
1042−
1043−```hoon
1044− ++ riff ,[p=desk q=(unit rave)] :: request/desist
1045−```
1046−
1047−This represents a request for data about a particular desk. If `q`
1048−contains a `rave`, then this opens a subscription to the desk for that
1049−data. If `q` is null, then this tells clay to cancel the subscription
1050−along this duct.
1051−
1052−#### `++riot:clay`, response
1053−
1054−```hoon
1055− ++ riot (unit rant) :: response/complete
1056−```
1057−
1058−A riot is a response to a subscription. If null, the subscription has
1059−been completed, and no more responses will be sent. Otherwise, the
1060−`rant` is the produced data.
1061−
1062−#### `++rant:clay`, response data
1063−
1064−```hoon
1065− ++ rant :: namespace binding
1066− $: p=[p=care q=case r=@tas] :: clade release book
1067− q=path :: spur
1068− r=* :: data
1069− == ::
1070−```
1071−
1072−This is the data at a particular node in the filesystem. `p.p` specifies
1073−the type of data that was requested (and is produced). `q.p` gives the
1074−specific version reported (since a range of versions may be requested in
1075−a subscription). `r.p` is the desk. `q` is the path to the filesystem
1076−node. `r` is the data itself (in the format specified by `p.p`).
1077−
1078−### `++nako`, subscription response data
1079−
1080−```hoon
1081− ++ nako $: gar=(map ,@ud tako) :: new ids
1082− let=@ud :: next id
1083− lar=(set yaki) :: new commits
1084− bar=(set blob) :: new content
1085− == ::
1086−```
1087−
1088−This is the data that is produced by a request for a range of revisions
1089−of a desk. This allows us to easily keep track of a remote repository --
1090−all the new information we need is contained in the `nako`.
1091−
1092−`gar` is a map of the revisions in the range to the hash of the commit
1093−at that revision. These hashes can be used with `hut:rang:clay` to find the
1094−commit itself.
1095−
1096−`let` is either the last revision number in the range or the most recent
1097−revision number, whichever is smaller.
1098−
1099−`lar` is the set of new commits, and `bar` is the set of new content.
1100−
1101−## Public Interface
1102−
1103−As with all vanes, there are exactly two ways to interact with clay.
1104−`%clay` exports a namespace accessible through `.^`, which is described
1105−above under `++care:clay`. The primary way of interacting with clay, though,
1106−is by sending kisses and receiving gifts.
1107−
1108−```hoon
1109− ++ gift :: out result <-$
1110− $% [%ergo p=@p q=@tas r=@ud] :: version update
1111− [%note p=@tD q=tank] :: debug message
1112− [%writ p=riot] :: response
1113− == ::
1114− ++ kiss :: in request ->$
1115− $% [%info p=@p q=@tas r=nori] :: internal edit
1116− [%ingo p=@p q=@tas r=nori] :: internal noun edit
1117− [%init p=@p] :: report install
1118− [%into p=@p q=@tas r=nori] :: external edit
1119− [%invo p=@p q=@tas r=nori] :: external noun edit
1120− [%merg p=@p q=@tas r=mizu] :: internal change
1121− [%wart p=sock q=@tas r=path s=*] :: network request
1122− [%warp p=sock q=riff] :: file request
1123− == ::
1124−```
1125−
1126−There are only a small number of possible kisses, so it behooves us to
1127−describe each in detail.
1128−
1129−```hoon
1130− $% [%info p=@p q=@tas r=nori] :: internal edit
1131−
1132− [%into p=@p q=@tas r=nori] :: external edit
1133−```
1134−
1135−These two kisses are nearly identical. At a high level, they apply
1136−changes to the filesystem. Whenever we add, remove, or edit a file, one
1137−of these cards is sent. The `p` is the ship whose filesystem we're
1138−trying to change, the `q` is the desk we're changing, and the `r` is the
1139−request change. For the format of the requested change, see the
1140−documentation for `++nori:clay` above.
1141−
1142−When a file is changed in the unix filesystem, vere will send a `%into`
1143−kiss. This tells clay that the duct over which the kiss was sent is the
1144−duct that unix is listening on for changes. From within Arvo, though, we
1145−should never send a `%into` kiss. The `%info` kiss is exactly identical
1146−except it does not reset the duct.
1147−
1148−```hoon
1149− [%ingo p=@p q=@tas r=nori] :: internal noun edit
1150−
1151− [%invo p=@p q=@tas r=nori] :: external noun edit
1152−```
1153−
1154−These kisses are currently identical to `%info` and `%into`, though this
1155−will not always be the case. The intent is for these kisses to allow
1156−typed changes to clay so that we may store typed data. This is currently
1157−unimplemented.
1158−
1159−```hoon
1160− [%init p=@p] :: report install
1161−```
1162−
1163−Init is called when a ship is started on our pier. This simply creates a
1164−default `room` to go into our `raft`. Essentially, this initializes the
1165−filesystem for a ship.
1166−
1167−```hoon
1168− [%merg p=@p q=@tas r=mizu] :: internal change
1169−```
1170−
1171−This is called to perform a merge. This is most visibly called by
1172−:update to update the filesystem of the current ship to that of its
1173−sein. The `p` and `q` are as in `%info`, and the `r` is the description
1174−of the merge. See `++mizu:clay` above.
1175−
1176−XX
1177−`XX [%wake ~] :: timer activate XX`
1178−XX\
1179−XX This card is sent by unix at the time specified by `++doze`. This
1180−time is XX usually the closest time specified in a subscription request.
1181−When `%wake` is XX called, we update our subscribers if there have been
1182−any changes.
1183−
1184−```hoon
1185− [%wart p=sock q=@tas r=path s=*] :: network request
1186−```
1187−
1188−This is a request that has come across the network for a particular
1189−file. When another ship asks for a file from us, that request comes to
1190−us in the form of a `%wart` kiss. This is handled by trivially turning
1191−it into a `%warp`.
1192−
1193−```hoon
1194− [%warp p=sock q=riff] :: file request
1195−```
1196−
1197−This is a request for information about a particular desk. This is, in
1198−its most general form, a subscription, though in many cases it is the
1199−trivial case of a subscription -- a read. See `++riff:clay` for the format of
1200−the request.
1201−
1202−## Lifecycle of a Local Read
1203−
1204−There are two real types of interaction with a filesystem: you can read,
1205−and you can write. We'll describe each process, detailing both the flow
1206−of control followed by the kernel and the algorithms involved. The
1207−simpler case is that of the read, so we'll begin with that.
1208−
1209−When a vane or an application wishes to read a file from the filesystem,
1210−it sends a `%warp` kiss, as described above. Of course, you may request
1211−a file on another ship and, being a global filesystem, clay will happily
1212−produce it for you. That code pathway will be described in another
1213−section; here, we will restrict ourselves to examining the case of a
1214−read from a ship on our own pier.
1215−
1216−The kiss can request either a single version of a file node or a range
1217−of versions of a desk. Here, we'll deal only with a request for a single
1218−version.
1219−
1220−As in all vanes, a kiss enters clay via a call to `++call`. Scanning
1221−through the arm, we quickly see where `%warp` is handled.
1222−
1223−```hoon
1224− ?: =(p.p.q.hic q.p.q.hic)
1225− =+ une=(un p.p.q.hic now ruf)
1226− =+ wex=(di:une p.q.q.hic)
1227− =+ ^= wao
1228− ?~ q.q.q.hic
1229− (ease:wex hen)
1230− (eave:wex hen u.q.q.q.hic)
1231− =+ ^= woo
1232− abet:wao
1233− [-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)]
1234−```
1235−
1236−We're following the familar patern of producing a list of moves and an
1237−updated state. In this case, the state is `++raft`.
1238−
1239−We first check to see if the sending and receiving ships are the same.
1240−If they're not, then this is a request for data on another ship. We
1241−describe that process later. Here, we discuss only the case of a local
1242−read.
1243−
1244−At a high level, the call to `++un` sets up the core for the domestic
1245−ship that contains the files we're looking for. The call to `++di` sets
1246−up the core for the particular desk we're referring to.
1247−
1248−After this, we perform the actual request. If there is no rave in the
1249−riff, then that means we are cancelling a request, so we call
1250−`++ease:de`. Otherwise, we start a subscription with `++eave:de`. We
1251−call `++abet:de` to resolve our various types of output into actual
1252−moves. We produce the moves we found above and the `++un` core resolved
1253−with `++pish:un` (putting the modified desk in the room) and `++abet:un`
1254−(putting the modified room in the raft).
1255−
1256−Much of this is fairly straightforward, so we'll only describe `++ease`,
1257−`++eave`, and `++abet:de`. Feel free to look up the code to the other
1258−steps -- it should be easy to follow.
1259−
1260−Although it's called last, it's usually worth examining `++abet` first,
1261−since it defines in what ways we can cause side effects. Let's do that,
1262−and also a few of the lines at the beginning of `++de`.
1263−
1264−```hoon
1265− =| yel=(list ,[p=duct q=gift])
1266− =| byn=(list ,[p=duct q=riot])
1267− =| vag=(list ,[p=duct q=gift])
1268− =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]])
1269− =| tag=(list ,[p=duct q=path c=note])
1270− |%
1271− ++ abet
1272− ^- [(list move) rede]
1273− :_ red
1274− ;: weld
1275− %+ turn (flop yel)
1276− |=([a=duct b=gift] [hun %give b])
1277− ::
1278− %+ turn (flop byn)
1279− |=([a=duct b=riot] [a %give [%writ b]])
1280− ::
1281− %+ turn (flop vag)
1282− |=([a=duct b=gift] [a %give b])
1283− ::
1284− %+ turn (flop say)
1285− |= [a=duct b=path c=ship d=[p=@ud q=riff]]
1286− :- a
1287− [%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d]
1288− ::
1289− %+ turn (flop tag)
1290− |=([a=duct b=path c=note] [a %pass b c])
1291− ==
1292−```
1293−
1294−This is very simple code. We see there are exactly five different kinds
1295−of side effects we can generate.
1296−
1297−In `yel` we put gifts that we wish to be sent along the `hun:room` duct
1298−to dill. See the documentation for `++room` above. This is how we
1299−display messages to the terminal.
1300−
1301−In `byn` we put riots that we wish returned to subscribers. Recall that
1302−a riot is a response to a subscription. These are returned to our
1303−subscribers in the form of a `%writ` gift.
1304−
1305−In `vag` we put gifts along with the ducts on which to send them. This
1306−allows us to produce arbitrary gifts, but in practice this is only used
1307−to produce `%ergo` gifts.
1308−
1309−In `say` we put messages we wish to pass to ames. These messages are
1310−used to request information from clay on other piers. We must provide
1311−not only the duct and the request (the riff), but also the return path,
1312−the other ship to talk to, and the sequence number of the request.
1313−
1314−In `tag` we put arbitrary notes we wish to pass to other vanes. For now,
1315−the only notes we pass here are `%wait` and `%rest` to the timer vane.
1316−
1317−Now that we know what kinds of side effects we may have, we can jump
1318−into the handling of requests.
1319−
1320−```hoon
1321− ++ ease :: release request
1322− |= hen=duct
1323− ^+ +>
1324− ?~ ref +>
1325− =+ rov=(~(got by qyx) hen)
1326− =. qyx (~(del by qyx) hen)
1327− (mabe rov (cury best hen))
1328− =. qyx (~(del by qyx) hen)
1329− |- ^+ +>+.$
1330− =+ nux=(~(get by fod.u.ref) hen)
1331− ?~ nux +>+.$
1332− %= +>+.$
1333− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
1334− fod.u.ref (~(del by fod.u.ref) hen)
1335− bom.u.ref (~(del by bom.u.ref) u.nux)
1336− ==
1337−```
1338−
1339−This is called when we're cancelling a subscription. For domestic desks,
1340−`ref` is null, so we're going to cancel any timer we might have created.
1341−We first delete the duct from our map of requests, and then we call
1342−`++mabe` with `++best` to send a `%rest` kiss to the timer vane if we
1343−have started a timer. We'll describe `++best` and `++mabe` momentarily.
1344−
1345−Although we said we're not going to talk about foreign requests yet,
1346−it's easy to see that for foreign desks, we cancel any outstanding
1347−requests for this duct and send a message over ames to the other ship
1348−telling them to cancel the subscription.
1349−
1350−```hoon
1351− ++ best
1352− |= [hen=duct tym=@da]
1353− %_(+> tag :_(tag [hen /tyme %t %rest tym]))
1354−```
1355−
1356−This simply pushes a `%rest` note onto `tag`, from where it will be
1357−passed back to arvo to be handled. This cancels the timer at the given
1358−duct (with the given time).
1359−
1360−```hoon
1361− ++ mabe :: maybe fire function
1362− |* [rov=rove fun=$+(@da _+>.^$)]
1363− ^+ +>.$
1364− %- fall :_ +>.$
1365− %- bind :_ fun
1366− ^- (unit ,@da)
1367− ?- -.rov
1368− %&
1369− ?. ?=(%da -.q.p.rov) ~
1370− `p.q.p.rov
1371− %|
1372− =* mot p.rov
1373− %+ hunt
1374− ?. ?=(%da -.p.mot) ~
1375− ?.((lth now p.p.mot) ~ [~ p.p.mot])
1376− ?. ?=(%da -.q.mot) ~
1377− ?.((lth now p.q.mot) [~ now] [~ p.q.mot])
1378− ==
1379−```
1380−
1381−This decides whether the given request can only be satsified in the
1382−future. In that case, we call the given function with the time in the
1383−future when we expect to have an update to give to this request. This is
1384−called with `++best` to cancel timers and with `++bait` to start them.
1385−
1386−For single requests, we have a time if the request is for a particular
1387−time (which is assumed to be in the future). For ranges of requests, we
1388−check both the start and end cases to see if they are time cases. If so,
1389−we choose the earlier time.
1390−
1391−If any of those give us a time, then we call the given funciton with the
1392−smallest time.
1393−
1394−The more interesting case is, of course, when we're not cancelling a
1395−subscription but starting one.
1396−
1397−```hoon
1398− ++ eave :: subscribe
1399− |= [hen=duct rav=rave]
1400− ^+ +>
1401− ?- -.rav
1402− &
1403− ?: &(=(p.p.rav %u) !=(p.q.p.rav now))
1404− ~& [%clay-fail p.q.p.rav %now now]
1405− !!
1406− =+ ver=(aver p.rav)
1407− ?~ ver
1408− (duce hen rav)
1409− ?~ u.ver
1410− (blub hen)
1411− (blab hen p.rav u.u.ver)
1412−```
1413−
1414−There are two types of subscriptions -- either we're requesting a single
1415−file or we're requesting a range of versions of a desk. We'll dicuss the
1416−simpler case first.
1417−
1418−First, we check that we're not requesting the `rang` from any time other
1419−than the present. Since we don't store that information for any other
1420−time, we can't produce it in a referentially transparent manner for any
1421−time other than the present.
1422−
1423−Then, we try to read the requested `mood:clay` `p.rav`. If we can't access
1424−the request data right now, we call `++duce` to put the request in our
1425−queue to be satisfied when the information becomes available.
1426−
1427−This case occurs when we make a request for a case whose (1) date is
1428−after the current date, (2) number is after the current number, or (3)
1429−label is not yet used.
1430−
1431−```hoon
1432− ++ duce :: produce request
1433− |= [hen=duct rov=rove]
1434− ^+ +>
1435− =. qyx (~(put by qyx) hen rov)
1436− ?~ ref
1437− (mabe rov (cury bait hen))
1438− |- ^+ +>+.$ :: XX why?
1439− =+ rav=(reve rov)
1440− =+ ^= vaw ^- rave
1441− ?. ?=([%& %v *] rav) rav
1442− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
1443− =+ inx=nix.u.ref
1444− %= +>+.$
1445− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
1446− nix.u.ref +(nix.u.ref)
1447− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
1448− fod.u.ref (~(put by fod.u.ref) hen inx)
1449− ==
1450−```
1451−
1452−The code for `++duce` is nearly the exact inverse of `++ease`, which in
1453−the case of a domestic desk is very simple -- we simply put the duct and
1454−rave into `qyx` and possibly start a timer with `++mabe` and `++bait`.
1455−Recall that `ref` is null for domestic desks and that `++mabe` fires the
1456−given function with the time we need to be woken up at, if we need to be
1457−woken up at a particular time.
1458−
1459−```hoon
1460− ++ bait
1461− |= [hen=duct tym=@da]
1462− %_(+> tag :_(tag [hen /tyme %t %wait tym]))
1463−```
1464−
1465−This sets an alarm by sending a `%wait` card with the given time to the
1466−timer vane.
1467−
1468−Back in `++eave`, if `++aver` returned `[~ ~]`, then we cancel the
1469−subscription. This occurs when we make (1) a `%x` request for a file
1470−that does not exist, (2) a `%w` request with a case that is not a
1471−number, or (3) a `%w` request with a nonempty path. The `++blub` is
1472−exactly what you would expect it to be.
1473−
1474−```hoon
1475− ++ blub :: ship stop
1476− |= hen=duct
1477− %_(+> byn [[hen ~] byn])
1478−```
1479−
1480−We notify the duct that we're cancelling their subscription since it
1481−isn't satisfiable.
1482−
1483−Otherwise, we have received the desired information, so we send it on to
1484−the subscriber with `++blab`.
1485−
1486−```hoon
1487− ++ blab :: ship result
1488− |= [hen=duct mun=mood dat=*]
1489− ^+ +>
1490− +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn])
1491−```
1492−
1493−The most interesting arm called in `++eave` is, of course, `++aver`,
1494−where we actually try to read the data.
1495−
1496−```hoon
1497− ++ aver :: read
1498− |= mun=mood
1499− ^- (unit (unit ,*))
1500− ?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things
1501− ~& [%clay-fail p.q.mun %now now]
1502− !!
1503− =+ ezy=?~(ref ~ (~(get by haw.u.ref) mun))
1504− ?^ ezy ezy
1505− =+ nao=(~(case-to-aeon ze lim dom ran) q.mun)
1506− ?~(nao ~ [~ (~(read-at-aeon ze lim dom ran) u.nao mun)])
1507−```
1508−
1509−We check immediately that we're not requesting the `rang` for any time
1510−other than the present.
1511−
1512−If this is a foreign desk, then we check our cache for the specific
1513−request. If either this is a domestic desk or we don't have the request
1514−in our cache, then we have to actually go read the data from our dome.
1515−
1516−We need to do two things. First, we try to find the number of the commit
1517−specified by the given case, and then we try to get the data there.
1518−
1519−Here, we jump into `arvo/zuse.hoon`, which is where much of the
1520−algorithmic code is stored, as opposed to the clay interface, which is
1521−stored in `arvo/clay.hoon`. We examine `++case-to-aeon:ze`.
1522−
1523−```hoon
1524− ++ case-to-aeon :: case-to-aeon:ze
1525− |= lok=case :: act count through
1526− ^- (unit aeon)
1527− ?- -.lok
1528− %da
1529− ?: (gth p.lok lim) ~
1530− |- ^- (unit aeon)
1531− ?: =(0 let) [~ 0] :: avoid underflow
1532− ?: %+ gte p.lok
1533− =< t
1534− %- tako-to-yaki
1535− %- aeon-to-tako
1536− let
1537− [~ let]
1538− $(let (dec let))
1539− ::
1540− %tas (~(get by lab) p.lok)
1541− %ud ?:((gth p.lok let) ~ [~ p.lok])
1542− ==
1543−```
1544−
1545−We handle each type of `case:clay` differently. The latter two types are
1546−easy.
1547−
1548−If we're requesting a revision by label, then we simply look up the
1549−requested label in `lab` from the given dome. If it exists, that is our
1550−aeon; else we produce null, indicating the requested revision does not
1551−yet exist.
1552−
1553−If we're requesting a revision by number, we check if we've yet reached
1554−that number. If so, we produce the number; else we produce null.
1555−
1556−If we're requesting a revision by date, we check first if the date is in
1557−the future, returning null if so. Else we start from the most recent
1558−revision and scan backwards until we find the first revision committed
1559−before that date, and we produce that. If we requested a date before any
1560−revisions were committed, we produce `0`.
1561−
1562−The definitions of `++aeon-to-tako` and `++tako-to-yaki` are trivial.
1563−
1564−```hoon
1565− ++ aeon-to-tako ~(got by hit)
1566−
1567− ++ tako-to-yaki ~(got by hut) :: grab yaki
1568−```
1569−
1570−We simply look up the aeon or tako in their respective maps (`hit` and
1571−`hut`).
1572−
1573−Assuming we got a valid version number, `++aver` calls
1574−`++read-at-aeon:ze`, which reads the requested data at the given
1575−revision.
1576−
1577−```hoon
1578− ++ read-at-aeon :: read-at-aeon:ze
1579− |= [oan=aeon mun=mood] :: seek and read
1580− ^- (unit)
1581− ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed
1582− ?^(r.mun ~ [~ oan])
1583− (read:(rewind oan) mun)
1584−```
1585−
1586−If we're requesting the revision number with a case other than by
1587−number, then we go ahead and just produce the number we were given.
1588−Otherwise, we call `++rewind` to rewind our state to the given revision,
1589−and then we call `++read` to get the requested information.
1590−
1591−```hoon
1592− ++ rewind :: rewind:ze
1593− |= oan=aeon :: rewind to aeon
1594− ^+ +>
1595− ?: =(let oan) +>
1596− ?: (gth oan let) !! :: don't have version
1597− +>(ank (checkout-ankh q:(tako-to-yaki (aeon-to-tako oan))), let oan)
1598−```
1599−
1600−If we're already at the requested version, we do nothing. If we're
1601−requesting a version later than our head, we are unable to comply.
1602−
1603−Otherwise, we get the hash of the commit at the number, and from that we
1604−get the commit itself (the yaki), which has the map of path to lobe that
1605−represents a version of the filesystem. We call `++checkout-ankh` to
1606−checkout the commit, and we replace `ank` in our context with the
1607−result.
1608−
1609−```hoon
1610− ++ checkout-ankh :: checkout-ankh:ze
1611− |= hat=(map path lobe) :: checkout commit
1612− ^- ankh
1613− %- cosh
1614− %+ roll (~(tap by hat) ~)
1615− |= [[pat=path bar=lobe] ank=ankh]
1616− ^- ankh
1617− %- cosh
1618− ?~ pat
1619− =+ zar=(lobe-to-noun bar)
1620− ank(q [~ (sham zar) zar])
1621− =+ nak=(~(get by r.ank) i.pat)
1622− %= ank
1623− r %+ ~(put by r.ank) i.pat
1624− $(pat t.pat, ank (fall nak _ankh))
1625− ==
1626−```
1627−
1628−Twice we call `++cosh`, which hashes a commit, updating `p` in an
1629−`ankh`. Let's jump into that algorithm before we describe
1630−`++checkout-ankh`.
1631−
1632−```hoon
1633− ++ cosh :: locally rehash
1634− |= ank=ankh :: NB v/unix.c
1635− ank(p rehash:(zu ank))
1636−```
1637−
1638−We simply replace `p` in the hash with the `cash` we get from a call to
1639−`++rehash:zu`.
1640−
1641−```hoon
1642− ++ zu !: :: filesystem
1643− |= ank=ankh :: filesystem state
1644− =| myz=(list ,[p=path q=miso]) :: changes in reverse
1645− =| ram=path :: reverse path into
1646− |%
1647− ++ rehash :: local rehash
1648− ^- cash
1649− %+ mix ?~(q.ank 0 p.u.q.ank)
1650− =+ axe=1
1651− |- ^- cash
1652− ?~ r.ank _@
1653− ;: mix
1654− (shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank))))
1655− $(r.ank l.r.ank, axe (peg axe 2))
1656− $(r.ank r.r.ank, axe (peg axe 3))
1657− ==
1658−```
1659−
1660−`++zu` is a core we set up with a particular filesystem node to traverse
1661−a checkout of the filesystem and access the actual data inside it. One
1662−of the things we can do with it is to create a recursive hash of the
1663−node.
1664−
1665−In `++rehash`, if this node is a file, then we xor the remainder of the
1666−hash with the hash of the contents of the file. The remainder of the
1667−hash is `0` if we have no children, else we descend into our children.
1668−Basically, we do a half SHA-256 of the xor of the axis of this child and
1669−the half SHA-256 of the xor of the name of the child and the hash of the
1670−child. This is done for each child and all the results are xored
1671−together.
1672−
1673−Now we return to our discussion of `++checkout-ankh`.
1674−
1675−We fold over every path in this version of the filesystem and create a
1676−great ankh out of them. First, we call `++lobe-to-noun` to get the raw
1677−data referred to be each lobe.
1678−
1679−```hoon
1680− ++ lobe-to-noun :: grab blob
1681− |= p=lobe :: ^- *
1682− %- blob-to-noun
1683− (lobe-to-blob p)
1684−```
1685−
1686−This converts a lobe into the raw data it refers to by first getting the
1687−blob with `++lobe-to-blob` and converting that into data with
1688−`++blob-to-noun`.
1689−
1690−```hoon
1691− ++ lobe-to-blob ~(got by lat) :: grab blob
1692−```
1693−
1694−This just grabs the blob that the lobe refers to.
1695−
1696−```hoon
1697− ++ blob-to-noun :: grab blob
1698− |= p=blob
1699− ?- -.p
1700− %delta (lump r.p (lobe-to-noun q.p))
1701− %direct q.p
1702− %indirect q.p
1703− ==
1704−```
1705−
1706−If we have either a direct or an indirect blob, then the data is stored
1707−right in the blob. Otherwise, we have to reconstruct it from the diffs.
1708−We do this by calling `++lump` on the diff in the blob with the data
1709−obtained by recursively calling the parent of this blob.
1710−
1711−```hoon
1712− ++ lump :: apply patch
1713− |= [don=udon src=*]
1714− ^- *
1715− ?+ p.don ~|(%unsupported !!)
1716− %a
1717− ?+ -.q.don ~|(%unsupported !!)
1718− %a q.q.don
1719− %c (lurk ((hard (list)) src) p.q.don)
1720− %d (lure src p.q.don)
1721− ==
1722− ::
1723− %c
1724− =+ dst=(lore ((hard ,@) src))
1725− %- roly
1726− ?+ -.q.don ~|(%unsupported !!)
1727− %a ((hard (list ,@t)) q.q.don)
1728− %c (lurk dst p.q.don)
1729− ==
1730− ==
1731−```
1732−
1733−This is defined in `arvo/hoon.hoon` for historical reasons which are
1734−likely no longer applicable. Since the `++umph` structure will likely
1735−change we convert clay to be a typed filesystem, we'll only give a
1736−high-level description of this process. If we have a `%a` udon, then
1737−we're performing a trivial replace, so we produce simply `q.q.don`. If
1738−we have a `%c` udon, then we're performing a list merge (as in, for
1739−example, lines of text). The merge is performed by `++lurk`.
1740−
1741−```hoon
1742− ++ lurk :: apply list patch
1743− |* [hel=(list) rug=(urge)]
1744− ^+ hel
1745− =+ war=`_hel`~
1746− |- ^+ hel
1747− ?~ rug (flop war)
1748− ?- -.i.rug
1749− &
1750− %= $
1751− rug t.rug
1752− hel (slag p.i.rug hel)
1753− war (weld (flop (scag p.i.rug hel)) war)
1754− ==
1755− ::
1756− |
1757− %= $
1758− rug t.rug
1759− hel =+ gur=(flop p.i.rug)
1760− |- ^+ hel
1761− ?~ gur hel
1762− ?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur))
1763− war (weld q.i.rug war)
1764− ==
1765− ==
1766−```
1767−
1768−We accumulate our final result in `war`. If there's nothing more in our
1769−list of merge instructions (unces), we just reverse `war` and produce
1770−it. Otherwise, we process another unce. If the unce is of type `&`, then
1771−we have `p.i.rug` lines of no changes, so we just copy them over from
1772−`hel` to `war`. If the unice is of type `|`, then we verify that the
1773−source lines (in `hel`) are what we expect them to be (`p.i.rug`),
1774−crashing on failure. If they're good, then we append the new lines in
1775−`q.i.rug` onto `war`.
1776−
1777−And that's really it. List merges are pretty easy. Anyway, if you
1778−recall, we were discussing `++checkout-ankh`.
1779−
1780−```hoon
1781− ++ checkout-ankh :: checkout-ankh:ze
1782− |= hat=(map path lobe) :: checkout commit
1783− ^- ankh
1784− %- cosh
1785− %+ roll (~(tap by hat) ~)
1786− |= [[pat=path bar=lobe] ank=ankh]
1787− ^- ankh
1788− %- cosh
1789− ?~ pat
1790− =+ zar=(lobe-to-noun bar)
1791− ank(q [~ (sham zar) zar])
1792− =+ nak=(~(get by r.ank) i.pat)
1793− %= ank
1794− r %+ ~(put by r.ank) i.pat
1795− $(pat t.pat, ank (fall nak _ankh))
1796− ==
1797−```
1798−
1799−If the path is null, then we calculate `zar`, the raw data at the path
1800−`pat` in this version. We produce the given ankh with the correct data.
1801−
1802−Otherwise, we try to get the child we're looking at from our parent
1803−ankh. If it's already been created, this succeeds; otherwise, we simply
1804−create a default blank ankh. We place ourselves in our parent after
1805−recursively computing our children.
1806−
1807−This algorithm really isn't that complicated, but it may not be
1808−immediately obvious why it works. An example should clear everything up.
1809−
1810−Suppose `hat` is a map of the following information.
1811−
1812−```
1813− /greeting --> "customary upon meeting"
1814− /greeting/english --> "hello"
1815− /greeting/spanish --> "hola"
1816− /greeting/russian/short --> "привет"
1817− /greeting/russian/long --> "Здравствуйте"
1818− /farewell/russian --> "до свидания"
1819−```
1820−
1821−Furthermore, let's say that we process them in this order:
1822−
1823−```
1824− /greeting/english
1825− /greeting/russian/short
1826− /greeting/russian/long
1827− /greeting
1828− /greeting/spanish
1829− /farewell/russian
1830−```
1831−
1832−Then, the first path we process is `/greeting/english` . Since our path
1833−is not null, we try to get `nak`, but because our ankh is blank at this
1834−point it doesn't find anything. Thus, update our blank top-level ankh
1835−with a child `%greeting`. and recurse with the blank `nak` to create the
1836−ankh of the new child.
1837−
1838−In the recursion, we our path is `/english` and our ankh is again blank.
1839−We try to get the `english` child of our ankh, but this of course fails.
1840−Thus, we update our blank `/greeting` ankh with a child `english`
1841−produced by recursing.
1842−
1843−Now our path is null, so we call `++lobe-to-noun` to get the actual
1844−data, and we place it in the brand-new ankh.
1845−
1846−Next, we process `/greeting/russian/short`. Since our path is not null,
1847−we try to get the child named `%greeting`, which does exist since we
1848−created it earlier. We put modify this child by recursing on it. Our
1849−path is now `/russian/short`, so we look for a `%russian` child in our
1850−`/greeting` ankh. This doesn't exist, so we add it by recursing. Our
1851−path is now `/short`, so we look for a `%short` child in our
1852−`/greeting/russian` ankh. This doesn't exist, so we add it by recursing.
1853−Now our path is null, so we set the contents of this node to `"привет"`,
1854−and we're done processing this path.
1855−
1856−Next, we process `/greeting/russian/long`. This proceeds similarly to
1857−the previous except that now the ankh for `/greeting/russian` already
1858−exists, so we simply reuse it rather than creating a new one. Of course,
1859−we still must create a new `/greeting/russian/long` ankh.
1860−
1861−Next, we process `/greeting`. This ankh already exists, so after we've
1862−recursed once, our path is null, and our ankh is not blank -- it already
1863−has two children (and two grandchildren). We don't touch those, though,
1864−since a node may be both a file and a directory. We just add the
1865−contents of the file -- "customary upon meeting" -- to the existing
1866−ankh.
1867−
1868−Next, we process `/greeting/spanish`. Of course, the `/greeting` ankh
1869−already exists, but it doesn't have a `%spanish` child, so we create
1870−that, taking care not to disturb the contents of the `/greeting` file.
1871−We put "hola" into the ankh and call it good.
1872−
1873−Finally, we process `/farewell/russian`. Here, the `/farewell` ankh
1874−doesn't exist, so we create it. Clearly the newly-created ankh doesn't
1875−have any children, so we have to add a `%russian` child, and in this
1876−child we put our last content -- "до свидания".
1877−
1878−We hope it's fairly obvious that the order we process the paths doesn't
1879−affect the final ankh tree. The tree will be constructed in a very
1880−different order depending on what order the paths come in, but the
1881−resulting tree is independent of order.
1882−
1883−At any rate, we were talking about something important, weren't we? If
1884−you recall, that concludes our discussion of `++rewind`, which was
1885−called from `++read-at-aeon`. In summary, `++rewind` returns a context
1886−in which our current state is (very nearly) as it was when the specified
1887−version of the desk was the head. This allows `++read-at-aeon` to call
1888−`++read` to read the requested information.
1889−
1890−```hoon
1891− ++ read :: read:ze
1892− |= mun=mood :: read at point
1893− ^- (unit)
1894− ?: ?=(%v p.mun)
1895− [~ `dome`+<+<.read]
1896− ?: &(?=(%w p.mun) !?=(%ud -.q.mun))
1897− ?^(r.mun ~ [~ let])
1898− ?: ?=(%w p.mun)
1899− =+ ^= yak
1900− %- tako-to-yaki
1901− %- aeon-to-tako
1902− let
1903− ?^(r.mun ~ [~ [t.yak (forge-nori yak)]])
1904− ::?> ?=(^ hit) ?^(r.mun ~ [~ i.hit]) :: what do?? need [@da nori]
1905− (query(ank ank:(descend-path:(zu ank) r.mun)) p.mun)
1906−```
1907−
1908−If we're requesting the dome, then we just return that immediately.
1909−
1910−If we're requesting the revision number of the desk and we're not
1911−requesting it by number, then we just return the current number of this
1912−desk. Note of course that this was really already handled in
1913−`++read-at-aeon`.
1914−
1915−If we're requesting a `%w` with a specific revision number, then we do
1916−something or other with the commit there. It's kind of weird, and it
1917−doesn't seem to work, so we'll ignore this case.
1918−
1919−Otherwise, we descend into the ankh tree to the given path with
1920−`++descend-path:zu`, and then we handle specific request in `++query`.
1921−
1922−```hoon
1923− ++ descend-path :: descend recursively
1924− |= way=path
1925− ^+ +>
1926− ?~(way +> $(way t.way, +> (descend i.way)))
1927−```
1928−
1929−This is simple recursion down into the ankh tree. `++descend` descends
1930−one level, so this will eventually get us down to the path we want.
1931−
1932−```hoon
1933− ++ descend :: descend
1934− |= lol=@ta
1935− ^+ +>
1936− =+ you=(~(get by r.ank) lol)
1937− +>.$(ram [lol ram], ank ?~(you [*cash ~ ~] u.you))
1938−```
1939−
1940−`ram` is the path that we're at, so to descend one level we push the
1941−name of this level onto that path. We update the ankh with the correct
1942−one at that path if it exists; else we create a blank one.
1943−
1944−Once we've decscended to the correct level, we need to actually deal
1945−with the request.
1946−
1947−```hoon
1948− ++ query :: query:ze
1949− |= ren=?(%u %v %x %y %z) :: endpoint query
1950− ^- (unit ,*)
1951− ?- ren
1952− %u [~ `rang`+<+>.query]
1953− %v [~ `dome`+<+<.query]
1954− %x ?~(q.ank ~ [~ q.u.q.ank])
1955− %y [~ as-arch]
1956− %z [~ ank]
1957− ==
1958−```
1959−
1960−Now that everything's set up, it's really easy. If they're requesting
1961−the rang, dome, or ankh, we give it to them. If the contents of a file,
1962−we give it to them if it is in fact a file. If the `arch`, then we
1963−calculate it with `++as-arch`.
1964−
1965−```hoon
1966− ++ as-arch :: as-arch:ze
1967− ^- arch :: arch report
1968− :+ p.ank
1969− ?~(q.ank ~ [~ p.u.q.ank])
1970− |- ^- (map ,@ta ,~)
1971− ?~ r.ank ~
1972− [[p.n.r.ank ~] $(r.ank l.r.ank) $(r.ank r.r.ank)]
1973−```
1974−
1975−This very simply strips out all the "real" data and returns just our own
1976−hash, the hash of the file contents (if we're a file), and a map of the
1977−names of our immediate children.
1978−
1979−## Lifecycle of a Local Subscription
1980−
1981−A subscription to a range of revisions of a desk initially follows the
1982−same path that a single read does. In `++aver`, we checked the head of
1983−the given rave. If the head was `&`, then it was a single request, so we
1984−handled it above. If `|`, then we handle it with the following code.
1985−
1986−```hoon
1987− =+ nab=(~(case-to-aeon ze lim dom ran) p.p.rav)
1988− ?~ nab
1989− ?> =(~ (~(case-to-aeon ze lim dom ran) q.p.rav))
1990− (duce hen (rive rav))
1991− =+ huy=(~(case-to-aeon ze lim dom ran) q.p.rav)
1992− ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab))))
1993− (blub hen)
1994− =+ top=?~(huy let.dom u.huy)
1995− =+ sar=(~(lobes-at-path ze lim dom ran) u.nab r.p.rav)
1996− =+ ear=(~(lobes-at-path ze lim dom ran) top r.p.rav)
1997− =. +>.$
1998− ?: =(sar ear) +>.$
1999− =+ fud=(~(make-nako ze lim dom ran) u.nab top)
2000− (bleb hen u.nab fud)
2001− ?^ huy
2002− (blub hen)
2003− =+ ^= ptr ^- case
2004− [%ud +(let.dom)]
2005− (duce hen `rove`[%| ptr q.p.rav r.p.rav ear])
2006− ==
2007−```
2008−
2009−Recall that `++case-to-aeon:ze` produces the revision number that a case
2010−corresponds to, if it corresponds to any. If it doesn't yet correspond
2011−to a revision, then it produces null.
2012−
2013−Thus, we first check to see if we've even gotten to the beginning of the
2014−range of revisions requested. If not, then we assert that we haven't yet
2015−gotten to the end of the range either, because that would be really
2016−strange. If not, then we immediately call `++duce`, which, if you
2017−recall, for a local request, simply puts this duct and rove into our
2018−cult `qyx`, so that we know who to respond to when the revision does
2019−appear.
2020−
2021−If we've already gotten to the first revision, then we can produce some
2022−content immediately. If we've also gotten to the final revision, and
2023−that revision is earlier than the start revision, then it's a bad
2024−request and we call `++blub`, which tells the subscriber that his
2025−subscription will not be satisfied.
2026−
2027−Otherwise, we find the data at the given path at the beginning of the
2028−subscription and at the last available revision in the subscription. If
2029−they're the same, then we don't send a notification. Otherwise, we call
2030−`++gack`, which creates the `++nako` we need to produce. We call
2031−`++bleb` to actually produce the information.
2032−
2033−If we already have the last requested revision, then we also tell the
2034−subscriber with `++blub` that the subscription will receive no further
2035−updates.
2036−
2037−If there will be more revisions in the subscription, then we call
2038−`++duce`, adding the duct to our subscribers. We modify the rove to
2039−start at the next revision since we've already handled all the revisions
2040−up to the present.
2041−
2042−We glossed over the calls to `++lobes-at-path`, `++make-nako`, and
2043−`++bleb`, so we'll get back to those right now. `++bleb` is simple, so
2044−we'll start with that.
2045−
2046−```hoon
2047− ++ bleb :: ship sequence
2048− |= [hen=duct ins=@ud hip=nako]
2049− ^+ +>
2050− (blab hen [%w [%ud ins] ~] hip)
2051−```
2052−
2053−We're given a duct, the beginning revision number, and the nako that
2054−contains the updates since that revision. We use `++blab` to produce
2055−this result to the subscriber. The case is `%w` with a revision number
2056−of the beginning of the subscription, and the data is the nako itself.
2057−
2058−We call `++lobes-at-path:ze` to get the data at the particular path.
2059−
2060−```hoon
2061− ++ lobes-at-path :: lobes-at-path:ze
2062− |= [oan=aeon pax=path] :: data at path
2063− ^- (map path lobe)
2064− ?: =(0 oan) ~
2065− %- mo
2066− %+ skim
2067− %. ~
2068− %~ tap by
2069− =< q
2070− %- tako-to-yaki
2071− %- aeon-to-tako
2072− oan
2073− |= [p=path q=lobe]
2074− ?| ?=(~ pax)
2075− ?& !?=(~ p)
2076− =(-.pax -.p)
2077− $(p +.p, pax +.pax)
2078− == ==
2079−```
2080−
2081−At revision zero, the theoretical common revision between all
2082−repositories, there is no data, so we produce null.
2083−
2084−We get the list of paths (paired with their lobe) in the revision
2085−referred to by the given number and we keep only those paths which begin
2086−with `pax`. Converting to a map, we now have a map from the subpaths at
2087−the given path to the hash of their data. This is simple and efficient
2088−to calculate and compare to later revisions. This allows us to easily
2089−tell if a node or its children have changed.
2090−
2091−Finally, we will describe `++make-nako:ze`.
2092−
2093−```hoon
2094− ++ make-nako :: gack a through b
2095− |= [a=aeon b=aeon]
2096− ^- [(map aeon tako) aeon (set yaki) (set blob)]
2097− :_ :- b
2098− =- [(takos-to-yakis -<) (lobes-to-blobs ->)]
2099− %+ reachable-between-takos
2100− (~(get by hit) a) :: if a not found, a=0
2101− (aeon-to-tako b)
2102− ^- (map aeon tako)
2103− %- mo %+ skim (~(tap by hit) ~)
2104− |= [p=aeon *]
2105− &((gth p a) (lte p b))
2106−```
2107−
2108−We need to produce four things -- the numbers of the new commits, the
2109−number of the latest commit, the new commits themselves, and the new
2110−data itself.
2111−
2112−The first is fairly easy to produce. We simply go over our map of
2113−numbered commits and produce all those numbered greater than `a` and not
2114−greater than `b`.
2115−
2116−The second is even easier to produce -- `b` is clearly our most recent
2117−commit.
2118−
2119−The third and fourth are slightly more interesting, though not too
2120−terribly difficult. First, we call `++reachable-between-takos`.
2121−
2122−```hoon
2123− ++ reachable-between-takos
2124− |= [a=(unit tako) b=tako] :: pack a through b
2125− ^- [(set tako) (set lobe)]
2126− =+ ^= sar
2127− ?~ a ~
2128− (reachable-takos r:(tako-to-yaki u.a))
2129− =+ yak=`yaki`(tako-to-yaki b)
2130− %+ new-lobes-takos (new-lobes ~ sar) :: get lobes
2131− |- ^- (set tako) :: walk onto sar
2132− ?: (~(has in sar) r.yak)
2133− ~
2134− =+ ber=`(set tako)`(~(put in `(set tako)`~) `tako`r.yak)
2135− %- ~(uni in ber)
2136− ^- (set tako)
2137− %+ roll p.yak
2138− |= [yek=tako bar=(set tako)]
2139− ^- (set tako)
2140− ?: (~(has in bar) yek) :: save some time
2141− bar
2142− %- ~(uni in bar)
2143− ^$(yak (tako-to-yaki yek))
2144−```
2145−
2146−We take a possible starting commit and a definite ending commit, and we
2147−produce the set of commits and the set of data between them.
2148−
2149−We let `sar` be the set of commits reachable from `a`. If `a` is null,
2150−then obviously no commits are reachable. Otherwise, we call
2151−`++reachable-takos` to calculate this.
2152−
2153−```hoon
2154− ++ reachable-takos :: reachable
2155− |= p=tako :: XX slow
2156− ^- (set tako)
2157− =+ y=(tako-to-yaki p)
2158− =+ t=(~(put in _(set tako)) p)
2159− %+ roll p.y
2160− |= [q=tako s=_t]
2161− ?: (~(has in s) q) :: already done
2162− s :: hence skip
2163− (~(uni in s) ^$(p q)) :: otherwise traverse
2164−```
2165−
2166−We very simply produce the set of the given tako plus its parents,
2167−recursively.
2168−
2169−Back in `++reachable-between-takos`, we let `yak` be the yaki of `b`,
2170−the ending commit. With this, we create a set that is the union of `sar`
2171−and all takos reachable from `b`.
2172−
2173−We pass `sar` into `++new-lobes` to get all the lobes referenced by any
2174−tako referenced by `a`. The result is passed into `++new-lobes-takos` to
2175−do the same, but not recomputing those in already calculated last
2176−sentence. This produces the sets of takos and lobes we need.
2177−
2178−```hoon
2179− ++ new-lobes :: object hash set
2180− |= [b=(set lobe) a=(set tako)] :: that aren't in b
2181− ^- (set lobe)
2182− %+ roll (~(tap in a) ~)
2183− |= [tak=tako bar=(set lobe)]
2184− ^- (set lobe)
2185− =+ yak=(tako-to-yaki tak)
2186− %+ roll (~(tap by q.yak) ~)
2187− |= [[path lob=lobe] far=_bar]
2188− ^- (set lobe)
2189− ?~ (~(has in b) lob) :: don't need
2190− far
2191− =+ gar=(lobe-to-blob lob)
2192− ?- -.gar
2193− %direct (~(put in far) lob)
2194− %delta (~(put in $(lob q.gar)) lob)
2195− %indirect (~(put in $(lob s.gar)) lob)
2196− ==
2197−```
2198−
2199−Here, we're creating a set of lobes referenced in a commit in `a`. We
2200−start out with `b` as the initial set of lobes, so we don't need to
2201−recompute any of the lobes referenced in there.
2202−
2203−The algorithm is pretty simple, so we won't bore you with the details.
2204−We simply traverse every commit in `a`, looking at every blob referenced
2205−there, and, if it's not already in `b`, we add it to `b`. In the case of
2206−a direct blob, we're done. For a delta or an indirect blob, we
2207−recursively add every blob referenced within the blob.
2208−
2209−```hoon
2210− ++ new-lobes-takos :: garg & repack
2211− |= [b=(set lobe) a=(set tako)]
2212− ^- [(set tako) (set lobe)]
2213− [a (new-lobes b a)]
2214−```
2215−
2216−Here, we just update the set of lobes we're given with the commits we're
2217−given and produce both sets.
2218−
2219−This concludes our discussion of a local subscription.
2220−
2221−## Lifecycle of a Foreign Read or Subscription
2222−
2223−Foreign reads and subscriptions are handled in much the same way as
2224−local ones. The interface is the same -- a vane or app sends a `%warp`
2225−kiss with the request. The difference is simply that the `sock` refers
2226−to the foreign ship.
2227−
2228−Thus, we start in the same place -- in `++call`, handling `%warp`.
2229−However, since the two side of the `sock` are different, we follow a
2230−different path.
2231−
2232−```hoon
2233− =+ wex=(do now p.q.hic p.q.q.hic ruf)
2234− =+ ^= woo
2235− ?~ q.q.q.hic
2236− abet:(ease:wex hen)
2237− abet:(eave:wex hen u.q.q.q.hic)
2238− [-.woo (posh q.p.q.hic p.q.q.hic +.woo ruf)]
2239−```
2240−
2241−If we compare this to how the local case was handled, we see that it's
2242−not all that different. We use `++do` rather than `++un` and `++de` to
2243−set up the core for the foreign ship. This gives us a `++de` core, so we
2244−either cancel or begin the request by calling `++ease` or `++eave`,
2245−exactly as in the local case. In either case, we call `++abet:de` to
2246−resolve our various types of output into actual moves, as described in
2247−the local case. Finally, we call `++posh` to update our raft, putting
2248−the modified rung into the raft.
2249−
2250−We'll first trace through `++do`.
2251−
2252−```hoon
2253− ++ do
2254− |= [now=@da [who=ship him=ship] syd=@tas ruf=raft]
2255− =+ ^= rug ^- rung
2256− =+ rug=(~(get by hoy.ruf) him)
2257− ?^(rug u.rug *rung)
2258− =+ ^= red ^- rede
2259− =+ yit=(~(get by rus.rug) syd)
2260− ?^(yit u.yit `rede`[~2000.1.1 ~ [~ *rind] *dome])
2261− ((de now ~ ~) [who him] syd red ran.ruf)
2262−```
2263−
2264−If we already have a rung for this foreign ship, then we use that.
2265−Otherwise, we create a new blank one. If we already have a rede in this
2266−rung, then we use that, otherwise we create a blank one. An important
2267−point to note here is that we let `ref` in the rede be `[~ *rind]`.
2268−Recall, for domestic desks `ref` is null. We use this to distinguish
2269−between foreign and domestic desks in `++de`.
2270−
2271−With this information, we create a `++de` core as usual.
2272−
2273−Although we've already covered `++ease` and `++eave`, we'll go through
2274−them quickly again, highlighting the case of foreign request.
2275−
2276−```hoon
2277− ++ ease :: release request
2278− |= hen=duct
2279− ^+ +>
2280− ?~ ref +>
2281− =+ rov=(~(got by qyx) hen)
2282− =. qyx (~(del by qyx) hen)
2283− (mabe rov (cury best hen))
2284− =. qyx (~(del by qyx) hen)
2285− |- ^+ +>+.$
2286− =+ nux=(~(get by fod.u.ref) hen)
2287− ?~ nux +>+.$
2288− %= +>+.$
2289− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
2290− fod.u.ref (~(del by fod.u.ref) hen)
2291− bom.u.ref (~(del by bom.u.ref) u.nux)
2292− ==
2293−```
2294−
2295−Here, we still remove the duct from our cult (we maintain a cult even
2296−for foreign desks), but we also need to tell the foreign desk to cancel
2297−our subscription. We do this by sending a request (by appending to
2298−`say`, which gets resolved in `++abet:de` to a `%want` kiss to ames) to
2299−the foreign ship to cancel the subscription. Since we don't anymore
2300−expect a response on this duct, we remove it from `fod` and `bom`, which
2301−are the maps between ducts, raves, and request sequence numbers.
2302−Basically, we remove every trace of the subscription from our request
2303−manager.
2304−
2305−In the case of `++eave`, where we're creating a new request, everything
2306−is exactly identical to the case of the local request except `++duce`.
2307−We said that `++duce` simply puts the request into our cult. This is
2308−true for a domestic request, but distinctly untrue for foreign requests.
2309−
2310−```hoon
2311− ++ duce :: produce request
2312− |= [hen=duct rov=rove]
2313− ^+ +>
2314− =. qyx (~(put by qyx) hen rov)
2315− ?~ ref +>.$
2316− |- ^+ +>+.$ :: XX why?
2317− =+ rav=(reve rov)
2318− =+ ^= vaw ^- rave
2319− ?. ?=([%& %v *] rav) rav
2320− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
2321− =+ inx=nix.u.ref
2322− %= +>+.$
2323− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
2324− nix.u.ref +(nix.u.ref)
2325− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
2326− fod.u.ref (~(put by fod.u.ref) hen inx)
2327− ==
2328−```
2329−
2330−If we have a request manager (i.e. this is a foreign desk), then we do
2331−the approximate inverse of `++ease`. We create a rave out of the given
2332−request and send it off to the foreign desk by putting it in `say`. Note
2333−that the rave is created to request the information starting at the next
2334−revision number. Since this is a new request, we put it into `fod` and
2335−`bom` to associate the request with its duct and its sequence number.
2336−Since we're using another sequence number, we must increment `nix`,
2337−which represents the next available sequence number.
2338−
2339−And that's really it for this side of the request. Requesting foreign
2340−information isn't that hard. Let's see what it looks like on the other
2341−side. When we get a request from another ship for information on our
2342−ship, that comes to us in the form of a `%wart` from ames.
2343−
2344−We handle a `%wart` in `++call`, right next to where we handle the
2345−`%warp` case.
2346−
2347−```hoon
2348− %wart
2349− ?> ?=(%re q.q.hic)
2350− =+ ryf=((hard riff) s.q.hic)
2351− :_ ..^$
2352− :~ :- hen
2353− :^ %pass [(scot %p p.p.q.hic) (scot %p q.p.q.hic) r.q.hic]
2354− %c
2355− [%warp [p.p.q.hic p.p.q.hic] ryf]
2356− ==
2357−```
2358−
2359−Every request we receive should be of type `riff`, so we coerce it into
2360−that type. We just convert this into a new `%warp` kiss that we pass to
2361−ourself. This gets handled like normal, as a local request. When the
2362−request produces a value, it does so like normal as a `%writ`, which is
2363−returned to `++take` along the path we just sent it on.
2364−
2365−```hoon
2366− %writ
2367− ?> ?=([@ @ *] tea)
2368− =+ our=(need (slaw %p i.tea))
2369− =+ him=(need (slaw %p i.t.tea))
2370− :_ ..^$
2371− :~ :- hen
2372− [%pass ~ %a [%want [our him] [%r %re %c t.t.tea] p.+.q.hin]]
2373− ==
2374−```
2375−
2376−Since we encoded the ship we need to respond to in the path, we can just
2377−pass our `%want` back to ames, so that we tell the requesting ship about
2378−the new data.
2379−
2380−This comes back to the original ship as a `%waft` from ames, which comes
2381−into `++take`, right next to where we handled `%writ`.
2382−
2383−```hoon
2384− %waft
2385− ?> ?=([@ @ ~] tea)
2386− =+ syd=(need (slaw %tas i.tea))
2387− =+ inx=(need (slaw %ud i.t.tea))
2388− =+ ^= zat
2389− =< wake
2390− (knit:(do now p.+.q.hin syd ruf) [inx ((hard riot) q.+.q.hin)])
2391− =^ mos ruf
2392− =+ zot=abet.zat
2393− [-.zot (posh q.p.+.q.hin syd +.zot ruf)]
2394− [mos ..^$(ran.ruf ran.zat)] :: merge in new obj
2395−```
2396−
2397−This gets the desk and sequence number from the path the request was
2398−sent over. This determines exactly which request is being responded to.
2399−We call `++knit:de` to apply the changes to our local desk, and we call
2400−`++wake` to update our subscribers. Then we call `++abet:de` and
2401−`++posh` as normal (like in `++eave`).
2402−
2403−We'll examine `++knit` and `++wake`, in that order.
2404−
2405−```hoon
2406− ++ knit :: external change
2407− |= [inx=@ud rot=riot]
2408− ^+ +>
2409− ?> ?=(^ ref)
2410− |- ^+ +>+.$
2411− =+ ruv=(~(get by bom.u.ref) inx)
2412− ?~ ruv +>+.$
2413− => ?. |(?=(~ rot) ?=(& -.q.u.ruv)) .
2414− %_ .
2415− bom.u.ref (~(del by bom.u.ref) inx)
2416− fod.u.ref (~(del by fod.u.ref) p.u.ruv)
2417− ==
2418− ?~ rot
2419− =+ rav=`rave`q.u.ruv
2420− %= +>+.$
2421− lim
2422− ?.(&(?=(| -.rav) ?=(%da -.q.p.rav)) lim `@da`p.q.p.rav)
2423− ::
2424− haw.u.ref
2425− ?. ?=(& -.rav) haw.u.ref
2426− (~(put by haw.u.ref) p.rav ~)
2427− ==
2428− ?< ?=(%v p.p.u.rot)
2429− =. haw.u.ref
2430− (~(put by haw.u.ref) [p.p.u.rot q.p.u.rot q.u.rot] ~ r.u.rot)
2431− ?. ?=(%w p.p.u.rot) +>+.$
2432− |- ^+ +>+.^$
2433− =+ nez=[%w [%ud let.dom] ~]
2434− =+ nex=(~(get by haw.u.ref) nez)
2435− ?~ nex +>+.^$
2436− ?~ u.nex +>+.^$ :: should never happen
2437− =. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
2438− ?>(?=(^ ref.roo) roo)
2439− %= $
2440− haw.u.ref (~(del by haw.u.ref) nez)
2441− ==
2442−```
2443−
2444−This is kind of a long gate, but don't worry, it's not bad at all.
2445−
2446−First, we assert that we're not a domestic desk. That wouldn't make any
2447−sense at all.
2448−
2449−Since we have the sequence number of the request, we can get the duct
2450−and rave from `bom` in our request manager. If we didn't actually
2451−request this data (or the request was canceled before we got it), then
2452−we do nothing.
2453−
2454−Else, we remove the request from `bom` and `fod` unless this was a
2455−subscription request and we didn't receive a null riot (which would
2456−indicate the last message on the subscription).
2457−
2458−Now, if we received a null riot, then if this was a subscription request
2459−by date, then we update `lim` in our request manager (representing the
2460−latest time at which we have complete information for this desk) to the
2461−date that was requested. If this was a single read request, then we put
2462−the result in our simple cache `haw` to make future requests faster.
2463−Then we're done.
2464−
2465−If we received actual data, then we put it into our cache `haw`. Unless
2466−it's a `%w` request, we're done.
2467−
2468−If it is a `%w` request, then we try to get the `%w` at our current head
2469−from the cache. In general, that should be the thing we just put in a
2470−moment ago, but that is not guaranteed. The most common case where this
2471−is different is when we receive desk updates out of order. At any rate,
2472−since we now have new information, we need to apply it to our local copy
2473−of the desk. We do so in `++edis`, and then we remove the stuff we just
2474−applied from the cache, since it's not really a true "single read", like
2475−what should really be in the cache.
2476−
2477−```hoon
2478− ++ edis :: apply subscription
2479− |= nak=nako
2480− ^+ +>
2481− %= +>
2482− hit.dom (~(uni by hit.dom) gar.nak)
2483− let.dom let.nak
2484− lat.ran %+ roll (~(tap in bar.nak) ~)
2485− =< .(yeb lat.ran)
2486− |= [sar=blob yeb=(map lobe blob)]
2487− =+ zax=(blob-to-lobe sar)
2488− %+ ~(put by yeb) zax sar
2489− hut.ran %+ roll (~(tap in lar.nak) ~)
2490− =< .(yeb hut.ran)
2491− |= [sar=yaki yeb=(map tako yaki)]
2492− %+ ~(put by yeb) r.sar sar
2493− ==
2494−```
2495−
2496−This shows, of course, exactly why nako is defined the way it is. To
2497−become completely up to date with the foreign desk, we need to merge
2498−`hit` with the foreign one so that we have all the revision numbers. We
2499−update `let` so that we know which revision is the head.
2500−
2501−We merge the new blobs in `lat`, keying them by their hash, which we get
2502−from a call to `++blob-to-lobe`. Recall that the hash is stored in the
2503−actual blob itself. We do the same thing to the new yakis, putting them
2504−in `hut`, keyed by their hash.
2505−
2506−Now, our local dome should be exactly the same as the foreign one.
2507−
2508−This concludes our discussion of `++knit`. Now the changes have been
2509−applied to our local copy of the desk, and we just need to update our
2510−subscribers. We do so in `++wake:de`.
2511−
2512−```hoon
2513− ++ wake :: update subscribers
2514− ^+ .
2515− =+ xiq=(~(tap by qyx) ~)
2516− =| xaq=(list ,[p=duct q=rove])
2517− |- ^+ ..wake
2518− ?~ xiq
2519− ..wake(qyx (~(gas by *cult) xaq))
2520− ?- -.q.i.xiq
2521− &
2522− =+ cas=?~(ref ~ (~(get by haw.u.ref) `mood`p.q.i.xiq))
2523− ?^ cas
2524− %= $
2525− xiq t.xiq
2526− ..wake ?~ u.cas (blub p.i.xiq)
2527− (blab p.i.xiq p.q.i.xiq u.u.cas)
2528− ==
2529− =+ nao=(~(case-to-aeon ze lim dom ran) q.p.q.i.xiq)
2530− ?~ nao $(xiq t.xiq, xaq [i.xiq xaq])
2531− $(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq))
2532− ::
2533− |
2534− =+ mot=`moot`p.q.i.xiq
2535− =+ nab=(~(case-to-aeon ze lim dom ran) p.mot)
2536− ?~ nab
2537− $(xiq t.xiq, xaq [i.xiq xaq])
2538− =+ huy=(~(case-to-aeon ze lim dom ran) q.mot)
2539− ?~ huy
2540− =+ ptr=[%ud +(let.dom)]
2541− %= $
2542− xiq t.xiq
2543− xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq]
2544− ..wake =+ ^= ear
2545− (~(lobes-at-path ze lim dom ran) let.dom r.p.q.i.xiq)
2546− ?: =(s.p.q.i.xiq ear) ..wake
2547− =+ fud=(~(make-nako ze lim dom ran) u.nab let.dom)
2548− (bleb p.i.xiq let.dom fud)
2549− ==
2550− %= $
2551− xiq t.xiq
2552− ..wake =- (blub:- p.i.xiq)
2553− =+ ^= ear
2554− (~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
2555− ?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
2556− =+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
2557− (bleb p.i.xiq +(u.nab) fud)
2558− ==
2559− ==
2560− --
2561−```
2562−
2563−This is even longer than `++knit`, but it's pretty similar to `++eave`.
2564−We loop through each of our subscribers `xiq`, processing each in turn.
2565−When we're done, we just put the remaining subscribers back in our
2566−subscriber list.
2567−
2568−If the subscriber is a single read, then, if this is a foreign desk
2569−(note that `++wake` is called from other arms, and not only on foreign
2570−desks). Obviously, if we find an identical request there, then we can
2571−produce the result immediately. Referential transparency for the win. We
2572−produce the result with a call to `++blab`. If this is a foreign desk
2573−but the result is not in the cache, then we produce `++blub` (canceled
2574−subscription with no data) for reasons entirely opaque to me. Seriously,
2575−it seems like we should wait until we get an actual response to the
2576−request. If someone figures out why this is, let me know. At any rate,
2577−it seems to work.
2578−
2579−If this is a domestic desk, then we check to see if the case exists yet.
2580−If it doesn't, then we simply move on to the next subscriber, consing
2581−this one onto `xaq` so that we can check again the next time around. If
2582−it does exist, then we call `++balk` to fulfill the request and produce
2583−it.
2584−
2585−`++balk` is very simple, so we'll describe it here before we get to the
2586−subscription case.
2587−
2588−```hoon
2589− ++ balk :: read and send
2590− |= [hen=duct oan=@ud mun=mood]
2591− ^+ +>
2592− =+ vid=(~(read-at-aeon ze lim dom ran) oan mun)
2593− ?~ vid (blub hen) (blab hen mun u.vid)
2594−```
2595−
2596−We call `++read-at-aeon` on the given request and aeon. If you recall,
2597−this processes a `mood` at a particular aeon and produces the result, if
2598−there is one. If there is data at the requested location, then we
2599−produce it with `++blab`. Else, we call `++blub` to notify the
2600−subscriber that no data can ever come over this subscriptioin since it
2601−is now impossible for there to ever be data for the given request.
2602−Because referential transparency.
2603−
2604−At any rate, back to `++wake`. If the given rave is a subscription
2605−request, then we proceed similarly to how we do in `++eave`. We first
2606−try to get the aeon referred to by the starting case. If it doesn't
2607−exist yet, then we can't do anything interesting with this subscription,
2608−so we move on to the next one.
2609−
2610−Otherwise, we try to get the aeon referred to by the ending case. If it
2611−doesn't exist yet, then we produce all the information we can. We call
2612−`++lobes-at-path` at the given aeon and path to see if the requested
2613−path has actually changed. If it hasn't, then we don't produce anything;
2614−else, we produce the correct nako by calling `++bleb` on the result of
2615−`++make-nako`, as in `++eave`. At any rate, we move on to the next
2616−subscription, putting back into our cult the current subscription with a
2617−new start case of the next aeon after the present.
2618−
2619−If the aeon referred to by the ending case does exist, then we drop this
2620−subscriber from our cult and satisfy its request immediately. This is
2621−the same as before -- we check to see if the data at the path has
2622−actually changed, producing it if it has; else, we call `++blub` since
2623−no more data can be produced over this subscription.
2624−
2625−This concludes our discussion of foreign requests.