* Access table index data. This is the actual data which backs a logical
* Index, where one or more logical indexes can be backed by the same index
* data.
- *
+ *
* @author Tim McCune
*/
public class IndexData {
-
+
protected static final Log LOG = LogFactory.getLog(Index.class);
/** special entry which is less than any other entry */
public static final Entry FIRST_ENTRY =
createSpecialEntry(RowIdImpl.FIRST_ROW_ID);
-
+
/** special entry which is greater than any other entry */
public static final Entry LAST_ENTRY =
createSpecialEntry(RowIdImpl.LAST_ROW_ID);
public static final Object MIN_VALUE = new Object();
private static final DataPage NEW_ROOT_DATA_PAGE = new RootDataPage();
-
- protected static final int INVALID_INDEX_PAGE_NUMBER = 0;
-
+
+ protected static final int INVALID_INDEX_PAGE_NUMBER = 0;
+
/** Max number of columns in an index */
public static final int MAX_COLUMNS = 10;
-
+
protected static final byte[] EMPTY_PREFIX = new byte[0];
static final short COLUMN_UNUSED = -1;
private static final int MAGIC_INDEX_NUMBER = 1923;
private static final ByteOrder ENTRY_BYTE_ORDER = ByteOrder.BIG_ENDIAN;
-
+
/** type attributes for Entries which simplify comparisons */
public enum EntryType {
/** comparable type indicating this Entry should always compare less than
than valid RowIds */
ALWAYS_LAST;
}
-
+
public static final Comparator<byte[]> BYTE_CODE_COMPARATOR =
new Comparator<byte[]>() {
public int compare(byte[] left, byte[] right) {
((left.length > right.length) ? 1 : 0));
}
};
-
-
+
+
/** name, generated on demand */
private String _name;
/** owning table */
private String _unsupportedReason;
/** Cache which manages the index pages */
private final IndexPageCache _pageCache;
-
+
protected IndexData(TableImpl table, int number, int uniqueEntryCount,
int uniqueEntryCountOffset)
{
} else {
_name = String.valueOf(_number);
}
- }
+ }
return _name;
}
public TableImpl getTable() {
return _table;
}
-
+
public JetFormat getFormat() {
return getTable().getFormat();
}
public int getIndexDataNumber() {
return _number;
}
-
+
public int getUniqueEntryCount() {
return _uniqueEntryCount;
}
public boolean isUnique() {
return(isBackingPrimaryKey() || ((_indexFlags & UNIQUE_INDEX_FLAG) != 0));
}
-
+
/**
* Whether or not values are required in the columns.
*/
return _rootPageNumber;
}
- private void setUnsupportedReason(String reason, ColumnImpl col) {
+ private void setUnsupportedReason(String reason, ColumnImpl col) {
_unsupportedReason = withErrorContext(reason);
if(!col.getTable().isSystem()) {
LOG.warn(_unsupportedReason + ", making read-only");
public int getOwnedPageCount() {
return _ownedPages.getPageCount();
}
-
+
void addOwnedPage(int pageNumber) throws IOException {
_ownedPages.addPageNumber(pageNumber);
}
void collectUsageMapPages(Collection<Integer> pages) {
pages.add(_ownedPages.getTablePageNumber());
}
-
+
/**
* Used by unit tests to validate the internal status of the index.
* @usage _advanced_method_
}
return count;
}
-
+
/**
* Forces initialization of this index (actual parsing of index pages).
* normally, the index will not be initialized until the entries are
{
// make sure we've parsed the entries
initialize();
-
+
if(_unsupportedReason != null) {
throw new UnsupportedOperationException(
"Cannot write indexes of this type due to " + _unsupportedReason);
}
_ownedPages = UsageMap.read(getTable().getDatabase(), tableBuffer);
-
+
_rootPageNumber = tableBuffer.getInt();
ByteUtil.forward(tableBuffer, getFormat().SKIP_BEFORE_INDEX_FLAGS); //Forward past Unknown
* @param buffer Buffer to write to
*/
protected static void writeDefinition(
- TableMutator creator, ByteBuffer buffer,
+ TableMutator creator, ByteBuffer buffer,
TableMutator.IndexDataState idxDataState, ByteBuffer rootPageBuffer)
throws IOException
{
creator.getDatabase(), creator.getTableName(), idx.getName()));
}
}
-
+
buffer.putShort(columnNumber); // table column number
buffer.put(flags); // column flags (e.g. ordering)
}
ByteUtil.put3ByteInt(buffer, idxDataState.getUmapPageNumber()); // umap page
// write empty root index page
- creator.getPageChannel().writePage(rootPageBuffer,
+ creator.getPageChannel().writePage(rootPageBuffer,
idxDataState.getRootPageNumber());
buffer.putInt(idxDataState.getRootPageNumber());
ByteUtil.forward(buffer, 5); // unknown
}
- private static ByteBuffer createRootPageBuffer(TableMutator creator)
+ private static ByteBuffer createRootPageBuffer(TableMutator creator)
throws IOException
{
ByteBuffer rootPageBuffer = creator.getPageChannel().createPageBuffer();
- writeDataPage(rootPageBuffer, NEW_ROOT_DATA_PAGE,
+ writeDataPage(rootPageBuffer, NEW_ROOT_DATA_PAGE,
creator.getTdefPageNumber(), creator.getFormat());
return rootPageBuffer;
}
* this method returns.
* <p>
* Forces index initialization.
- *
+ *
* @param row Row to add
* @param rowId rowId of the row to be added
*
{
return prepareAddRow(row, rowId, new AddRowPendingChange(nextChange));
}
-
+
private PendingChange prepareAddRow(Object[] row, RowIdImpl rowId,
AddRowPendingChange change)
throws IOException
"Null value found in row " + Arrays.asList(row) +
" for primary key or required index"));
}
-
+
// make sure we've parsed the entries
initialize();
DataPage dataPage = findDataPage(newEntry);
int idx = dataPage.findEntry(newEntry);
if(idx < 0) {
-
+
// this is a new entry
idx = missingIndexToInsertionPoint(idx);
Position newPos = new Position(dataPage, idx, newEntry, true);
Position nextPos = getNextPosition(newPos);
Position prevPos = getPreviousPosition(newPos);
-
+
// determine if the addition of this entry would break the uniqueness
// constraint. See isUnique() for some notes about uniqueness as
// defined by Access.
* before this method returns.
* <p>
* Forces index initialization.
- *
+ *
* @param oldRow Row to be removed
* @param newRow Row to be added
* @param rowId rowId of the row to be updated
* @return a PendingChange which can complete the update or roll it back
*/
public PendingChange prepareUpdateRow(Object[] oldRow, RowIdImpl rowId,
- Object[] newRow,
+ Object[] newRow,
PendingChange nextChange)
throws IOException
{
throw e;
}
}
-
+
/**
* Removes a row from this index
* <p>
* Forces index initialization.
- *
+ *
* @param row Row to remove
* @param rowId rowId of the row to be removed
*/
{
deleteRowImpl(row, rowId);
}
-
+
private Entry deleteRowImpl(Object[] row, RowIdImpl rowId)
throws IOException
{
// nothing to do
return null;
}
-
+
// make sure we've parsed the entries
initialize();
++_modCount;
} else {
LOG.warn(withErrorContext(
- "Failed removing index entry " + oldEntry + " for row: " +
+ "Failed removing index entry " + oldEntry + " for row: " +
Arrays.asList(row)));
}
return removedEntry;
dataPage.addEntry(missingIndexToInsertionPoint(idx), removedEntry);
}
}
-
+
/**
* Removes an entry from the relevant index dataPage, maintaining the order.
* Will search by RowId if entry is not found (in case a partial entry was
// found it!
removedEntry = dataPage.removeEntry(idx);
}
-
+
return removedEntry;
}
-
+
public static void commitAll(PendingChange change) throws IOException {
while(change != null) {
change.commit();
change = change.getNext();
}
}
-
+
/**
* Gets a new cursor for this index.
* <p>
{
return cursor(null, true, null, true);
}
-
+
/**
* Gets a new cursor for this index, narrowed to the range defined by the
* given startRow and endRow.
* <p>
* Forces index initialization.
- *
+ *
* @param startRow the first row of data for the cursor, or {@code null} for
* the first entry
* @param startInclusive whether or not startRow is inclusive or exclusive
int valIdx = 0;
Object[] idxRow = new Object[getTable().getColumnCount()];
for(ColumnDescriptor col : _columns) {
- idxRow[col.getColumnIndex()] =
+ idxRow[col.getColumnIndex()] =
((valIdx < values.length) ? values[valIdx] : filler);
++valIdx;
}
return idxRow;
}
-
+
/**
* Constructs an array of values appropriate for this index from the given
* column value.
idxRow[col.getColumnIndex()] = row.get(col.getName());
}
return idxRow;
- }
+ }
/**
* Constructs an array of values appropriate for this index from the given
Object[] idxRow = new Object[getTable().getColumnCount()];
int valIdx = 0;
for(ColumnDescriptor col : _columns) {
- idxRow[col.getColumnIndex()] =
+ idxRow[col.getColumnIndex()] =
((valIdx < numCols) ? row.get(col.getName()) : filler);
++valIdx;
}
sb.append("pageCache", _pageCache);
return sb.toString();
}
-
+
/**
* Write the given index page out to a buffer
*/
if(dataPage.getCompressedEntrySize() > _maxPageEntrySize) {
throw new IllegalStateException(withErrorContext("data page is too large"));
}
-
+
ByteBuffer buffer = _indexBufferH.getPageBuffer(getPageChannel());
writeDataPage(buffer, dataPage, getTable().getTableDefPageNumber(),
// first entry includes the prefix
buffer.put(entryPrefix);
-
+
for(Entry entry : dataPage.getEntries()) {
entry.write(buffer, entryPrefix);
}
"Unexpected order in index entries, " +
prevEntry + " >= " + entry));
}
-
+
entries.add(entry);
if((entries.size() == 1) && (entryPrefixLength > 0)) {
dataPage.setEntryPrefix(entryPrefix != null ? entryPrefix : EMPTY_PREFIX);
dataPage.setEntries(entries);
dataPage.setTotalEntrySize(totalEntrySize);
-
+
int prevPageNumber = buffer.getInt(getFormat().OFFSET_PREV_INDEX_PAGE);
int nextPageNumber = buffer.getInt(getFormat().OFFSET_NEXT_INDEX_PAGE);
int childTailPageNumber =
/**
* Returns a new Entry of the correct type for the given data and page type.
*/
- private static Entry newEntry(ByteBuffer buffer, int entryLength,
+ private static Entry newEntry(ByteBuffer buffer, int entryLength,
boolean isLeaf)
throws IOException
{
tmpEntryBuffer.put(valuePrefix);
tmpEntryBuffer.put(indexPage.array(), indexPage.position(), entryLen);
tmpEntryBuffer.flip();
-
+
return tmpEntryBuffer;
}
-
+
/**
* Determines if the given index page is a leaf or node page.
*/
}
throw new IOException(withErrorContext("Unexpected page type " + pageType));
}
-
+
/**
* Determines the number of {@code null} values for this index from the
* given row.
if(values == null) {
return _columns.size();
}
-
+
// annoyingly, the values array could come from different sources, one
// of which will make it a different size than the other. we need to
// handle both situations.
++nullCount;
}
}
-
+
return nullCount;
}
if(values == null) {
return null;
}
-
+
if(_entryBuffer == null) {
_entryBuffer = new ByteStream();
}
_entryBuffer.reset();
-
+
for(ColumnDescriptor col : _columns) {
Object value = values[col.getColumnIndex()];
col.writeValue(value, _entryBuffer);
}
-
+
return _entryBuffer.toByteArray();
- }
+ }
/**
* Finds the data page for the given entry.
{
return _pageCache.findCacheDataPage(entry);
}
-
+
/**
* Gets the data page for the pageNumber.
*/
{
return _pageCache.getCacheDataPage(pageNumber);
}
-
+
/**
* Flips the first bit in the byte at the given index.
*/
static byte[] flipBytes(byte[] value, int offset, int length) {
for(int i = offset; i < (offset + length); ++i) {
value[i] = (byte)(~value[i]);
- }
+ }
return value;
}
{
// always write in big endian order
return column.write(value, 0, ENTRY_BYTE_ORDER).array();
- }
+ }
/**
* Writes a binary value using the general binary entry encoding rules.
// bit twiddling rules:
// - isAsc => nothing
- // - !isAsc => flipBytes, _but keep intermediate 09 unflipped_!
+ // - !isAsc => flipBytes, _but keep intermediate 09 unflipped_!
// first, write any intermediate segements
int segmentLen = dataLen;
default:
// we can't modify this index at this point in time
- setUnsupportedReason("unsupported data type " + col.getType() +
+ setUnsupportedReason("unsupported data type " + col.getType() +
" for index", col);
return new ReadOnlyColumnDescriptor(col, flags);
}
return msg + " (Db=" + db.getName() + ";Table=" + tableName +
";Index=" + idxName + ")";
}
-
+
/**
* Information about the columns in an index. Also encodes new index
* values.
public boolean isAscending() {
return((getFlags() & ASCENDING_COLUMN_FLAG) != 0);
}
-
+
public int getColumnIndex() {
return getColumn().getColumnIndex();
}
-
+
public String getName() {
return getColumn().getName();
}
protected boolean isNullValue(Object value) {
return (value == null);
}
-
+
protected final void writeValue(Object value, ByteStream bout)
throws IOException
{
bout.write(getNullEntryFlag(isAscending()));
return;
}
-
+
// write the start flag
bout.write(getStartEntryFlag(isAscending()));
// write the rest of the value
}
protected abstract void writeNonNullValue(Object value, ByteStream bout)
- throws IOException;
-
+ throws IOException;
+
@Override
public String toString() {
return CustomToStringStyle.builder(this)
{
super(column, flags);
}
-
+
@Override
protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
byte[] valueBytes = encodeNumberColumnValue(value, getColumn());
-
+
// bit twiddling rules:
// - isAsc => flipFirstBit
// - !isAsc => flipFirstBit, flipBytes
-
+
flipFirstBitInByte(valueBytes, 0);
if(!isAscending()) {
flipBytes(valueBytes);
}
-
+
bout.write(valueBytes);
- }
+ }
}
-
+
/**
* ColumnDescriptor for floating point based columns.
*/
{
super(column, flags);
}
-
+
@Override
protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
byte[] valueBytes = encodeNumberColumnValue(value, getColumn());
-
+
// determine if the number is negative by testing if the first bit is
// set
boolean isNegative = ((valueBytes[0] & 0x80) != 0);
// isAsc && isNeg => flipBytes
// !isAsc && !isNeg => flipFirstBit, flipBytes
// !isAsc && isNeg => nothing
-
+
if(!isNegative) {
flipFirstBitInByte(valueBytes, 0);
}
if(isNegative == isAscending()) {
flipBytes(valueBytes);
}
-
+
bout.write(valueBytes);
- }
+ }
}
-
+
/**
* ColumnDescriptor for fixed point based columns (legacy sort order).
*/
}
// reverse the sign byte (after any previous byte flipping)
- valueBytes[0] = (isNegative ? (byte)0x00 : (byte)0xFF);
+ valueBytes[0] = (isNegative ? (byte)0x00 : (byte)0xFF);
}
-
+
@Override
protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
byte[] valueBytes = encodeNumberColumnValue(value, getColumn());
-
+
// determine if the number is negative by testing if the first bit is
// set
boolean isNegative = ((valueBytes[0] & 0x80) != 0);
// isAsc && isNeg => flipBytes, setReverseSignByte => 00 FF FF ...
// !isAsc && !isNeg => flipBytes, setReverseSignByte => FF FF FF ...
// !isAsc && isNeg => setReverseSignByte => 00 00 00 ...
-
+
// v2007 bit twiddling rules (old ordering was a bug, MS kb 837148):
// isAsc && !isNeg => setSignByte 0xFF => FF 00 00 ...
// isAsc && isNeg => setSignByte 0xFF, flipBytes => 00 FF FF ...
handleNegationAndOrder(isNegative, valueBytes);
bout.write(valueBytes);
- }
+ }
}
-
+
/**
* ColumnDescriptor for new-style fixed point based columns.
*/
{
super(column, flags);
}
-
+
@Override
protected void handleNegationAndOrder(boolean isNegative,
byte[] valueBytes)
if(isNegative == isAscending()) {
flipBytes(valueBytes);
}
- }
+ }
}
-
+
/**
* ColumnDescriptor for byte based columns.
*/
{
super(column, flags);
}
-
+
@Override
protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
byte[] valueBytes = encodeNumberColumnValue(value, getColumn());
-
+
// bit twiddling rules:
// - isAsc => nothing
// - !isAsc => flipBytes
if(!isAscending()) {
flipBytes(valueBytes);
}
-
+
bout.write(valueBytes);
- }
+ }
}
-
+
/**
* ColumnDescriptor for boolean columns.
*/
// null values are handled as booleans
return false;
}
-
+
@Override
protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
(isAscending() ? ASC_BOOLEAN_FALSE : DESC_BOOLEAN_FALSE));
}
}
-
+
/**
* ColumnDescriptor for "general legacy" sort order text based columns.
*/
- private static final class GenLegTextColumnDescriptor
+ private static final class GenLegTextColumnDescriptor
extends ColumnDescriptor
{
private GenLegTextColumnDescriptor(ColumnImpl column, byte flags)
{
super(column, flags);
}
-
+
@Override
protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
GeneralLegacyIndexCodes.GEN_LEG_INSTANCE.writeNonNullIndexTextValue(
value, bout, isAscending());
- }
+ }
}
/**
{
super(column, flags);
}
-
+
@Override
protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
{
GeneralIndexCodes.GEN_INSTANCE.writeNonNullIndexTextValue(
value, bout, isAscending());
- }
+ }
}
/**
{
super(column, flags);
}
-
+
@Override
protected void writeNonNullValue(Object value, ByteStream bout)
throws IOException
bout);
}
}
-
+
/**
* ColumnDescriptor for BINARY columns.
ColumnImpl.toByteArray(value), isAscending(), bout);
}
}
-
-
+
+
/**
* ColumnDescriptor for columns which we cannot currently write.
*/
"Cannot write indexes of this type due to " + _unsupportedReason);
}
}
-
+
/**
* A single leaf entry in an index (points to a single row)
*/
private final byte[] _entryBytes;
/** comparable type for the entry */
private final EntryType _type;
-
+
/**
* Create a new entry
* @param entryBytes encoded bytes for this index entry
_entryBytes = entryBytes;
_type = type;
}
-
+
/**
* Create a new entry
* @param entryBytes encoded bytes for this index entry
{
this(buffer, entryLen, 0);
}
-
+
/**
* Read an existing entry in from a buffer
*/
// read the rowId
int page = ByteUtil.get3ByteInt(buffer, ENTRY_BYTE_ORDER);
int row = ByteUtil.getUnsignedByte(buffer);
-
+
_rowId = new RowIdImpl(page, row);
_type = EntryType.NORMAL;
}
-
+
public RowIdImpl getRowId() {
return _rowId;
}
public Integer getSubPageNumber() {
throw new UnsupportedOperationException();
}
-
+
public boolean isLeafEntry() {
return true;
}
-
+
public boolean isValid() {
return(_entryBytes != null);
}
protected final byte[] getEntryBytes() {
return _entryBytes;
}
-
+
/**
* Size of this entry in the db.
*/
// need 4 trailing bytes for the rowId
return _entryBytes.length + 4;
}
-
+
/**
* Write this entry into a buffer
*/
throws IOException
{
if(prefix.length <= _entryBytes.length) {
-
+
// write entry bytes, not including prefix
buffer.put(_entryBytes, prefix.length,
(_entryBytes.length - prefix.length));
ByteUtil.put3ByteInt(buffer, getRowId().getPageNumber(),
ENTRY_BYTE_ORDER);
-
+
} else if(prefix.length <= (_entryBytes.length + 3)) {
-
+
// the prefix includes part of the page number, write to temp buffer
// and copy last bytes to output buffer
ByteBuffer tmp = ByteBuffer.allocate(3);
tmp.flip();
tmp.position(prefix.length - _entryBytes.length);
buffer.put(tmp);
-
+
} else {
-
+
// since the row number would never be the same if the page number is
// the same, nothing past the page number should ever be included in
// the prefix.
// FIXME, this could happen if page has only one row...
throw new IllegalStateException("prefix should never be this long");
}
-
+
buffer.put((byte)getRowId().getRowNumber());
}
}
return sb;
}
-
+
@Override
public String toString() {
return entryBytesToStringBuilder(
public boolean equalsEntryBytes(Entry o) {
return(BYTE_CODE_COMPARATOR.compare(_entryBytes, o._entryBytes) == 0);
}
-
+
public int compareTo(Entry other) {
if (this == other) {
return 0;
return typeCmp;
}
}
-
+
// at this point we let the RowId decide the final result
return _rowId.compareTo(other.getRowId());
}
protected Entry asNodeEntry(Integer subPageNumber) {
return new NodeEntry(_entryBytes, _rowId, _type, subPageNumber);
}
-
+
}
/**
super(entryBytes, rowId, type);
_subPageNumber = subPageNumber;
}
-
+
/**
* Read an existing node entry in from a buffer
*/
public boolean isLeafEntry() {
return false;
}
-
+
@Override
protected int size() {
// need 4 trailing bytes for the sub-page number
return super.size() + 4;
}
-
+
@Override
protected void write(ByteBuffer buffer, byte[] prefix) throws IOException {
super.write(buffer, prefix);
ByteUtil.putInt(buffer, _subPageNumber, ENTRY_BYTE_ORDER);
}
-
+
@Override
public boolean equals(Object o) {
return((this == o) ||
.append("rowId", getRowId())
.append("subPage", _subPageNumber))
.toString();
- }
+ }
}
/**
private int getIndexModCount() {
return IndexData.this._modCount;
}
-
+
/**
* Returns the first entry (exclusive) as defined by this cursor.
*/
public Entry getFirstEntry() {
return _firstPos.getEntry();
}
-
+
/**
* Returns the last entry (exclusive) as defined by this cursor.
*/
public boolean isUpToDate() {
return(getIndexModCount() == _lastModCount);
}
-
+
public void reset() {
beforeFirst();
}
/**
* Repositions the cursor so that the next row will be the first entry
- * >= the given row.
+ * >= the given row.
*/
public void beforeEntry(Object[] row)
throws IOException
{
- restorePosition(new Entry(IndexData.this.createEntryBytes(row),
+ restorePosition(new Entry(IndexData.this.createEntryBytes(row),
RowIdImpl.FIRST_ROW_ID));
}
-
+
/**
* Repositions the cursor so that the previous row will be the first
- * entry <= the given row.
+ * entry <= the given row.
*/
public void afterEntry(Object[] row)
throws IOException
{
- restorePosition(new Entry(IndexData.this.createEntryBytes(row),
+ restorePosition(new Entry(IndexData.this.createEntryBytes(row),
RowIdImpl.LAST_ROW_ID));
}
-
+
/**
* @return valid entry if there was a next entry,
* {@code #getLastEntry} otherwise
{
restorePosition(curEntry, _curPos.getEntry());
}
-
+
/**
* Restores a current and previous position for the cursor.
*/
checkForModification();
}
}
-
+
/**
* Gets another entry in the given direction, returning the new entry.
*/
withErrorContext("Invalid entry given " + entry));
}
}
-
+
Position pos = findEntryPosition(entry);
if(pos.compareTo(_lastPos) >= 0) {
return _lastPos;
}
return pos;
}
-
+
/**
* Updates any the boundary info (_firstPos/_lastPos).
*/
_firstPos = findEntryPosition(_firstPos.getEntry());
_lastPos = findEntryPosition(_lastPos.getEntry());
}
-
+
@Override
public String toString() {
return CustomToStringStyle.valueBuilder(this)
.append("prevPosition", _prevPos)
.toString();
}
-
+
/**
* Handles moving the cursor in a given direction. Separates cursor
* logic from value storage.
public abstract Position getBeginningPosition();
public abstract Position getEndPosition();
}
-
+
/**
* Handles moving the cursor forward.
*/
return _lastPos;
}
}
-
+
/**
* Handles moving the cursor backward.
*/
{
this(dataPage, idx, dataPage.getEntries().get(idx), false);
}
-
+
private Position(DataPage dataPage, int idx, Entry entry, boolean between)
{
_dataPage = dataPage;
public DataPage getDataPage() {
return _dataPage;
}
-
+
public int getIndex() {
return _idx;
}
// non-between case
return(_idx - 1);
}
-
+
public Entry getEntry() {
return _entry;
}
public boolean equalsEntry(Entry entry) {
return _entry.equals(entry);
}
-
+
public int compareTo(Position other)
{
if(this == other) {
return idxCmp;
}
}
-
+
// compare the entries.
return _entry.compareTo(other._entry);
}
-
+
@Override
public int hashCode() {
return _entry.hashCode();
}
-
+
@Override
public boolean equals(Object o) {
return((this == o) ||
protected static abstract class DataPage {
public abstract int getPageNumber();
-
+
public abstract boolean isLeaf();
public abstract void setLeaf(boolean isLeaf);
public abstract void setNextPageNumber(int pageNumber);
public abstract int getChildTailPageNumber();
public abstract void setChildTailPageNumber(int pageNumber);
-
+
public abstract int getTotalEntrySize();
public abstract void setTotalEntrySize(int totalSize);
public abstract byte[] getEntryPrefix();
public final boolean isEmpty() {
return getEntries().isEmpty();
}
-
+
public final int getCompressedEntrySize() {
// when written to the index page, the entryPrefix bytes will only be
// written for the first entry, so we subtract the entry prefix size
public final String toString() {
List<Entry> entries = getEntries();
- String objName =
+ String objName =
(isLeaf() ? "Leaf" : "Node") + "DataPage[" + getPageNumber() +
"] " + getPrevPageNumber() + ", " + getNextPageNumber() + ", (" +
getChildTailPageNumber() + ")";
@Override
public int getPageNumber() { return 0; }
-
+
@Override
public boolean isLeaf() { return true; }
@Override
public int getChildTailPageNumber() { return 0; }
@Override
public void setChildTailPageNumber(int pageNumber) { }
-
+
@Override
public int getTotalEntrySize() { return 0; }
@Override
public void setEntryPrefix(byte[] entryPrefix) { }
@Override
- public List<Entry> getEntries() { return Collections.emptyList(); }
+ public List<Entry> getEntries() { return Collections.emptyList(); }
@Override
public void setEntries(List<Entry> entries) { }
@Override
public PendingChange getNext() {
return _next;
}
-
+
/**
* Completes the pending change.
*/
super(next);
}
- public void setAddRow(Entry addEntry, DataPage dataPage, int idx,
+ public void setAddRow(Entry addEntry, DataPage dataPage, int idx,
boolean isDupe) {
_addEntry = addEntry;
_addDataPage = dataPage;
public void commit() throws IOException {
commitAddRow(_addEntry, _addDataPage, _addIdx, _isDupe, _oldEntry);
}
-
+
@Override
public void rollback() throws IOException {
_addEntry = null;