mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-16 19:22:22 +03:00
Merge branch 'test' of https://github.com/urbit/urbit into test
Conflicts: urb/urbit.pill
This commit is contained in:
commit
d54584a164
@ -439,7 +439,7 @@
|
||||
vix=(bex +((cut 0 [25 2] mag))) :: width of sender
|
||||
tay=(cut 0 [27 5] mag) :: message type
|
||||
==
|
||||
?> =(7 vez)
|
||||
?> =(1 vez)
|
||||
?> =(chk (end 0 20 (mug bod)))
|
||||
:+ [(end 3 wix bod) (cut 3 [wix vix] bod)]
|
||||
(kins tay)
|
||||
@ -459,7 +459,7 @@
|
||||
=+ tay=(ksin q.kec)
|
||||
%+ mix
|
||||
%+ can 0
|
||||
:~ [3 7]
|
||||
:~ [3 1]
|
||||
[20 (mug bod)]
|
||||
[2 yax]
|
||||
[2 qax]
|
||||
@ -1047,7 +1047,7 @@
|
||||
++ gnaw :: gnaw:am
|
||||
|= [kay=cape ryn=lane pac=rock] :: process packet
|
||||
^- [p=(list boon) q=fort]
|
||||
?. =(7 (end 0 3 pac)) [~ fox]
|
||||
?. =(1 (end 0 3 pac)) [~ fox]
|
||||
=+ kec=(bite pac)
|
||||
?: (goop p.p.kec) [~ fox]
|
||||
?. (~(has by urb.ton.fox) q.p.kec)
|
||||
|
@ -338,8 +338,9 @@
|
||||
=+ nex=(~(get by haw.u.ref) nez)
|
||||
?~ nex +>+.^$
|
||||
?~ u.nex +>+.^$ :: should never happen
|
||||
=. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
|
||||
?>(?=(^ ref.roo) roo)
|
||||
=. +>+.^$
|
||||
=+ roo=(edis ((hard nako) u.u.nex))
|
||||
?>(?=(^ ref.roo) roo)
|
||||
%= $
|
||||
haw.u.ref (~(del by haw.u.ref) nez)
|
||||
==
|
||||
@ -397,7 +398,7 @@
|
||||
..wake =- (blub:- p.i.xiq)
|
||||
=+ ^= ear
|
||||
(~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
|
||||
?: =(s.p.q.i.xiq ear) ..wake
|
||||
?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
|
||||
=+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
|
||||
(bleb p.i.xiq +(u.nab) fud)
|
||||
==
|
||||
|
@ -1645,3 +1645,393 @@ Here, we just update the set of lobes we're given with the commits we're given
|
||||
and produce both sets.
|
||||
|
||||
This concludes our discussion of a local subscription.
|
||||
|
||||
Lifecycle of a Foreign Read or Subscription
|
||||
-------------------------------------------
|
||||
|
||||
Foreign reads and subscriptions are handled in much the same way as local ones.
|
||||
The interface is the same -- a vane or app sends a `%warp` kiss with the
|
||||
request. The difference is simply that the `sock` refers to the foreign ship.
|
||||
|
||||
Thus, we start in the same place -- in `++call`, handling `%warp`. However,
|
||||
since the two side of the `sock` are different, we follow a different path.
|
||||
|
||||
```
|
||||
=+ wex=(do now p.q.hic p.q.q.hic ruf)
|
||||
=+ ^= woo
|
||||
?~ q.q.q.hic
|
||||
abet:(ease:wex hen)
|
||||
abet:(eave:wex hen u.q.q.q.hic)
|
||||
[-.woo (posh q.p.q.hic p.q.q.hic +.woo ruf)]
|
||||
```
|
||||
|
||||
If we compare this to how the local case was handled, we see that it's not all
|
||||
that different. We use `++do` rather than `++un` and `++de` to set up the core
|
||||
for the foreign ship. This gives us a `++de` core, so we either cancel or
|
||||
begin the request by calling `++ease` or `++eave`, exactly as in the local
|
||||
case. In either case, we call `++abet:de` to resolve our various types of
|
||||
output into actual moves, as described in the local case. Finally, we call
|
||||
`++posh` to update our raft, putting the modified rung into the raft.
|
||||
|
||||
We'll first trace through `++do`.
|
||||
|
||||
```
|
||||
++ do
|
||||
|= [now=@da [who=ship him=ship] syd=@tas ruf=raft]
|
||||
=+ ^= rug ^- rung
|
||||
=+ rug=(~(get by hoy.ruf) him)
|
||||
?^(rug u.rug *rung)
|
||||
=+ ^= red ^- rede
|
||||
=+ yit=(~(get by rus.rug) syd)
|
||||
?^(yit u.yit `rede`[~2000.1.1 ~ [~ *rind] *dome])
|
||||
((de now ~ ~) [who him] syd red ran.ruf)
|
||||
```
|
||||
|
||||
If we already have a rung for this foreign ship, then we use that. Otherwise,
|
||||
we create a new blank one. If we already have a rede in this rung, then we use
|
||||
that, otherwise we create a blank one. An important point to note here is that
|
||||
we let `ref` in the rede be `[~ *rind]`. Recall, for domestic desks `ref` is
|
||||
null. We use this to distinguish between foreign and domestic desks in `++de`.
|
||||
|
||||
With this information, we create a `++de` core as usual.
|
||||
|
||||
Although we've already covered `++ease` and `++eave`, we'll go through them
|
||||
quickly again, highlighting the case of foreign request.
|
||||
|
||||
```
|
||||
++ 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)
|
||||
==
|
||||
```
|
||||
|
||||
Here, we still remove the duct from our cult (we maintain a cult even for
|
||||
foreign desks), but we also need to tell the foreign desk to cancel our
|
||||
subscription. We do this by sending a request (by appending to `say`, which
|
||||
gets resolved in `++abet:de` to a `%want` kiss to ames) to the foreign ship to
|
||||
cancel the subscription. Since we don't anymore expect a response on this
|
||||
duct, we remove it from `fod` and `bom`, which are the maps between ducts,
|
||||
raves, and request sequence numbers. Basically, we remove every trace of the
|
||||
subscription from our request manager.
|
||||
|
||||
In the case of `++eave`, where we're creating a new request, everything is
|
||||
exactly identical to the case of the local request except `++duce`. We said
|
||||
that `++duce` simply puts the request into our cult. This is true for a
|
||||
domestic request, but distinctly untrue for foreign requests.
|
||||
|
||||
```
|
||||
++ duce :: produce request
|
||||
|= [hen=duct rov=rove]
|
||||
^+ +>
|
||||
=. qyx (~(put by qyx) hen rov)
|
||||
?~ ref +>.$
|
||||
|- ^+ +>+.$ :: XX why?
|
||||
=+ rav=(reve rov)
|
||||
=+ ^= vaw ^- rave
|
||||
?. ?=([%& %v *] rav) rav
|
||||
[%| [%ud let.dom] `case`q.p.rav r.p.rav]
|
||||
=+ inx=nix.u.ref
|
||||
%= +>+.$
|
||||
say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
|
||||
nix.u.ref +(nix.u.ref)
|
||||
bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
|
||||
fod.u.ref (~(put by fod.u.ref) hen inx)
|
||||
==
|
||||
```
|
||||
|
||||
If we have a request manager (i.e. this is a foreign desk), then we do the
|
||||
approximate inverse of `++ease`. We create a rave out of the given request and
|
||||
send it off to the foreign desk by putting it in `say`. Note that the rave is
|
||||
created to request the information starting at the next revision number. Since
|
||||
this is a new request, we put it into `fod` and `bom` to associate the request
|
||||
with its duct and its sequence number. Since we're using another sequence
|
||||
number, we must increment `nix`, which represents the next available sequence
|
||||
number.
|
||||
|
||||
And that's really it for this side of the request. Requesting foreign
|
||||
information isn't that hard. Let's see what it looks like on the other side.
|
||||
When we get a request from another ship for information on our ship, that comes
|
||||
to us in the form of a `%wart` from ames.
|
||||
|
||||
We handle a `%wart` in `++call`, right next to where we handle the `%warp` case.
|
||||
|
||||
```
|
||||
%wart
|
||||
?> ?=(%re q.q.hic)
|
||||
=+ ryf=((hard riff) s.q.hic)
|
||||
:_ ..^$
|
||||
:~ :- hen
|
||||
:^ %pass [(scot %p p.p.q.hic) (scot %p q.p.q.hic) r.q.hic]
|
||||
%c
|
||||
[%warp [p.p.q.hic p.p.q.hic] ryf]
|
||||
==
|
||||
```
|
||||
|
||||
Every request we receive should be of type `riff`, so we coerce it into that
|
||||
type. We just convert this into a new `%warp` kiss that we pass to ourself.
|
||||
This gets handled like normal, as a local request. When the request produces
|
||||
a value, it does so like normal as a `%writ`, which is returned to `++take`
|
||||
along the path we just sent it on.
|
||||
|
||||
```
|
||||
%writ
|
||||
?> ?=([@ @ *] tea)
|
||||
=+ our=(need (slaw %p i.tea))
|
||||
=+ him=(need (slaw %p i.t.tea))
|
||||
:_ ..^$
|
||||
:~ :- hen
|
||||
[%pass ~ %a [%want [our him] [%r %re %c t.t.tea] p.+.q.hin]]
|
||||
==
|
||||
```
|
||||
|
||||
Since we encoded the ship we need to respond to in the path, we can just pass
|
||||
our `%want` back to ames, so that we tell the requesting ship about the new
|
||||
data.
|
||||
|
||||
This comes back to the original ship as a `%waft` from ames, which comes into
|
||||
`++take`, right next to where we handled `%writ`.
|
||||
|
||||
```
|
||||
%waft
|
||||
?> ?=([@ @ ~] tea)
|
||||
=+ syd=(need (slaw %tas i.tea))
|
||||
=+ inx=(need (slaw %ud i.t.tea))
|
||||
=+ ^= zat
|
||||
=< wake
|
||||
(knit:(do now p.+.q.hin syd ruf) [inx ((hard riot) q.+.q.hin)])
|
||||
=^ mos ruf
|
||||
=+ zot=abet.zat
|
||||
[-.zot (posh q.p.+.q.hin syd +.zot ruf)]
|
||||
[mos ..^$(ran.ruf ran.zat)] :: merge in new obj
|
||||
```
|
||||
|
||||
This gets the desk and sequence number from the path the request was sent over.
|
||||
This determines exactly which request is being responded to. We call
|
||||
`++knit:de` to apply the changes to our local desk, and we call `++wake` to
|
||||
update our subscribers. Then we call `++abet:de` and `++posh` as normal (like
|
||||
in `++eave`).
|
||||
|
||||
We'll examine `++knit` and `++wake`, in that order.
|
||||
|
||||
```
|
||||
++ knit :: external change
|
||||
|= [inx=@ud rot=riot]
|
||||
^+ +>
|
||||
?> ?=(^ ref)
|
||||
|- ^+ +>+.$
|
||||
=+ ruv=(~(get by bom.u.ref) inx)
|
||||
?~ ruv +>+.$
|
||||
=> ?. |(?=(~ rot) ?=(& -.q.u.ruv)) .
|
||||
%_ .
|
||||
bom.u.ref (~(del by bom.u.ref) inx)
|
||||
fod.u.ref (~(del by fod.u.ref) p.u.ruv)
|
||||
==
|
||||
?~ rot
|
||||
=+ rav=`rave`q.u.ruv
|
||||
%= +>+.$
|
||||
lim
|
||||
?.(&(?=(| -.rav) ?=(%da -.q.p.rav)) lim `@da`p.q.p.rav)
|
||||
::
|
||||
haw.u.ref
|
||||
?. ?=(& -.rav) haw.u.ref
|
||||
(~(put by haw.u.ref) p.rav ~)
|
||||
==
|
||||
?< ?=(%v p.p.u.rot)
|
||||
=. haw.u.ref
|
||||
(~(put by haw.u.ref) [p.p.u.rot q.p.u.rot q.u.rot] ~ r.u.rot)
|
||||
?. ?=(%w p.p.u.rot) +>+.$
|
||||
|- ^+ +>+.^$
|
||||
=+ nez=[%w [%ud let.dom] ~]
|
||||
=+ nex=(~(get by haw.u.ref) nez)
|
||||
?~ nex +>+.^$
|
||||
?~ u.nex +>+.^$ :: should never happen
|
||||
=. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
|
||||
?>(?=(^ ref.roo) roo)
|
||||
%= $
|
||||
haw.u.ref (~(del by haw.u.ref) nez)
|
||||
==
|
||||
```
|
||||
|
||||
This is kind of a long gate, but don't worry, it's not bad at all.
|
||||
|
||||
First, we assert that we're not a domestic desk. That wouldn't make any sense
|
||||
at all.
|
||||
|
||||
Since we have the sequence number of the request, we can get the duct and rave
|
||||
from `bom` in our request manager. If we didn't actually request this data (or
|
||||
the request was canceled before we got it), then we do nothing.
|
||||
|
||||
Else, we remove the request from `bom` and `fod` unless this was a subscription
|
||||
request and we didn't receive a null riot (which would indicate the last
|
||||
message on the subscription).
|
||||
|
||||
Now, if we received a null riot, then if this was a subscription request by
|
||||
date, then we update `lim` in our request manager (representing the latest time
|
||||
at which we have complete information for this desk) to the date that was
|
||||
requested. If this was a single read request, then we put the result in our
|
||||
simple cache `haw` to make future requests faster. Then we're done.
|
||||
|
||||
If we received actual data, then we put it into our cache `haw`. Unless it's a
|
||||
`%w` request, we're done.
|
||||
|
||||
If it is a `%w` request, then we try to get the `%w` at our current head from
|
||||
the cache. In general, that should be the thing we just put in a moment ago,
|
||||
but that is not guaranteed. The most common case where this is different is
|
||||
when we receive desk updates out of order. At any rate, since we now have new
|
||||
information, we need to apply it to our local copy of the desk. We do so in
|
||||
`++edis`, and then we remove the stuff we just applied from the cache, since
|
||||
it's not really a true "single read", like what should really be in the cache.
|
||||
|
||||
```
|
||||
++ edis :: apply subscription
|
||||
|= nak=nako
|
||||
^+ +>
|
||||
%= +>
|
||||
hit.dom (~(uni by hit.dom) gar.nak)
|
||||
let.dom let.nak
|
||||
lat.ran %+ roll (~(tap in bar.nak) ~)
|
||||
=< .(yeb lat.ran)
|
||||
|= [sar=blob yeb=(map lobe blob)]
|
||||
=+ zax=(blob-to-lobe sar)
|
||||
%+ ~(put by yeb) zax sar
|
||||
hut.ran %+ roll (~(tap in lar.nak) ~)
|
||||
=< .(yeb hut.ran)
|
||||
|= [sar=yaki yeb=(map tako yaki)]
|
||||
%+ ~(put by yeb) r.sar sar
|
||||
==
|
||||
```
|
||||
|
||||
This shows, of course, exactly why nako is defined the way it is. To become
|
||||
completely up to date with the foreign desk, we need to merge `hit` with the
|
||||
foreign one so that we have all the revision numbers. We update `let` so that
|
||||
we know which revision is the head.
|
||||
|
||||
We merge the new blobs in `lat`, keying them by their hash, which we get from a
|
||||
call to `++blob-to-lobe`. Recall that the hash is stored in the actual blob
|
||||
itself. We do the same thing to the new yakis, putting them in `hut`, keyed by
|
||||
their hash.
|
||||
|
||||
Now, our local dome should be exactly the same as the foreign one.
|
||||
|
||||
This concludes our discussion of `++knit`. Now the changes have been applied to
|
||||
our local copy of the desk, and we just need to update our subscribers. We do
|
||||
so in `++wake:de`.
|
||||
|
||||
```
|
||||
++ wake :: update subscribers
|
||||
^+ .
|
||||
=+ xiq=(~(tap by qyx) ~)
|
||||
=| xaq=(list ,[p=duct q=rove])
|
||||
|- ^+ ..wake
|
||||
?~ xiq
|
||||
..wake(qyx (~(gas by *cult) xaq))
|
||||
?- -.q.i.xiq
|
||||
&
|
||||
=+ cas=?~(ref ~ (~(get by haw.u.ref) `mood`p.q.i.xiq))
|
||||
?^ cas
|
||||
%= $
|
||||
xiq t.xiq
|
||||
..wake ?~ u.cas (blub p.i.xiq)
|
||||
(blab p.i.xiq p.q.i.xiq u.u.cas)
|
||||
==
|
||||
=+ nao=(~(case-to-aeon ze lim dom ran) q.p.q.i.xiq)
|
||||
?~ nao $(xiq t.xiq, xaq [i.xiq xaq])
|
||||
$(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq))
|
||||
::
|
||||
|
|
||||
=+ mot=`moot`p.q.i.xiq
|
||||
=+ nab=(~(case-to-aeon ze lim dom ran) p.mot)
|
||||
?~ nab
|
||||
$(xiq t.xiq, xaq [i.xiq xaq])
|
||||
=+ huy=(~(case-to-aeon ze lim dom ran) q.mot)
|
||||
?~ huy
|
||||
=+ ptr=[%ud +(let.dom)]
|
||||
%= $
|
||||
xiq t.xiq
|
||||
xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq]
|
||||
..wake =+ ^= ear
|
||||
(~(lobes-at-path ze lim dom ran) let.dom r.p.q.i.xiq)
|
||||
?: =(s.p.q.i.xiq ear) ..wake
|
||||
=+ fud=(~(make-nako ze lim dom ran) u.nab let.dom)
|
||||
(bleb p.i.xiq let.dom fud)
|
||||
==
|
||||
%= $
|
||||
xiq t.xiq
|
||||
..wake =- (blub:- p.i.xiq)
|
||||
=+ ^= ear
|
||||
(~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
|
||||
?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
|
||||
=+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
|
||||
(bleb p.i.xiq +(u.nab) fud)
|
||||
==
|
||||
==
|
||||
--
|
||||
```
|
||||
|
||||
This is even longer than `++knit`, but it's pretty similar to `++eave`. We loop
|
||||
through each of our subscribers `xiq`, processing each in turn. When we're done,
|
||||
we just put the remaining subscribers back in our subscriber list.
|
||||
|
||||
If the subscriber is a single read, then, if this is a foreign desk (note that
|
||||
`++wake` is called from other arms, and not only on foreign desks). Obviously,
|
||||
if we find an identical request there, then we can produce the result
|
||||
immediately. Referential transparency for the win. We produce the result with
|
||||
a call to `++blab`. If this is a foreign desk but the result is not in the
|
||||
cache, then we produce `++blub` (canceled subscription with no data) for
|
||||
reasons entirely opaque to me. Seriously, it seems like we should wait until
|
||||
we get an actual response to the request. If someone figures out why this is,
|
||||
let me know. At any rate, it seems to work.
|
||||
|
||||
If this is a domestic desk, then we check to see if the case exists yet. If
|
||||
it doesn't, then we simply move on to the next subscriber, consing this one
|
||||
onto `xaq` so that we can check again the next time around. If it does exist,
|
||||
then we call `++balk` to fulfill the request and produce it.
|
||||
|
||||
`++balk` is very simple, so we'll describe it here before we get to the
|
||||
subscription case.
|
||||
|
||||
```
|
||||
++ balk :: read and send
|
||||
|= [hen=duct oan=@ud mun=mood]
|
||||
^+ +>
|
||||
=+ vid=(~(read-at-aeon ze lim dom ran) oan mun)
|
||||
?~ vid (blub hen) (blab hen mun u.vid)
|
||||
```
|
||||
|
||||
We call `++read-at-aeon` on the given request and aeon. If you recall, this
|
||||
processes a `mood` at a particular aeon and produces the result, if there is
|
||||
one. If there is data at the requested location, then we produce it with
|
||||
`++blab`. Else, we call `++blub` to notify the subscriber that no data can
|
||||
ever come over this subscriptioin since it is now impossible for there to ever
|
||||
be data for the given request. Because referential transparency.
|
||||
|
||||
At any rate, back to `++wake`. If the given rave is a subscription request,
|
||||
then we proceed similarly to how we do in `++eave`. We first try to get the
|
||||
aeon referred to by the starting case. If it doesn't exist yet, then we can't
|
||||
do anything interesting with this subscription, so we move on to the next one.
|
||||
|
||||
Otherwise, we try to get the aeon referrred to by the ending case. If it
|
||||
doesn't exist yet, then we produce all the information we can. We call
|
||||
`++lobes-at-path` at the given aeon and path to see if the requested path has
|
||||
actually changed. If it hasn't, then we don't produce anything; else, we
|
||||
produce the correct nako by calling `++bleb` on the result of `++make-nako`, as
|
||||
in `++eave`. At any rate, we move on to the next subscription, putting back
|
||||
into our cult the current subscription with a new start case of the next aeon
|
||||
after the present.
|
||||
|
||||
If the aeon referred to by the ending case does exist, then we drop this
|
||||
subscriber from our cult and satisfy its request immediately. This is the same
|
||||
as before -- we check to see if the data at the path has actually changed,
|
||||
producing it if it has; else, we call `++blub` since no more data can be
|
||||
produced over this subscription.
|
||||
|
||||
This concludes our discussion of foreign requests.
|
||||
|
Loading…
Reference in New Issue
Block a user