From: <ls...@us...> - 2011-08-21 20:03:14
|
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. |