updated clay doc and code

This commit is contained in:
Ubuntu 2014-09-16 14:19:15 +00:00
parent c33eab7645
commit fabf390eac
3 changed files with 177 additions and 14 deletions

View File

@ -72,7 +72,7 @@
== ::
++ room :: fs per ship
$: hun=duct :: terminal duct
hez=(unit duct) :: sync duch
hez=(unit duct) :: sync duct
dos=(map desk dojo) :: native desk
== ::
++ rove (each mood moot) :: stored request

View File

@ -1798,17 +1798,13 @@
++ equiv :: test paths
|= [p=(map path lobe) q=(map path lobe)]
^- ?
%- |= qat=?
?. qat %.n
%+ roll (~(tap by q) ~)
|= [[pat=path lob=lobe] eq=?]
^- ?
?. eq %.n
=- ?. qat %.n
%+ levy (~(tap by q) ~)
|= [pat=path lob=lobe]
(~(has by p) pat)
%+ roll (~(tap by p) ~)
|= [[pat=path lob=lobe] eq=?]
^- ?
?. eq %.n
^= qat
%+ levy (~(tap by p) ~)
|= [pat=path lob=lobe]
=+ zat=(~(get by q) pat)
?~ zat %.n
=((lobe-to-noun u.zat) (lobe-to-noun lob))
@ -1817,13 +1813,11 @@
|= [wen=@da lem=nori] :: edit
^+ +>
?- -.lem
& =+ ^= yet
& =^ yak lat :: merge objects
%+ forge-yaki wen
?: =(let 0) :: initial import
[~ q.lem]
[(some r:(aeon-to-yaki let)) q.lem]
=+ yak=-.yet
=. lat +.yet :: merge objects
?. ?| =(0 let)
!=((lent p.yak) 1)
!(equiv q.yak q:(aeon-to-yaki let))

View File

@ -2136,4 +2136,173 @@ It remains to discuss `++edit:de`.
+>.$(dom d, ran r)
```
We very simply call `++edit:ze` and apply the resultant dome and rang back into
ourself. As we should expect, the actual handling of the changes themselves
is delegated to `++ze` in `arvo/zuse.hoon`.
```
++ edit :: edit:ze
|= [wen=@da lem=nori] :: edit
^+ +>
?- -.lem
& =^ yak lat :: merge objects
%+ forge-yaki wen
?: =(let 0) :: initial import
[~ q.lem]
[(some r:(aeon-to-yaki let)) q.lem]
?. ?| =(0 let)
!=((lent p.yak) 1)
!(equiv q.yak q:(aeon-to-yaki let))
==
+>.$ :: silently ignore
=: let +(let)
hit (~(put by hit) +(let) r.yak)
hut (~(put by hut) r.yak yak)
==
+>.$(ank (checkout-ankh q.yak))
| +>.$(lab ?<((~(has by lab) p.lem) (~(put by lab) p.lem let)))
==
```
Two kinds of changes may be made to a filesystem: we can modify the contents
or we can label a revision.
Labeling a revision (the `|` case) is much simpler. We first assert that the
label doesn't already exist. Then, we put in `lab` in our dome the label
associated with the current revision number.
In the `&` case, we're actually modifying the contents of the filesystem.
First, we create the commit in `++forge-yaki` by applying the given changes to
our current revision. This also updates `lat` in our rang with the new data
objects.
Unless either this is the initial import, the generated yaki doesn't have
exactly one parent, or the data in the generated yaki is the same as that in
our current revision, we silently ignore the request. Note that this only
allows changes that don't affect the contents of the filesystem if this is a
merge.
If one of the conditions does hold, then we apply the generated commit. We
increment `let`, the revision number of our head; associate the new revision
number with the hash of the new commit; and put the new commit in `hut`.
Finally, we update our current ankh by checking out the new commit.
We discussed `++checkout-ankh` above, so it remains only to discuss
`++forge-yaki` and `++equiv`. We begin with the simpler, `++equiv:ze`.
```
++ equiv :: test paths
|= [p=(map path lobe) q=(map path lobe)]
^- ?
=- ?. qat %.n
%+ levy (~(tap by q) ~)
|= [pat=path lob=lobe]
(~(has by p) pat)
^= qat
%+ levy (~(tap by p) ~)
|= [pat=path lob=lobe]
=+ zat=(~(get by q) pat)
?~ zat %.n
=((lobe-to-noun u.zat) (lobe-to-noun lob))
```
We're checking to see if the data in both filesystem trees is identical. We
start by going through `p` and checking to see if (1) the path exists in `q`
and (2) the data is the same as in `q`.
This shows that `q` is a superset of `p`. To show that `p` and `q` are
equivalent, we have to make sure there is nothing in `q` that is not also in
`p`. Once we've done that, we know `p` and `q` are equivalent.
```
++ forge-yaki :: forge-yaki:ze
|= [wen=@da par=(unit tako) lem=soba] :: forge yaki
=+ ^= per
?~ par ~
~[u.par]
=+ gar=(update-lat (apply-changes q.lem) lat)
:- %^ make-yaki per +.gar wen :: from existing diff
-.gar :: fix lat
```
Here, we first make `per`, our list of parents. If we have a parent, we put it
in the list, else the list is empty. Simple.
We then apply the changes and update `lat`, our object store. Finally, we make
a yaki out of the generated change information and produce both it and the new
object store.
Lifecycle of a Local Merge
--------------------------
Merges are pretty simple from the perspective of clay. A `%merg` kiss is sent
with already-generated merge state, and we simply apply the new state. The
question of how the merge is generated is much more complicated, but it is also
out of the scope of this section.
We've seen most of the arms involved, so we'll go through most of it pretty
quickly. In `++call` we handle the `%merg` kiss.
```
%merg :: direct state up
=^ mos ruf
=+ une=(un p.q.hic now ruf)
=+ ^= zat
(exem:(di:wake:une q.q.hic) hen now r.q.hic)
=+ zot=abet.zat
:- -.zot
=. une (pish:une q.q.hic +.zot ran.zat)
abet:une(hez.yar ?.(=(%into -.q.hic) hez.yar.une [~ hen]))
[mos ..^$]
```
As we've seen several times before, we set up a core for the local ship with
`++un`. We set up a core for the local desk with `++di` and updating our
subscribers with `++wake`. We call `++exem` to execute the merge. `++abet:de`,
`++pish:un` and `++abet:un` resolve all our changes.
The only new arm here is `++exem:de`.
```
++ exem :: execute merge
|= [hen=duct wen=@da mer=mizu] :: aka direct change
?. (gte p.mer let.dom) !! :: no
=. +>.$ %= +>.$
hut.ran (~(uni by hut.r.mer) hut.ran)
lat.ran (~(uni by lat.r.mer) lat.ran)
let.dom p.mer
hit.dom (~(uni by q.mer) hit.dom)
==
=+ ^= hed :: head commit
=< q
%- ~(got by hut.ran)
%- ~(got by hit.dom)
let.dom
=. ank.dom :: real checkout
(~(checkout-ankh ze lim dom ran) hed)
(echa:wake hen wen mer) :: notify or w/e
```
We first do a quick sanity check that the head of the merge data is greater
than the head of the old data. Merges must add at least one revision.
We merge the new data in the obvious way. We do map merges for `hut` and `lat`
in rang to get all the new data and commits, we do a map merge in`hit` in our
dome to get all the new revision numbers, and we update our head to the most
recent revision.
Then, we checkout the commit at our head and announce the results to unix.
`++echa` is the only new arm here.
```
++ echa :: announce raw
|= [hen=duct wen=@da mer=mizu]
^+ +>
%= +>
vag ?~(hez vag :_(vag [u.hez [%ergo who syd let.dom]]))
==
```
If we have a sync duct, we tell unix that a new revision is available.
This concludes our discussion of a local merge.