]> source.dussan.org Git - jackcess.git/commitdiff
add usage maps for lval cols
authorJames Ahlborn <jtahlborn@yahoo.com>
Fri, 29 Apr 2016 02:45:02 +0000 (02:45 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Fri, 29 Apr 2016 02:45:02 +0000 (02:45 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/branches/mutateops@985 f203690c-595d-4dc9-a70b-905162fa7fd2

src/main/java/com/healthmarketscience/jackcess/impl/LongValueColumnImpl.java
src/main/java/com/healthmarketscience/jackcess/impl/TableImpl.java
src/main/java/com/healthmarketscience/jackcess/impl/TableMutator.java

index b33c84a58f3d832cec45b03543e189ffea0125fd..8a137ea3dc5c93bee5395fec20745afc9c1c5ed6 100644 (file)
@@ -71,8 +71,9 @@ class LongValueColumnImpl extends ColumnImpl
     _lvalBufferH = new UmapLongValueBufferHolder(ownedPages, freeSpacePages);
   }
 
+  @Override
   void collectUsageMapPages(Collection<Integer> pages) {
-    // FIXME, writeme
+    _lvalBufferH.collectUsageMapPages(pages);
   }
   
   @Override
@@ -446,6 +447,10 @@ class LongValueColumnImpl extends ColumnImpl
       getBufferHolder().clear();
     }
 
+    public void collectUsageMapPages(Collection<Integer> pages) {
+      // base does nothing
+    }
+
     protected abstract TempPageHolder getBufferHolder();
   }
 
@@ -522,5 +527,11 @@ class LongValueColumnImpl extends ColumnImpl
       }
       super.clear();
     }
+
+    @Override
+    public void collectUsageMapPages(Collection<Integer> pages) {
+      pages.add(_ownedPages.getTablePageNumber());
+      pages.add(_freeSpacePages.getTablePageNumber());
+    }
   }
 }
index 4d27ed72e09a2611963927e1dd51cbaf90b5457c..a789404dbcff841acb0f3bf724b6595e20be23da 100644 (file)
@@ -29,12 +29,12 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeSet;
 
 import com.healthmarketscience.jackcess.BatchUpdateException;
 import com.healthmarketscience.jackcess.Column;
@@ -1185,6 +1185,12 @@ public class TableImpl implements Table
     int umapPos = -1;
     if(isLongVal) {
 
+      // allocate usage maps for the long value col
+      Map.Entry<Integer,Integer> umapInfo = addUsageMaps(2);
+      int umapPageNum = umapInfo.getKey();
+      int umapRow1 = umapInfo.getValue();
+      int umapRow2 = umapRow1 + 1;
+
       // skip past index defs
       ByteUtil.forward(tableBuffer, (_indexDatas.size() * 
                                      (format.SIZE_INDEX_DEFINITION + 
@@ -1195,7 +1201,12 @@ public class TableImpl implements Table
         ByteUtil.forward(tableBuffer, tableBuffer.getShort());
       }
 
-      // FIXME add usage maps...
+      // owned pages umap (both are on same page)
+      tableBuffer.put((byte)umapRow1);
+      ByteUtil.put3ByteInt(tableBuffer, umapPageNum);
+      // free space pages umap
+      tableBuffer.put((byte)umapRow2);
+      ByteUtil.put3ByteInt(tableBuffer, umapPageNum);
     }
 
     // sanity check the updates
@@ -1277,28 +1288,61 @@ public class TableImpl implements Table
     return tableBuffer;
   }
 
-  private Map.Entry<Integer,Integer> addUsageMaps(int numMaps)
+  private Map.Entry<Integer,Integer> addUsageMaps(int numMaps) throws IOException
   {
     JetFormat format = getFormat();
+    PageChannel pageChannel = getPageChannel();
     int umapRowLength = format.OFFSET_USAGE_MAP_START +
       format.USAGE_MAP_TABLE_BYTE_LENGTH;
     int totalUmapSpaceUsage = getRowSpaceUsage(umapRowLength, format) * numMaps;
     int umapPageNumber = PageChannel.INVALID_PAGE_NUMBER;
     int firstRowNum = -1;
-    ByteBuffer umapBuf = null;
     int freeSpace = 0;
-    int rowStart = 0;
-    int umapRowNum = 0;
 
     // search currently known usage map buffers to find one with enough free
     // space (the numMaps should always be small enough to put them all on one
-    // page)
-    Set<Integer> knownPages = new HashSet<Integer>();
+    // page).  pages will free space will probaby be newer pages (higher
+    // numbers), so we sort in reverse order.
+    Set<Integer> knownPages = new TreeSet<Integer>(Collections.reverseOrder());
     collectUsageMapPages(knownPages);
-    // FIXME
 
-    
-    
+    ByteBuffer umapBuf = pageChannel.createPageBuffer();
+    for(Integer pageNum : knownPages) {
+      pageChannel.readPage(umapBuf, pageNum);
+      freeSpace = umapBuf.getShort(format.OFFSET_FREE_SPACE);
+      if(freeSpace >= totalUmapSpaceUsage) {
+        // found a page!
+        umapPageNumber = pageNum;
+        firstRowNum = getRowsOnDataPage(umapBuf, format);
+        break;
+      }
+    }
+
+    if(umapPageNumber == PageChannel.INVALID_PAGE_NUMBER) {
+      
+      // didn't find any existing pages, need to create a new one
+      freeSpace = format.DATA_PAGE_INITIAL_FREE_SPACE;
+      firstRowNum = 0;
+      umapBuf = createUsageMapDefPage(pageChannel, freeSpace);
+    }
+
+    // write the actual usage map defs
+    int rowStart = findRowEnd(umapBuf, firstRowNum, format) - umapRowLength;
+    int umapRowNum = firstRowNum;
+    for(int i = 0; i < numMaps; ++i) {
+      umapBuf.putShort(getRowStartOffset(umapRowNum, format), (short)rowStart);
+      umapBuf.put(rowStart, UsageMap.MAP_TYPE_INLINE);
+      rowStart -= umapRowLength;      
+      ++umapRowNum;
+    }
+
+    // finish the page
+    freeSpace -= totalUmapSpaceUsage;
+    umapBuf.putShort(format.OFFSET_FREE_SPACE, (short)freeSpace);
+    umapBuf.putShort(format.OFFSET_NUM_ROWS_ON_DATA_PAGE, 
+                     (short)umapRowNum);
+    pageChannel.writePage(umapBuf, umapPageNumber);
+
     return new AbstractMap.SimpleImmutableEntry<Integer,Integer>(
         umapPageNumber, firstRowNum);
   }
@@ -1310,6 +1354,10 @@ public class TableImpl implements Table
     for(IndexData idx : _indexDatas) {
       idx.collectUsageMapPages(pages);
     }
+
+    for(ColumnImpl col : _columns) {
+      col.collectUsageMapPages(pages);
+    }
   }    
   
   /**
@@ -1407,13 +1455,7 @@ public class TableImpl implements Table
 
         freeSpace = format.DATA_PAGE_INITIAL_FREE_SPACE;
 
-        umapBuf = pageChannel.createPageBuffer();
-        umapBuf.put(PageTypes.DATA);
-        umapBuf.put((byte) 0x1);  //Unknown
-        umapBuf.putShort((short)freeSpace);  //Free space in page
-        umapBuf.putInt(0); //Table definition
-        umapBuf.putInt(0); //Unknown
-        umapBuf.putShort((short)0); //Number of records on this page
+        umapBuf = createUsageMapDefPage(pageChannel, freeSpace);
 
         rowStart = findRowEnd(umapBuf, 0, format) - umapRowLength;
         umapRowNum = 0;
@@ -1497,6 +1539,19 @@ public class TableImpl implements Table
     }
   }
 
+  private static ByteBuffer createUsageMapDefPage(
+      PageChannel pageChannel, int freeSpace)
+  {
+    ByteBuffer umapBuf = pageChannel.createPageBuffer();
+    umapBuf.put(PageTypes.DATA);
+    umapBuf.put((byte) 0x1);  //Unknown
+    umapBuf.putShort((short)freeSpace);  //Free space in page
+    umapBuf.putInt(0); //Table definition
+    umapBuf.putInt(0); //Unknown
+    umapBuf.putShort((short)0); //Number of records on this page    
+    return umapBuf;
+  }
+
   /**
    * Returns a single ByteBuffer which contains the entire table definition
    * (which may span multiple database pages).
index fe1500faa0ff3a941af12fde560d1907451b354a..2dd2fa5ec8ca8f82ad659d5858364fefb1bb279c 100644 (file)
@@ -35,7 +35,6 @@ public class TableMutator extends DBMutator
   private final TableImpl _table;
 
   private ColumnBuilder _column;
-  private ColumnState _columnState;
 
   public TableMutator(TableImpl table) {
     super(table.getDatabase());
@@ -55,10 +54,6 @@ public class TableMutator extends DBMutator
     // assign column numbers and do some assorted column bookkeeping
     short columnNumber = (short)_table.getMaxColumnCount();
     _column.setColumnNumber(columnNumber);
-    if(_column.getType().isLongValue()) {      
-      // only lval columns need extra state
-      _columnState = new ColumnState();
-    }
 
     getPageChannel().startExclusiveWrite();
     try {