Package org.apache.cassandra.utils
Class MerkleTree
- java.lang.Object
-
- org.apache.cassandra.utils.MerkleTree
-
public class MerkleTree extends java.lang.ObjectA 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.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static classMerkleTree.RowHashHash value representing a row, to be used to pass hashes to the MerkleTree.static classMerkleTree.TreeRangeThe public interface to a range in the tree.static classMerkleTree.TreeRangeIteratorReturns the leaf (range) of a given tree in increasing order.
-
Field Summary
Fields Modifier and Type Field Description static byteRECOMMENDED_DEPTH
-
Constructor Summary
Constructors Constructor Description MerkleTree(IPartitioner partitioner, Range<Token> range, int hashdepth, long maxsize)
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description static MerkleTreedeserialize(DataInputPlus in, boolean offHeapRequested, int version)static MerkleTreedeserialize(DataInputPlus in, int version)static java.util.List<MerkleTree.TreeRange>difference(MerkleTree ltree, MerkleTree rtree)booleanequals(java.lang.Object other)static intestimatedMaxDepthForBytes(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.MerkleTree.TreeRangeget(Token t)For testing purposes.voidinit()Initializes this tree by splitting it until hashdepth is reached, or until an additional level of splits would violate maxsize.longmaxsize()voidmaxsize(long maxsize)IPartitionerpartitioner()voidrelease()longrowCount()voidserialize(DataOutputPlus out, int version)longserializedSize(int version)longsize()The number of distinct ranges contained in this tree.booleansplit(Token t)Splits the range containing the given token, if no tree limits would be violated.java.lang.StringtoString()
-
-
-
Field Detail
-
RECOMMENDED_DEPTH
public static final byte RECOMMENDED_DEPTH
- See Also:
- Constant Field Values
-
-
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 covershashdepth- 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()
-
partitioner
public IPartitioner partitioner()
-
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:
toStringin classjava.lang.Object
-
equals
public boolean equals(java.lang.Object other)
- Overrides:
equalsin classjava.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 withinbytesPerHash- : 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
-
get
public MerkleTree.TreeRange get(Token t)
For testing purposes. Gets the smallest range containing the token.
-
-