Last active
July 21, 2021 20:49
-
-
Save eduardonunesp/367df320957e75ef43f1002a68cbec49 to your computer and use it in GitHub Desktop.
HAMT Container test
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"github.com/ipfs/go-cid" | |
hamt "github.com/ipld/go-ipld-adl-hamt" | |
ipld "github.com/ipld/go-ipld-prime" | |
_ "github.com/ipld/go-ipld-prime/codec/dagcbor" | |
cidlink "github.com/ipld/go-ipld-prime/linking/cid" | |
"github.com/multiformats/go-multicodec" | |
) | |
// HAMTContainer is just a way to put together all HAMT needed structures in norder to create a ipld.Node | |
// representing the HAMT after the builder runs | |
type HAMTContainer struct { | |
storage Memory | |
linkSystem ipld.LinkSystem | |
linkProto ipld.LinkPrototype | |
assembler ipld.MapAssembler | |
node ipld.Node | |
link ipld.Link | |
cid cid.Cid | |
builder *hamt.Builder | |
isBuild bool | |
} | |
// NewHAMTContainer creates a new HAMTContainer | |
func NewHAMTContainer() (*HAMTContainer, error) { | |
var err error | |
newHAMTContainer := HAMTContainer{ | |
storage: Memory{}, | |
} | |
// Sets the link system | |
newHAMTContainer.linkSystem = cidlink.DefaultLinkSystem() | |
newHAMTContainer.linkProto = cidlink.LinkPrototype{Prefix: cid.Prefix{ | |
Version: 1, // Usually '1'. | |
Codec: uint64(multicodec.DagCbor), | |
MhType: uint64(multicodec.Sha2_512), | |
MhLength: 64, // sha2-512 hash has a 64-byte sum. | |
}} | |
// Sets the writer and reader interfaces for the link system | |
newHAMTContainer.linkSystem.StorageWriteOpener = newHAMTContainer.storage.OpenWrite | |
newHAMTContainer.linkSystem.StorageReadOpener = newHAMTContainer.storage.OpenRead | |
// Creates the builder for the HAMT | |
newHAMTContainer.builder = hamt.NewBuilder(hamt.Prototype{BitWidth: 3, BucketSize: 64}). | |
WithLinking(newHAMTContainer.linkSystem, newHAMTContainer.linkProto) | |
// Sets the assembler to build the k/v for the map structure | |
newHAMTContainer.assembler, err = newHAMTContainer.builder.BeginMap(0) | |
if err != nil { | |
return nil, err | |
} | |
return &newHAMTContainer, nil | |
} | |
// GetCID will return the cid.Cid for the ipld.Node | |
// Or it will return an error if the ipld.Node for the HAMT isn't built | |
func (hc HAMTContainer) GetCID() (cid.Cid, error) { | |
if !hc.isBuild { | |
return cid.Cid{}, fmt.Errorf("HAMT not ready, build first") | |
} | |
return hc.cid, nil | |
} | |
// GetLink will return the ipld.Link for the ipld.Node | |
// Or it will return an error if the ipld.Node for the HAMT isn't built | |
func (hc HAMTContainer) GetLink() (ipld.Link, error) { | |
if !hc.isBuild { | |
return nil, fmt.Errorf("HAMT not ready, build first") | |
} | |
return hc.link, nil | |
} | |
// SetKV adds a new k/v content for the HAMT | |
// For string values it will add k/v pair of strings | |
// For ipld.Link values it will add string key and a link for another HAMT structure as value | |
func (hc HAMTContainer) SetKV(key string, value interface{}) error { | |
err := hc.assembler.AssembleKey().AssignString(key) | |
switch v := value.(type) { | |
case string: | |
err = hc.assembler.AssembleValue().AssignString(v) | |
if err != nil { | |
return err | |
} | |
case ipld.Link: | |
err = hc.assembler.AssembleValue().AssignLink(v) | |
if err != nil { | |
return err | |
} | |
default: | |
return fmt.Errorf("Invalid type for value") | |
} | |
return nil | |
} | |
// BuildHAMTNode will build the HAMT internal representation inside the container | |
// It will have Link, and ipld.Node representing the HAMT also CID for the root content | |
func (hc *HAMTContainer) BuildHAMTNode() error { | |
err := hc.assembler.Finish() | |
if err != nil { | |
return err | |
} | |
hc.node = hamt.Build(hc.builder) | |
link, err := hc.linkSystem.Store( | |
ipld.LinkContext{}, | |
hc.linkProto, | |
hc.node, | |
) | |
if err != nil { | |
return err | |
} | |
hc.link = link | |
hc.cid, err = cid.Parse(link.String()) | |
if err != nil { | |
return err | |
} | |
hc.isBuild = true | |
return err | |
} | |
func main() { | |
// Create the first HAMT | |
childHC, err := NewHAMTContainer() | |
errCheck(err) | |
// Set some k/v | |
err = childHC.SetKV("foo", "bar") | |
errCheck(err) | |
// Build the HAMT Node | |
err = childHC.BuildHAMTNode() | |
errCheck(err) | |
// Creates the parent HAMT | |
parentHC, err := NewHAMTContainer() | |
errCheck(err) | |
// Gets the link for the child HAMT | |
childHCLink, err := childHC.GetLink() | |
errCheck(err) | |
// Put the child HAMT as values of the parent HAMT | |
err = parentHC.SetKV("zar", childHCLink) | |
errCheck(err) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"fmt" | |
"io" | |
"github.com/ipld/go-ipld-prime" | |
) | |
// Memory is a simple in-memory storage for data indexed by ipld.Link. | |
// (It's little more than a map -- in fact, the map is exported, | |
// and you can poke it directly.) | |
// | |
// The OpenRead method conforms to ipld.BlockReadOpener, | |
// and the OpenWrite method conforms to ipld.BlockWriteOpener. | |
// Therefore it's easy to use in a LinkSystem like this: | |
// | |
// store := storage.Memory{} | |
// lsys.StorageReadOpener = (&store).OpenRead | |
// lsys.StorageWriteOpener = (&store).OpenWrite | |
// | |
// This storage is mostly expected to be used for testing and demos, | |
// and as an example of how you can implement and integrate your own storage systems. | |
type Memory struct { | |
Bag map[ipld.Link][]byte | |
} | |
func (store *Memory) beInitialized() { | |
if store.Bag != nil { | |
return | |
} | |
store.Bag = make(map[ipld.Link][]byte) | |
} | |
func (store *Memory) OpenRead(_ ipld.LinkContext, lnk ipld.Link) (io.Reader, error) { | |
store.beInitialized() | |
data, exists := store.Bag[lnk] | |
if !exists { | |
return nil, fmt.Errorf("404") // FIXME this needs a standard error type | |
} | |
return bytes.NewReader(data), nil | |
} | |
func (store *Memory) OpenWrite(_ ipld.LinkContext) (io.Writer, ipld.BlockWriteCommitter, error) { | |
store.beInitialized() | |
buf := bytes.Buffer{} | |
return &buf, func(lnk ipld.Link) error { | |
store.Bag[lnk] = buf.Bytes() | |
return nil | |
}, nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
func errCheck(err error) { | |
if err != nil { | |
panic(err) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment