Package org.apache.cassandra.utils
Class MerkleTree
- java.lang.Object
-
- org.apache.cassandra.utils.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.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static class
MerkleTree.RowHash
Hash value representing a row, to be used to pass hashes to the MerkleTree.static class
MerkleTree.TreeRange
The public interface to a range in the tree.static class
MerkleTree.TreeRangeIterator
Returns the leaf (range) of a given tree in increasing order.
-
Field Summary
Fields Modifier and Type Field Description static byte
RECOMMENDED_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 MerkleTree
deserialize(DataInputPlus in, boolean offHeapRequested, int version)
static MerkleTree
deserialize(DataInputPlus in, int version)
static java.util.List<MerkleTree.TreeRange>
difference(MerkleTree ltree, MerkleTree rtree)
boolean
equals(java.lang.Object other)
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.MerkleTree.TreeRange
get(Token t)
For testing purposes.void
init()
Initializes this tree by splitting it until hashdepth is reached, or until an additional level of splits would violate maxsize.long
maxsize()
void
maxsize(long maxsize)
IPartitioner
partitioner()
void
release()
long
rowCount()
void
serialize(DataOutputPlus out, int version)
long
serializedSize(int version)
long
size()
The number of distinct ranges contained in this tree.boolean
split(Token t)
Splits the range containing the given token, if no tree limits would be violated.java.lang.String
toString()
-
-
-
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:
toString
in classjava.lang.Object
-
equals
public boolean equals(java.lang.Object other)
- Overrides:
equals
in 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.
-
-