merkledag.go 4.53 KB
Newer Older
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
1 2 3
package merkledag

import (
4
	"fmt"
Chas Leichner's avatar
Chas Leichner committed
5

6
	mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
7
	blocks "github.com/jbenet/go-ipfs/blocks"
8
	bserv "github.com/jbenet/go-ipfs/blockservice"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
9
	u "github.com/jbenet/go-ipfs/util"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
10 11
)

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12
var log = u.Logger("merkledag")
Jeromy's avatar
Jeromy committed
13

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
14 15 16
// NodeMap maps u.Keys to Nodes.
// We cannot use []byte/Multihash for keys :(
// so have to convert Multihash bytes to string (u.Key)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
17 18
type NodeMap map[u.Key]*Node

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
19
// Node represents a node in the IPFS Merkle DAG.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
20
// nodes have opaque data and a set of navigable links.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
21
type Node struct {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
22 23
	Links []*Link
	Data  []byte
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
24 25 26

	// cache encoded/marshaled value
	encoded []byte
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
27 28
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
29
// Link represents an IPFS Merkle DAG Link between Nodes.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
30
type Link struct {
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
31 32
	// utf string name. should be unique per object
	Name string // utf8
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
33

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
34 35
	// cumulative size of target object
	Size uint64
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
36

Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
37 38
	// multihash of the target object
	Hash mh.Multihash
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
39 40 41

	// a ptr to the actual node for graph manipulation
	Node *Node
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
42 43
}

Jeromy's avatar
Jeromy committed
44 45
func MakeLink(n *Node) (*Link, error) {
	s, err := n.Size()
46
	if err != nil {
Jeromy's avatar
Jeromy committed
47
		return nil, err
48 49
	}

Jeromy's avatar
Jeromy committed
50
	h, err := n.Multihash()
51
	if err != nil {
Jeromy's avatar
Jeromy committed
52
		return nil, err
53
	}
Jeromy's avatar
Jeromy committed
54
	return &Link{
55 56
		Size: s,
		Hash: h,
Jeromy's avatar
Jeromy committed
57
	}, nil
58 59
}

Jeromy's avatar
Jeromy committed
60 61 62
// AddNodeLink adds a link to another node.
func (n *Node) AddNodeLink(name string, that *Node) error {
	lnk, err := MakeLink(that)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
63 64 65
	if err != nil {
		return err
	}
Jeromy's avatar
Jeromy committed
66 67 68 69 70 71
	lnk.Name = name
	lnk.Node = that

	n.Links = append(n.Links, lnk)
	return nil
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
72

Jeromy's avatar
Jeromy committed
73 74 75 76
// 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)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
77 78 79
	if err != nil {
		return err
	}
Jeromy's avatar
Jeromy committed
80
	lnk.Name = name
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81

Jeromy's avatar
Jeromy committed
82
	n.Links = append(n.Links, lnk)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
83 84
	return nil
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
85

86 87 88 89 90 91 92 93 94 95
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 u.ErrNotFound
}

96 97
// Copy returns a copy of the node.
// NOTE: does not make copies of Node objects in the links.
Jeromy's avatar
Jeromy committed
98 99 100 101 102 103 104 105 106 107
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
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
108 109
// Size returns the total size of the data addressed by node,
// including the total sizes of references.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
110
func (n *Node) Size() (uint64, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
111
	b, err := n.Encoded(false)
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
112 113 114 115
	if err != nil {
		return 0, err
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
116
	s := uint64(len(b))
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
117 118 119 120
	for _, l := range n.Links {
		s += l.Size
	}
	return s, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
121
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
122

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
123
// Multihash hashes the encoded data of this node.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
124 125 126 127 128 129
func (n *Node) Multihash() (mh.Multihash, error) {
	b, err := n.Encoded(false)
	if err != nil {
		return nil, err
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
130
	return u.Hash(b), nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
131
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
132

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
133
// Key returns the Multihash as a key, for maps.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
134 135 136 137
func (n *Node) Key() (u.Key, error) {
	h, err := n.Multihash()
	return u.Key(h), err
}
138

139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
// Recursively update all hash links and size values in the tree
func (n *Node) Update() error {
	log.Debug("node update")
	for _, l := range n.Links {
		if l.Node != nil {
			err := l.Node.Update()
			if err != nil {
				return err
			}
			nhash, err := l.Node.Multihash()
			if err != nil {
				return err
			}
			l.Hash = nhash
			size, err := l.Node.Size()
			if err != nil {
				return err
			}
			l.Size = size
		}
	}
	_, err := n.Encoded(true)
	return err
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
164 165 166
// DAGService is an IPFS Merkle DAG service.
// - the root is virtual (like a forest)
// - stores nodes' data in a BlockService
167 168
// TODO: should cache Nodes that are in memory, and be
//       able to free some of them when vm pressure is high
169
type DAGService struct {
170
	Blocks *bserv.BlockService
171 172
}

173 174 175
// Add adds a node to the DAGService, storing the block in the BlockService
func (n *DAGService) Add(nd *Node) (u.Key, error) {
	k, _ := nd.Key()
Jeromy's avatar
Jeromy committed
176
	log.Debug("DagService Add [%s]\n", k.Pretty())
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
	if n == nil {
		return "", fmt.Errorf("DAGService is nil")
	}

	d, err := nd.Encoded(false)
	if err != nil {
		return "", err
	}

	b, err := blocks.NewBlock(d)
	if err != nil {
		return "", err
	}

	return n.Blocks.AddBlock(b)
}

194 195 196
func (n *DAGService) AddRecursive(nd *Node) error {
	_, err := n.Add(nd)
	if err != nil {
Jeromy's avatar
Jeromy committed
197
		log.Info("AddRecursive Error: %s\n", err)
198 199 200 201
		return err
	}

	for _, link := range nd.Links {
202 203 204 205 206
		if link.Node != nil {
			err := n.AddRecursive(link.Node)
			if err != nil {
				return err
			}
207 208 209 210 211 212
		}
	}

	return nil
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
213
// Get retrieves a node from the DAGService, fetching the block in the BlockService
214 215 216 217 218 219 220 221 222 223 224 225
func (n *DAGService) Get(k u.Key) (*Node, error) {
	if n == nil {
		return nil, fmt.Errorf("DAGService is nil")
	}

	b, err := n.Blocks.GetBlock(k)
	if err != nil {
		return nil, err
	}

	return Decoded(b.Data)
}