fixed clay bug

This commit is contained in:
Ubuntu 2014-09-03 19:56:16 +00:00
parent 8d7ecb1f5b
commit 06b0890e22
2 changed files with 246 additions and 5 deletions

View File

@ -1251,7 +1251,7 @@
^+ +>
?: =(let oan) +>
?: (gth oan let) !! :: don't have this version
+>(ank (azel q:(need (~(get by hut) (need (~(get by hit) oan))))), let oan)
+>(ank (azel q:(~(got by hut) (~(got by hit) oan))), let oan)
::
::::
++ aqel :: aqel:ze
@ -1310,8 +1310,9 @@
|= [[pat=path bar=lobe] ank=ankh]
^- ankh
%- cosh
=+ zar=(zaul bar)
?~ pat [_cash [~ [(sham zar) zar]] `(map ,@ta ankh)`~]
?~ pat
=+ zar=(zaul bar)
ank(q [~ (sham zar) zar])
=+ nak=(~(get by r.ank) i.pat)
%= ank
r %+ ~(put by r.ank) i.pat

View File

@ -30,7 +30,8 @@ skimming, this so that you get a rough idea of how our state is organized.
The types that are certainly worth reading are `++raft`, `++room`, `++dome`,
`++ankh`, `++rung`, `++rang`, `++blob`, `++yaki`, and `++nori` (possibly in
that order). All in all, though, this section isn't too long, so many readers
may wish to quickly read through all of it.
may wish to quickly read through all of it. If you get bored, though, just
skip to the next section. You can always come back when you need to.
###`++raft`, formal state
@ -988,9 +989,248 @@ to get the requested information.
^+ +>
?: =(let oan) +>
?: (gth oan let) !! :: don't have this version
+>(ank (azel q:(need (~(get by hut) (need (~(get by hit) oan))))), let oan)
+>(ank (azel q:(~(got by hut) (~(got by hit) oan))), let oan)
```
If we're already at the requested version, we do nothing. If we're requesting
a version later than our head, we are unable to comply.
Otherwise, we get the hash of the commit at the number, and from that we get
the commit itself (the yaki), which has the map of path to lobe that represents
a version of the filesystem. We call `++azel` to checkout the commit, and we
replace `ank` in our context with the result.
```
++ azel :: azel:ze
|= hat=(map path lobe) :: checkout commit
^- ankh
%- cosh
%+ roll (~(tap by hat) ~)
|= [[pat=path bar=lobe] ank=ankh]
^- ankh
%- cosh
?~ pat
=+ zar=(zaul bar)
[_cash [~ [(sham zar) zar]] `(map ,@ta ankh)`~]
=+ nak=(~(get by r.ank) i.pat)
%= ank
r %+ ~(put by r.ank) i.pat
$(pat t.pat, ank (fall nak _ankh))
==
```
Twice we call `++cosh`, which hashes a commit, updating `p` in an `ankh`.
Let's jump into that algorithm before we describe `++azel`.
```
++ cosh :: locally rehash
|= ank=ankh
ank(p dash:(zu ank))
```
We simply replace `p` in the hash with the `cash` we get from a call to
`++dash:zu`.
```
++ zu !: :: filesystem
|= ank=ankh :: filesystem state
=| myz=(list ,[p=path q=miso]) :: changes in reverse
=| ram=path :: reverse path into
|%
++ dash :: local rehash
^- cash
%+ mix ?~(q.ank 0 p.u.q.ank)
=+ axe=1
|- ^- cash
?~ r.ank _@
;: mix
(shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank))))
$(r.ank l.r.ank, axe (peg axe 2))
$(r.ank r.r.ank, axe (peg axe 3))
==
```
`++zu` is a core we set up with a particular filesystem node to traverse a
checkout of the filesystem and access the actual data inside it. One of the
things we can do with it is to create a recursive hash of the node.
In `++dash`, if this node is a file, then we xor the remainder of the hash with
the hash of the contents of the file. The remainder of the hash is `0` if we
have no children, else we descend into our children. Basically, we do a half
SHA-256 of the xor of the axis of this child and the half SHA-256 of the xor of
the name of the child and the hash of the child. This is done for each child
and all the results are xored together.
Now we return to our discussion of `++azel`.
We fold over every path in this version of the filesystem and create a great
ankh out of them. First, we call `++zaul` to get the raw data referred to be
each lobe.
```
++ zaul :: grab blob
|= p=lobe :: ^- *
%- zaru
(zaal p)
```
This converts a lobe into the raw data it refers to by first getting the blob
with `++zaal` and converting that into data with `++zaru`.
```
++ zaal :: grab blob
|= p=lobe :: (raw)
^- blob
(~(got by lat) p)
```
This just grabs the blob that the lobe refers to.
```
++ zaru :: grab blob
|= p=blob
?- -.p
%delta (lump r.p (zaul q.p))
%direct q.p
%indirect q.p
==
```
If we have either a direct or an indirect blob, then the data is stored right
in the blob. Otherwise, we have to reconstruct it from the diffs. We do this
by calling `++lump` on the diff in the blob with the data obtained by
recursively calling the parent of this blob.
```
++ lump :: apply patch
|= [don=udon src=*]
^- *
?+ p.don ~|(%unsupported !!)
%a
?+ -.q.don ~|(%unsupported !!)
%a q.q.don
%c (lurk ((hard (list)) src) p.q.don)
%d (lure src p.q.don)
==
::
%c
=+ dst=(lore ((hard ,@) src))
%- roly
?+ -.q.don ~|(%unsupported !!)
%a ((hard (list ,@t)) q.q.don)
%c (lurk dst p.q.don)
==
==
```
This is defined in `arvo/hoon.hoon` for historical reasons which are likely no
longer applicable. Since the `++umph` structure will likely change we convert
clay to be a typed filesystem, we'll only give a high-level description of this
process. If we have a `%a` udon, then we're performing a trivial replace, so
we produce simply `q.q.don`. If we have a `%c` udon, then we're performing a
list merge (as in, for example, lines of text). The merge is performed by
`++lurk`.
```
++ lurk :: apply list patch
|* [hel=(list) rug=(urge)]
^+ hel
=+ war=`_hel`~
|- ^+ hel
?~ rug (flop war)
?- -.i.rug
&
%= $
rug t.rug
hel (slag p.i.rug hel)
war (weld (flop (scag p.i.rug hel)) war)
==
::
|
%= $
rug t.rug
hel =+ gur=(flop p.i.rug)
|- ^+ hel
?~ gur hel
?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur))
war (weld q.i.rug war)
==
==
```
We accumulate our final result in `war`. If there's nothing more in our list
of merge instructions (unces), we just reverse `war` and produce it.
Otherwise, we process another unce. If the unce is of type `&`, then we have
`p.i.rug` lines of no changes, so we just copy them over from `hel` to `war`.
If the unice is of type `|`, then we verify that the source lines (in `hel`)
are what we expect them to be (`p.i.rug`), crashing on failure. If they're
good, then we append the new lines in `q.i.rug` onto `war`.
And that's really it. List merges are pretty easy. Anyway, if you recall, we
were discussing `++azel`.
```
++ azel :: azel:ze
|= hat=(map path lobe) :: checkout commit
^- ankh
%- cosh
%+ roll (~(tap by hat) ~)
|= [[pat=path bar=lobe] ank=ankh]
^- ankh
%- cosh
?~ pat
=+ zar=(zaul bar)
[_cash [~ [(sham zar) zar]] `(map ,@ta ankh)`~]
=+ nak=(~(get by r.ank) i.pat)
%= ank
r %+ ~(put by r.ank) i.pat
$(pat t.pat, ank (fall nak _ankh))
==
```
If the path is null, then we calculate `zar`, the raw data at the path `pat` in
this version. We produce a default ankh with the correct data (and its hash)
and no children.
Otherwise, we try to get the child we're looking at from our parent `ankh`. If
it's already been created, this succeeds; otherwise, we simply create a default
blank ankh. We place ourselves in our parent after recursively computing our
children.
This algorithm really isn't that complicated, but it may not be immediately
obvious why it works. An example should clear everything up.
Suppose `hat` is a map of the following information.
/greeting --> "customary upon meeting"
/greeting/english --> "hello"
/greeting/spanish --> "hola"
/greeting/russian/short --> "привет"
/greeting/russian/long --> "Здравствуйте"
/farewell/russian --> "до свидания"
Furthermore, let's say that we process them in this order:
/greeting/english
/greeting/russian/short
/greeting/russian/long
/greeting
/greeting/spanish
/farewell/russian
Then, the first path we process is `/greeting/english` . Since our path is not
null, we try to get `nak`, but because our ankh is blank at this point it
doesn't find anything. Thus, update our blank top-level ankh with a child
`greeting`. and recurse with the blank `nak` to create the ankh of the new
child.
In the recursion, we our path is `/english` and our ankh is again blank. We
try to get the `english` child of our ankh, but this of course fails. Thus,
we update our blank `/greeting` ankh with a child `english` produced by recursing.
Now our path is null, so we call `++zaul` to get the actual data, and we place
it in a brand-new ankh filled with this data and no children.
```
|
=+ nab=(~(aeon ze lim dom ran) p.p.rav)