merkledag.go 3.92 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
	"github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto"
7

8
	mh "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
9
	blocks "github.com/jbenet/go-ipfs/blocks"
10
	bserv "github.com/jbenet/go-ipfs/blockservice"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
11
	u "github.com/jbenet/go-ipfs/util"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
12 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
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
44
// AddNodeLink adds a link to another node.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
func (n *Node) AddNodeLink(name string, that *Node) error {
	s, err := that.Size()
	if err != nil {
		return err
	}

	h, err := that.Multihash()
	if err != nil {
		return err
	}

	n.Links = append(n.Links, &Link{
		Name: name,
		Size: s,
		Hash: h,
60
		Node: that,
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
61 62 63
	})
	return nil
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
64

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
65 66
// 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
67
func (n *Node) Size() (uint64, error) {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
68
	b, err := n.Encoded(false)
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
69 70 71 72
	if err != nil {
		return 0, err
	}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
73
	s := uint64(len(b))
Juan Batiz-Benet's avatar
gofmt  
Juan Batiz-Benet committed
74 75 76 77
	for _, l := range n.Links {
		s += l.Size
	}
	return s, nil
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
78
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
79

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
80
// Multihash hashes the encoded data of this node.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
81 82 83 84 85 86
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
87
	return u.Hash(b)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
88
}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
89

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
90
// Key returns the Multihash as a key, for maps.
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
91 92 93 94
func (n *Node) Key() (u.Key, error) {
	h, err := n.Multihash()
	return u.Key(h), err
}
95

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
96 97 98
// DAGService is an IPFS Merkle DAG service.
// - the root is virtual (like a forest)
// - stores nodes' data in a BlockService
99 100
// TODO: should cache Nodes that are in memory, and be
//       able to free some of them when vm pressure is high
101
type DAGService struct {
102
	Blocks *bserv.BlockService
103 104
}

105 106 107 108
// 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()
	u.DOut("DagService Add [%s]\n", k.Pretty())
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
	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)
}

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
func (n *DAGService) AddRecursive(nd *Node) error {
	_, err := n.Add(nd)
	if err != nil {
		return err
	}

	for _, link := range nd.Links {
		fmt.Println("Adding link.")
		if link.Node == nil {
			panic("Why does this node have a nil link?\n")
		}
		err := n.AddRecursive(link.Node)
		if err != nil {
			return err
		}
	}

	return nil
}

Juan Batiz-Benet's avatar
go lint  
Juan Batiz-Benet committed
146
// Get retrieves a node from the DAGService, fetching the block in the BlockService
147 148 149 150 151 152 153 154 155 156 157 158
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)
}
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199

func FilePBData() []byte {
	pbfile := new(PBData)
	typ := PBData_File
	pbfile.Type = &typ

	data, err := proto.Marshal(pbfile)
	if err != nil {
		//this really shouldnt happen, i promise
		panic(err)
	}
	return data
}

func FolderPBData() []byte {
	pbfile := new(PBData)
	typ := PBData_Directory
	pbfile.Type = &typ

	data, err := proto.Marshal(pbfile)
	if err != nil {
		//this really shouldnt happen, i promise
		panic(err)
	}
	return data
}

func WrapData(b []byte) []byte {
	pbdata := new(PBData)
	typ := PBData_Raw
	pbdata.Data = b
	pbdata.Type = &typ

	out, err := proto.Marshal(pbdata)
	if err != nil {
		// This shouldnt happen. seriously.
		panic(err)
	}

	return out
}