From ca15878cc1c40b87d38acd3e735da1f80c25c01d Mon Sep 17 00:00:00 2001 From: James Ahlborn Date: Fri, 21 Mar 2008 04:04:09 +0000 Subject: [PATCH] allow for TempBufferHolder which does not maintain reference (cleans up addRows) git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@289 f203690c-595d-4dc9-a70b-905162fa7fd2 --- .../healthmarketscience/jackcess/Index.java | 5 +- .../healthmarketscience/jackcess/Table.java | 43 ++++++++---- .../jackcess/TempBufferHolder.java | 68 +++++++++++++++---- .../jackcess/TempPageHolder.java | 12 ++-- .../jackcess/UsageMap.java | 2 +- 5 files changed, 91 insertions(+), 39 deletions(-) diff --git a/src/java/com/healthmarketscience/jackcess/Index.java b/src/java/com/healthmarketscience/jackcess/Index.java index 4307279..fe8fa23 100644 --- a/src/java/com/healthmarketscience/jackcess/Index.java +++ b/src/java/com/healthmarketscience/jackcess/Index.java @@ -177,7 +177,7 @@ public class Index implements Comparable { private int _modCount; /** temp buffer used to writing the index */ private final TempBufferHolder _indexBufferH = - TempBufferHolder.newHolder(false, true); + TempBufferHolder.newHolder(TempBufferHolder.Type.SOFT, true); /** FIXME, for now, we can't write multi-page indexes or indexes using the funky primary key compression scheme */ boolean _readOnly; @@ -504,7 +504,8 @@ public class Index implements Comparable { byte[] valuePrefix = null; boolean firstEntry = true; TempBufferHolder tmpEntryBufferH = - TempBufferHolder.newHolder(true, true, ByteOrder.BIG_ENDIAN); + TempBufferHolder.newHolder(TempBufferHolder.Type.HARD, true, + ByteOrder.BIG_ENDIAN); for (int i = 0; i < entryMaskLength; i++) { byte entryMask = indexPage.get(entryMaskPos + i); diff --git a/src/java/com/healthmarketscience/jackcess/Table.java b/src/java/com/healthmarketscience/jackcess/Table.java index 6523bc1..c69fc89 100644 --- a/src/java/com/healthmarketscience/jackcess/Table.java +++ b/src/java/com/healthmarketscience/jackcess/Table.java @@ -111,13 +111,17 @@ public class Table private int _modCount; /** page buffer used to update data pages when adding rows */ private final TempPageHolder _addRowBufferH = - TempPageHolder.newHolder(false); + TempPageHolder.newHolder(TempBufferHolder.Type.SOFT); /** page buffer used to update the table def page */ private final TempPageHolder _tableDefBufferH = - TempPageHolder.newHolder(false); + TempPageHolder.newHolder(TempBufferHolder.Type.SOFT); /** buffer used to writing single rows of data */ private final TempBufferHolder _singleRowBufferH = - TempBufferHolder.newHolder(false, true); + TempBufferHolder.newHolder(TempBufferHolder.Type.SOFT, true); + /** "buffer" used to writing multi rows of data (will create new buffer on + every call) */ + private final TempBufferHolder _multiRowBufferH = + TempBufferHolder.newHolder(TempBufferHolder.Type.NONE, true); /** common cursor for iterating through the table, kept here for historic reasons */ @@ -203,7 +207,7 @@ public class Table } public RowState createRowState() { - return new RowState(true); + return new RowState(TempBufferHolder.Type.HARD); } protected UsageMap.PageCursor getOwnedPagesCursor() { @@ -1100,7 +1104,7 @@ public class Table * Add a single row to this table and write it to disk */ public void addRow(Object... row) throws IOException { - addRows(Collections.singletonList(row)); + addRows(Collections.singletonList(row), _singleRowBufferH); } /** @@ -1110,15 +1114,26 @@ public class Table * @param rows List of Object[] row values */ public void addRows(List rows) throws IOException { + addRows(rows, _multiRowBufferH); + } + + /** + * Add multiple rows to this table, only writing to disk after all + * rows have been written, and every time a data page is filled. This + * is much more efficient than calling addRow multiple times. + * @param rows List of Object[] row values + * @param writeRowBufferH TempBufferHolder used to generate buffers for + * writing the row data + */ + private void addRows(List rows, + TempBufferHolder writeRowBufferH) + throws IOException + { ByteBuffer[] rowData = new ByteBuffer[rows.size()]; Iterator iter = rows.iterator(); for (int i = 0; iter.hasNext(); i++) { - // note, use the cached _singleRowBufferH for the first row. this will - // speed up single row writes - rowData[i] = createRow( - iter.next(), getFormat().MAX_ROW_SIZE, - ((i == 0) ? _singleRowBufferH.getPageBuffer(getPageChannel()) : - getPageChannel().createPageBuffer())); + rowData[i] = createRow(iter.next(), getFormat().MAX_ROW_SIZE, + writeRowBufferH.getPageBuffer(getPageChannel())); if (rowData[i].limit() > getFormat().MAX_ROW_SIZE) { throw new IOException("Row size " + rowData[i].limit() + " is too large"); @@ -1589,7 +1604,7 @@ public class Table private RowStatus _rowStatus = RowStatus.INIT; /** buffer used for reading overflow pages */ private final TempPageHolder _overflowRowBufferH = - TempPageHolder.newHolder(false); + TempPageHolder.newHolder(TempBufferHolder.Type.SOFT); /** the row buffer which contains the final data (after following any overflow pointers) */ private ByteBuffer _finalRowBuffer; @@ -1605,8 +1620,8 @@ public class Table data */ private int _lastModCount; - private RowState(boolean hardRowBuffer) { - _headerRowBufferH = TempPageHolder.newHolder(hardRowBuffer); + private RowState(TempBufferHolder.Type headerType) { + _headerRowBufferH = TempPageHolder.newHolder(headerType); _rowValues = new Object[Table.this.getColumnCount()]; _lastModCount = Table.this._modCount; } diff --git a/src/java/com/healthmarketscience/jackcess/TempBufferHolder.java b/src/java/com/healthmarketscience/jackcess/TempBufferHolder.java index d94c9ee..9afae0b 100644 --- a/src/java/com/healthmarketscience/jackcess/TempBufferHolder.java +++ b/src/java/com/healthmarketscience/jackcess/TempBufferHolder.java @@ -17,6 +17,20 @@ public abstract class TempBufferHolder { private static final Reference EMPTY_BUFFER_REF = new SoftReference(null); + /** + * The caching type for the buffer holder. + */ + public enum Type { + /** a hard reference is maintained to the created buffer */ + HARD, + /** a soft reference is maintained to the created buffer (may be garbage + collected if memory gets tight) */ + SOFT, + /** no reference is maintained to a created buffer (new buffer every + time) */ + NONE; + } + /** whether or not every get automatically rewinds the buffer */ private final boolean _autoRewind; /** ByteOrder for all allocated buffers */ @@ -39,32 +53,34 @@ public abstract class TempBufferHolder { /** * Creates a new TempBufferHolder. - * @param hard iff true, the TempBufferHolder will maintain a hard reference - * to the current buffer, otherwise will maintain a - * SoftReference. + * @param type the type of reference desired for any created buffer * @param autoRewind whether or not every get automatically rewinds the * buffer */ - public static TempBufferHolder newHolder(boolean hard, boolean autoRewind) { - return newHolder(hard, autoRewind, PageChannel.DEFAULT_BYTE_ORDER); + public static TempBufferHolder newHolder(Type type, boolean autoRewind) { + return newHolder(type, autoRewind, PageChannel.DEFAULT_BYTE_ORDER); } /** * Creates a new TempBufferHolder. - * @param hard iff true, the TempBufferHolder will maintain a hard reference - * to the current buffer, otherwise will maintain a - * SoftReference. + * @param type the type of reference desired for any created buffer * @param autoRewind whether or not every get automatically rewinds the * buffer * @param order byte order for all allocated buffers */ - public static TempBufferHolder newHolder(boolean hard, boolean autoRewind, + public static TempBufferHolder newHolder(Type type, boolean autoRewind, ByteOrder order) { - if(hard) { + switch(type) { + case HARD: return new HardTempBufferHolder(autoRewind, order); + case SOFT: + return new SoftTempBufferHolder(autoRewind, order); + case NONE: + return new NoneTempBufferHolder(autoRewind, order); + default: + throw new IllegalStateException("Unknown type " + type); } - return new SoftTempBufferHolder(autoRewind, order); } /** @@ -112,7 +128,7 @@ public abstract class TempBufferHolder { protected abstract void setNewBuffer(ByteBuffer newBuffer); /** - * TempBufferHolder which has a hard reference to the buffer buffer. + * TempBufferHolder which has a hard reference to the buffer. */ private static final class HardTempBufferHolder extends TempBufferHolder { @@ -139,7 +155,7 @@ public abstract class TempBufferHolder { } /** - * TempBufferHolder which has a soft reference to the buffer buffer. + * TempBufferHolder which has a soft reference to the buffer. */ private static final class SoftTempBufferHolder extends TempBufferHolder { @@ -158,8 +174,6 @@ public abstract class TempBufferHolder { protected void setNewBuffer(ByteBuffer newBuffer) { _buffer.clear(); _buffer = new SoftReference(newBuffer); -// // FIXME, enable for testing (make this automatic) -// _buffer = new PhantomReference(newBuffer, null); } @Override @@ -168,5 +182,29 @@ public abstract class TempBufferHolder { } } + /** + * TempBufferHolder which has a no reference to the buffer. + */ + private static final class NoneTempBufferHolder extends TempBufferHolder + { + private NoneTempBufferHolder(boolean autoRewind, ByteOrder order) { + super(autoRewind, order); + } + + @Override + public ByteBuffer getExistingBuffer() { + return null; + } + + @Override + protected void setNewBuffer(ByteBuffer newBuffer) { + // nothing to do + } + + @Override + public void clear() { + // nothing to do + } + } } diff --git a/src/java/com/healthmarketscience/jackcess/TempPageHolder.java b/src/java/com/healthmarketscience/jackcess/TempPageHolder.java index f1fbcd6..d310a30 100644 --- a/src/java/com/healthmarketscience/jackcess/TempPageHolder.java +++ b/src/java/com/healthmarketscience/jackcess/TempPageHolder.java @@ -44,19 +44,17 @@ public final class TempPageHolder { buffer has been discarded since the last page read */ private int _bufferModCount; - private TempPageHolder(boolean hard) { - _buffer = TempBufferHolder.newHolder(hard, false); + private TempPageHolder(TempBufferHolder.Type type) { + _buffer = TempBufferHolder.newHolder(type, false); _bufferModCount = _buffer.getModCount(); } /** * Creates a new TempPageHolder. - * @param hard iff true, the TempPageHolder will maintain a hard reference - * to the current page buffer, otherwise will maintain a - * SoftReference. + * @param type the type of reference desired for any create page buffers */ - public static TempPageHolder newHolder(boolean hard) { - return new TempPageHolder(hard); + public static TempPageHolder newHolder(TempBufferHolder.Type type) { + return new TempPageHolder(type); } /** diff --git a/src/java/com/healthmarketscience/jackcess/UsageMap.java b/src/java/com/healthmarketscience/jackcess/UsageMap.java index 64656ba..9b286e6 100644 --- a/src/java/com/healthmarketscience/jackcess/UsageMap.java +++ b/src/java/com/healthmarketscience/jackcess/UsageMap.java @@ -638,7 +638,7 @@ public class UsageMap { /** Buffer that contains the current reference map page */ private final TempPageHolder _mapPageHolder = - TempPageHolder.newHolder(false); + TempPageHolder.newHolder(TempBufferHolder.Type.SOFT); private ReferenceHandler() throws IOException -- 2.39.5