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  }