updated %clay doc

This commit is contained in:
Ubuntu 2014-09-03 01:37:24 +00:00
parent 2278666a05
commit 8d7ecb1f5b
2 changed files with 339 additions and 4 deletions

View File

@ -139,7 +139,7 @@ pre, .codeblock {
margin-top: 0;
margin-bottom: 1rem;
padding: 1rem;
font-size: .9rem;
font-size: .8rem;
line-height: 1.4;
white-space: pre;
white-space: pre-wrap;

View File

@ -157,7 +157,7 @@ not a `%da` for now.
`%v` requests the `++dome` at the specified commit.
`%w` requests the current revsion number of the desk.
`%w` requests the revsion number of the desk.
`%x` requests the file at a specified path at the specified commit. If there
is no node at that path or if the node has no contents (that is, if `q:ankh` is
@ -296,7 +296,8 @@ stuff before this time.
simply `p:dojo`, all subscribers to the desk, while in foreign desks this is
all the subscribers from our ship to the foreign desk.
`ref` is the request manager for the desk.
`ref` is the request manager for the desk. For domestic desks, this is null
since we handle requests ourselves.
`dom` is the actual data in the desk.
@ -311,7 +312,7 @@ all the subscribers from our ship to the foreign desk.
== ::
```
This is the request manager for a desk.
This is the request manager for a foreign desk.
`nix` is one more than the index of the most recent request. Thus, it is the
next available request number.
@ -574,6 +575,32 @@ This represents a request for data about a particular desk. If `q` contains a
`rave`, then this opens a subscription to the desk for that data. If `q` is
null, then this tells clay to cancel the subscription along this duct.
###`++riot`, response
```
++ riot (unit rant) :: response/complete
```
A riot is a response to a subscription. If null, the subscription has been
completed, and no more responses will be sent. Otherwise, the `rant` is the
produced data.
###`++rant`, response data
```
++ rant :: namespace binding
$: p=[p=care q=case r=@tas] :: clade release book
q=path :: spur
r=* :: data
== ::
```
This is the data at a particular node in the filesystem. `p.p` specifies the
type of data that was requested (and is produced). `q.p` gives the specific
version reported (since a range of versions may be requested in a
subscription). `r.p` is the desk. `q` is the path to the filesystem node.
`r` is the data itself (in the format specified by `p.p`).
Interface
---------
@ -677,3 +704,311 @@ another ship asks for a file from us, that request comes to us in the form of a
This is a request for information about a particular desk. This is, in its
most general form, a subscription, though in many cases it is the trivial case
of a subscription -- a read. See `++riff` for the format of the request.
Lifecycle of a Local Read
-------------------------
There are two real types of interaction with a filesystem: you can read, and
you can write. We'll describe each process, detailing both the flow of control
followed by the kernel and the algorithms involved. The simpler case is that
of the read, so we'll begin with that.
When a vane or an application wishes to read a file from the filesystem, it
sends a `%warp` kiss, as described above. Of course, you may request a file on
another ship and, being a global filesystem, clay will happily produce it for
you. That code pathway will be described in another section; here, we will
restrict ourselves to examining the case of a read from a ship on our own pier.
The kiss can request either a single version of a file or a range of versions
of a desk. We'll trace through both paths at once.
As in all vanes, a kiss enters clay via a call to `++call`. Scanning through
the arm, we quickly see where `%warp` is handled.
```
?: =(p.p.q.hic q.p.q.hic)
=+ une=(un p.p.q.hic now ruf)
=+ wex=(di:une p.q.q.hic)
=+ ^= wao
?~ q.q.q.hic
(ease:wex hen)
(eave:wex hen u.q.q.q.hic)
=+ ^= woo
abet:wao
[-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)]
```
We're following the familar patern of producing a list of moves and an updated
state. In this case, the state is `++raft`.
We first check to see if the sending and receiving ships are the same. If
they're not, then this is a request for data on another ship. We describe that
process later. Here, we discuss only the case of a local read.
At a high level, the call to `++un` sets up the core for the domestic ship that
contains the files we're looking for. The call to `++di` sets up the core for
the particular desk we're referring to.
After this, we perform the actual request. If there is no rave in the riff,
then that means we are cancelling a request, so we call `++ease:de`.
Otherwise, we start a subscription with `++eave:de`. We call `++abet:de` to
resolve our various types of output into actual moves. We produce the moves we
found above and the `++un` core resolved with `++pish:un` (putting the modified
desk in the room) and `++abet:un` (putting the modified room in the raft).
Much of this is fairly straightforward, so we'll only describe `++ease`,
`++eave`, and `++abet:de`. Feel free to look up the code to the other steps --
it should be easy to follow.
Although it's called last, it's usually worth examining `++abet` first, since
it defines in what ways we can cause side effects. Let's do that, and also a
few of the lines at the beginning of `++de`.
```
=| yel=(list ,[p=duct q=gift])
=| byn=(list ,[p=duct q=riot])
=| vag=(list ,[p=duct q=gift])
=| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]])
|%
++ abet
^- [(list move) rede]
:_ red
;: weld
%+ turn (flop yel)
|=([a=duct b=gift] [hun %give b])
::
%+ turn (flop byn)
|=([a=duct b=riot] [a %give [%writ b]])
::
%+ turn (flop vag)
|=([a=duct b=gift] [a %give b])
::
%+ turn (flop say)
|= [a=duct b=path c=ship d=[p=@ud q=riff]]
:- a
[%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d]
==
```
This is very simple code. We see there are exactly four different kinds of
side effects we can generate.
In `yel` we put gifts that we wish to be sent along the `hun:room` duct to
dill. See the documentation for `++room` above. This is how we display
messages to the terminal.
In `byn` we put riots that we wish returned to subscribers. Recall that a riot
is a response to a subscription. These are returned to our subscribers in the
form of a `%writ` gift.
In `vag` we put gifts along with the ducts on which to send them. This allows
us to produce arbitrary gifts, but in practice this is only used to produce
`%ergo` gifts.
In `say` we put messages we wish to pass to ames. These messages are used to
request information from clay on other piers. We must provide not only the
duct and the request (the riff), but also the return path, the other ship to
talk to, and the sequence number of the request.
Now that we know what kinds of side effects we may have, we can jump into the
handling of requests.
```
++ ease :: release request
|= hen=duct
^+ +>
=. qyx (~(del by qyx) hen)
?~ ref +>
|- ^+ +>+.$
=+ nux=(~(get by fod.u.ref) hen)
?~ nux +>+.$
%= +>+.$
say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
fod.u.ref (~(del by fod.u.ref) hen)
bom.u.ref (~(del by bom.u.ref) u.nux)
==
```
This is called when we're cancelling a subscription. First, we remove the duct
from our map of subscribers. For domestic desks, `ref` is null, so we're done.
Although we said we're not going to talk about foreign requests yet, it's easy
to see that for foreign desks, we cancel any outstanding requests for this duct
and send a message over ames to the other ship telling them to cancel the
subscription.
The more interesting case is, of course, when we're not cancelling a
subscription but starting one.
```
++ eave :: subscribe
|= [hen=duct rav=rave]
^+ +>
?- -.rav
&
?: &(=(p.p.rav %u) !=(p.q.p.rav now))
~& [%clay-fail p.q.p.rav %now now]
!!
=+ ver=(aver p.rav)
?~ ver
(duce hen rav)
?~ u.ver
(blub hen)
(blab hen p.rav u.u.ver)
```
There are two types of subscriptions -- either we're requesting a single file
or we're requesting a range of versions of a desk. We'll dicuss the simpler
case first.
First, we check that we're not requesting the `rang` from any time other than
the present. Since we don't store that information for any other time, we
can't produce it in a referentially transparent manner for any time other than
the present.
Then, we try to read the requested `mood` `p.rav`. If we can't access the
request data right now, we call `++duce` to put the request in our queue to be
satisfied when the information becomes available. The code for `++duce` is
nearly the exact inverse of `++ease`, which in the case of a domestic desk is
very simple -- we simply put the duct and rave into `qyx`. This case occurs
when we make a request for a case whose (1) date is after the current date, (2)
number is after the current number, or (3) label is not yet used.
If `++aver` returned `[~ ~]`, then we cancel the subscription. This occurs
when we make (1) a `%x` request for a file that does not exist, (2) a `%w`
request with a case that is not a number, or (3) a `%w` request with a nonempty
path. The `++blub` is exactly what you would expect it to be.
```
++ blub :: ship stop
|= hen=duct
%_(+> byn [[hen ~] byn])
```
We notify the duct that we're cancelling their subscription since it isn't
satisfiable.
Otherwise, we have received the desired information, so we send it on to the
subscriber with `++blab`.
```
++ blab :: ship result
|= [hen=duct mun=mood dat=*]
^+ +>
+>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn])
```
The most interesting arm called in `++eave` is, of course, `++aver`, where we
actually try to read the data.
```
++ aver :: read
|= mun=mood
^- (unit (unit ,*))
?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things
~& [%clay-fail p.q.mun %now now]
!!
=+ ezy=?~(ref ~ (~(get by haw.u.ref) mun))
?^ ezy ezy
=+ nao=(~(aeon ze lim dom ran) q.mun)
:: ~& [%aver-mun nao [%from syd lim q.mun]]
?~(nao ~ [~ (~(avid ze lim dom ran) u.nao mun)])
```
We check immediately that we're not requesting the `rang` for any time other
than the present.
If this is a foreign desk, then we check our cache for the specific request.
If either this is a domestic desk or we don't have the request in our cache,
then we have to actually go read the data from our dome.
We need to do two things. First, we try to find the number of the commit
specified by the given case, and then we try to get the data there.
Here, we jump into `arvo/zuse.hoon`, which is where much of the algorithmic
code is stored, as opposed to the clay interface, which is stored in
`arvo/clay.hoon`. We examine `++aeon:ze`.
```
++ aeon :: aeon:ze
|= lok=case :: act count through
^- (unit ,@ud)
?- -.lok
%da
?: (gth p.lok lim) ~
|- ^- (unit ,@ud)
?: =(0 let) [~ 0] :: avoid underflow
?: %+ gte p.lok
=< t
%- ~(got by hut)
%- ~(got by hit)
let
[~ let]
$(let (dec let))
::
%tas (~(get by lab) p.lok)
%ud ?:((gth p.lok let) ~ [~ p.lok])
==
```
We handle each type of `case` differently. The latter two types are easy.
If we're requesting a revision by label, then we simply look up the requested
label in `lab` from the given dome. If it exists, that is our number; else we
produce null, indicating the requested revision does not yet exist.
If we're requesting a revision by number, we check if we've yet reached that
number. If so, we produce the number; else we produce null.
If we're requesting a revision by date, we check first if the date is in the
future, returning null if so. Else we start from the most recent revision and
scan backwards until we find the first revision committed before that date, and
we produce that. If we requested a date before any revisions were committed,
we produce `0`.
Assuming we got a valid version number, `++aver` calls `++avid:ze`, which reads
the requested data at the given revision.
```
++ avid :: avid:ze
|= [oan=@ud mun=mood] :: seek and read
^- (unit)
?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed
?^(r.mun ~ [~ oan])
(auto:(argo oan) mun)
```
If we're requesting the revision number with a case other than by number, then
we go ahead and just produce the number we were given. Otherwise, we call
`++argo` to rewind our state to the given revision, and then we call `++auto`
to get the requested information.
```
++ argo :: argo:ze
|= oan=@ud :: rewind to aeon
^+ +>
?: =(let oan) +>
?: (gth oan let) !! :: don't have this version
+>(ank (azel q:(need (~(get by hut) (need (~(get by hit) oan))))), let oan)
```
```
|
=+ nab=(~(aeon ze lim dom ran) p.p.rav)
?~ nab
?> =(~ (~(aeon ze lim dom ran) q.p.rav))
(duce hen rav)
=+ huy=(~(aeon ze lim dom ran) q.p.rav)
?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab))))
(blub hen)
=+ top=?~(huy let.dom u.huy)
=+ fud=(~(gack ze lim dom ran) u.nab let.dom)
=. +>.$ (bleb hen u.nab fud)
?^ huy
(blub hen)
=+ ^= ptr ^- case
[%ud +(let.dom)]
(duce hen `rave`[%| ptr q.p.rav])
==
```
(this is from `++eave`)