package com.bigdata.htree;
import com.bigdata.btree.BTree;
import com.bigdata.htree.data.IDirectoryData;
import com.bigdata.io.AbstractFixedByteArrayBuffer;
import com.bigdata.rawstore.IRawStore;
/**
* Implementation maintains Java objects corresponding to the persistent data
* and defines methods for a variety of mutations on the {@link IDirectoryData}
* record which operate by direct manipulation of the Java objects.
* <p>
* Note: package private fields are used so that they may be directly accessed
* by the {@link DirectoryPage} class.
*
* @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a>
* @version $Id: MutableNodeData.java 2265 2009-10-26 12:51:06Z thompsonbry $
*
* FIXME Unit tests for this class, including constructors.
*/
public class MutableDirectoryPageData implements IDirectoryData {
final byte[] overflowKey;
/**
* The persistent address of each child page (each child may be either a
* {@link DirectoryPage} or a {@link BucketPage}). The capacity of this
* array is <code>1<<addressBits</code>. An entry in this array is
* {@link #NULL} until the child has been persisted. The protocol for
* persisting child nodes requires that we use a pre-order traversal (the
* general case is a directed graph) so that we can update the addresses
* record in the parent before the parent itself is persisted. Unlike the
* {@link BTree}, a {@link IRawStore#NULL} entry is permitted in the array.
* This is because the {@link HTree} is not balanced and empty paths may be
* folded up.
*/
final long[] childAddr;
// /**
// * The #of entries spanned by this node. This value should always be equal
// * to the sum of the defined values in {@link #childEntryCounts}.
// * <p>
// * When a node is split, the value is updated by subtracting off the counts
// * for the children that are being moved to the new sibling.
// * <p>
// * When a node is joined, the value is updated by adding in the counts for
// * the children that are being moved to the new sibling.
// * <p>
// * When a key is redistributed from a node to a sibling, the value is
// * updated by subtracting off the count for the child from the source
// * sibling and adding it in to this node.
// * <p>
// * This field is initialized by the various {@link Node} constructors.
// */
// int nentries;
// /**
// * The #of entries spanned by each direct child of this node.
// * <p>
// * The appropriate element in this array is incremented on all ancestor
// * nodes by {@link Leaf#insert(Object, Object)} and decremented on all
// * ancestors nodes by {@link Leaf#remove(Object)}. Since the ancestors are
// * guaranteed to be mutable as preconditions for those operations we are
// * able to traverse the {@link AbstractNode#parent} reference in a straight
// * forward manner.
// */
// final int[] childEntryCounts;
/**
* <code>true</code> iff the B+Tree is maintaining per tuple revision
* timestamps.
*/
final boolean hasVersionTimestamps;
/**
* The minimum tuple revision timestamp for any leaf spanned by this node
* IFF the B+Tree is maintaining tuple revision timestamps.
*/
long minimumVersionTimestamp;
/**
* The maximum tuple revision timestamp for any leaf spanned by this node
* IFF the B+Tree is maintaining tuple revision timestamps.
*/
long maximumVersionTimestamp;
/**
* Create an empty mutable data record.
*
* @param addressBits
* The #of address bits.
* @param hasVersionTimestamps
* <code>true</code> iff the HTree is maintaining per tuple
* version timestamps.
*/
public MutableDirectoryPageData(final byte[] overflowKey,
final int addressBits,
final boolean hasVersionTimestamps) {
// nentries = 0;
this.overflowKey = overflowKey;
childAddr = new long[1 << addressBits];
// childEntryCounts = new int[branchingFactor + 1];
this.hasVersionTimestamps = hasVersionTimestamps;
minimumVersionTimestamp = maximumVersionTimestamp = 0L;
}
/**
* Makes a mutable copy of the source data record.
*
* @param addressBits
* The #of address bits owning {@link HTree}. This is used to
* initialize the various arrays to the correct capacity.
* @param src
* The source data record.
*/
public MutableDirectoryPageData(final int addressBits, final IDirectoryData src) {
if (src == null)
throw new IllegalArgumentException();
this.overflowKey = src.getOverflowKey();
// nentries = src.getSpannedTupleCount();
childAddr = new long[1 << addressBits];
this.hasVersionTimestamps = src.hasVersionTimestamps();
copyFrom(src);
}
void copyFrom(final IDirectoryData src) {
// childEntryCounts = new int[branchingFactor + 1];
final int nchildren = src.getChildCount();
// int sum = 0;
for (int i = 0; i < nchildren; i++) {
childAddr[i] = src.getChildAddr(i);
// final int tmp = childEntryCounts[i] = src.getChildEntryCount(i);
// sum += tmp;
}
if (src.hasVersionTimestamps()) {
minimumVersionTimestamp = src.getMinimumVersionTimestamp();
maximumVersionTimestamp = src.getMaximumVersionTimestamp();
}
// assert sum == nentries;
}
/**
* Ctor based on just the "data" -- used by unit tests.
*
* @param nentries
* @param keys
* @param childAddr
* @param childEntryCounts
*/
public MutableDirectoryPageData(//final int nentries, final IRaba keys,
final byte[] overflowKey,//
final long[] childAddr, //final int[] childEntryCounts,
final boolean hasVersionTimestamps,
final long minimumVersionTimestamp,
final long maximumVersionTimestamp) {
assert childAddr != null;
// assert childEntryCounts != null;
// assert keys.capacity() + 1 == childAddr.length;
// assert childAddr.length == childEntryCounts.length;
this.overflowKey = overflowKey;
// this.nentries = nentries;
this.childAddr = childAddr;
// this.childEntryCounts = childEntryCounts;
this.hasVersionTimestamps = hasVersionTimestamps;
this.minimumVersionTimestamp = minimumVersionTimestamp;
this.maximumVersionTimestamp = maximumVersionTimestamp;
}
/**
* No - this is a mutable data record.
*/
final public boolean isReadOnly() {
return false;
}
/**
* No.
*/
final public boolean isCoded() {
return false;
}
final public AbstractFixedByteArrayBuffer data() {
throw new UnsupportedOperationException();
}
public final long getChildAddr(final int index) {
return childAddr[index];
}
/**
* {@inheritDoc}
* <p>
* Overridden to report the size of the address space.
*/
final public int getChildCount() {
return childAddr.length;
}
final public boolean isOverflowDirectory() {
return overflowKey != null;
}
final public boolean isLeaf() {
return false;
}
final public boolean hasVersionTimestamps() {
return hasVersionTimestamps;
}
final public long getMaximumVersionTimestamp() {
if (!hasVersionTimestamps)
throw new UnsupportedOperationException();
return maximumVersionTimestamp;
}
final public long getMinimumVersionTimestamp() {
if (!hasVersionTimestamps)
throw new UnsupportedOperationException();
return minimumVersionTimestamp;
}
public byte[] getOverflowKey() {
return overflowKey;
}
}