github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/importer/trickle/trickledag.go (about) 1 package trickle 2 3 import ( 4 "errors" 5 6 context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context" 7 8 h "github.com/ipfs/go-ipfs/importer/helpers" 9 dag "github.com/ipfs/go-ipfs/merkledag" 10 ft "github.com/ipfs/go-ipfs/unixfs" 11 ) 12 13 // layerRepeat specifies how many times to append a child tree of a 14 // given depth. Higher values increase the width of a given node, which 15 // improves seek speeds. 16 const layerRepeat = 4 17 18 func TrickleLayout(db *h.DagBuilderHelper) (*dag.Node, error) { 19 root := h.NewUnixfsNode() 20 if err := db.FillNodeLayer(root); err != nil { 21 return nil, err 22 } 23 for level := 1; !db.Done(); level++ { 24 for i := 0; i < layerRepeat && !db.Done(); i++ { 25 next := h.NewUnixfsNode() 26 if err := fillTrickleRec(db, next, level); err != nil { 27 return nil, err 28 } 29 if err := root.AddChild(next, db); err != nil { 30 return nil, err 31 } 32 } 33 } 34 35 out, err := db.Add(root) 36 if err != nil { 37 return nil, err 38 } 39 40 if err := db.Close(); err != nil { 41 return nil, err 42 } 43 44 return out, nil 45 } 46 47 func fillTrickleRec(db *h.DagBuilderHelper, node *h.UnixfsNode, depth int) error { 48 // Always do this, even in the base case 49 if err := db.FillNodeLayer(node); err != nil { 50 return err 51 } 52 53 for i := 1; i < depth && !db.Done(); i++ { 54 for j := 0; j < layerRepeat && !db.Done(); j++ { 55 next := h.NewUnixfsNode() 56 if err := fillTrickleRec(db, next, i); err != nil { 57 return err 58 } 59 60 if err := node.AddChild(next, db); err != nil { 61 return err 62 } 63 } 64 } 65 return nil 66 } 67 68 // TrickleAppend appends the data in `db` to the dag, using the Trickledag format 69 func TrickleAppend(ctx context.Context, base *dag.Node, db *h.DagBuilderHelper) (out *dag.Node, err_out error) { 70 defer func() { 71 if err_out == nil { 72 if err := db.Close(); err != nil { 73 err_out = err 74 } 75 } 76 }() 77 78 // Convert to unixfs node for working with easily 79 ufsn, err := h.NewUnixfsNodeFromDag(base) 80 if err != nil { 81 return nil, err 82 } 83 84 // Get depth of this 'tree' 85 n, layerProgress := trickleDepthInfo(ufsn, db.Maxlinks()) 86 if n == 0 { 87 // If direct blocks not filled... 88 if err := db.FillNodeLayer(ufsn); err != nil { 89 return nil, err 90 } 91 92 if db.Done() { 93 return ufsn.GetDagNode() 94 } 95 96 // If continuing, our depth has increased by one 97 n++ 98 } 99 100 // Last child in this node may not be a full tree, lets file it up 101 if err := appendFillLastChild(ctx, ufsn, n-1, layerProgress, db); err != nil { 102 return nil, err 103 } 104 105 // after appendFillLastChild, our depth is now increased by one 106 if !db.Done() { 107 n++ 108 } 109 110 // Now, continue filling out tree like normal 111 for i := n; !db.Done(); i++ { 112 for j := 0; j < layerRepeat && !db.Done(); j++ { 113 next := h.NewUnixfsNode() 114 err := fillTrickleRec(db, next, i) 115 if err != nil { 116 return nil, err 117 } 118 119 err = ufsn.AddChild(next, db) 120 if err != nil { 121 return nil, err 122 } 123 } 124 } 125 126 return ufsn.GetDagNode() 127 } 128 129 // appendFillLastChild will take in an incomplete trickledag node (uncomplete meaning, not full) and 130 // fill it out to the specified depth with blocks from the given DagBuilderHelper 131 func appendFillLastChild(ctx context.Context, ufsn *h.UnixfsNode, depth int, layerFill int, db *h.DagBuilderHelper) error { 132 if ufsn.NumChildren() <= db.Maxlinks() { 133 return nil 134 } 135 // Recursive step, grab last child 136 last := ufsn.NumChildren() - 1 137 lastChild, err := ufsn.GetChild(ctx, last, db.GetDagServ()) 138 if err != nil { 139 return err 140 } 141 142 // Fill out last child (may not be full tree) 143 nchild, err := trickleAppendRec(ctx, lastChild, db, depth-1) 144 if err != nil { 145 return err 146 } 147 148 // Update changed child in parent node 149 ufsn.RemoveChild(last, db) 150 err = ufsn.AddChild(nchild, db) 151 if err != nil { 152 return err 153 } 154 155 // Partially filled depth layer 156 if layerFill != 0 { 157 for ; layerFill < layerRepeat && !db.Done(); layerFill++ { 158 next := h.NewUnixfsNode() 159 err := fillTrickleRec(db, next, depth) 160 if err != nil { 161 return err 162 } 163 164 err = ufsn.AddChild(next, db) 165 if err != nil { 166 return err 167 } 168 } 169 } 170 171 return nil 172 } 173 174 // recursive call for TrickleAppend 175 func trickleAppendRec(ctx context.Context, ufsn *h.UnixfsNode, db *h.DagBuilderHelper, depth int) (*h.UnixfsNode, error) { 176 if depth == 0 || db.Done() { 177 return ufsn, nil 178 } 179 180 // Get depth of this 'tree' 181 n, layerProgress := trickleDepthInfo(ufsn, db.Maxlinks()) 182 if n == 0 { 183 // If direct blocks not filled... 184 if err := db.FillNodeLayer(ufsn); err != nil { 185 return nil, err 186 } 187 n++ 188 } 189 190 // If at correct depth, no need to continue 191 if n == depth { 192 return ufsn, nil 193 } 194 195 if err := appendFillLastChild(ctx, ufsn, n, layerProgress, db); err != nil { 196 return nil, err 197 } 198 199 // after appendFillLastChild, our depth is now increased by one 200 if !db.Done() { 201 n++ 202 } 203 204 // Now, continue filling out tree like normal 205 for i := n; i < depth && !db.Done(); i++ { 206 for j := 0; j < layerRepeat && !db.Done(); j++ { 207 next := h.NewUnixfsNode() 208 if err := fillTrickleRec(db, next, i); err != nil { 209 return nil, err 210 } 211 212 if err := ufsn.AddChild(next, db); err != nil { 213 return nil, err 214 } 215 } 216 } 217 218 return ufsn, nil 219 } 220 221 func trickleDepthInfo(node *h.UnixfsNode, maxlinks int) (int, int) { 222 n := node.NumChildren() 223 if n < maxlinks { 224 return 0, 0 225 } 226 227 return ((n - maxlinks) / layerRepeat) + 1, (n - maxlinks) % layerRepeat 228 } 229 230 // VerifyTrickleDagStructure checks that the given dag matches exactly the trickle dag datastructure 231 // layout 232 func VerifyTrickleDagStructure(nd *dag.Node, ds dag.DAGService, direct int, layerRepeat int) error { 233 return verifyTDagRec(nd, -1, direct, layerRepeat, ds) 234 } 235 236 // Recursive call for verifying the structure of a trickledag 237 func verifyTDagRec(nd *dag.Node, depth, direct, layerRepeat int, ds dag.DAGService) error { 238 if depth == 0 { 239 // zero depth dag is raw data block 240 if len(nd.Links) > 0 { 241 return errors.New("expected direct block") 242 } 243 244 pbn, err := ft.FromBytes(nd.Data) 245 if err != nil { 246 return err 247 } 248 249 if pbn.GetType() != ft.TRaw { 250 return errors.New("Expected raw block") 251 } 252 return nil 253 } 254 255 // Verify this is a branch node 256 pbn, err := ft.FromBytes(nd.Data) 257 if err != nil { 258 return err 259 } 260 261 if pbn.GetType() != ft.TFile { 262 return errors.New("expected file as branch node") 263 } 264 265 if len(pbn.Data) > 0 { 266 return errors.New("branch node should not have data") 267 } 268 269 for i := 0; i < len(nd.Links); i++ { 270 child, err := nd.Links[i].GetNode(context.TODO(), ds) 271 if err != nil { 272 return err 273 } 274 275 if i < direct { 276 // Direct blocks 277 err := verifyTDagRec(child, 0, direct, layerRepeat, ds) 278 if err != nil { 279 return err 280 } 281 } else { 282 // Recursive trickle dags 283 rdepth := ((i - direct) / layerRepeat) + 1 284 if rdepth >= depth && depth > 0 { 285 return errors.New("Child dag was too deep!") 286 } 287 err := verifyTDagRec(child, rdepth, direct, layerRepeat, ds) 288 if err != nil { 289 return err 290 } 291 } 292 } 293 return nil 294 }