Author: toad
Date: 2009-02-03 21:17:41 +0000 (Tue, 03 Feb 2009)
New Revision: 25518

Modified:
   branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucket.java
   
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
Log:
Shadow blob buckets


Modified: 
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucket.java
===================================================================
--- branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucket.java  
2009-02-03 21:17:21 UTC (rev 25517)
+++ branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucket.java  
2009-02-03 21:17:41 UTC (rev 25518)
@@ -18,7 +18,7 @@
 public class PersistentBlobTempBucket implements Bucket {
        
        public final long blockSize;
-       private long size;
+       long size;
        public final PersistentBlobTempBucketFactory factory;
        /** The index into the blob file of this specific bucket */
        final long index;
@@ -29,27 +29,32 @@
        private boolean persisted;
        private final int hashCode;
        final PersistentBlobTempBucketTag tag;
+       private boolean shadow;
        
        public int hashCode() {
                return hashCode;
        }
 
-       public PersistentBlobTempBucket(PersistentBlobTempBucketFactory 
factory2, long blockSize2, long slot, PersistentBlobTempBucketTag tag) {
+       public PersistentBlobTempBucket(PersistentBlobTempBucketFactory 
factory2, long blockSize2, long slot, PersistentBlobTempBucketTag tag, boolean 
shadow) {
                factory = factory2;
                blockSize = blockSize2;
                index = slot;
                hashCode = super.hashCode();
-               if(tag == null) throw new NullPointerException();
+               if(tag == null && !shadow) throw new NullPointerException();
                this.tag = tag;
+               this.shadow = shadow;
+               this.readOnly = shadow;
        }
 
        public Bucket createShadow() throws IOException {
-               // TODO Auto-generated method stub
-               return null;
+               return factory.createShadow(this);
        }
 
        public void free() {
-               factory.freeBucket(index, this); // will call onFree(): always 
take the outer lock first.
+               if(shadow)
+                       factory.freeShadow(index, this);
+               else
+                       factory.freeBucket(index, this); // will call onFree(): 
always take the outer lock first.
        }
        
        public boolean freed() {
@@ -86,10 +91,12 @@
                                        if(freed) throw new IOException("Bucket 
freed during read");
                                        max = Math.min(blockSize, size);
                                }
+                               if(length == 0) return 0;
                                if(bufOffset < 0) return -1; // throw new 
EOFException() ???
                                if(offset + length >= max)
                                        length = (int) Math.min(max - offset, 
Integer.MAX_VALUE);
                                if(length == 0) return -1;
+                               if(length < 0) throw new 
IllegalStateException("offset="+bufOffset+" length="+length+"buf len = 
"+buffer.length);
                                ByteBuffer buf = ByteBuffer.wrap(buffer, 
bufOffset, length);
                                int read = channel.read(buf, blockSize * index 
+ offset);
                                if(read > 0) offset += read;
@@ -119,6 +126,7 @@
        public OutputStream getOutputStream() throws IOException {
                if(freed) throw new IOException("Already freed");
                if(readOnly) throw new IOException("Read-only");
+               if(shadow) throw new IOException("Shadow");
                final FileChannel channel = factory.channel;
                
                return new OutputStream() {
@@ -178,6 +186,9 @@
        // temporary map, unless we have been freed.
        
        public void storeTo(ObjectContainer container) {
+               if(shadow) {
+                       throw new UnsupportedOperationException("Can't store a 
shadow");
+               }
                boolean p;
                // Race conditions with storeTo and removeFrom running on 
different threads
                // in parallel are possible... that sort of behaviour *should* 
be very rare,
@@ -192,6 +203,7 @@
        }
        
        public boolean objectCanNew(ObjectContainer container) {
+               if(shadow) throw new UnsupportedOperationException("Can't store 
a shadow");
                synchronized(this) {
                        if(persisted) return true;
                }
@@ -201,6 +213,7 @@
        }
        
        public void removeFrom(ObjectContainer container) {
+               if(shadow) throw new UnsupportedOperationException("Can't store 
a shadow");
                boolean p;
                synchronized(this) {
                        p = persisted;

Modified: 
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
===================================================================
--- 
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
   2009-02-03 21:17:21 UTC (rev 25517)
+++ 
branches/db4o/freenet/src/freenet/support/io/PersistentBlobTempBucketFactory.java
   2009-02-03 21:17:41 UTC (rev 25518)
@@ -23,6 +23,7 @@
 import freenet.client.async.DBJobRunner;
 import freenet.node.Ticker;
 import freenet.support.Logger;
+import freenet.support.api.Bucket;
 
 /**
  * Simple temporary storage mechanism using a single file (or a small number 
of 
@@ -55,6 +56,8 @@
         * Similar to notCommittedBlobs. */
        private transient TreeMap<Long,PersistentBlobTempBucketTag> 
almostFreeSlots;
        
+       private transient TreeMap<Long,PersistentBlobTempBucket> shadows;
+       
        private transient DBJobRunner jobRunner;
        
        private transient Random weakRandomSource;
@@ -87,6 +90,7 @@
                notCommittedBlobs = new 
TreeMap<Long,PersistentBlobTempBucket>();
                freeSlots = new TreeMap<Long,PersistentBlobTempBucketTag>();
                almostFreeSlots = new 
TreeMap<Long,PersistentBlobTempBucketTag>();
+               shadows = new TreeMap<Long,PersistentBlobTempBucket>();
                jobRunner = jobRunner2;
                weakRandomSource = fastWeakRandom;
                this.ticker = ticker;
@@ -251,7 +255,7 @@
                                        Logger.error(this, "Slot "+slot+" 
already occupied by a not committed blob despite being in freeSlots!!");
                                        return null;
                                }
-                               PersistentBlobTempBucket bucket = new 
PersistentBlobTempBucket(this, blockSize, slot, tag);
+                               PersistentBlobTempBucket bucket = new 
PersistentBlobTempBucket(this, blockSize, slot, tag, false);
                                notCommittedBlobs.put(slot, bucket);
                                if(Logger.shouldLog(Logger.MINOR, this)) 
Logger.minor(this, "Using slot "+slot+" for "+bucket);
                                return bucket;
@@ -266,7 +270,7 @@
                                        Logger.error(this, "Slot "+slot+" 
already occupied by a not committed blob despite being in freeSlots!!");
                                        return null;
                                }
-                               PersistentBlobTempBucket bucket = new 
PersistentBlobTempBucket(this, blockSize, slot, tag);
+                               PersistentBlobTempBucket bucket = new 
PersistentBlobTempBucket(this, blockSize, slot, tag, false);
                                notCommittedBlobs.put(slot, bucket);
                                if(Logger.shouldLog(Logger.MINOR, this)) 
Logger.minor(this, "Using slot "+slot+" for "+bucket+" (after waiting)");
                                return bucket;
@@ -284,6 +288,10 @@
                        // If it hasn't been written to the database, it 
doesn't need to be removed, so removeFrom() won't be called.
                        freeSlots.put(index, bucket.tag);
                }
+               PersistentBlobTempBucket shadow = shadows.get(index);
+               if(shadow != null) {
+                       shadow.freed();
+               }
        }
 
        private long lastCheckedEnd = -1;
@@ -504,4 +512,24 @@
                almostFreeSlots.clear();
        }
 
+       public Bucket createShadow(PersistentBlobTempBucket bucket) {
+               long index = bucket.index;
+               Long i = index;
+               synchronized(this) {
+                       if(shadows.containsKey(i)) return null;
+                       PersistentBlobTempBucket shadow = new 
PersistentBlobTempBucket(this, blockSize, index, null, true);
+                       shadow.size = bucket.size;
+                       shadows.put(i, shadow);
+                       return shadow;
+               }
+       }
+
+       public synchronized void freeShadow(long index, 
PersistentBlobTempBucket bucket) {
+               PersistentBlobTempBucket temp = shadows.remove(index);
+               if(temp != bucket) {
+                       Logger.error(this, "Freed wrong shadow: "+temp+" should 
be "+bucket);
+                       shadows.put(index, temp);
+               }
+       }
+
 }

_______________________________________________
cvs mailing list
[email protected]
http://emu.freenetproject.org/cgi-bin/mailman/listinfo/cvs

Reply via email to