You are viewing a plain text version of this content. The canonical link for it is here.
Posted to kato-commits@incubator.apache.org by mo...@apache.org on 2009/10/28 15:15:31 UTC
svn commit: r830571 - in
/incubator/kato/trunk/org.apache.kato/kato.cjvmti/src:
main/java/org/apache/kato/jvmti/util/CachedRandomAccessFile.java
test/java/org/apache/kato/jvmti/util/CachedRandomAccessFileTest.java
Author: monteith
Date: Wed Oct 28 15:15:29 2009
New Revision: 830571
URL: http://svn.apache.org/viewvc?rev=830571&view=rev
Log:
Added some documentation and another test. That should be all for now.
Modified:
incubator/kato/trunk/org.apache.kato/kato.cjvmti/src/main/java/org/apache/kato/jvmti/util/CachedRandomAccessFile.java
incubator/kato/trunk/org.apache.kato/kato.cjvmti/src/test/java/org/apache/kato/jvmti/util/CachedRandomAccessFileTest.java
Modified: incubator/kato/trunk/org.apache.kato/kato.cjvmti/src/main/java/org/apache/kato/jvmti/util/CachedRandomAccessFile.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/org.apache.kato/kato.cjvmti/src/main/java/org/apache/kato/jvmti/util/CachedRandomAccessFile.java?rev=830571&r1=830570&r2=830571&view=diff
==============================================================================
--- incubator/kato/trunk/org.apache.kato/kato.cjvmti/src/main/java/org/apache/kato/jvmti/util/CachedRandomAccessFile.java (original)
+++ incubator/kato/trunk/org.apache.kato/kato.cjvmti/src/main/java/org/apache/kato/jvmti/util/CachedRandomAccessFile.java Wed Oct 28 15:15:29 2009
@@ -20,27 +20,73 @@
import java.util.LinkedHashMap;
import java.util.Map;
-public class CachedRandomAccessFile extends RandomAccessFile {
+/*
+ * This class could be modified to implement the write methods.
+ * To do so the write methods could be modified to behave much like
+ * the read methods. However, the cache would have to contain more
+ * than just bytes such that they contain a "modified" boolean value
+ * so the array can be written back to disk when they are pushed out
+ * of the cache. Consideration will also need to be paid to length()
+ * , setLength() and writing new cache blocks.
+ *
+ * CachedLinkHashMap.removeEldestEntry() is passed the entry to remove.
+ * This could test for modification and then write it out if necessary.
+ *
+ * The constructors must be modified to open a writable file, but
+ * it's not necessary for it to be
+ *
+ * A flush method can be added to allow the cache to be written out
+ * and the cache blocks to be marked as unmodified - class can
+ * be modified to implement Flushable.
+ *
+ *
+ * The close method will have to write out the remaining dirty
+ * pages before closing.
+ *
+ *
+ */
+
+/**
+ * <p>
+ * A read-only RandomAccessFile with caching.
+ * Implements an LRU cache to store blocks.
+ * Blocks are implemented as byte arrays.
+ * </p><p>
+ * Only overrides the read methods that must be implemented.
+ * The final read methods call the ones we have implemented here,
+ * {@link readUTF()}, for instance.
+ * </p><p>
+ * {@link getFD()} and {@link getChannel()} won't benefit
+ * from this class's caching and won't report the same
+ * file position that would be returned by {@link getFilePointer()}.
+ * Also, if the file pointer is modified by FileChannel,
+ * </p>
+ *
+ */
+final public class CachedRandomAccessFile extends RandomAccessFile {
// The default block size, in bits. 4096 bytes.
final static private int DEFAULT_BITS=12;
- final static private int DEFAULT_SIZE=32;// in MB
- int cacheFactor = 10; // cache 10th of a file
- int cacheBits; // Number of bits representing cache.
- int blockSize; // block size.
- long cacheUpperMask;
- long cacheLowerMask;
- long length;
- int numCacheEntries;
- long position=0l;
-
- CacheLinkedHashMap<Long,byte[]> cacheMap;
-
- /**
- * Returns the block of bytes at a particular address.
- *
- * @param pos
- * @return
- * @throws IOException
+ final static private int DEFAULT_SIZE=16;// in MB
+ private int cacheBits; // Number of bits representing cache.
+ private int blockSize; // block size.
+ private long cacheUpperMask; // For extracting cache tag
+ private long cacheLowerMask; // For extracting position in block
+ private long length; // Length of the file
+ private int numCacheEntries; // Number of cache entries to maintain
+ private long position=0l; // Position in file.
+
+ // The map from file locations to byte arrays.
+ private CacheLinkedHashMap<Long,byte[]> cacheMap;
+
+ /**
+ * Returns the block of bytes at a particular address.
+ * The pos parameter will be within the block, not necessarily
+ * the beginning of the block.
+ * If necessary the block will be loaded from disk.
+ *
+ * @param pos file pointer to return appropriate block for.
+ * @return byte[] containing blocks
+ * @throws IOException thrown if underlying read fails.
*/
byte[] getBlock(long pos) throws IOException {
long tag = (pos & cacheUpperMask) >> cacheBits;
@@ -55,8 +101,11 @@
}
if (blockSize > length) {
- block = new byte[(int)length];
+ // a file could be less than the blocksize in length.
+ block = new byte[(int)length];
} else if (pos > (length-blockSize)) {
+ // The last block in the file. File sizes are unlikely to be
+ // a multiple of the cache block size.
block = new byte[(int)(length-pos)];
} else {
block = new byte[blockSize];
@@ -71,10 +120,11 @@
}
/**
+ * Initialises the field variables and the cache.
*
* @param cacheBits size of cache block in powers of 2
* @param cacheSize size of cache in megabytes
- * @throws IOException
+ * @throws IOException if length() fails.
*/
private void init(int cacheBits, int cacheSize) throws IOException {
this.cacheBits = cacheBits;
@@ -89,30 +139,85 @@
this.cacheMap = new CacheLinkedHashMap<Long, byte[]>(numCacheEntries);
}
+ /**
+ * Creates a CachedRandomAccessFile open against the
+ * past File.
+ *
+ * @param file File to open.
+ * @throws IOException if file is not found.
+ */
public CachedRandomAccessFile(File file)
throws IOException {
this(file, DEFAULT_BITS, DEFAULT_SIZE);
}
+ /**
+ * Creates a CachedRandomAccessFile open against the
+ * past file name.
+ *
+ * @param name Name of file to open.
+ * @throws IOException if file is not found.
+ */
public CachedRandomAccessFile(String name)
throws IOException {
this(name, DEFAULT_BITS, DEFAULT_SIZE);
}
+ /**
+ * <p>Creates a CachedRandomAccessFile open against the
+ * past File.
+ * </p><p>
+ * The cacheBits parameter is the number of bits that are
+ * used to address entries within cache blocks. The default
+ * value is 12, which equates to 4096 bytes per block. This
+ * is the amount of data read at once and stored within the cache.
+ * </p><p>
+ * The cacheSize is the maximum amount of memory occupied by the cache.
+ * This value is in megabytes. The default is 16, which is 16 megabytes.
+ * </p>
+ *
+ * @param file File to open.
+ * @param cacheBits Number of bits representing cache block size
+ * @param cacheSize Cache size in megabytes.
+ * @throws IOException if file is not found.
+ */
public CachedRandomAccessFile(File file, int cacheBits, int cacheSize)
throws IOException {
super(file, "r");
init(cacheBits, cacheSize);
}
-
+ /**
+ * <p>Creates a CachedRandomAccessFile open against the
+ * past file name.
+ * </p><p>
+ * The cacheBits parameter is the number of bits that are
+ * used to address entries within cache blocks. The default
+ * value is 12, which equates to 4096 bytes per block. This
+ * is the amount of data read at once and stored within the cache.
+ * </p><p>
+ * The cacheSize is the maximum amount of memory occupied by the cache.
+ * This value is in megabytes. The default is 16, which is 16 megabytes.
+ * </p>
+ *
+ * @param name Name fo file to open.
+ * @param cacheBits Number of bits representing cache block size
+ * @param cacheSize Cache size in megabytes.
+ * @throws IOException if file is not found.
+ */
public CachedRandomAccessFile(String name, int cacheBits, int cacheSize)
throws IOException {
super(name, "r");
init(cacheBits, cacheSize);
}
-
+
+ /**
+ * Reads a byte value.
+ *
+ * @return unsigned byte value, or -1 if beyond end of file.
+ * @throws IOException if underlying read fails.
+ */
@Override
public int read() throws IOException {
// At end of file.
@@ -200,13 +305,25 @@
}
+ /**
+ * Returns the position within the file.
+ * The underlying RandomAccessFile file pointer may be different
+ * from this value as seeks are carried out only when cache blocks
+ * are read from disk.
+ *
+ */
@Override
public long getFilePointer() throws IOException {
return position;
}
/**
+ * Repositions the file-pointer offset to where the
+ * next read will occur. This does not affect the underlying
+ * RandomAccessFile unless a cache block has to be read in.
*
+ *
+ * @throws IOException is throws if pos is < 0.
*/
@Override
public void seek(long pos) throws IOException {
@@ -217,7 +334,10 @@
}
/**
- * Skips over the number
+ * Skips over some bytes without reading them.
+ * This doesn't affect the RandomAccessFile
+ * position.
+ *
* @param n number of bytes to skip over.
* @returns number of bytes skipped
*/
@@ -238,6 +358,15 @@
return n;
}
+ /**
+ * Closes the open file and empties the cache.
+ * As the cache is empty after this, future accesses
+ * will try to load the cache blocks from disk, and so
+ * will fail. Operations affecting the file position will
+ * continue to work without exceptions being thrown.
+ *
+ * @throws IOException if underlying close throws IOException.
+ */
@Override
public void close() throws IOException {
super.close();
@@ -249,43 +378,70 @@
// Don't allow any write operations
+ /**
+ * No write operations are supported, so an IOException is always
+ * thrown.
+ *
+ * @throws IOException is thrown unconditionally.
+ */
@Override
public void write(int b) throws IOException {
throw new IOException("CachedRandomAccessFile is not writable");
}
+ /**
+ * No write operations are supported, so an IOException is always
+ * thrown.
+ *
+ * @throws IOException is thrown unconditionally.
+ */
@Override
public void write(byte[] b) throws IOException {
throw new IOException("CachedRandomAccessFile is not writable");
}
+ /**
+ * No write operations are supported, so an IOException is always
+ * thrown.
+ *
+ * @throws IOException is thrown unconditionally.
+ */
@Override
public void write(byte[] b, int off, int len) throws IOException {
throw new IOException("CachedRandomAccessFile is not writable");
}
+ /**
+ * No write operations are supported, so an IOException is always
+ * thrown.
+ *
+ * @throws IOException is thrown unconditionally.
+ */
@Override
public void setLength(long newLength) throws IOException {
throw new IOException("CachedRandomAccessFile is not writable");
}
/**
- * LinkedHashMap for our caching purposes.
- * Ensures the cache uses access ordering.
+ * LinkedHashMap for our caching purposes.
+ * Used as a LRU cache, holding up to a fixed
+ * number of cache entries.
*
- *
- * @param <K>
- * @param <V>
+ * @param <K> Key type
+ * @param <V> Value type
*/
- private static class CacheLinkedHashMap<K,V> extends LinkedHashMap<K,V> {
+ @SuppressWarnings("serial")
+ private final static class CacheLinkedHashMap<K,V> extends LinkedHashMap<K,V> {
private int maxCacheEntries;
/**
+ * Creates a LinkedHashMap with access ordering.
+ * The oldest entry is the oldest entry to be put or
+ * got.
+ * Takes the number of entries to cache.
*
*
- *
- * @param initialCapacity
- * @param maxCacheEntries
+ * @param maxCacheEntries maximum number of entries to hold.
*/
public CacheLinkedHashMap(int maxCacheEntries) {
super(maxCacheEntries, 0.75f, true);
@@ -298,7 +454,7 @@
* the cache size.
*
* @return true if cache entry is to be removed.
- * @param entru
+ * @param entry oldest entry to handle.
*/
@Override
protected boolean removeEldestEntry(Map.Entry<K,V> entry) {
Modified: incubator/kato/trunk/org.apache.kato/kato.cjvmti/src/test/java/org/apache/kato/jvmti/util/CachedRandomAccessFileTest.java
URL: http://svn.apache.org/viewvc/incubator/kato/trunk/org.apache.kato/kato.cjvmti/src/test/java/org/apache/kato/jvmti/util/CachedRandomAccessFileTest.java?rev=830571&r1=830570&r2=830571&view=diff
==============================================================================
--- incubator/kato/trunk/org.apache.kato/kato.cjvmti/src/test/java/org/apache/kato/jvmti/util/CachedRandomAccessFileTest.java (original)
+++ incubator/kato/trunk/org.apache.kato/kato.cjvmti/src/test/java/org/apache/kato/jvmti/util/CachedRandomAccessFileTest.java Wed Oct 28 15:15:29 2009
@@ -101,6 +101,29 @@
}
/**
+ * Tests that reading a closed file fails with an IOException.
+ *
+ * @throws Exception
+ */
+ public void testClose() throws Exception {
+ craf = new CachedRandomAccessFile(file, 2, 32);
+ byte bytes[] = new byte[FILE_SIZE];
+
+ craf.read(bytes);
+
+ craf.close();
+
+ craf.seek(0);
+
+ try{
+ craf.read(bytes);
+ fail("Failed to throw IOException on closed file.");
+ } catch (IOException e) {
+ // expected
+ }
+
+ }
+ /**
* Check that when the file is read into an offset
* within the array, that only the bytes in the file
* are read.