Revision: 5857
          http://jnode.svn.sourceforge.net/jnode/?rev=5857&view=rev
Author:   lsantha
Date:     2011-08-21 20:03:08 +0000 (Sun, 21 Aug 2011)

Log Message:
-----------
A RAMFile is stored in a list of Buffer object to support arbitrary large files.

Modified Paths:
--------------
    trunk/fs/src/fs/org/jnode/fs/ramfs/RAMFile.java

Modified: trunk/fs/src/fs/org/jnode/fs/ramfs/RAMFile.java
===================================================================
--- trunk/fs/src/fs/org/jnode/fs/ramfs/RAMFile.java     2011-08-21 20:00:18 UTC 
(rev 5856)
+++ trunk/fs/src/fs/org/jnode/fs/ramfs/RAMFile.java     2011-08-21 20:03:08 UTC 
(rev 5857)
@@ -21,8 +21,11 @@
 package org.jnode.fs.ramfs;
 
 import java.io.IOException;
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 
+import java.util.ArrayList;
 import org.jnode.fs.FSAccessRights;
 import org.jnode.fs.FSDirectory;
 import org.jnode.fs.FSEntry;
@@ -34,6 +37,7 @@
  * A File implementation in the system RAM
  * 
  * @author peda
+ * @author Levente S\u00e1ntha
  */
 public class RAMFile implements FSEntry, FSFile {
 
@@ -41,7 +45,7 @@
     private RAMDirectory parent;
 
     private String filename;
-    private ByteBuffer buffer;
+    private BufferList bufferList;
 
     private long created;
     private long lastModified;
@@ -63,42 +67,36 @@
 
         // TODO accessRights
 
-        buffer = ByteBuffer.allocate(128);
-        buffer.limit(0);
+        bufferList = new BufferList();
 
         fileSystem = (RAMFileSystem) parent.getFileSystem();
 
-        fileSystem.addSummmedBufferSize(128);
+        fileSystem.addSummmedBufferSize(bufferList.capacity());
     }
 
     private void enlargeBuffer() throws FileSystemFullException {
 
-        int oldCapacity = buffer.capacity();
+        int oldCapacity = bufferList.capacity();
 
         if (oldCapacity > fileSystem.getFreeSpace())
             throw new FileSystemFullException("RAMFileSystem reached maxSize");
 
-        ByteBuffer temp = ByteBuffer.allocate(oldCapacity * 2);
-        buffer.position(0);
-        temp.put(buffer);
-        buffer = temp;
-        buffer.position(0);
+        bufferList.enlarge();
+        int newCapacity = bufferList.capacity();
 
         // update fileSystem values
-        fileSystem.addSummmedBufferSize(oldCapacity);
+        fileSystem.addSummmedBufferSize(newCapacity - oldCapacity);
     }
 
     private void shrinkBuffer() {
 
-        int toShrink = buffer.capacity() / 2;
+        int oldCapacity = bufferList.capacity();
 
-        ByteBuffer temp = ByteBuffer.allocate(toShrink);
-        temp.put(buffer.array(), 0, toShrink);
-        buffer = temp;
-        buffer.position(0);
+        bufferList.shrink();
+        int newCapacity = bufferList.capacity();
 
         // update fileSystem counter
-        fileSystem.addSummmedBufferSize(-toShrink);
+        fileSystem.addSummmedBufferSize(newCapacity - oldCapacity);
     }
 
     /**
@@ -232,7 +230,7 @@
      * @see org.jnode.fs.FSFile#getLength()
      */
     public long getLength() {
-        return buffer.limit();
+        return bufferList.limit();
     }
 
     /**
@@ -245,15 +243,15 @@
         if (length > Integer.MAX_VALUE)
             throw new IOException("Filesize too large");
 
-        while (buffer.capacity() < length)
+        while (bufferList.capacity() < length)
             enlargeBuffer();
 
-        long toEnlarge = length - buffer.limit();
+        long toEnlarge = length - bufferList.limit();
 
-        while (length < buffer.capacity() / 2)
+        while (length < bufferList.capacity() / 2)
             shrinkBuffer();
 
-        buffer.limit((int) length);
+        bufferList.limit((int) length);
 
         // update fileSystem counters
         fileSystem.addSummedFileSize(toEnlarge);
@@ -267,14 +265,14 @@
      */
     public void read(long fileOffset, ByteBuffer dest) throws IOException {
 
-        long currentSize = buffer.limit();
+        long currentSize = bufferList.limit();
         long toRead = dest.limit();
 
         if (fileOffset + toRead > currentSize)
             throw new IOException("FileOffest outside file");
 
-        buffer.position((int) fileOffset);
-        buffer.get(dest.array(), 0, dest.limit());
+        bufferList.position((int) fileOffset);
+        bufferList.get(dest.array(), 0, dest.limit());
     }
 
     /**
@@ -284,14 +282,14 @@
      */
     public void write(long fileOffset, ByteBuffer src) throws IOException {
 
-        long currentSize = buffer.limit();
+        long currentSize = bufferList.limit();
         long toWrite = src.limit();
 
         if (fileOffset + toWrite >= currentSize)
             setLength(fileOffset + toWrite);
 
-        buffer.position((int) fileOffset);
-        buffer.put(src);
+        bufferList.position((int) fileOffset);
+        bufferList.put(src);
         setLastModified(System.currentTimeMillis());
     }
 
@@ -305,13 +303,184 @@
 
     void remove() throws IOException {
 
-        long capacity = buffer.capacity();
+        long capacity = bufferList.capacity();
         long filesize = getLength();
 
         this.parent = null;
-        this.buffer = null;
+        this.bufferList = null;
 
         fileSystem.addSummedFileSize(-filesize);
         fileSystem.addSummmedBufferSize(-capacity);
     }
+
+    /**
+     * A resizing Buffer-like structure combining a set of NIO Buffers into 
one entity.
+     *
+     * @author Levente S\u00e1ntha
+     */
+    private static class BufferList {
+        private static final int MAX_BUFFER_SIZE = 12 * 1024 * 1024;
+        private final ArrayList<ByteBuffer> bufferList;
+
+        BufferList() {
+            bufferList = new ArrayList<ByteBuffer>();
+            ByteBuffer buffer = ByteBuffer.allocate(128);
+            buffer.limit(0);
+            bufferList.add(buffer);
+        }
+
+        private void enlarge() {
+            int oldCapacity = capacity();
+            if (bufferList.size() == 1) {
+                final ByteBuffer oldBuffer = bufferList.get(0);
+                final int newCapacity = oldCapacity * 2;
+                bufferList.clear();
+                if (newCapacity > MAX_BUFFER_SIZE) {
+                    final ByteBuffer newBuffer = 
ByteBuffer.allocate(MAX_BUFFER_SIZE);
+                    oldBuffer.position(0);
+                    newBuffer.put(oldBuffer);
+                    newBuffer.position(0);
+
+                    bufferList.add(newBuffer);
+                    bufferList.add(ByteBuffer.allocate(newCapacity - 
MAX_BUFFER_SIZE));
+                } else {
+                    ByteBuffer buffer2 = ByteBuffer.allocate(newCapacity);
+                    oldBuffer.position(0);
+                    buffer2.put(oldBuffer);
+                    buffer2.position(0);
+
+                    bufferList.add(buffer2);
+                }
+            } else {
+                bufferList.add(ByteBuffer.allocate(MAX_BUFFER_SIZE));
+            }
+        }
+
+        private void shrink() {
+            final int oldCapacity = capacity();
+            if (bufferList.size() == 1) {
+                final ByteBuffer oldBuffer = bufferList.get(0);
+                final int newCapacity = oldCapacity / 2;
+                bufferList.clear();
+
+                final ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity);
+                oldBuffer.position(0);
+                oldBuffer.limit(newCapacity);
+                newBuffer.put(oldBuffer);
+                newBuffer.position(0);
+
+                bufferList.add(newBuffer);
+            } else {
+                bufferList.remove(bufferList.size() - 1);
+            }
+        }
+
+        private int capacity() {
+            int capacity = 0;
+            for (ByteBuffer buffer : bufferList) {
+                capacity += buffer.capacity();
+            }
+            return capacity;
+        }
+
+        private int limit() {
+            int limit = 0;
+            for (ByteBuffer buffer : bufferList) {
+                limit += buffer.limit();
+            }
+            return limit;
+        }
+
+        private void limit(int limit) {
+            for (ByteBuffer buffer : bufferList) {
+                if (limit < 0) {
+                    buffer.limit(0);
+                } else {
+                    int capacity = buffer.capacity();
+                    if (limit <= capacity) {
+                        buffer.limit(limit);
+                    } else {
+                        buffer.limit(capacity);
+                    }
+                    limit -= capacity;
+                }
+            }
+        }
+
+        private int position() {
+            int position = 0;
+            for (ByteBuffer buffer : bufferList) {
+                position += buffer.position();
+            }
+            return position;
+        }
+
+        public void position(int position) {
+            for (ByteBuffer buffer : bufferList) {
+                if (position < 0) {
+                    buffer.position(0);
+                } else {
+                    int limit = buffer.limit();
+                    if (position <= limit) {
+                        buffer.position(position);
+                    } else {
+                        buffer.position(limit);
+                    }
+                    position -= limit;
+                }
+            }
+        }
+
+        public int remaining() {
+            int remaining = 0;
+            for (ByteBuffer buffer : bufferList) {
+                remaining += buffer.remaining();
+            }
+            return remaining;
+        }
+
+        public void get(byte[] array, int offset, int length) {
+
+            if ((offset | length | (offset + length) | (array.length - (offset 
+ length))) < 0)
+                throw new IndexOutOfBoundsException();
+
+            if (length > remaining())
+                throw new BufferUnderflowException();
+
+            for (ByteBuffer buffer : bufferList) {
+                int remaining = buffer.remaining();
+                if (remaining > 0) {
+                    if (length > remaining) {
+                        buffer.get(array, offset, remaining);
+                        offset += remaining;
+                        length -= remaining;
+                    } else {
+                        buffer.get(array, offset, length);
+                        return;
+                    }
+                }
+            }
+        }
+
+        public void put(ByteBuffer src) {
+            int length = src.remaining();
+            if (length > remaining())
+                throw new BufferOverflowException();
+
+            for (ByteBuffer buffer : bufferList) {
+                int remaining = buffer.remaining();
+                if (remaining > 0) {
+                    if (length > remaining) {
+                        src.limit(src.position() + remaining);
+                        buffer.put(src);
+                        length -= remaining;
+                    } else {
+                        src.limit(src.position() + length);
+                        buffer.put(src);
+                        return;
+                    }
+                }
+            }
+        }
+    }
 }


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

------------------------------------------------------------------------------
Get a FREE DOWNLOAD! and learn more about uberSVN rich system, 
user administration capabilities and model configuration. Take 
the hassle out of deploying and managing Subversion and the 
tools developers use with it. http://p.sf.net/sfu/wandisco-d2d-2
_______________________________________________
Jnode-svn-commits mailing list
Jnode-svn-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jnode-svn-commits

Reply via email to