mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-15 01:52:42 +03:00
updated %clay doc
This commit is contained in:
parent
2278666a05
commit
8d7ecb1f5b
@ -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;
|
||||
|
@ -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`)
|
||||
|
Loading…
Reference in New Issue
Block a user