diff options
author | James Ahlborn <jtahlborn@yahoo.com> | 2007-11-26 21:26:27 +0000 |
---|---|---|
committer | James Ahlborn <jtahlborn@yahoo.com> | 2007-11-26 21:26:27 +0000 |
commit | 59ae9fca1910244e5c39b7e6d1a3a6d3b078744b (patch) | |
tree | 79e61a7a0172ca809c33e327416ce0f99da87e75 | |
parent | 2c900e17e9bd5299ecbc7c4bc19eff06583e1069 (diff) | |
download | jackcess-59ae9fca1910244e5c39b7e6d1a3a6d3b078744b.tar.gz jackcess-59ae9fca1910244e5c39b7e6d1a3a6d3b078744b.zip |
rework Index cursor to match behavior of usagemap cursor and Cursor
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@184 f203690c-595d-4dc9-a70b-905162fa7fd2
-rw-r--r-- | src/java/com/healthmarketscience/jackcess/Index.java | 237 | ||||
-rw-r--r-- | src/java/com/healthmarketscience/jackcess/Table.java | 2 | ||||
-rw-r--r-- | src/java/com/healthmarketscience/jackcess/UsageMap.java | 39 |
3 files changed, 199 insertions, 79 deletions
diff --git a/src/java/com/healthmarketscience/jackcess/Index.java b/src/java/com/healthmarketscience/jackcess/Index.java index da6b0b2..a2726d6 100644 --- a/src/java/com/healthmarketscience/jackcess/Index.java +++ b/src/java/com/healthmarketscience/jackcess/Index.java @@ -57,6 +57,11 @@ import org.apache.commons.logging.LogFactory; public class Index implements Comparable<Index> { private static final Log LOG = LogFactory.getLog(Index.class); + + /** index of the first (exclusive) index entry */ + private static final int FIRST_ENTRY_IDX = -1; + /** index of the last (exclusive) index entry */ + private static final int LAST_ENTRY_IDX = -2; /** Max number of columns in an index */ private static final int MAX_COLUMNS = 10; @@ -207,7 +212,7 @@ public class Index implements Comparable<Index> { /** <code>true</code> if the index entries have been initialized, <code>false</code> otherwise */ private boolean _initialized; - /** modification count for the table, keeps iterators up-to-date */ + /** modification count for the table, keeps cursors up-to-date */ private int _modCount; /** FIXME, for now, we can't write multi-page indexes or indexes using the funky primary key compression scheme */ boolean _readOnly; @@ -1247,20 +1252,33 @@ public class Index implements Comparable<Index> { } /** - * Utility class to iterate over the entries in the Index. Note, since the - * iterators hold on to entries, they should stay valid even as the - * entries are updated. + * Utility class to traverse the entries in the Index. Remains valid in the + * face of index entry modifications. */ - public class EntryIterator + public final class EntryCursor { - private Entry _nextEntry; - private int _nextEntryIdx; + /** handler for moving the page cursor forward */ + private final DirHandler _forwardDirHandler = new ForwardDirHandler(); + /** handler for moving the page cursor backward */ + private final DirHandler _reverseDirHandler = new ReverseDirHandler(); + private Entry _curEntry; + private int _curEntryIdx; + private boolean _curEntryDeleted; + private Entry _prevEntry; + private int _prevEntryIdx; private int _lastModCount; - private EntryIterator() { + private EntryCursor() { reset(); } + /** + * Returns the DirHandler for the given direction + */ + private DirHandler getDirHandler(boolean moveForward) { + return (moveForward ? _forwardDirHandler : _reverseDirHandler); + } + public boolean isUpToDate() { return(Index.this._modCount == _lastModCount); } @@ -1278,56 +1296,38 @@ public class Index implements Comparable<Index> { } protected void reset(boolean moveForward) { - _nextEntry = null; - _nextEntryIdx = (moveForward ? 0 : _entries.size()); + _curEntry = null; + _prevEntry = null; + _curEntryDeleted = false; + _curEntryIdx = getDirHandler(moveForward).getBeginningIndex(); + _prevEntryIdx = _curEntryIdx; _lastModCount = Index.this._modCount; } - private void resyncIndex() { - if(!isUpToDate()) { - if(_nextEntryIdx == 0) { - // we were at the beginning of the list - _nextEntry = _entries.get(_nextEntryIdx); - } else if(_nextEntry == null) { - // we were at the end of the list - _nextEntryIdx = _entries.size(); - } else { - // we were somewhere in the middle of the list - int idx = findEntry(_nextEntry); - if(idx >= 0) { - _nextEntryIdx = idx; - } else { - // current entry was deleted - _nextEntryIdx = missingIndexToInsertionPoint(idx); - _nextEntry = _entries.get(_nextEntryIdx); - } - } - _lastModCount = Index.this._modCount; - } - } - /** - * Repositions the iterator so that the next row will be the first entry + * Repositions the cursor so that the next row will be the first entry * >= the given row. */ public void beforeEntry(Object[] row) throws IOException { + // FIXME, change how row is given? moveToEntry(new Entry(row, RowId.FIRST_ROW_ID)); } /** - * Repositions the iterator so that the previous row will be the first + * Repositions the cursor so that the previous row will be the first * entry <= the given row. */ public void afterEntry(Object[] row) throws IOException { + // FIXME, change how row is given? moveToEntry(new Entry(row, RowId.LAST_ROW_ID)); } /** - * Repositions the iterator relative to a given entry. The given entry + * Repositions the cursor relative to a given entry. The given entry * must have a fake rowId. */ private void moveToEntry(Entry entry) @@ -1335,41 +1335,156 @@ public class Index implements Comparable<Index> { { // note, we will never get a real index back from findIndex because we // are using a fake rowId which will never match a real row - _nextEntryIdx = missingIndexToInsertionPoint(findEntry(entry)); - _nextEntry = ((_nextEntryIdx < _entries.size()) ? - _entries.get(_nextEntryIdx) : null); - _lastModCount = Index.this._modCount; + // FIXME +// _nextEntryIdx = missingIndexToInsertionPoint(findEntry(entry)); +// _nextEntry = ((_nextEntryIdx < _entries.size()) ? +// _entries.get(_nextEntryIdx) : null); +// _lastModCount = Index.this._modCount; } - public boolean hasNextRowId() { - resyncIndex(); - return(_nextEntryIdx < _entries.size()); + public RowId getNextRowId() { + return getAnotherRowId(true); } - public boolean hasPreviousRowId() { - resyncIndex(); - return(_nextEntryIdx > 0); + public RowId getPreviousRowId() { + return getAnotherRowId(false); } - - public RowId getNextRowId() { - if(hasNextRowId()) { - RowId nextRowId = _nextEntry.getRowId(); - ++_nextEntryIdx; - _nextEntry = ((_nextEntryIdx < _entries.size()) ? - _entries.get(_nextEntryIdx) : null); - return nextRowId; + + private void restorePosition(int curEntryIdx, Entry curEntry) + { + _prevEntryIdx = _curEntryIdx; + _prevEntry = _curEntry; + _curEntryIdx = curEntryIdx; + _curEntry = curEntry; + checkForModification(); + } + + private void checkForModification() { + if(!isUpToDate()) { + + if(_curEntry != null) { + // find the new position for this entry + int idx = findEntry(_curEntry); + if(idx >= 0) { + _curEntryIdx = idx; + } else { + // current entry was deleted. our current position is now really + // between two indexes, but we cannot support that as an integer + // value so we set a flag instead + _curEntryIdx = missingIndexToInsertionPoint(idx); + _curEntryDeleted = true; + } + } + + _lastModCount = Index.this._modCount; } - return RowId.LAST_ROW_ID; } + + private RowId getAnotherRowId(boolean moveForward) { + DirHandler handler = getDirHandler(moveForward); + if(_curEntryIdx == handler.getEndIndex()) { + if(!isUpToDate()) { + restorePosition(_prevEntryIdx, _prevEntry); + // drop through and retry moving to another entry + } else { + // at end, no more + return handler.getEndRowId(); + } + } - public RowId getPreviousRowId() { - if(hasPreviousRowId()) { - --_nextEntryIdx; - _nextEntry = _entries.get(_nextEntryIdx); - return _nextEntry.getRowId(); + checkForModification(); + + if(_curEntryDeleted) { + // the current position is technically between the current index and + // the current index - 1. reset the current position to the previous + // position as defined by the given direction + _curEntryIdx = handler.getPreviousIndexForDeletion(_curEntryIdx); + if(_curEntryIdx >= 0) { + _curEntry = _entries.get(_curEntryIdx); + } + _curEntryDeleted = false; + } + + _prevEntryIdx = _curEntryIdx; + _prevEntry = _curEntry; + _curEntryIdx = handler.getAnotherIndex(_curEntryIdx); + if(_curEntryIdx >= 0) { + _curEntry = _entries.get(_curEntryIdx); + return _curEntry.getRowId(); + } + _curEntry = null; + return handler.getEndRowId(); + } + + /** + * Handles moving the cursor in a given direction. Separates cursor + * logic from value storage. + */ + private abstract class DirHandler { + public abstract int getAnotherIndex(int curIdx); + public abstract int getPreviousIndexForDeletion(int curIdx); + public abstract int getBeginningIndex(); + public abstract int getEndIndex(); + public abstract RowId getEndRowId(); + } + + /** + * Handles moving the cursor forward. + */ + private final class ForwardDirHandler extends DirHandler { + @Override + public int getAnotherIndex(int curIdx) { + curIdx = ((curIdx == FIRST_ENTRY_IDX) ? 0 : (curIdx + 1)); + return ((curIdx < _entries.size()) ? curIdx : LAST_ENTRY_IDX); + } + @Override + public int getPreviousIndexForDeletion(int curIdx) { + curIdx = curIdx - 1; + return((curIdx >= 0) ? curIdx : FIRST_ENTRY_IDX); + } + @Override + public int getBeginningIndex() { + return FIRST_ENTRY_IDX; + } + @Override + public int getEndIndex() { + return LAST_ENTRY_IDX; + } + @Override + public RowId getEndRowId() { + return RowId.LAST_ROW_ID; + } + } + + /** + * Handles moving the cursor backward. + */ + private final class ReverseDirHandler extends DirHandler { + @Override + public int getAnotherIndex(int curIdx) { + curIdx = ((curIdx == LAST_ENTRY_IDX) ? + (_entries.size() - 1) : (curIdx - 1)); + return ((curIdx >= 0) ? curIdx : FIRST_ENTRY_IDX); + } + @Override + public int getPreviousIndexForDeletion(int curIdx) { + // the curIdx is already pointing to the "previous" index + return((curIdx < _entries.size()) ? curIdx : LAST_ENTRY_IDX); + } + @Override + public int getBeginningIndex() { + return LAST_ENTRY_IDX; + } + @Override + public int getEndIndex() { + return FIRST_ENTRY_IDX; + } + @Override + public RowId getEndRowId() { + return RowId.FIRST_ROW_ID; } - return RowId.FIRST_ROW_ID; } + } } diff --git a/src/java/com/healthmarketscience/jackcess/Table.java b/src/java/com/healthmarketscience/jackcess/Table.java index 7a3df79..d5eacd2 100644 --- a/src/java/com/healthmarketscience/jackcess/Table.java +++ b/src/java/com/healthmarketscience/jackcess/Table.java @@ -1457,7 +1457,7 @@ public class Table /** * Maintains the state of reading a row of data. */ - public class RowState + public final class RowState { /** Buffer used for reading the header row data pages */ private final TempPageHolder _headerRowBufferH; diff --git a/src/java/com/healthmarketscience/jackcess/UsageMap.java b/src/java/com/healthmarketscience/jackcess/UsageMap.java index ee25d95..e43fe6e 100644 --- a/src/java/com/healthmarketscience/jackcess/UsageMap.java +++ b/src/java/com/healthmarketscience/jackcess/UsageMap.java @@ -197,12 +197,13 @@ public class UsageMap } protected int getFirstPageNumber() { - return bitIndexToPageNumber(getNextBitIndex(-1)); + return bitIndexToPageNumber(getNextBitIndex(-1), RowId.LAST_PAGE_NUMBER); } protected int getNextPageNumber(int curPage) { return bitIndexToPageNumber( - getNextBitIndex(pageNumberToBitIndex(curPage))); + getNextBitIndex(pageNumberToBitIndex(curPage)), + RowId.LAST_PAGE_NUMBER); } protected int getNextBitIndex(int curIndex) { @@ -210,12 +211,14 @@ public class UsageMap } protected int getLastPageNumber() { - return bitIndexToPageNumber(getPrevBitIndex(_pageNumbers.length())); + return bitIndexToPageNumber(getPrevBitIndex(_pageNumbers.length()), + RowId.FIRST_PAGE_NUMBER); } protected int getPrevPageNumber(int curPage) { return bitIndexToPageNumber( - getPrevBitIndex(pageNumberToBitIndex(curPage))); + getPrevBitIndex(pageNumberToBitIndex(curPage)), + RowId.FIRST_PAGE_NUMBER); } protected int getPrevBitIndex(int curIndex) { @@ -226,9 +229,9 @@ public class UsageMap return curIndex; } - protected int bitIndexToPageNumber(int bitIndex) { - return((bitIndex >= 0) ? (_startPage + bitIndex) : - PageChannel.INVALID_PAGE_NUMBER); + protected int bitIndexToPageNumber(int bitIndex, + int invalidPageNumber) { + return((bitIndex >= 0) ? (_startPage + bitIndex) : invalidPageNumber); } protected int pageNumberToBitIndex(int pageNumber) { @@ -702,7 +705,7 @@ public class UsageMap * Utility class to traverse over the pages in the UsageMap. Remains valid * in the face of usage map modifications. */ - public class PageCursor + public final class PageCursor { /** handler for moving the page cursor forward */ private final DirHandler _forwardDirHandler = new ForwardDirHandler(); @@ -786,9 +789,10 @@ public class UsageMap } } + checkForModification(); + _prevPageNumber = _curPageNumber; _curPageNumber = handler.getAnotherPageNumber(_curPageNumber); - _lastModCount = UsageMap.this._modCount; return _curPageNumber; } @@ -820,9 +824,9 @@ public class UsageMap * Resets this page cursor for traversing the given direction. */ protected void reset(boolean moveForward) { - _lastModCount = UsageMap.this._modCount; _curPageNumber = getDirHandler(moveForward).getBeginningPageNumber(); _prevPageNumber = _curPageNumber; + _lastModCount = UsageMap.this._modCount; } /** @@ -831,7 +835,12 @@ public class UsageMap private void restorePosition(int curPageNumber) { _prevPageNumber = _curPageNumber; _curPageNumber = curPageNumber; - _lastModCount = UsageMap.this._modCount; + checkForModification(); + } + + private void checkForModification() { + // since we store page numbers, we don't need to adjust anything + _lastModCount = UsageMap.this._modCount; } /** @@ -853,9 +862,7 @@ public class UsageMap if(curPageNumber == RowId.FIRST_PAGE_NUMBER) { return UsageMap.this.getFirstPageNumber(); } - int anotherPageNumber = UsageMap.this.getNextPageNumber(curPageNumber); - return ((anotherPageNumber >= 0) ? anotherPageNumber : - RowId.LAST_PAGE_NUMBER); + return UsageMap.this.getNextPageNumber(curPageNumber); } @Override public int getBeginningPageNumber() { @@ -876,9 +883,7 @@ public class UsageMap if(curPageNumber == RowId.LAST_PAGE_NUMBER) { return UsageMap.this.getLastPageNumber(); } - int anotherPageNumber = UsageMap.this.getPrevPageNumber(curPageNumber); - return ((anotherPageNumber >= 0) ? anotherPageNumber : - RowId.FIRST_PAGE_NUMBER); + return UsageMap.this.getPrevPageNumber(curPageNumber); } @Override public int getBeginningPageNumber() { |