diff options
author | James Ahlborn <jtahlborn@yahoo.com> | 2019-08-06 21:20:51 +0000 |
---|---|---|
committer | James Ahlborn <jtahlborn@yahoo.com> | 2019-08-06 21:20:51 +0000 |
commit | 5329ce15298859aff24512986c07305cf08a137f (patch) | |
tree | b9db533a6ff76292e07e01adf1e3b540f80d8f3f /src | |
parent | ff9e16462ef5b3e720b676f9d11670e0d6a8d0b2 (diff) | |
download | jackcess-5329ce15298859aff24512986c07305cf08a137f.tar.gz jackcess-5329ce15298859aff24512986c07305cf08a137f.zip |
add separate method for reading root db page
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/a97_indexes@1306 f203690c-595d-4dc9-a70b-905162fa7fd2
Diffstat (limited to 'src')
3 files changed, 66 insertions, 45 deletions
diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java index bc3cf80..e00c82b 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/DatabaseImpl.java @@ -942,7 +942,7 @@ public class DatabaseImpl implements Database, DateTimeContext private void initRootPageInfo() throws IOException { ByteBuffer buffer = takeSharedBuffer(); try { - _pageChannel.readPage(buffer, 0); + _pageChannel.readRootPage(buffer); _defaultSortOrder = ColumnImpl.readSortOrder( buffer, _format.OFFSET_SORT_ORDER, _format); _defaultCodePage = buffer.getShort(_format.OFFSET_CODE_PAGE); @@ -1586,7 +1586,7 @@ public class DatabaseImpl implements Database, DateTimeContext { ByteBuffer buffer = takeSharedBuffer(); try { - _pageChannel.readPage(buffer, 0); + _pageChannel.readRootPage(buffer); byte[] pwdBytes = new byte[_format.SIZE_PASSWORD]; buffer.position(_format.OFFSET_PASSWORD); diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/DefaultCodecProvider.java b/src/main/java/com/healthmarketscience/jackcess/impl/DefaultCodecProvider.java index 11854e7..87e6ec8 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/DefaultCodecProvider.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/DefaultCodecProvider.java @@ -30,15 +30,15 @@ import java.nio.charset.Charset; public class DefaultCodecProvider implements CodecProvider { /** common instance of DefaultCodecProvider */ - public static final CodecProvider INSTANCE = + public static final CodecProvider INSTANCE = new DefaultCodecProvider(); /** common instance of {@link DummyHandler} */ - public static final CodecHandler DUMMY_HANDLER = + public static final CodecHandler DUMMY_HANDLER = new DummyHandler(); /** common instance of {@link UnsupportedHandler} */ - public static final CodecHandler UNSUPPORTED_HANDLER = + public static final CodecHandler UNSUPPORTED_HANDLER = new UnsupportedHandler(); @@ -62,7 +62,7 @@ public class DefaultCodecProvider implements CodecProvider case OFFICE: // check for an encode key. if 0, not encoded ByteBuffer bb = channel.createPageBuffer(); - channel.readPage(bb, 0); + channel.readRootPage(bb); int codecKey = bb.getInt(format.OFFSET_ENCODING_KEY); return((codecKey == 0) ? DUMMY_HANDLER : UNSUPPORTED_HANDLER); @@ -93,15 +93,15 @@ public class DefaultCodecProvider implements CodecProvider @Override public void decodePage(ByteBuffer inPage, ByteBuffer outPage, - int pageNumber) - throws IOException + int pageNumber) + throws IOException { // does nothing } @Override - public ByteBuffer encodePage(ByteBuffer page, int pageNumber, - int pageOffset) + public ByteBuffer encodePage(ByteBuffer page, int pageNumber, + int pageOffset) throws IOException { // does nothing @@ -127,16 +127,16 @@ public class DefaultCodecProvider implements CodecProvider } @Override - public void decodePage(ByteBuffer inPage, ByteBuffer outPage, - int pageNumber) - throws IOException + public void decodePage(ByteBuffer inPage, ByteBuffer outPage, + int pageNumber) + throws IOException { throw new UnsupportedCodecException("Decoding not supported. Please choose a CodecProvider which supports reading the current database encoding."); } @Override - public ByteBuffer encodePage(ByteBuffer page, int pageNumber, - int pageOffset) + public ByteBuffer encodePage(ByteBuffer page, int pageNumber, + int pageOffset) throws IOException { throw new UnsupportedCodecException("Encoding not supported. Please choose a CodecProvider which supports writing the current database encoding."); diff --git a/src/main/java/com/healthmarketscience/jackcess/impl/PageChannel.java b/src/main/java/com/healthmarketscience/jackcess/impl/PageChannel.java index 41c164c..101a3e0 100644 --- a/src/main/java/com/healthmarketscience/jackcess/impl/PageChannel.java +++ b/src/main/java/com/healthmarketscience/jackcess/impl/PageChannel.java @@ -29,22 +29,22 @@ import java.nio.channels.FileChannel; * @author Tim McCune */ public class PageChannel implements Channel, Flushable { - + static final int INVALID_PAGE_NUMBER = -1; static final ByteOrder DEFAULT_BYTE_ORDER = ByteOrder.LITTLE_ENDIAN; - + /** invalid page header, used when deallocating old pages. data pages generally have 4 interesting bytes at the beginning which we want to reset. */ private static final byte[] INVALID_PAGE_BYTE_HEADER = new byte[]{PageTypes.INVALID, (byte)0, (byte)0, (byte)0}; - + /** Global usage map always lives on page 1 */ static final int PAGE_GLOBAL_USAGE_MAP = 1; /** Global usage map always lives at row 0 */ static final int ROW_GLOBAL_USAGE_MAP = 0; - + /** Channel containing the database */ private final FileChannel _channel; /** whether or not the _channel should be closed by this class */ @@ -67,7 +67,7 @@ public class PageChannel implements Channel, Flushable { private TempPageHolder _fullPageEncodeBufferH; private TempBufferHolder _tempDecodeBufferH; private int _writeCount; - + /** * Only used by unit tests */ @@ -117,7 +117,7 @@ public class PageChannel implements Channel, Flushable { _globalUsageMap = UsageMap.read(database, PAGE_GLOBAL_USAGE_MAP, ROW_GLOBAL_USAGE_MAP, true); } - + public JetFormat getFormat() { return _format; } @@ -177,7 +177,7 @@ public class PageChannel implements Channel, Flushable { throw new IllegalStateException("No write operation in progress"); } } - + /** * Returns the next page number based on the given file size. */ @@ -191,7 +191,7 @@ public class PageChannel implements Channel, Flushable { private long getPageOffset(int pageNumber) { return((long) pageNumber * (long) getFormat().PAGE_SIZE); } - + /** * Validates that the given pageNumber is valid for this database. */ @@ -203,7 +203,7 @@ public class PageChannel implements Channel, Flushable { throw new IllegalStateException("invalid page number " + pageNumber); } } - + /** * @param buffer Buffer to read the page into * @param pageNumber Number of the page to read in (starting at 0) @@ -211,11 +211,16 @@ public class PageChannel implements Channel, Flushable { public void readPage(ByteBuffer buffer, int pageNumber) throws IOException { + if(pageNumber == 0) { + readRootPage(buffer); + return; + } + validatePageNumber(pageNumber); ByteBuffer inPage = buffer; ByteBuffer outPage = buffer; - if((pageNumber != 0) && !_codecHandler.canDecodeInline()) { + if(!_codecHandler.canDecodeInline()) { inPage = _tempDecodeBufferH.getPageBuffer(this); outPage.clear(); } @@ -230,14 +235,30 @@ public class PageChannel implements Channel, Flushable { pageNumber + ", only read " + bytesRead); } - if(pageNumber == 0) { - // de-mask header (note, page 0 never has additional encoding) - applyHeaderMask(buffer); - } else { - _codecHandler.decodePage(inPage, outPage, pageNumber); + _codecHandler.decodePage(inPage, outPage, pageNumber); + } + + /** + * @param buffer Buffer to read the root page into + */ + public void readRootPage(ByteBuffer buffer) + throws IOException + { + // special method for reading root page, can be done before PageChannel is + // fully initialized + buffer.clear(); + int bytesRead = _channel.read(buffer, 0L); + buffer.flip(); + if(bytesRead != getFormat().PAGE_SIZE) { + throw new IOException("Failed attempting to read " + + getFormat().PAGE_SIZE + " bytes from page " + + 0 + ", only read " + bytesRead); } + + // de-mask header (note, page 0 never has additional encoding) + applyHeaderMask(buffer); } - + /** * Write a page to disk * @param page Page to write @@ -246,7 +267,7 @@ public class PageChannel implements Channel, Flushable { public void writePage(ByteBuffer page, int pageNumber) throws IOException { writePage(page, pageNumber, 0); } - + /** * Write a page (or part of a page) to disk * @param page Page to write @@ -259,7 +280,7 @@ public class PageChannel implements Channel, Flushable { { assertWriting(); validatePageNumber(pageNumber); - + page.rewind().position(pageOffset); int writeLen = page.remaining(); @@ -267,7 +288,7 @@ public class PageChannel implements Channel, Flushable { throw new IllegalArgumentException( "Page buffer is too large, size " + (writeLen + pageOffset)); } - + ByteBuffer encodedPage = page; if(pageNumber == 0) { // re-mask header @@ -315,7 +336,7 @@ public class PageChannel implements Channel, Flushable { } } } - + /** * Allocates a new page in the database. Data in the page is undefined * until it is written in a call to {@link #writePage(ByteBuffer,int)}. @@ -334,9 +355,9 @@ public class PageChannel implements Channel, Flushable { " is not multiple of page size " + getFormat().PAGE_SIZE); } - + _forceBytes.rewind(); - + // push the buffer to the end of the page, so that a full page's worth of // data is written int pageOffset = (getFormat().PAGE_SIZE - _forceBytes.remaining()); @@ -358,15 +379,15 @@ public class PageChannel implements Channel, Flushable { assertWriting(); validatePageNumber(pageNumber); - + // don't write the whole page, just wipe out the header (which should be // enough to let us know if we accidentally try to use an invalid page) _invalidPageBytes.rewind(); _channel.write(_invalidPageBytes, getPageOffset(pageNumber)); - + _globalUsageMap.addPageNumber(pageNumber); //force is done here } - + /** * @return A newly-allocated buffer that can be passed to readPage */ @@ -381,19 +402,19 @@ public class PageChannel implements Channel, Flushable { public static ByteBuffer createBuffer(int size) { return createBuffer(size, DEFAULT_BYTE_ORDER); } - + /** * @return A newly-allocated buffer of the given size and byte order */ public static ByteBuffer createBuffer(int size, ByteOrder order) { return ByteBuffer.allocate(size).order(order); } - + @Override public void flush() throws IOException { _channel.force(true); } - + @Override public void close() throws IOException { flush(); @@ -401,7 +422,7 @@ public class PageChannel implements Channel, Flushable { _channel.close(); } } - + @Override public boolean isOpen() { return _channel.isOpen(); @@ -419,7 +440,7 @@ public class PageChannel implements Channel, Flushable { buffer.put(pos, b); } } - + /** * @return a duplicate of the current buffer narrowed to the given position * and limit. mark will be set at the current position. |