public abstract class AbstractNode<T extends AbstractNode> extends PO implements IAbstractNode, IAbstractNodeData, IKeysData
Modifier and Type | Field and Description |
---|---|
protected AbstractBTree |
btree
The BTree.
|
protected static boolean |
DEBUG
True iff the
log level is DEBUG or less. |
protected static org.apache.log4j.Logger |
log
Log for node and leaf operations.
|
protected Reference<Node> |
parent
The parent of this node.
|
protected int |
referenceCount
The #of times that this node is present on the
HardReferenceQueue . |
protected Reference<? extends AbstractNode<T>> |
self
|
NULL
Modifier | Constructor and Description |
---|---|
protected |
AbstractNode(AbstractBTree btree,
boolean dirty)
All constructors delegate to this constructor to set the btree and
branching factor and to compute the minimum and maximum #of keys for the
node.
|
protected |
AbstractNode(AbstractNode<T> src)
Copy constructor.
|
Modifier and Type | Method and Description |
---|---|
protected void |
assertInvariants()
Invariants:
A node with nkeys + 1 children.
A node must have between [m/2:m] children (alternatively, between
[m/2-1:m-1] keys since nkeys + 1 == nchildren for a node).
A leaf has no children and has between [m/2:m] key-value pairs (the
same as the #of children on a node).
The root leaf may be deficient (may have less than m/2 key-value
pairs).
where
m is the branching factor and a node is understood
to be a non-leaf node in the tree. |
protected void |
assertKeysMonotonic()
Verify keys are monotonically increasing.
|
protected void |
copyKey(int dstpos,
IRaba srckeys,
int srcpos)
Copy a key from the source node into this node.
|
protected AbstractNode<?> |
copyOnWrite()
Return this leaf iff it is dirty (aka mutable) and otherwise return a
copy of this leaf.
|
protected AbstractNode<T> |
copyOnWrite(long triggeredByChildId)
Return this node or leaf iff it is dirty (aka mutable) and otherwise
return a copy of this node or leaf.
|
void |
delete()
Deletes the persistence capable object.
|
boolean |
dump(org.apache.log4j.Level level,
PrintStream out)
Dump the data onto the
PrintStream . |
abstract boolean |
dump(org.apache.log4j.Level level,
PrintStream out,
int height,
boolean recursive)
Dump the data onto the
PrintStream . |
boolean |
dump(PrintStream out)
Dump the data onto the
PrintStream (non-recursive). |
ITupleIterator |
entryIterator()
Traversal of index values in key order.
|
int |
getBranchingFactor() |
Node |
getParent()
The parent iff the node has been added as the child of another node and
the parent reference has not been cleared.
|
abstract long |
indexOf(byte[] searchKey)
Recursive search locates the appropriate leaf and returns the index
position of the entry.
|
abstract Tuple |
insert(byte[] key,
byte[] val,
boolean delete,
boolean putIfAbsent,
long timestamp,
Tuple tuple)
Insert or update a value.
|
abstract boolean |
isLeaf()
True iff this is a leaf node.
|
protected boolean |
isLeftMostNode()
Return
true if this node is the left-most node at its
level within the tree. |
protected boolean |
isRightMostNode()
Return
true if this node is the right-most node at its
level within the tree. |
protected void |
join()
Join this node (must be deficient) with either its left or right sibling.
|
protected static String |
keyAsString(byte[] key)
Return a human readable representation of the key.
|
abstract byte[] |
keyAt(long index)
Recursive search locates the entry at the specified index position in the
btree and returns the key for that entry.
|
abstract Tuple |
lookup(byte[] searchKey,
Tuple tuple)
Lookup a key.
|
protected abstract int |
maxKeys()
The maximum #of keys.
|
protected abstract void |
merge(AbstractNode sibling,
boolean isRightSibling)
Merge the sibling into this node.
|
protected abstract int |
minKeys()
The minimum #of keys.
|
abstract Iterator<AbstractNode> |
postOrderIterator(byte[] fromKey,
byte[] toKey)
Post-order traversal of nodes and leaves in the tree with a key range
constraint.
|
Iterator<AbstractNode> |
postOrderNodeIterator()
Post-order traveral of nodes and leaves in the tree.
|
Iterator<AbstractNode> |
postOrderNodeIterator(boolean dirtyNodesOnly)
Post-order traversal of nodes and leaves in the tree.
|
abstract Iterator<AbstractNode> |
postOrderNodeIterator(boolean dirtyNodesOnly,
boolean nodesOnly)
Post-order traversal of nodes and leaves in the tree.
|
ITupleIterator |
rangeIterator(byte[] fromKey,
byte[] toKey,
int flags)
Return an iterator that visits the entries in a half-open key range but
filters the values.
|
protected abstract void |
redistributeKeys(AbstractNode sibling,
boolean isRightSibling)
Redistribute the one key from the sibling into this node.
|
abstract Tuple |
remove(byte[] searchKey,
Tuple tuple)
Recursive search locates the appropriate leaf and removes the entry for
the key.
|
protected abstract IAbstractNode |
split()
Split a node or leaf that is over capacity (by one).
|
abstract void |
valueAt(long index,
Tuple tuple)
Recursive search locates the entry at the specified index position in the
btree and returns the value for that entry.
|
getIdentity, indent, isDeleted, isDirty, isPersistent, setDirty, setIdentity, toShortString, toString
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
data, getMaximumVersionTimestamp, getMinimumVersionTimestamp, hasVersionTimestamps, isCoded, isReadOnly
getKeyCount, getKeys
protected static final org.apache.log4j.Logger log
Category.isInfoEnabled()
before generating log
messages at this level to avoid string concatenation operations would
otherwise kill performance.Category.isDebugEnabled()
before generating log
messages at this level to avoid string concatenation operations would
otherwise kill performance.AbstractBTree.log
,
AbstractBTree.dumpLog
protected static final boolean DEBUG
log
level is DEBUG or less.protected final transient AbstractBTree btree
protected transient Reference<Node> parent
BTree
) or a dirty child (held by the Node
). The parent
reference is set when a node is attached as the child of another node.
Note: When a node is cloned by copyOnWrite()
the parent
references for its clean children are set to the new copy of the
node. This is referred to in several places as "stealing" the children
since they are no longer linked back to their old parents via their
parent reference.
protected final transient Reference<? extends AbstractNode<T extends AbstractNode>> self
protected transient int referenceCount
HardReferenceQueue
.
This value is incremented each time the node is added to the queue and is
decremented each time the node is evicted from the queue. On eviction, if
the counter is zero(0) after it is decremented then the node is written
on the store. This mechanism is critical because it prevents a node
entering the queue from forcing IO for the same node in the edge case
where the node is also on the tail on the queue. Since the counter is
incremented before it is added to the queue, it is guaranteed to be
non-zero when the node forces its own eviction from the tail of the
queue. Preventing this edge case is important since the node can
otherwise become immutable at the very moment that it is touched to
indicate that we are going to update its state, e.g., during an insert,
split, or remove operation. This mechanism also helps to defer IOs since
IO can not occur until the last reference to the node is evicted from the
queue.
Note that only mutable BTree
s may have dirty nodes and the
BTree
is NOT thread-safe for writers so we do not need to use
synchronization or an AtomicInteger for the referenceCount
field.
protected AbstractNode(AbstractBTree btree, boolean dirty)
final
data fields
rather than permitting that logic to be replicated throughout the code
with the corresponding difficulty in ensuring that the logic is correct
throughout.btree
- The btree to which the node belongs.branchingFactor
- The branching factor for the node. By passing the branching
factor rather than using the branching factor declared on the
btree we are able to support different branching factors at
different levels of the tree.dirty
- Used to set the PO.dirty
state. All nodes and leaves
created by non-deserialization constructors begin their life
cycle as dirty := true
All nodes or leaves
de-serialized from the backing store begin their life cycle as
clean (dirty := false). This we read nodes and leaves into
immutable objects, those objects will remain clean. Eventually
a copy-on-write will create a mutable node or leaf from the
immutable one and that node or leaf will be dirty.protected AbstractNode(AbstractNode<T> src)
Note: The copy constructor steals the state of the source node, creating a new node with the same state but a distinct (and not yet assigned) address on the backing store. If the source node has immutable data for some aspect of its state, then a mutable copy of that data is made.
Note: The caller MUST delete()
the source node
after invoking this copy constructor. If the backing store supports the
operation, the source node will be reclaimed as free space at the next
commit.
The source node must be deleted since it is no longer accessible and various aspects of its state have been stolen by the copy constructor. If the btree is committed then both the delete of the source node and the new tree structure will be made restart-safe atomically and all is well. If the operation is aborted then both changes will be undone and all is well. In no case can we access the source node after this operation unless all changes have been aborted, in which case it will simply be re-read from the backing store.
src
- The source node.protected abstract int minKeys()
protected abstract int maxKeys()
public void delete()
IIdentityAccess
delete
in interface IIdentityAccess
public final Node getParent()
WeakReference
to the parent has been cleared.protected AbstractNode<?> copyOnWrite()
Return this leaf iff it is dirty (aka mutable) and otherwise return a
copy of this leaf. If a copy is made of the leaf, then a copy will also
be made of each immutable parent up to the first mutable parent or the
root of the tree, which ever comes first. If the root is copied, then the
new root will be set on the BTree
. This method must MUST be
invoked any time an mutative operation is requested for the leaf.
Note: You can not modify a node that has been written onto the store. Instead, you have to clone the node causing it and all nodes up to the root to be dirty and transient. This method handles that cloning process, but the caller MUST test whether or not the node was copied by this method, MUST delegate the mutation operation to the copy iff a copy was made, and MUST result in an awareness in the caller that the copy exists and needs to be used in place of the immutable version of the node.
protected AbstractNode<T> copyOnWrite(long triggeredByChildId)
Return this node or leaf iff it is dirty (aka mutable) and otherwise
return a copy of this node or leaf. If a copy is made of the node, then a
copy will also be made of each immutable parent up to the first mutable
parent or the root of the tree, which ever comes first. If the root is
copied, then the new root will be set on the BTree
. This method
must MUST be invoked any time an mutative operation is requested for the
leaf.
Note: You can not modify a node that has been written onto the store. Instead, you have to clone the node causing it and all nodes up to the root to be dirty and transient. This method handles that cloning process, but the caller MUST test whether or not the node was copied by this method, MUST delegate the mutation operation to the copy iff a copy was made, and MUST be aware that the copy exists and needs to be used in place of the immutable version of the node.
triggeredByChildId
- The persistent identity of child that triggered this event if
any.public final Iterator<AbstractNode> postOrderNodeIterator()
IAbstractNode
postOrderNodeIterator
in interface IAbstractNode
IAbstractNode
s.public final Iterator<AbstractNode> postOrderNodeIterator(boolean dirtyNodesOnly)
dirtyNodesOnly
- When true, only dirty nodes and leaves will be visitedAbstractNode
s.public abstract Iterator<AbstractNode> postOrderNodeIterator(boolean dirtyNodesOnly, boolean nodesOnly)
dirtyNodesOnly
- When true, only dirty nodes and leaves will be visitednodesOnly
- When true
, the leaves will not be visited.AbstractNode
s.public ITupleIterator entryIterator()
IAbstractNode
entryIterator
in interface IAbstractNode
public ITupleIterator rangeIterator(byte[] fromKey, byte[] toKey, int flags)
fromKey
- The first key that will be visited (inclusive). When
null
there is no lower bound.toKey
- The first key that will NOT be visited (exclusive). When
null
there is no upper bound.flags
- indicating whether the keys and/or values will be
materialized.public abstract Iterator<AbstractNode> postOrderIterator(byte[] fromKey, byte[] toKey)
fromKey
- The first key that will be visited (inclusive). When
null
there is no lower bound.toKey
- The first key that will NOT be visited (exclusive). When
null
there is no upper bound.AbstractNode
s.protected final void assertInvariants()
Invariants:
m
is the branching factor and a node is understood
to be a non-leaf node in the tree.
In addition, all leaves are at the same level (not tested by this assertion).
protected final void assertKeysMonotonic()
protected static final String keyAsString(byte[] key)
Object.toString()
.key
- The key.protected final void copyKey(int dstpos, IRaba srckeys, int srcpos)
Note: Whenever possible the key reference is copied rather than copying the data. This optimization is valid since we never modify the contents of a key.
dstpos
- The index position to which the key will be copied on this
node.srckeys
- The source keys.srcpos
- The index position from which the key will be copied.public abstract boolean isLeaf()
IAbstractNodeData
isLeaf
in interface IAbstractNodeData
public final int getBranchingFactor()
protected abstract IAbstractNode split()
Split a node or leaf that is over capacity (by one).
protected void join()
Join this node (must be deficient) with either its left or right sibling. A join will either cause a single key and value (child) to be redistributed from a sibling to this leaf (node) or it will cause a sibling leaf (node) to be merged into this leaf (node). Both situations also cause the separator key in the parent to be adjusted.
Join is invoked when a leaf has become deficient (too few keys/values). This method is never invoked for the root leaf therefore the parent of this leaf must be defined. Further, since the minimum #of children is two (2) for the smallest branching factor three (3), there is always a sibling to consider.
Join first considers the immediate siblings. if either is materialized and has more than the minimum #of values, then it redistributes one key and value (child) from the sibling into this leaf (node). If either sibling is materialized and has only the minimum #of values, then it merges this leaf (node) with that sibling.
If no materialized immediate sibling meets these criteria, then first materialize and test the right sibling. if the right sibling does not meet these criteria, then materialize and test the left sibling.
Note that (a) we prefer to merge a materialized sibling with this leaf to materializing a sibling; and (b) merging siblings is the only way that a separator key is removed from a parent. If the parent becomes deficient through merging then join is invoked on the parent as well. Note that join is never invoked on the root node (or leaf) since it by definition has no siblings.
Note that we must invoked copy-on-write before modifying a sibling. However, the parent of the leaf MUST already be mutable (aka dirty) since that is a precondition for removing a key from the leaf. This means that copy-on-write will not force the parent to be cloned.
protected boolean isLeftMostNode()
true
if this node is the left-most node at its
level within the tree.true
iff the child is the left-most node at its
level within the tree.protected boolean isRightMostNode()
true
if this node is the right-most node at its
level within the tree.true
iff the child is the right-most node at its
level within the tree.protected abstract void redistributeKeys(AbstractNode sibling, boolean isRightSibling)
sibling
- The sibling.isRightSibling
- True iff the sibling is the rightSibling of this node.protected abstract void merge(AbstractNode sibling, boolean isRightSibling)
sibling
- The sibling.isRightSibling
- True iff the sibling is the rightSibling of this node.public abstract Tuple insert(byte[] key, byte[] val, boolean delete, boolean putIfAbsent, long timestamp, Tuple tuple)
key
- The key (non-null).val
- The value (may be null).delete
- true
iff the entry is to marked as deleted
(delete markers must be supported for if this is true).putIfAbsent
- When true
, a pre-existing entry for the key will
NOT be replaced (unless it is a deleted tuple, which is the
same as if there was no entry under the key). This should ONLY
be true when the top-level method is putIfAbsent
.
Historical code paths should specify false for an unconditional
mutation. See BLZG-1539.timestamp
- The timestamp associated with the version (the value is
ignored unless version metadata is being maintained).tuple
- A tuple that may be used to obtain the data and metadata for
the pre-existing index entry overwritten by the insert
operation (optional).null
otherwise.public abstract Tuple remove(byte[] searchKey, Tuple tuple)
Note: It is an error to call this method if delete markers are in use.
searchKey
- The search key.tuple
- A tuple that may be used to obtain the data and metadata for
the pre-existing index entry that was either removed by the
remove operation (optional).null
otherwise.public abstract Tuple lookup(byte[] searchKey, Tuple tuple)
searchKey
- The search key.tuple
- A tuple that may be used to obtain the data and metadata for
the pre-existing index entry (required).null
otherwise.public abstract long indexOf(byte[] searchKey)
searchKey
- The search key.(-(insertion point) - 1)
. The insertion point is
defined as the point at which the key would be found it it were
inserted into the btree without intervening mutations. Note that
this guarantees that the return value will be >= 0 if and only if
the key is found.public abstract byte[] keyAt(long index)
index
- The index position of the entry (origin zero and relative to
this node or leaf).IndexOutOfBoundsException
- if index is less than zero.IndexOutOfBoundsException
- if index is greater than the #of entries.public abstract void valueAt(long index, Tuple tuple)
index
- The index position of the entry (origin zero and relative to
this node or leaf).tuple
- A tuple that may be used to obtain the data and metadata for
the pre-existing index entry (required).IndexOutOfBoundsException
- if index is less than zero.IndexOutOfBoundsException
- if index is greater than the #of entries.public boolean dump(PrintStream out)
PrintStream
(non-recursive).out
- Where to write the dump.public boolean dump(org.apache.log4j.Level level, PrintStream out)
PrintStream
.level
- The logging level.out
- Where to write the dump.public abstract boolean dump(org.apache.log4j.Level level, PrintStream out, int height, boolean recursive)
PrintStream
.level
- The logging level.out
- Where to write the dump.height
- The height of this node in the tree or -1 iff you need to
invoke this method on a node or leaf whose height in the tree
is not known.recursive
- When true, the node will be dumped recursively using a
pre-order traversal.Copyright © 2006–2019 SYSTAP, LLC DBA Blazegraph. All rights reserved.