Class MerkleTree


  • public class MerkleTree
    extends java.lang.Object
    A MerkleTree implemented as a binary tree. A MerkleTree is a full binary tree that represents a perfect binary tree of depth 'hashdepth'. In a perfect binary tree, each leaf contains a sequentially hashed range, and each inner node contains the binary hash of its two children. In the MerkleTree, many ranges will not be split to the full depth of the perfect binary tree: the leaves of this tree are Leaf objects, which contain the computed values of the nodes that would be below them if the tree were perfect. The hash values of the inner nodes of the MerkleTree are calculated lazily based on their children when the hash of a range is requested with hash(range). Inputs passed to TreeRange.validate should be calculated using a very secure hash, because all hashing internal to the tree is accomplished using XOR. If two MerkleTrees have the same hashdepth, they represent a perfect tree of the same depth, and can always be compared, regardless of size or splits.
    • Constructor Detail

      • MerkleTree

        public MerkleTree​(IPartitioner partitioner,
                          Range<Token> range,
                          int hashdepth,
                          long maxsize)
        Parameters:
        partitioner - The partitioner in use.
        range - the range this tree covers
        hashdepth - The maximum depth of the tree. 100/(2^depth) is the % of the key space covered by each subrange of a fully populated tree.
        maxsize - The maximum number of subranges in the tree.
    • Method Detail

      • init

        public void init()
        Initializes this tree by splitting it until hashdepth is reached, or until an additional level of splits would violate maxsize. NB: Replaces all nodes in the tree, and always builds on the heap
      • release

        public void release()
      • size

        public long size()
        The number of distinct ranges contained in this tree. This is a reasonable measure of the memory usage of the tree (assuming 'this.order' is significant).
      • maxsize

        public long maxsize()
      • maxsize

        public void maxsize​(long maxsize)
      • difference

        public static java.util.List<MerkleTree.TreeRange> difference​(MerkleTree ltree,
                                                                      MerkleTree rtree)
        Parameters:
        ltree - First tree.
        rtree - Second tree.
        Returns:
        A list of the largest contiguous ranges where the given trees disagree.
      • split

        public boolean split​(Token t)
        Splits the range containing the given token, if no tree limits would be violated. If the range would be split to a depth below hashdepth, or if the tree already contains maxsize subranges, this operation will fail.
        Returns:
        True if the range was successfully split.
      • rowCount

        public long rowCount()
      • toString

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object
      • equals

        public boolean equals​(java.lang.Object other)
        Overrides:
        equals in class java.lang.Object
      • serialize

        public void serialize​(DataOutputPlus out,
                              int version)
                       throws java.io.IOException
        Throws:
        java.io.IOException
      • serializedSize

        public long serializedSize​(int version)
      • deserialize

        public static MerkleTree deserialize​(DataInputPlus in,
                                             int version)
                                      throws java.io.IOException
        Throws:
        java.io.IOException
      • deserialize

        public static MerkleTree deserialize​(DataInputPlus in,
                                             boolean offHeapRequested,
                                             int version)
                                      throws java.io.IOException
        Throws:
        java.io.IOException
      • estimatedMaxDepthForBytes

        public static int estimatedMaxDepthForBytes​(IPartitioner partitioner,
                                                    long numBytes,
                                                    int bytesPerHash)
        Estimate the allowable depth while keeping the resulting heap usage of this tree under the provided number of bytes. This is important for ensuring that we do not allocate overly large trees that could OOM the JVM and cause instability. Calculated using the following logic: Let T = size of a tree of depth n T = #leafs * sizeof(leaf) + #inner * sizeof(inner) T = 2^n * L + 2^n - 1 * I T = 2^n * L + 2^n * I - I; So to solve for n given sizeof(tree_n) T: n = floor(log_2((T + I) / (L + I))
        Parameters:
        numBytes - The number of bytes to fit the tree within
        bytesPerHash - The number of bytes stored in a leaf node, for example 2 * murmur128 will be 256 bits or 32 bytes
        Returns:
        the estimated depth that will fit within the provided number of bytes