]> source.dussan.org Git - jackcess.git/commitdiff
more minor refactoring
authorJames Ahlborn <jtahlborn@yahoo.com>
Tue, 8 Apr 2008 01:05:15 +0000 (01:05 +0000)
committerJames Ahlborn <jtahlborn@yahoo.com>
Tue, 8 Apr 2008 01:05:15 +0000 (01:05 +0000)
git-svn-id: https://svn.code.sf.net/p/jackcess/code/jackcess/trunk@317 f203690c-595d-4dc9-a70b-905162fa7fd2

src/java/com/healthmarketscience/jackcess/Index.java
src/java/com/healthmarketscience/jackcess/IndexPageCache.java

index 4dc822fd5ae32da918cb86477647a6b10847e796..cb8867f8a7da1b472b14a13de7f9ab3704dc59bb 100644 (file)
@@ -586,7 +586,7 @@ public abstract class Index implements Comparable<Index> {
       DataPage nextDataPage = null;
       while(nextPageNumber != INVALID_INDEX_PAGE_NUMBER) {
         DataPage dp = getDataPage(nextPageNumber);
-        if(!dp.getEntries().isEmpty()) {
+        if(!dp.isEmpty()) {
           nextDataPage = dp;
           break;
         }
@@ -615,7 +615,7 @@ public abstract class Index implements Comparable<Index> {
       DataPage prevDataPage = null;
       while(prevPageNumber != INVALID_INDEX_PAGE_NUMBER) {
         DataPage dp = getDataPage(prevPageNumber);
-        if(!dp.getEntries().isEmpty()) {
+        if(!dp.isEmpty()) {
           prevDataPage = dp;
           break;
         }
@@ -2199,6 +2199,10 @@ public abstract class Index implements Comparable<Index> {
       throws IOException;
     public abstract void removeEntry(int idx)
       throws IOException;
+
+    public final boolean isEmpty() {
+      return getEntries().isEmpty();
+    }
     
     public final int getCompressedEntrySize() {
       // when written to the index page, the entryPrefix bytes will only be
index da4acb7be74824555bc7daaac30e4a0b1b53e8dc..1e94f8650b7bd405d1703a66e32ff159a3d54a4f 100644 (file)
@@ -34,8 +34,10 @@ import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+
 import org.apache.commons.lang.ObjectUtils;
 
 import static com.healthmarketscience.jackcess.Index.*;
@@ -86,26 +88,56 @@ public class IndexPageCache
   public void write()
     throws IOException
   {
+    // first discard any empty pages
+    handleEmptyPages();
+    // next, handle any necessary page splitting
     preparePagesForWriting();
+    // finally, write all the modified pages (which are not being deleted)
     writeDataPages();
   }
 
-  private void preparePagesForWriting()
-    throws IOException
+  private void handleEmptyPages() throws IOException
   {
-    // FIXME, writeme
+    for(Iterator<CacheDataPage> iter = _modifiedPages.iterator();
+        iter.hasNext(); ) {
+      CacheDataPage cacheDataPage = iter.next();
+      if(cacheDataPage.isEmpty()) {
+        if(!cacheDataPage._main.isRoot()) {
+          deleteDataPage(cacheDataPage);
+        } else {
+          writeDataPage(cacheDataPage);
+        }
+        iter.remove();
+      }
+    }
+  }
+  
+  private void preparePagesForWriting() throws IOException
+  {
+    boolean splitPages = false;
+    int maxPageEntrySize = getIndex().getMaxPageEntrySize();
+    do {
+      splitPages = false;
+
+      for(CacheDataPage cacheDataPage : _modifiedPages) {
+        if(cacheDataPage.getCompressedEntrySize() > maxPageEntrySize) {
+          // need to split this page
+          splitPages = true;
+          splitDataPage(cacheDataPage);
+        }
+      }
+      
+    } while(splitPages);
   }
 
-  private void writeDataPages()
-    throws IOException
+  private void writeDataPages() throws IOException
   {
     for(CacheDataPage cacheDataPage : _modifiedPages) {
-      if(!cacheDataPage.getEntries().isEmpty() ||
-         cacheDataPage._main.isRoot()) {
-        writeDataPage(cacheDataPage);
-      } else {
-        deleteDataPage(cacheDataPage);
+      if(cacheDataPage.isEmpty()) {
+        throw new IllegalStateException("Unexpected empty page " +
+                                        cacheDataPage);
       }
+      writeDataPage(cacheDataPage);
     }
     _modifiedPages.clear();
   }
@@ -219,12 +251,12 @@ public class IndexPageCache
     
     setModified(cacheDataPage);
 
-    boolean updateFirst = false;
+    boolean updateFirst = (entryIdx == 0);
     boolean updateLast = false;
+    boolean mayUpdatePrefix = true;
 
     switch(upType) {
     case ADD: {
-      updateFirst = (entryIdx == 0);
       updateLast = (entryIdx == dpExtra._entries.size());
 
       dpExtra._entries.add(entryIdx, newEntry);
@@ -232,7 +264,6 @@ public class IndexPageCache
       break;
     }
     case REPLACE: {
-      updateFirst = (entryIdx == 0);
       updateLast = (entryIdx == (dpExtra._entries.size() - 1));
 
       Entry oldEntry = dpExtra._entries.set(entryIdx, newEntry);
@@ -240,18 +271,20 @@ public class IndexPageCache
       break;
     }
     case REMOVE: {
-      updateFirst = (entryIdx == 0);
       updateLast = (entryIdx == (dpExtra._entries.size() - 1));
 
       Entry oldEntry = dpExtra._entries.remove(entryIdx);
       dpExtra._totalEntrySize -= oldEntry.size();
+      // note, we don't need to futz with the _entryPrefix on removal because
+      // the prefix is always still valid after removal
+      mayUpdatePrefix = false;
       break;
     }
     default:
       throw new RuntimeException("unknown update type " + upType);
     }
     
-    if(dpExtra._entries.isEmpty()) {
+    if(cacheDataPage.isEmpty()) {
       // this page is dead
       removeDataPage(cacheDataPage);
     } else {
@@ -261,9 +294,7 @@ public class IndexPageCache
       if(updateLast) {
         dpMain._lastEntry = dpExtra.getLastEntry();
       }
-      // note, we don't need to futz with the _entryPrefix on removal because
-      // the prefix is always still valid after removal
-      if((upType != UpdateType.REMOVE) && (updateFirst || updateLast)) {
+      if(mayUpdatePrefix && (updateFirst || updateLast)) {
         // update the prefix
         dpExtra._entryPrefix = findNewPrefix(dpExtra._entryPrefix, newEntry);
       }
@@ -306,20 +337,12 @@ public class IndexPageCache
     setModified(parentDataPage);
     
     DataPageMain parentMain = parentDataPage._main;
-    DataPageExtra parentExtra = parentDataPage._extra;
 
     if(childMain.isTail()) {
       parentMain._childTailPageNumber = INVALID_INDEX_PAGE_NUMBER;
     } else {
-      Entry oldParentEntry = childMain._firstEntry.asNodeEntry(
-          childMain._pageNumber);
-      int idx = parentExtra.findEntry(oldParentEntry);
-      if(idx < 0) {
-        throw new IllegalStateException(
-            "Could not find child entry in parent; child " + childDataPage +
-            "; parent " + parentDataPage);
-      }
-      removeEntry(parentDataPage, idx);
+      updateParentEntry(parentDataPage, childDataPage,
+                        childMain._firstEntry, null, UpdateType.REMOVE);
     }
   }
 
@@ -354,31 +377,65 @@ public class IndexPageCache
     dpMain._firstEntry = dpExtra.getFirstEntry();
     DataPageMain parentMain = dpMain.getParentPage();
     if(parentMain != null) {
-      Entry oldParentEntry = oldEntry.asNodeEntry(dpMain._pageNumber);
-      Entry newParentEntry =
-        dpMain._firstEntry.asNodeEntry(dpMain._pageNumber);
       updateParentEntry(new CacheDataPage(parentMain),
-                        oldParentEntry, newParentEntry);
+                        cacheDataPage,
+                        oldEntry, dpMain._firstEntry,
+                        UpdateType.REPLACE);
     }
   }
   
   private void updateParentEntry(CacheDataPage parentDataPage,
-                                 Entry oldEntry, Entry newEntry)
+                                 CacheDataPage childDataPage,
+                                 Entry oldEntry, Entry newEntry,
+                                 UpdateType upType)
     throws IOException
   {
+    DataPageMain childMain = childDataPage._main;
     DataPageExtra parentExtra = parentDataPage._extra;
 
-    setModified(parentDataPage);
+    if(oldEntry != null) {
+      oldEntry = oldEntry.asNodeEntry(childMain._pageNumber);
+    }
+    if(newEntry != null) {
+      newEntry = newEntry.asNodeEntry(childMain._pageNumber);
+    }
+
+    boolean expectFound = true;
+    int idx = 0;
+    
+    switch(upType) {
+    case ADD:
+      expectFound = false;
+      idx = parentExtra.findEntry(newEntry);
+      break;
 
-    int idx = parentExtra.findEntry(oldEntry);
+    case REPLACE:
+    case REMOVE:
+      idx = parentExtra.findEntry(oldEntry);
+      break;
+    
+    default:
+      throw new RuntimeException("unknown update type " + upType);
+    }
+        
     if(idx < 0) {
-      throw new IllegalStateException(
-          "Could not find child entry in parent; childEntry " + oldEntry +
-          "; parent " + parentDataPage);
+      if(expectFound) {
+        throw new IllegalStateException(
+            "Could not find child entry in parent; childEntry " + oldEntry +
+            "; parent " + parentDataPage);
+      }
+      idx = missingIndexToInsertionPoint(idx);
+    } else {
+      if(!expectFound) {
+        throw new IllegalStateException(
+            "Unexpectedly found child entry in parent; childEntry " +
+            newEntry + "; parent " + parentDataPage);
+      }
     }
-    replaceEntry(parentDataPage, idx, newEntry);
+    updateEntry(parentDataPage, idx, newEntry, upType);
   }
   
+  
   private void validateEntryForPage(DataPageMain dataPage, Entry entry) {
     if(dataPage._leaf != entry.isLeafEntry()) {
       throw new IllegalStateException(
@@ -386,6 +443,12 @@ public class IndexPageCache
           dataPage._leaf + ", entryLeaf " + entry.isLeafEntry());
     }
   }
+
+  private void splitDataPage(CacheDataPage cacheDataPage)
+    throws IOException
+  {
+    // FIXME, writeme
+  }
   
   public CacheDataPage findCacheDataPage(Entry e)
     throws IOException