From 06b0890e227817f342960ea91dcc23570efa0f8d Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Wed, 3 Sep 2014 19:56:16 +0000 Subject: [PATCH] fixed clay bug --- arvo/zuse.hoon | 7 +- main/pub/src/doc/ref/vol/4c.md | 244 ++++++++++++++++++++++++++++++++- 2 files changed, 246 insertions(+), 5 deletions(-) diff --git a/arvo/zuse.hoon b/arvo/zuse.hoon index 0ad2f74694..33a72a215d 100644 --- a/arvo/zuse.hoon +++ b/arvo/zuse.hoon @@ -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 diff --git a/main/pub/src/doc/ref/vol/4c.md b/main/pub/src/doc/ref/vol/4c.md index 8dc50518ec..020215af43 100644 --- a/main/pub/src/doc/ref/vol/4c.md +++ b/main/pub/src/doc/ref/vol/4c.md @@ -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)