You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ch...@apache.org on 2008/08/20 21:07:19 UTC

svn commit: r687427 - in /activemq/sandbox/kahadb/src/main/java/org/apache/kahadb: page/PageFile.java util/Sequence.java util/SequenceSet.java

Author: chirino
Date: Wed Aug 20 12:07:19 2008
New Revision: 687427

URL: http://svn.apache.org/viewvc?rev=687427&view=rev
Log:
PageFile can now allocate a sequencial set of pages.

Modified:
    activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/page/PageFile.java
    activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/util/Sequence.java
    activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/util/SequenceSet.java

Modified: activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/page/PageFile.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/page/PageFile.java?rev=687427&r1=687426&r2=687427&view=diff
==============================================================================
--- activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/page/PageFile.java (original)
+++ activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/page/PageFile.java Wed Aug 20 12:07:19 2008
@@ -51,6 +51,8 @@
 import org.apache.kahadb.util.IOHelper;
 import org.apache.kahadb.util.IntrospectionSupport;
 import org.apache.kahadb.util.LRUCache;
+import org.apache.kahadb.util.Sequence;
+import org.apache.kahadb.util.SequenceSet;
 
 /**
  * A PageFile provides you random access to fixed sized disk pages. This object is not thread safe and therefore access to it should 
@@ -87,7 +89,7 @@
     private byte[] readBuffer;
     private long nextFreePageId;
     
-    private LinkedList<Long> freeList = new LinkedList<Long>();
+    private SequenceSet freeList = new SequenceSet();
     private AtomicBoolean loaded = new AtomicBoolean();
     private LRUCache<Long, Page> pageCache;
     
@@ -287,7 +289,7 @@
                 lastTxId = redoRecoveryUpdates();
                 
                 // Scan all to find the free pages.
-                freeList.clear();
+                freeList = new SequenceSet();
                 long length = readFile.length();
                 Page page = new Page();
                 long offset = initialPageOffset;
@@ -373,7 +375,7 @@
 
     
     /** 
-     * Gives you back a free page that you can write data to.
+     * Allocates a free page that you can write data to.
      * 
      * @return a newly allocated page.  
      * @throws IOException
@@ -403,6 +405,48 @@
         addToCache(page);
         return page;
     }
+    
+    /** 
+     * Allocates a block of free pages that you can write data to.
+     * 
+     * @param count the number of sequential pages to allocate
+     * @return the first page of the sequential set. 
+     * @throws IOException
+     *         If an disk error occurred.
+     * @throws IllegalStateException
+     *         if the PageFile is not loaded
+     */
+    public Page allocate(int count) throws IOException {
+        if( !loaded.get() ) {
+            throw new IllegalStateException("Cannot allocate a page when the page file is not loaded");
+        }
+
+        Page page = null;
+        Sequence seq = freeList.removeFirstSequence(count);
+        if(seq!=null) {
+            page = new Page();
+            page.setPageId(seq.getFirst());
+            page.setType(Page.FREE_TYPE);
+        } else {
+            
+            // allocate the pages..
+            Page t = new Page();
+            while( count > 0 ) {
+                t.setPageId(nextFreePageId);
+                t.setType(Page.FREE_TYPE);
+                nextFreePageId ++;
+                write(t, null);
+                count--;
+                
+                if( page == null ) {
+                    page = t;
+                }
+            }
+            
+        }
+        addToCache(page);
+        return page;
+    }
 
     /**
      * Frees up a previously allocated page so that it can be re-allocated again.
@@ -1008,10 +1052,7 @@
     private void storeFreeList() throws IOException {
         FileOutputStream os = new FileOutputStream(getFreeFile());
         DataOutputStream dos = new DataOutputStream(os);
-        dos.writeLong(freeList.size());
-        for (Long offset : freeList) {
-            dos.writeLong(offset);
-        }
+        SequenceSet.Marshaller.INSTANCE.writePayload(freeList, dos);
         dos.close();
     }
 
@@ -1019,10 +1060,7 @@
         freeList.clear();
         FileInputStream is = new FileInputStream(getFreeFile());
         DataInputStream dis = new DataInputStream(is);
-        long size = dis.readLong();
-        for ( long i=-0 ; i < size; i++) {
-            freeList.add(dis.readLong());
-        }
+        freeList = SequenceSet.Marshaller.INSTANCE.readPayload(dis);
         dis.close();
     }
     

Modified: activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/util/Sequence.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/util/Sequence.java?rev=687427&r1=687426&r2=687427&view=diff
==============================================================================
--- activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/util/Sequence.java (original)
+++ activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/util/Sequence.java Wed Aug 20 12:07:19 2008
@@ -55,4 +55,20 @@
         return first == last ? "" + first : first + "-" + last;
     }
 
+    public long getFirst() {
+        return first;
+    }
+
+    public void setFirst(long first) {
+        this.first = first;
+    }
+
+    public long getLast() {
+        return last;
+    }
+
+    public void setLast(long last) {
+        this.last = last;
+    }
+
 }
\ No newline at end of file

Modified: activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/util/SequenceSet.java
URL: http://svn.apache.org/viewvc/activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/util/SequenceSet.java?rev=687427&r1=687426&r2=687427&view=diff
==============================================================================
--- activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/util/SequenceSet.java (original)
+++ activemq/sandbox/kahadb/src/main/java/org/apache/kahadb/util/SequenceSet.java Wed Aug 20 12:07:19 2008
@@ -16,8 +16,12 @@
  */
 package org.apache.kahadb.util;
 
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.NoSuchElementException;
 
 /**
  * Keeps track of a added long values. Collapses ranges of numbers using a
@@ -27,18 +31,61 @@
  * @author chirino
  */
 public class SequenceSet {
-    LinkedNodeList<Sequence> sequences = new LinkedNodeList<Sequence>();
+    
+    public static class Marshaller implements org.apache.kahadb.Marshaller<SequenceSet> {
+
+        public static final Marshaller INSTANCE = new Marshaller();
+        
+        public Class<SequenceSet> getType() {
+            return SequenceSet.class;
+        }
+
+        public SequenceSet readPayload(DataInput in) throws IOException {
+            SequenceSet value = new SequenceSet();
+            int count = in.readInt();
+            for (int i = 0; i < count; i++) {
+                if( in.readBoolean() ) {
+                    Sequence sequence = new Sequence(in.readLong(), in.readLong());
+                    value.sequences.addLast(sequence);
+                } else {
+                    Sequence sequence = new Sequence(in.readLong());
+                    value.sequences.addLast(sequence);
+                }
+            }
+            return value;
+        }
 
+        public void writePayload(SequenceSet value, DataOutput out) throws IOException {
+            out.writeInt(value.sequences.size());
+            Sequence sequence = value.sequences.getHead();
+            while (sequence != null ) {
+                if( sequence.range() > 1 ) {
+                    out.writeBoolean(true);
+                    out.writeLong(sequence.first);
+                    out.writeLong(sequence.last);
+                } else {
+                    out.writeBoolean(false);
+                    out.writeLong(sequence.first);
+                }
+                sequence = sequence.getNext();
+            }
+        }
+    }
+    
+    LinkedNodeList<Sequence> sequences = new LinkedNodeList<Sequence>();
+    int size;
+    
     /**
      * 
      * @param value
      *            the value to add to the list
      * @return false if the value was a duplicate.
      */
-    synchronized public boolean add(long value) {
+    public boolean add(long value) {
 
         if (sequences.isEmpty()) {
             sequences.addFirst(new Sequence(value));
+            size++;
             return true;
         }
 
@@ -57,6 +104,7 @@
                         next.unlink();
                     }
                 }
+                size++;
                 return true;
             }
 
@@ -73,6 +121,7 @@
                         prev.unlink();
                     }
                 }
+                size++;
                 return true;
             }
 
@@ -80,6 +129,7 @@
             if (value < sequence.first) {
                 // Then insert a new entry before this sequence item.
                 sequence.linkBefore(new Sequence(value));
+                size++;
                 return true;
             }
 
@@ -93,14 +143,59 @@
 
         // Then the value is getting appended to the tail of the sequence.
         sequences.addLast(new Sequence(value));
+        size++;
         return true;
     }
+    
+    /**
+     * Removes and returns the first element from this list.
+     *
+     * @return the first element from this list.
+     * @throws NoSuchElementException if this list is empty.
+     */
+    public long removeFirst() {
+        if (sequences.isEmpty()) {
+            throw new NoSuchElementException();
+        }
+        
+        Sequence rc = removeFirstSequence(1);
+        return rc.first;
+    }
+    
+    /**
+     * Removes and returns the first sequence that is count range large.
+     *
+     * @return a sequence that is count range large, or null if no sequence is that large in the list.
+     */
+    public Sequence removeFirstSequence(long count) {
+        if (sequences.isEmpty()) {
+            return null;
+        }
+        
+        Sequence sequence = sequences.getHead();
+        while (sequence != null ) {
+            if (sequence.range() == count ) {
+                sequence.unlink();
+                size--;
+                return sequence;
+            }
+            if (sequence.range() > count ) {
+                Sequence rc = new Sequence(sequence.first, sequence.first+count);
+                sequence.first+=count;
+                size--;
+                return rc;
+            }
+            sequence = sequence.getNext();
+        }
+        return null;
+    }
+
 
     /**
      * @return all the id Sequences that are missing from this set that are not
      *         in between the range provided.
      */
-    synchronized public List<Sequence> getMissing(long first, long last) {
+    public List<Sequence> getMissing(long first, long last) {
         ArrayList<Sequence> rc = new ArrayList<Sequence>();
         if (first > last) {
             throw new IllegalArgumentException("First cannot be more than last");
@@ -138,7 +233,7 @@
     /**
      * @return all the Sequence that are in this list
      */
-    synchronized public List<Sequence> getReceived() {
+    public List<Sequence> getReceived() {
         ArrayList<Sequence> rc = new ArrayList<Sequence>(sequences.size());
         Sequence sequence = sequences.getHead();
         while (sequence != null) {
@@ -147,4 +242,16 @@
         }
         return rc;
     }
+
+    public boolean isEmpty() {
+        return sequences.isEmpty();
+    }
+
+    public long size() {
+        return size;
+    }
+
+    public void clear() {
+        sequences = new LinkedNodeList<Sequence>();
+    }
 }
\ No newline at end of file