1
0
mirror of https://github.com/ipfs/kubo.git synced 2025-09-10 09:52:20 +08:00
Files
kubo/merkledag/node.go
Juan Batiz-Benet 6b2795338f ipfs object has learned stat
'ipfs object stat' is a plumbing command to print DAG
node statistics. <key> is a base58 encoded multihash.
It outputs to stdout:

  NumLinks        int number of links in link table
  BlockSize       int size of the raw, encoded data
  LinksSize       int size of the links segment
  DataSize        int size of the data segment
  CumulativeSize  int cumulative size of object and references
2015-01-07 02:31:29 -08:00

189 lines
4.3 KiB
Go

package merkledag
import (
"fmt"
mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
u "github.com/jbenet/go-ipfs/util"
)
// NodeMap maps u.Keys to Nodes.
// We cannot use []byte/Multihash for keys :(
// so have to convert Multihash bytes to string (u.Key)
type NodeMap map[u.Key]*Node
// Node represents a node in the IPFS Merkle DAG.
// nodes have opaque data and a set of navigable links.
type Node struct {
Links []*Link
Data []byte
// cache encoded/marshaled value
encoded []byte
cached mh.Multihash
}
// NodeStat is a statistics object for a Node. Mostly sizes.
type NodeStat struct {
NumLinks int // number of links in link table
BlockSize int // size of the raw, encoded data
LinksSize int // size of the links segment
DataSize int // size of the data segment
CumulativeSize int // cumulative size of object and its references
}
func (ns NodeStat) String() string {
f := "NodeStat{NumLinks: %d, BlockSize: %d, LinksSize: %d, DataSize: %d, CumulativeSize: %d}"
return fmt.Sprintf(f, ns.NumLinks, ns.BlockSize, ns.LinksSize, ns.DataSize, ns.CumulativeSize)
}
// Link represents an IPFS Merkle DAG Link between Nodes.
type Link struct {
// utf string name. should be unique per object
Name string // utf8
// cumulative size of target object
Size uint64
// multihash of the target object
Hash mh.Multihash
// a ptr to the actual node for graph manipulation
Node *Node
}
type LinkSlice []*Link
func (ls LinkSlice) Len() int { return len(ls) }
func (ls LinkSlice) Swap(a, b int) { ls[a], ls[b] = ls[b], ls[a] }
func (ls LinkSlice) Less(a, b int) bool { return ls[a].Name < ls[b].Name }
// MakeLink creates a link to the given node
func MakeLink(n *Node) (*Link, error) {
s, err := n.Size()
if err != nil {
return nil, err
}
h, err := n.Multihash()
if err != nil {
return nil, err
}
return &Link{
Size: s,
Hash: h,
}, nil
}
// GetNode returns the MDAG Node that this link points to
func (l *Link) GetNode(serv DAGService) (*Node, error) {
if l.Node != nil {
return l.Node, nil
}
return serv.Get(u.Key(l.Hash))
}
// AddNodeLink adds a link to another node.
func (n *Node) AddNodeLink(name string, that *Node) error {
lnk, err := MakeLink(that)
if err != nil {
return err
}
lnk.Name = name
lnk.Node = that
n.Links = append(n.Links, lnk)
return nil
}
// AddNodeLink adds a link to another node. without keeping a reference to
// the child node
func (n *Node) AddNodeLinkClean(name string, that *Node) error {
lnk, err := MakeLink(that)
if err != nil {
return err
}
lnk.Name = name
n.Links = append(n.Links, lnk)
return nil
}
// Remove a link on this node by the given name
func (n *Node) RemoveNodeLink(name string) error {
for i, l := range n.Links {
if l.Name == name {
n.Links = append(n.Links[:i], n.Links[i+1:]...)
return nil
}
}
return ErrNotFound
}
// Copy returns a copy of the node.
// NOTE: does not make copies of Node objects in the links.
func (n *Node) Copy() *Node {
nnode := new(Node)
nnode.Data = make([]byte, len(n.Data))
copy(nnode.Data, n.Data)
nnode.Links = make([]*Link, len(n.Links))
copy(nnode.Links, n.Links)
return nnode
}
// Size returns the total size of the data addressed by node,
// including the total sizes of references.
func (n *Node) Size() (uint64, error) {
b, err := n.Encoded(false)
if err != nil {
return 0, err
}
s := uint64(len(b))
for _, l := range n.Links {
s += l.Size
}
return s, nil
}
// Stat returns statistics on the node.
func (n *Node) Stat() (NodeStat, error) {
enc, err := n.Encoded(false)
if err != nil {
return NodeStat{}, err
}
cumSize, err := n.Size()
if err != nil {
return NodeStat{}, err
}
return NodeStat{
NumLinks: len(n.Links),
BlockSize: len(enc),
LinksSize: len(enc) - len(n.Data), // includes framing.
DataSize: len(n.Data),
CumulativeSize: int(cumSize),
}, nil
}
// Multihash hashes the encoded data of this node.
func (n *Node) Multihash() (mh.Multihash, error) {
// Note: Encoded generates the hash and puts it in n.cached.
_, err := n.Encoded(false)
if err != nil {
return nil, err
}
return n.cached, nil
}
// Key returns the Multihash as a key, for maps.
func (n *Node) Key() (u.Key, error) {
h, err := n.Multihash()
return u.Key(h), err
}