mirror of
https://github.com/urbit/shrub.git
synced 2025-01-05 19:46:50 +03:00
fixed clay bug
This commit is contained in:
parent
8d7ecb1f5b
commit
06b0890e22
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user