]> source.dussan.org Git - jackcess.git/commitdiff
allow for TempBufferHolder which does not maintain reference (cleans up addRows)
authorJames Ahlborn <jtahlborn@yahoo.com>
Fri, 21 Mar 2008 04:04:09 +0000 (04:04 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Fri, 21 Mar 2008 04:04:09 +0000 (04:04 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@289 f203690c-595d-4dc9-a70b-905162fa7fd2

src/java/com/healthmarketscience/jackcess/Index.java
src/java/com/healthmarketscience/jackcess/Table.java
src/java/com/healthmarketscience/jackcess/TempBufferHolder.java
src/java/com/healthmarketscience/jackcess/TempPageHolder.java
src/java/com/healthmarketscience/jackcess/UsageMap.java

index 4307279fe4e7f8760386935ae196e88c234b6860..fe8fa237da47e67f8a235cba5b975ccd24b8069b 100644 (file)
@@ -177,7 +177,7 @@ public class Index implements Comparable<Index> {
   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<Index> {
     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);
index 6523bc100868cb4c16d5c7f6035227278c249744..c69fc89119ac604d7427cc34748b4d2b19f3f87d 100644 (file)
@@ -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<? extends Object[]> 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 <code>addRow</code> 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<? extends Object[]> rows,
+                       TempBufferHolder writeRowBufferH)
+    throws IOException
+  {
     ByteBuffer[] rowData = new ByteBuffer[rows.size()];
     Iterator<? extends Object[]> 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;
     }
index d94c9ee8e3bcc253457bbf99384ea12d5718507f..9afae0bedd89974c5bf2c1c42d9a953298dd1194 100644 (file)
@@ -17,6 +17,20 @@ public abstract class TempBufferHolder {
   private static final Reference<ByteBuffer> EMPTY_BUFFER_REF =
     new SoftReference<ByteBuffer>(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<ByteBuffer>(newBuffer);
-//       // FIXME, enable for testing (make this automatic)
-//       _buffer = new PhantomReference<ByteBuffer>(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
+    }
+  }
   
 }
index f1fbcd6d31cad2d4e963d2ace460037f3ff51c56..d310a305182c6cceaa0adb7b3b99339f0c055d53 100644 (file)
@@ -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);
   }
 
   /**
index 64656ba11acc49da950fc89a8cb75822342bc21a..9b286e6945dae152cc754e16ed9ae3f3d46a6eb7 100644 (file)
@@ -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