1. Modified BufferCache to have a maxOpenFiles parameter. 2. BufferCache will not invalidate and flush pages upon last close of a file. 3. Pages of unreferenced files are invalidated and flushed lazily during a new openFile request.

git-svn-id: https://hyracks.googlecode.com/svn/branches/hyracks_indexes@471 123451ca-8445-de46-9d55-352943316053
diff --git a/hyracks-examples/btree-example/btreehelper/src/main/java/edu/uci/ics/hyracks/examples/btree/helper/RuntimeContext.java b/hyracks-examples/btree-example/btreehelper/src/main/java/edu/uci/ics/hyracks/examples/btree/helper/RuntimeContext.java
index 9f99468..623e625 100644
--- a/hyracks-examples/btree-example/btreehelper/src/main/java/edu/uci/ics/hyracks/examples/btree/helper/RuntimeContext.java
+++ b/hyracks-examples/btree-example/btreehelper/src/main/java/edu/uci/ics/hyracks/examples/btree/helper/RuntimeContext.java
@@ -37,7 +37,7 @@
         fileMapManager = new TransientFileMapManager();
         ICacheMemoryAllocator allocator = new HeapBufferAllocator();
         IPageReplacementStrategy prs = new ClockPageReplacementStrategy();
-        bufferCache = new BufferCache(appCtx.getRootContext().getIOManager(), allocator, prs, fileMapManager, 32768, 50);
+        bufferCache = new BufferCache(appCtx.getRootContext().getIOManager(), allocator, prs, fileMapManager, 32768, 50, 100);
         btreeRegistry = new BTreeRegistry();
     }
 
diff --git a/hyracks-examples/hyracks-integration-tests/src/test/java/edu/uci/ics/hyracks/tests/btree/BTreeOperatorsTest.java b/hyracks-examples/hyracks-integration-tests/src/test/java/edu/uci/ics/hyracks/tests/btree/BTreeOperatorsTest.java
index b9426d3..6a10daa 100644
--- a/hyracks-examples/hyracks-integration-tests/src/test/java/edu/uci/ics/hyracks/tests/btree/BTreeOperatorsTest.java
+++ b/hyracks-examples/hyracks-integration-tests/src/test/java/edu/uci/ics/hyracks/tests/btree/BTreeOperatorsTest.java
@@ -66,7 +66,7 @@
 
 public class BTreeOperatorsTest extends AbstractIntegrationTest {
 	static {
-		TestStorageManagerComponentHolder.init(8192, 20);
+		TestStorageManagerComponentHolder.init(8192, 20, 20);
 	}
 
 	private IStorageManagerInterface storageManager = new TestStorageManagerInterface();
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/BufferCache.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/BufferCache.java
index c2693ab..f9ac4d5 100644
--- a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/BufferCache.java
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/BufferCache.java
@@ -39,6 +39,8 @@
 
     private static final int MAX_VICTIMIZATION_TRY_COUNT = 3;
 
+    private final int maxOpenFiles;
+    
     private final IIOManager ioManager;
     private final int pageSize;
     private final int numPages;
@@ -52,10 +54,11 @@
     private boolean closed;
 
     public BufferCache(IIOManager ioManager, ICacheMemoryAllocator allocator,
-            IPageReplacementStrategy pageReplacementStrategy, IFileMapManager fileMapManager, int pageSize, int numPages) {
+            IPageReplacementStrategy pageReplacementStrategy, IFileMapManager fileMapManager, int pageSize, int numPages, int maxOpenFiles) {
         this.ioManager = ioManager;
         this.pageSize = pageSize;
         this.numPages = numPages;
+        this.maxOpenFiles = maxOpenFiles;
         pageReplacementStrategy.setBufferCache(this);
         ByteBuffer[] buffers = allocator.allocate(pageSize, numPages);
         cachedPages = new CachedPage[buffers.length];
@@ -84,11 +87,50 @@
         return numPages;
     }
 
-    @Override
-    public ICachedPage pin(long dpid, boolean newPage) throws HyracksDataException {
+    private void pinSanityCheck(long dpid) throws HyracksDataException {
         if (closed) {
             throw new HyracksDataException("pin called on a closed cache");
         }
+        
+        // check whether file has been created and opened
+        int fileId = BufferedFileHandle.getFileId(dpid);
+        BufferedFileHandle fInfo = fileInfoMap.get(fileId);
+        if(fInfo == null) {
+            throw new HyracksDataException("pin called on a fileId " + fileId + " that has not been created.");
+        } else if(fInfo.getReferenceCount() <= 0) {
+            throw new HyracksDataException("pin called on a fileId " + fileId + " that has not been opened.");
+        }
+    }
+    
+    @Override 
+    public ICachedPage tryPin(long dpid) throws HyracksDataException {        
+        pinSanityCheck(dpid);
+        
+        CachedPage cPage = null;
+        int hash = hash(dpid);
+        CacheBucket bucket = pageMap[hash];
+        bucket.bucketLock.lock();
+        try {
+            cPage = bucket.cachedPage;
+            while (cPage != null) {
+                if (cPage.dpid == dpid) {
+                    cPage.pinCount.incrementAndGet();
+                    pageReplacementStrategy.notifyCachePageAccess(cPage);
+                    return cPage;
+                }
+                cPage = cPage.next;
+            }
+        } finally {
+            bucket.bucketLock.unlock();
+        }
+        
+        return cPage;
+    }
+    
+    @Override
+    public ICachedPage pin(long dpid, boolean newPage) throws HyracksDataException {
+        pinSanityCheck(dpid);
+        
         CachedPage cPage = findPage(dpid, newPage);
         if (!newPage) {
             if (!cPage.valid) {
@@ -472,7 +514,7 @@
     }
 
     @Override
-    public void close() {
+    public void close() {        
         closed = true;
         synchronized (cleanerThread) {
             cleanerThread.shutdownStart = true;
@@ -484,7 +526,19 @@
                     e.printStackTrace();
                 }
             }
-        }
+        }    
+        
+        synchronized (fileInfoMap) {
+            try {
+                for(Map.Entry<Integer, BufferedFileHandle> entry : fileInfoMap.entrySet()) {
+                    sweepAndFlush(entry.getKey());
+                    ioManager.close(entry.getValue().getFileHandle());
+                }
+            } catch(HyracksDataException e) {
+                e.printStackTrace();
+            }
+            fileInfoMap.clear();
+        }        
     }
 
     @Override
@@ -506,6 +560,29 @@
             BufferedFileHandle fInfo;
             fInfo = fileInfoMap.get(fileId);
             if (fInfo == null) {
+                
+                // map is full, make room by removing cleaning up unreferenced files
+                boolean unreferencedFileFound = true;
+                while(fileInfoMap.size() >= maxOpenFiles && unreferencedFileFound) {                
+                    unreferencedFileFound = false;                    
+                    for(Map.Entry<Integer, BufferedFileHandle> entry : fileInfoMap.entrySet()) {
+                        if(entry.getValue().getReferenceCount() <= 0) {
+                            int entryFileId = entry.getKey();
+                            sweepAndFlush(entryFileId);
+                            fileInfoMap.remove(entryFileId);
+                            ioManager.close(entry.getValue().getFileHandle());
+                            unreferencedFileFound = true;
+                            // for-each iterator is invalid because we changed fileInfoMap
+                            break;
+                        }
+                    }
+                }
+                
+                if(fileInfoMap.size() >= maxOpenFiles) {
+                    throw new HyracksDataException("Could not open fileId " + fileId + ". Max number of files " + maxOpenFiles + " already opened and referenced.");
+                }
+                
+                // create, open, and map new file reference
                 FileReference fileRef = fileMapManager.lookupFileName(fileId);
                 FileHandle fh = ioManager.open(fileRef, IIOManager.FileReadWriteMode.READ_WRITE,
                         IIOManager.FileSyncMode.METADATA_ASYNC_DATA_ASYNC);
@@ -515,7 +592,7 @@
             fInfo.incReferenceCount();
         }
     }
-
+        
     private void sweepAndFlush(int fileId) throws HyracksDataException {
         for (int i = 0; i < pageMap.length; ++i) {
             CacheBucket bucket = pageMap[i];
@@ -574,10 +651,8 @@
             if (fInfo == null) {
                 throw new HyracksDataException("Closing unopened file");
             }
-            if (fInfo.decReferenceCount() <= 0) {
-                sweepAndFlush(fileId);
-                fileInfoMap.remove(fileId);
-                ioManager.close(fInfo.getFileHandle());
+            if (fInfo.decReferenceCount() < 0) {
+                throw new HyracksDataException("Closed fileId: " + fileId + " more times than it was opened.");                                
             }
         }
     }
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/IBufferCache.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/IBufferCache.java
index b21c054..e82c01b 100644
--- a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/IBufferCache.java
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/buffercache/IBufferCache.java
@@ -26,6 +26,8 @@
 
     public void deleteFile(int fileId) throws HyracksDataException;
 
+    public ICachedPage tryPin(long dpid) throws HyracksDataException;
+
     public ICachedPage pin(long dpid, boolean newPage) throws HyracksDataException;
 
     public void unpin(ICachedPage page) throws HyracksDataException;
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/file/BufferedFileHandle.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/file/BufferedFileHandle.java
index 1db0bf7..3137f20 100644
--- a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/file/BufferedFileHandle.java
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/file/BufferedFileHandle.java
@@ -44,6 +44,10 @@
     public int decReferenceCount() {
         return refCount.decrementAndGet();
     }
+    
+    public int getReferenceCount() {
+        return refCount.get();
+    }
 
     public long getDiskPageId(int pageId) {
         return getDiskPageId(fileId, pageId);
diff --git a/hyracks-test-support/src/main/java/edu/uci/ics/hyracks/test/support/TestStorageManagerComponentHolder.java b/hyracks-test-support/src/main/java/edu/uci/ics/hyracks/test/support/TestStorageManagerComponentHolder.java
index 5338d5e..3dfeac4 100644
--- a/hyracks-test-support/src/main/java/edu/uci/ics/hyracks/test/support/TestStorageManagerComponentHolder.java
+++ b/hyracks-test-support/src/main/java/edu/uci/ics/hyracks/test/support/TestStorageManagerComponentHolder.java
@@ -33,10 +33,12 @@
 
     private static int pageSize;
     private static int numPages;
+    private static int maxOpenFiles;
 
-    public static void init(int pageSize, int numPages) {
+    public static void init(int pageSize, int numPages, int maxOpenFiles) {
         TestStorageManagerComponentHolder.pageSize = pageSize;
         TestStorageManagerComponentHolder.numPages = numPages;
+        TestStorageManagerComponentHolder.maxOpenFiles = maxOpenFiles;
         bufferCache = null;
         fileMapProvider = null;
         btreeRegistry = null;
@@ -48,7 +50,7 @@
             IPageReplacementStrategy prs = new ClockPageReplacementStrategy();
             IFileMapProvider fileMapProvider = getFileMapProvider(ctx);
             bufferCache = new BufferCache(ctx.getIOManager(), allocator, prs, (IFileMapManager) fileMapProvider,
-                    pageSize, numPages);
+                    pageSize, numPages, maxOpenFiles);
         }
         return bufferCache;
     }
diff --git a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeFieldPrefixNSMTest.java b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeFieldPrefixNSMTest.java
index 8ef1c40..cfbc622 100644
--- a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeFieldPrefixNSMTest.java
+++ b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeFieldPrefixNSMTest.java
@@ -47,7 +47,6 @@
 import edu.uci.ics.hyracks.storage.am.common.ophelpers.MultiComparator;
 import edu.uci.ics.hyracks.storage.am.common.tuples.TypeAwareTupleWriter;
 import edu.uci.ics.hyracks.storage.common.buffercache.IBufferCache;
-import edu.uci.ics.hyracks.storage.common.buffercache.ICacheMemoryAllocator;
 import edu.uci.ics.hyracks.storage.common.buffercache.ICachedPage;
 import edu.uci.ics.hyracks.storage.common.file.BufferedFileHandle;
 import edu.uci.ics.hyracks.storage.common.file.IFileMapProvider;
@@ -58,20 +57,10 @@
 
 	private static final int PAGE_SIZE = 32768; // 32K
 	private static final int NUM_PAGES = 40;
+	private static final int MAX_OPEN_FILES = 10;
 	private static final int HYRACKS_FRAME_SIZE = 128;
 	private IHyracksStageletContext ctx = TestUtils.create(HYRACKS_FRAME_SIZE);
-	
-	public class BufferAllocator implements ICacheMemoryAllocator {
-		@Override
-		public ByteBuffer[] allocate(int pageSize, int numPages) {
-			ByteBuffer[] buffers = new ByteBuffer[numPages];
-			for (int i = 0; i < numPages; ++i) {
-				buffers[i] = ByteBuffer.allocate(pageSize);
-			}
-			return buffers;
-		}
-	}
-
+		
 	private ITupleReference createTuple(IHyracksStageletContext ctx, int f0,
 			int f1, int f2, boolean print) throws HyracksDataException {
 		if (print)
@@ -112,7 +101,7 @@
 	@Test
 	public void test01() throws Exception {
 		
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
diff --git a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeStatsTest.java b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeStatsTest.java
index df8da57..df7be4f 100644
--- a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeStatsTest.java
+++ b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeStatsTest.java
@@ -53,20 +53,14 @@
 	//private static final int PAGE_SIZE = 32768;
     private static final int PAGE_SIZE = 4096;
     private static final int NUM_PAGES = 1000;
+    private static final int MAX_OPEN_FILES = 10;
 	private static final int HYRACKS_FRAME_SIZE = 128;
 	private IHyracksStageletContext ctx = TestUtils.create(HYRACKS_FRAME_SIZE);
-
-	// FIXED-LENGTH KEY TEST
-	// create a B-tree with one fixed-length "key" field and one fixed-length
-	// "value" field
-	// fill B-tree with random values using insertions (not bulk load)
-	// perform ordered scan and range search
+	
 	@Test
 	public void test01() throws Exception {
 
-		print("FIXED-LENGTH KEY TEST\n");
-
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
@@ -135,9 +129,9 @@
 				TreeIndexOp.TI_INSERT, leafFrame, interiorFrame, metaFrame);
 
 		// 10000
-		for (int i = 0; i < 1000000; i++) {
+		for (int i = 0; i < 100000; i++) {
 
-			int f0 = rnd.nextInt() % 1000000;
+			int f0 = rnd.nextInt() % 100000;
 			int f1 = 5;
 
 			tb.reset();
@@ -151,10 +145,7 @@
 					.getSize());
 
 			tuple.reset(accessor, 0);
-
-			// System.out.println(tuple.getFieldCount() + " " +
-			// tuple.getFieldLength(0) + " " + tuple.getFieldLength(1));
-
+			
 			if (i % 10000 == 0) {
 				long end = System.currentTimeMillis();
 				print("INSERTING " + i + " : " + f0 + " " + f1 + " "
@@ -166,14 +157,8 @@
 			} catch (TreeIndexException e) {
 			} catch (Exception e) {
 				e.printStackTrace();
-			}
-
-			// btree.printTree(leafFrame, interiorFrame);
-			// System.out.println();
+			}			
 		}
-		// btree.printTree(leafFrame, interiorFrame);
-		// System.out.println();
-
 		
 		TreeIndexStatsGatherer statsGatherer = new TreeIndexStatsGatherer(bufferCache, freePageManager, fileId, btree.getRootPageId());		
 		TreeIndexStats stats = statsGatherer.gatherStats(leafFrame, interiorFrame, metaFrame);
diff --git a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeTest.java b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeTest.java
index 76f42f9..14b5903 100644
--- a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeTest.java
+++ b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/BTreeTest.java
@@ -62,7 +62,6 @@
 import edu.uci.ics.hyracks.storage.am.common.tuples.SimpleTupleWriterFactory;
 import edu.uci.ics.hyracks.storage.am.common.tuples.TypeAwareTupleWriterFactory;
 import edu.uci.ics.hyracks.storage.common.buffercache.IBufferCache;
-import edu.uci.ics.hyracks.storage.common.buffercache.ICacheMemoryAllocator;
 import edu.uci.ics.hyracks.storage.common.file.IFileMapProvider;
 import edu.uci.ics.hyracks.test.support.TestStorageManagerComponentHolder;
 import edu.uci.ics.hyracks.test.support.TestUtils;
@@ -71,20 +70,10 @@
 
 	private static final int PAGE_SIZE = 256;	
 	private static final int NUM_PAGES = 10;	
+	private static final int MAX_OPEN_FILES = 10;
 	private static final int HYRACKS_FRAME_SIZE = 128;
 	private IHyracksStageletContext ctx = TestUtils.create(HYRACKS_FRAME_SIZE);
-
-	public class BufferAllocator implements ICacheMemoryAllocator {
-		@Override
-		public ByteBuffer[] allocate(int pageSize, int numPages) {
-			ByteBuffer[] buffers = new ByteBuffer[numPages];
-			for (int i = 0; i < numPages; ++i) {
-				buffers[i] = ByteBuffer.allocate(pageSize);
-			}
-			return buffers;
-		}
-	}
-
+	
 	// FIXED-LENGTH KEY TEST
 	// create a B-tree with one fixed-length "key" field and one fixed-length
 	// "value" field
@@ -95,7 +84,7 @@
 
 		print("FIXED-LENGTH KEY TEST\n");
 
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
@@ -328,7 +317,7 @@
 
 		print("COMPOSITE KEY TEST\n");
 
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
@@ -539,7 +528,7 @@
 
 		print("VARIABLE-LENGTH KEY TEST\n");
 
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
@@ -738,7 +727,7 @@
 
 		print("DELETION TEST\n");
 
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
@@ -922,7 +911,7 @@
 
 		print("BULK LOAD TEST\n");
 
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
@@ -1099,7 +1088,7 @@
 
 		print("TIME-INTERVAL INTERSECTION DEMO\n");
 
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
diff --git a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/RangeSearchCursorTest.java b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/RangeSearchCursorTest.java
index 320fa1d..9ee3cb6 100644
--- a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/RangeSearchCursorTest.java
+++ b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/RangeSearchCursorTest.java
@@ -67,7 +67,6 @@
 import edu.uci.ics.hyracks.storage.am.common.ophelpers.TreeIndexOp;
 import edu.uci.ics.hyracks.storage.am.common.tuples.TypeAwareTupleWriterFactory;
 import edu.uci.ics.hyracks.storage.common.buffercache.IBufferCache;
-import edu.uci.ics.hyracks.storage.common.buffercache.ICacheMemoryAllocator;
 import edu.uci.ics.hyracks.storage.common.file.IFileMapProvider;
 import edu.uci.ics.hyracks.test.support.TestStorageManagerComponentHolder;
 import edu.uci.ics.hyracks.test.support.TestUtils;
@@ -75,18 +74,8 @@
 public class RangeSearchCursorTest extends AbstractBTreeTest {
 	private static final int PAGE_SIZE = 256;
 	private static final int NUM_PAGES = 10;
-	private static final int HYRACKS_FRAME_SIZE = 128;
-
-	public class BufferAllocator implements ICacheMemoryAllocator {
-		@Override
-		public ByteBuffer[] allocate(int pageSize, int numPages) {
-			ByteBuffer[] buffers = new ByteBuffer[numPages];
-			for (int i = 0; i < numPages; ++i) {
-				buffers[i] = ByteBuffer.allocate(pageSize);
-			}
-			return buffers;
-		}
-	}
+	private static final int MAX_OPEN_FILES = 10;
+	private static final int HYRACKS_FRAME_SIZE = 128;	
 
 	// declare fields
 	int fieldCount = 2;
@@ -130,7 +119,7 @@
 
 		System.out.println("TESTING RANGE SEARCH CURSOR ON UNIQUE INDEX");
 
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
@@ -235,7 +224,7 @@
 
 		System.out.println("TESTING RANGE SEARCH CURSOR ON NONUNIQUE INDEX");
 
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
@@ -344,7 +333,7 @@
 				tupleWriterFactory);
 		IBTreeLeafFrame leafFrame = leafFrameFactory.getFrame();
 
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
diff --git a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java
index 430a33c..1f08145 100644
--- a/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java
+++ b/hyracks-tests/hyracks-storage-am-btree-test/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java
@@ -25,6 +25,7 @@
 import edu.uci.ics.hyracks.api.context.IHyracksStageletContext;
 import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
 import edu.uci.ics.hyracks.api.io.FileReference;
+import edu.uci.ics.hyracks.storage.am.btree.AbstractBTreeTest;
 import edu.uci.ics.hyracks.storage.common.buffercache.IBufferCache;
 import edu.uci.ics.hyracks.storage.common.buffercache.ICachedPage;
 import edu.uci.ics.hyracks.storage.common.file.BufferedFileHandle;
@@ -36,6 +37,8 @@
 public class StorageManagerTest extends AbstractBTreeTest {
 	private static final int PAGE_SIZE = 256;
 	private static final int NUM_PAGES = 10;
+	private static final int MAX_OPEN_FILES = 10;
+	private static final int HYRACKS_FRAME_SIZE = 128;
 	private IHyracksStageletContext ctx = TestUtils.create(32768);
 
 	public class PinnedLatchedPage {
@@ -247,7 +250,7 @@
 
 	@Test
 	public void oneThreadOneFileTest() throws Exception {
-		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+		TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
 		IBufferCache bufferCache = TestStorageManagerComponentHolder
 				.getBufferCache(ctx);
 		IFileMapProvider fmp = TestStorageManagerComponentHolder
diff --git a/hyracks-tests/hyracks-storage-am-invertedindex-test/src/test/java/edu/uci/ics/hyracks/storage/am/invertedindex/BulkLoadTest.java b/hyracks-tests/hyracks-storage-am-invertedindex-test/src/test/java/edu/uci/ics/hyracks/storage/am/invertedindex/BulkLoadTest.java
index df96900..d4a9c4f 100644
--- a/hyracks-tests/hyracks-storage-am-invertedindex-test/src/test/java/edu/uci/ics/hyracks/storage/am/invertedindex/BulkLoadTest.java
+++ b/hyracks-tests/hyracks-storage-am-invertedindex-test/src/test/java/edu/uci/ics/hyracks/storage/am/invertedindex/BulkLoadTest.java
@@ -60,16 +60,16 @@
 
 public class BulkLoadTest extends AbstractInvIndexTest {
 	
-    // private static final int PAGE_SIZE = 65536;
     private static final int PAGE_SIZE = 32768;
     private static final int NUM_PAGES = 100;
+    private static final int MAX_OPEN_FILES = 10;
     private static final int HYRACKS_FRAME_SIZE = 32768;
     private IHyracksStageletContext stageletCtx = TestUtils.create(HYRACKS_FRAME_SIZE);    
 
     @Test
     public void singleFieldPayloadTest() throws Exception {
 
-        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
         IBufferCache bufferCache = TestStorageManagerComponentHolder.getBufferCache(stageletCtx);
         IFileMapProvider fmp = TestStorageManagerComponentHolder.getFileMapProvider(stageletCtx);
         
diff --git a/hyracks-tests/hyracks-storage-am-invertedindex-test/src/test/java/edu/uci/ics/hyracks/storage/am/invertedindex/SearchTest.java b/hyracks-tests/hyracks-storage-am-invertedindex-test/src/test/java/edu/uci/ics/hyracks/storage/am/invertedindex/SearchTest.java
index 0d6c7ca..761bd12 100644
--- a/hyracks-tests/hyracks-storage-am-invertedindex-test/src/test/java/edu/uci/ics/hyracks/storage/am/invertedindex/SearchTest.java
+++ b/hyracks-tests/hyracks-storage-am-invertedindex-test/src/test/java/edu/uci/ics/hyracks/storage/am/invertedindex/SearchTest.java
@@ -55,6 +55,7 @@
 import edu.uci.ics.hyracks.storage.am.invertedindex.impls.OccurrenceThresholdPanicException;
 import edu.uci.ics.hyracks.storage.am.invertedindex.impls.SearchResultCursor;
 import edu.uci.ics.hyracks.storage.am.invertedindex.impls.TOccurrenceSearcher;
+import edu.uci.ics.hyracks.storage.am.invertedindex.searchmodifiers.ConjunctiveSearchModifier;
 import edu.uci.ics.hyracks.storage.am.invertedindex.searchmodifiers.JaccardSearchModifier;
 import edu.uci.ics.hyracks.storage.common.buffercache.IBufferCache;
 import edu.uci.ics.hyracks.storage.common.file.IFileMapProvider;
@@ -63,12 +64,10 @@
 
 public class SearchTest extends AbstractInvIndexTest {
     
-	//private static final int PAGE_SIZE = 256;
-    //private static final int NUM_PAGES = 100;
-	
     // private static final int PAGE_SIZE = 65536;
     private static final int PAGE_SIZE = 32768;
     private static final int NUM_PAGES = 100;
+    private static final int MAX_OPEN_FILES = 10;
     private static final int HYRACKS_FRAME_SIZE = 32768;
     private static IHyracksStageletContext stageletCtx = TestUtils.create(HYRACKS_FRAME_SIZE);    
     
@@ -160,7 +159,7 @@
     
     @BeforeClass
     public static void start() throws Exception {
-    	TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+    	TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
     	bufferCache = TestStorageManagerComponentHolder.getBufferCache(stageletCtx);
     	fmp = TestStorageManagerComponentHolder.getFileMapProvider(stageletCtx);
     	
@@ -276,13 +275,10 @@
         
         // count occurrences        
         for(int i = 0; i < numQueryTokens; i++) {
-        	//System.out.println("LIST: " + i);
         	ArrayList<Integer> list = checkInvLists.get(queryTokenIndexes[i]);        	
         	for(int j = 0; j < list.size(); j++) {
-        		//System.out.print(list.get(j) + " ");
         		scanCountArray[list.get(j)]++;
         	}
-        	//System.out.println();
         }
         
         // check threshold
@@ -368,23 +364,20 @@
             }
         }               
     }
-    
-    /*
+        
     @Test
     public void conjunctiveKeywordQueryTest() throws Exception {
     	IInvertedIndexSearchModifier searchModifier = new ConjunctiveSearchModifier();
     	runQueries(searchModifier);
     }
-    */
-      
     
     @Test
     public void jaccardKeywordQueryTest() throws Exception {
     	JaccardSearchModifier searchModifier = new JaccardSearchModifier(1.0f);
     	
-    	//System.out.println("JACCARD: " + 1.0f);
-    	//searchModifier.setJaccThresh(1.0f);
-    	//runQueries(searchModifier);
+    	System.out.println("JACCARD: " + 1.0f);
+    	searchModifier.setJaccThresh(1.0f);
+    	runQueries(searchModifier);
     	
     	System.out.println("JACCARD: " + 0.9f);
     	searchModifier.setJaccThresh(0.9f);
@@ -415,232 +408,5 @@
     	bufferCache.closeFile(btreeFileId);
         bufferCache.closeFile(invListsFileId);        
     	bufferCache.close();
-    }
-    
-    /*
-    @Test
-    public void jaccardKeywordQueryTest() throws Exception {
-    	
-        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
-        IBufferCache bufferCache = TestStorageManagerComponentHolder.getBufferCache(stageletCtx);
-        IFileMapProvider fmp = TestStorageManagerComponentHolder.getFileMapProvider(stageletCtx);
-        
-        // create file refs
-        System.out.println(btreeFileName);
-        FileReference btreeFile = new FileReference(new File(btreeFileName));
-        bufferCache.createFile(btreeFile);
-        int btreeFileId = fmp.lookupFileId(btreeFile);
-        bufferCache.openFile(btreeFileId);
-
-        System.out.println(invListsFileName);
-        FileReference invListsFile = new FileReference(new File(invListsFileName));
-        bufferCache.createFile(invListsFile);
-        int invListsFileId = fmp.lookupFileId(invListsFile);
-        bufferCache.openFile(invListsFileId);
-                
-        // declare btree fields
-        int fieldCount = 5;
-        ITypeTrait[] typeTraits = new ITypeTrait[fieldCount];
-        // token (key)
-        typeTraits[0] = new TypeTrait(4);
-        // startPageId
-        typeTraits[1] = new TypeTrait(4);
-        // endPageId
-        typeTraits[2] = new TypeTrait(4);
-        // startOff
-        typeTraits[3] = new TypeTrait(4);
-        // numElements
-        typeTraits[4] = new TypeTrait(4);
-
-        // declare btree keys
-        int keyFieldCount = 1;
-        IBinaryComparator[] cmps = new IBinaryComparator[keyFieldCount];
-        cmps[0] = IntegerBinaryComparatorFactory.INSTANCE.createBinaryComparator();
-
-        MultiComparator cmp = new MultiComparator(typeTraits, cmps);
-
-        TypeAwareTupleWriterFactory tupleWriterFactory = new TypeAwareTupleWriterFactory(typeTraits);        
-        IBTreeLeafFrameFactory leafFrameFactory = new NSMLeafFrameFactory(tupleWriterFactory);
-        IBTreeInteriorFrameFactory interiorFrameFactory = new NSMInteriorFrameFactory(tupleWriterFactory);
-        ITreeIndexMetaDataFrameFactory metaFrameFactory = new LIFOMetaDataFrameFactory();
-
-        IBTreeLeafFrame leafFrame = leafFrameFactory.getFrame();
-        ITreeIndexMetaDataFrame metaFrame = metaFrameFactory.getFrame();
-
-        IFreePageManager freePageManager = new LinkedListFreePageManager(bufferCache, btreeFileId, 0, metaFrameFactory);
-        
-        BTree btree = new BTree(bufferCache, freePageManager, interiorFrameFactory, leafFrameFactory, cmp);            
-        btree.create(btreeFileId, leafFrame, metaFrame);
-        btree.open(btreeFileId);
-        
-        int invListFields = 1;
-        ITypeTrait[] invListTypeTraits = new ITypeTrait[invListFields];
-        invListTypeTraits[0] = new TypeTrait(4);
-        
-        int invListKeys = 1;
-        IBinaryComparator[] invListBinCmps = new IBinaryComparator[invListKeys];
-        invListBinCmps[0] = IntegerBinaryComparatorFactory.INSTANCE.createBinaryComparator();
-        
-        MultiComparator invListCmp = new MultiComparator(invListTypeTraits, invListBinCmps);
-        
-        InvertedIndex invIndex = new InvertedIndex(bufferCache, btree, invListCmp);
-        invIndex.open(invListsFileId);        
-        
-        Random rnd = new Random();
-        rnd.setSeed(50);
-
-        ByteBuffer frame = stageletCtx.allocateFrame();
-        FrameTupleAppender appender = new FrameTupleAppender(stageletCtx.getFrameSize());
-        ArrayTupleBuilder tb = new ArrayTupleBuilder(2);
-        DataOutput dos = tb.getDataOutput();
-
-        ISerializerDeserializer[] insertSerde = { UTF8StringSerializerDeserializer.INSTANCE,
-                IntegerSerializerDeserializer.INSTANCE };
-        RecordDescriptor insertRecDesc = new RecordDescriptor(insertSerde);
-        IFrameTupleAccessor accessor = new FrameTupleAccessor(stageletCtx.getFrameSize(), insertRecDesc);
-        accessor.reset(frame);
-        FrameTupleReference tuple = new FrameTupleReference();
-
-        List<String> tokens = new ArrayList<String>();
-        tokens.add("compilers");
-        tokens.add("computer");
-        tokens.add("databases");
-        tokens.add("fast");
-        tokens.add("hyracks");  
-        tokens.add("major");
-        tokens.add("science");
-        tokens.add("systems");
-        tokens.add("university");        
-        
-        ArrayList<TreeSet<Integer>> checkSets = new ArrayList<TreeSet<Integer>>();
-        for(int i = 0; i < tokens.size(); i++) {
-        	checkSets.add(new TreeSet<Integer>());
-        }
-        
-        int maxId = 1000000;
-        int addProb = 0;
-        int addProbStep = 10;
-
-        IInvertedListBuilder invListBuilder = new FixedSizeElementInvertedListBuilder(invListTypeTraits);
-        InvertedIndex.BulkLoadContext ctx = invIndex.beginBulkLoad(invListBuilder, HYRACKS_FRAME_SIZE);
-        
-        int totalElements = 0;        
-        for (int i = 0; i < tokens.size(); i++) {
-
-            addProb += addProbStep * (i+1);
-            for (int j = 0; j < maxId; j++) {
-                if ((Math.abs(rnd.nextInt()) % addProb) == 0) {                   
-                	
-                	totalElements++;
-                	
-                	tb.reset();
-                    UTF8StringSerializerDeserializer.INSTANCE.serialize(tokens.get(i), dos);
-                    tb.addFieldEndOffset();
-                    IntegerSerializerDeserializer.INSTANCE.serialize(j, dos);
-                    tb.addFieldEndOffset();
-                    
-                    checkSets.get(i).add(j);
-                    
-                    appender.reset(frame, true);
-                    appender.append(tb.getFieldEndOffsets(), tb.getByteArray(), 0, tb.getSize());
-                                                            
-                    tuple.reset(accessor, 0);                                      
-                    
-                    try {
-                        invIndex.bulkLoadAddTuple(ctx, tuple);                    
-                    } catch (Exception e) {
-                        e.printStackTrace();
-                    }
-                }
-            }
-        }
-        invIndex.endBulkLoad(ctx);
-        
-        // --------------------------- TEST A
-        // build query as tuple reference
-        ISerializerDeserializer[] querySerde = { UTF8StringSerializerDeserializer.INSTANCE };
-        RecordDescriptor queryRecDesc = new RecordDescriptor(querySerde);
-
-        FrameTupleAppender queryAppender = new FrameTupleAppender(stageletCtx.getFrameSize());
-        ArrayTupleBuilder queryTb = new ArrayTupleBuilder(querySerde.length);
-        DataOutput queryDos = queryTb.getDataOutput();
-
-        IFrameTupleAccessor queryAccessor = new FrameTupleAccessor(stageletCtx.getFrameSize(), queryRecDesc);
-        queryAccessor.reset(frame);
-        FrameTupleReference queryTuple = new FrameTupleReference();
-                
-        ITokenFactory tokenFactory = new UTF8WordTokenFactory();
-        IBinaryTokenizer queryTokenizer = new DelimitedUTF8StringBinaryTokenizer(true, false, tokenFactory);
-
-        
-        
-        TOccurrenceSearcher searcher = new TOccurrenceSearcher(stageletCtx, invIndex, queryTokenizer);        
-        IInvertedIndexSearchModifier searchModifier = new ConjunctiveSearchModifier();
-        IInvertedIndexResultCursor resultCursor = new SearchResultCursor(searcher.createResultFrameTupleAccessor(), searcher.createResultTupleReference());
-        
-        // generate random queries
-        int queries = 100;
-        int[] queryTokenIndexes = new int[tokens.size()];
-        for(int i = 0; i < queries; i++) {
-        	
-        	int numQueryTokens = Math.abs(rnd.nextInt() % tokens.size()) + 1;
-        	for(int j = 0; j < numQueryTokens; j++) {
-        		queryTokenIndexes[j] = Math.abs(rnd.nextInt() % tokens.size());        		        		
-        	}
-        	
-        	StringBuilder strBuilder = new StringBuilder();
-        	for(int j = 0; j < numQueryTokens; j++) {
-        		strBuilder.append(tokens.get(queryTokenIndexes[j]));
-        		if(j+1 != numQueryTokens) strBuilder.append(" ");
-        	}
-        	
-        	String queryString = strBuilder.toString();
-        	
-        	queryTb.reset();
-            UTF8StringSerializerDeserializer.INSTANCE.serialize(queryString, queryDos);
-            queryTb.addFieldEndOffset();
-
-            queryAppender.reset(frame, true);
-            queryAppender.append(queryTb.getFieldEndOffsets(), queryTb.getByteArray(), 0, queryTb.getSize());
-            queryTuple.reset(queryAccessor, 0);
-        
-            int repeats = 10;
-            double totalTime = 0;
-            for(int j = 0; j < repeats; j++) {
-            	long timeStart = System.currentTimeMillis();
-            	searcher.reset();
-            	searcher.search(resultCursor, queryTuple, 0, searchModifier);
-            	long timeEnd = System.currentTimeMillis();
-            	totalTime += timeEnd - timeStart;
-            }
-            double avgTime = totalTime / (double)repeats;
-            System.out.println(i + ": " + "\"" + queryString + "\": " + avgTime + "ms");                     
-            
-            // TODO:
-            // generate intersection for verification
-            TreeSet<Integer> checkResults = new TreeSet<Integer>(checkSets.get(queryTokenIndexes[0]));
-            for(int j = 1; j < numQueryTokens; j++) {
-            	checkResults.retainAll(checkSets.get(queryTokenIndexes[j]));
-            }
-            Integer[] check = new Integer[checkResults.size()];
-            check = checkResults.toArray(check);           
-            
-            // verify results
-            int checkIndex = 0;
-            while(resultCursor.hasNext()) {
-            	resultCursor.next();
-            	ITupleReference resultTuple = resultCursor.getTuple();
-            	int id = IntegerSerializerDeserializer.getInt(resultTuple.getFieldData(0), resultTuple.getFieldStart(0));            	
-            	Assert.assertEquals(id, check[checkIndex].intValue());      	
-            	checkIndex++;
-            }
-            Assert.assertEquals(check.length, checkIndex);            
-        }
-        
-        btree.close();
-        bufferCache.closeFile(btreeFileId);
-        bufferCache.closeFile(invListsFileId);
-        bufferCache.close();
-    }
-    */
+    }        
 }
diff --git a/hyracks-tests/hyracks-storage-am-rtree-test/src/test/java/edu/uci/ics/hyracks/storage/am/rtree/RTreeTest.java b/hyracks-tests/hyracks-storage-am-rtree-test/src/test/java/edu/uci/ics/hyracks/storage/am/rtree/RTreeTest.java
index b105588..66ae703 100644
--- a/hyracks-tests/hyracks-storage-am-rtree-test/src/test/java/edu/uci/ics/hyracks/storage/am/rtree/RTreeTest.java
+++ b/hyracks-tests/hyracks-storage-am-rtree-test/src/test/java/edu/uci/ics/hyracks/storage/am/rtree/RTreeTest.java
@@ -50,13 +50,14 @@
 
     private static final int PAGE_SIZE = 1024;
     private static final int NUM_PAGES = 10000;
+    private static final int MAX_OPEN_FILES = 10;
     private static final int HYRACKS_FRAME_SIZE = 128;
     private IHyracksStageletContext ctx = TestUtils.create(HYRACKS_FRAME_SIZE);
 
     @Test
     public void test01() throws Exception {
 
-        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
         IBufferCache bufferCache = TestStorageManagerComponentHolder.getBufferCache(ctx);
         IFileMapProvider fmp = TestStorageManagerComponentHolder.getFileMapProvider(ctx);
         FileReference file = new FileReference(new File(fileName));
@@ -198,7 +199,7 @@
     // @Test
     public void test02() throws Exception {
 
-        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
         IBufferCache bufferCache = TestStorageManagerComponentHolder.getBufferCache(ctx);
         IFileMapProvider fmp = TestStorageManagerComponentHolder.getFileMapProvider(ctx);
         FileReference file = new FileReference(new File(fileName));
diff --git a/hyracks-tests/hyracks-storage-am-rtree-test/src/test/java/edu/uci/ics/hyracks/storage/am/rtree/SearchCursorTest.java b/hyracks-tests/hyracks-storage-am-rtree-test/src/test/java/edu/uci/ics/hyracks/storage/am/rtree/SearchCursorTest.java
index a5f0594..59dfe10 100644
--- a/hyracks-tests/hyracks-storage-am-rtree-test/src/test/java/edu/uci/ics/hyracks/storage/am/rtree/SearchCursorTest.java
+++ b/hyracks-tests/hyracks-storage-am-rtree-test/src/test/java/edu/uci/ics/hyracks/storage/am/rtree/SearchCursorTest.java
@@ -51,13 +51,14 @@
 public class SearchCursorTest extends AbstractRTreeTest {
     private static final int PAGE_SIZE = 256;
     private static final int NUM_PAGES = 10;
+    private static final int MAX_OPEN_FILES = 10;
     private static final int HYRACKS_FRAME_SIZE = 128;
     private IHyracksStageletContext ctx = TestUtils.create(HYRACKS_FRAME_SIZE);
 
     @Test
     public void searchCursorTest() throws Exception {
 
-        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES);
+        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
         IBufferCache bufferCache = TestStorageManagerComponentHolder.getBufferCache(ctx);
         IFileMapProvider fmp = TestStorageManagerComponentHolder.getFileMapProvider(ctx);
         FileReference file = new FileReference(new File(fileName));
diff --git a/hyracks-tests/hyracks-storage-common-test/pom.xml b/hyracks-tests/hyracks-storage-common-test/pom.xml
new file mode 100644
index 0000000..cd94e8b
--- /dev/null
+++ b/hyracks-tests/hyracks-storage-common-test/pom.xml
@@ -0,0 +1,54 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>edu.uci.ics.hyracks</groupId>
+  <artifactId>hyracks-storage-common-test</artifactId>
+  <version>0.1.5</version>
+
+  <parent>
+    <groupId>edu.uci.ics.hyracks</groupId>
+    <artifactId>hyracks-tests</artifactId>
+    <version>0.1.5</version>
+  </parent>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>2.0.2</version>
+        <configuration>
+          <source>1.6</source>
+          <target>1.6</target>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <dependencies>
+  	<dependency>
+  		<groupId>junit</groupId>
+  		<artifactId>junit</artifactId>
+  		<version>4.8.1</version>
+  		<type>jar</type>
+  		<scope>test</scope>
+  	</dependency>
+  	<dependency>
+  		<groupId>edu.uci.ics.hyracks</groupId>
+  		<artifactId>hyracks-control-nc</artifactId>
+  		<version>0.1.5</version>
+  		<scope>compile</scope>
+  	</dependency>
+  	<dependency>
+  		<groupId>edu.uci.ics.hyracks</groupId>
+  		<artifactId>hyracks-storage-common</artifactId>
+  		<version>0.1.5</version>
+  		<scope>compile</scope>
+  	</dependency>
+  	<dependency>
+  		<groupId>edu.uci.ics.hyracks</groupId>
+  		<artifactId>hyracks-test-support</artifactId>
+  		<version>0.1.5</version>
+  		<type>jar</type>
+  		<scope>test</scope>
+  	</dependency>
+  </dependencies>
+</project>
diff --git a/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheTest.java b/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheTest.java
new file mode 100644
index 0000000..680fd3b
--- /dev/null
+++ b/hyracks-tests/hyracks-storage-common-test/src/test/java/edu/uci/ics/hyracks/storage/common/BufferCacheTest.java
@@ -0,0 +1,311 @@
+package edu.uci.ics.hyracks.storage.common;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Test;
+
+import edu.uci.ics.hyracks.api.context.IHyracksStageletContext;
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+import edu.uci.ics.hyracks.api.io.FileReference;
+import edu.uci.ics.hyracks.storage.common.buffercache.IBufferCache;
+import edu.uci.ics.hyracks.storage.common.buffercache.ICachedPage;
+import edu.uci.ics.hyracks.storage.common.file.BufferedFileHandle;
+import edu.uci.ics.hyracks.storage.common.file.IFileMapProvider;
+import edu.uci.ics.hyracks.test.support.TestStorageManagerComponentHolder;
+import edu.uci.ics.hyracks.test.support.TestUtils;
+
+public class BufferCacheTest {
+    protected static final List<String> openedFiles = new ArrayList<String>();    
+    protected static final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("ddMMyy-hhmmssSS");
+    protected static final String tmpDir = System.getProperty("java.io.tmpdir");
+    protected static final String sep = System.getProperty("file.separator");    
+    
+    private static final int PAGE_SIZE = 256;
+    private static final int NUM_PAGES = 10;
+    private static final int MAX_OPEN_FILES = 20;
+    private static final int HYRACKS_FRAME_SIZE = PAGE_SIZE;
+    private IHyracksStageletContext ctx = TestUtils.create(HYRACKS_FRAME_SIZE);
+    
+    private static final Random rnd = new Random(50);
+    
+    private String getFileName() {
+        String fileName = tmpDir + sep + simpleDateFormat.format(new Date()) + openedFiles.size();
+        openedFiles.add(fileName);
+        return fileName;
+    }          
+    
+    @Test
+    public void simpleOpenPinCloseTest() throws HyracksDataException {
+        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
+        IBufferCache bufferCache = TestStorageManagerComponentHolder.getBufferCache(ctx);
+        IFileMapProvider fmp = TestStorageManagerComponentHolder.getFileMapProvider(ctx);
+        String fileName = getFileName();
+        FileReference file = new FileReference(new File(fileName));
+        bufferCache.createFile(file);
+        int fileId = fmp.lookupFileId(file);
+        int num = 10;
+        int testPageId = 0;
+        
+        bufferCache.openFile(fileId);
+        
+        ICachedPage page = null;
+        
+        // tryPin should fail
+        page = bufferCache.tryPin(BufferedFileHandle.getDiskPageId(fileId, testPageId));
+        Assert.assertNull(page);
+        
+        // pin page should succeed
+        page = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, testPageId), true);
+        page.acquireWriteLatch();
+        try {            
+            for(int i = 0; i < num; i++) {
+                page.getBuffer().putInt(i * 4, i);
+            }               
+            
+            // try pin should succeed         
+            ICachedPage page2 = bufferCache.tryPin(BufferedFileHandle.getDiskPageId(fileId, testPageId));
+            Assert.assertNotNull(page2);
+            bufferCache.unpin(page2);
+            
+        } finally {
+            page.releaseWriteLatch();
+            bufferCache.unpin(page);
+        }                        
+        
+        bufferCache.closeFile(fileId);
+        
+        boolean exceptionThrown = false;
+        
+        // tryPin should fail since file is not open
+        try {
+            page = bufferCache.tryPin(BufferedFileHandle.getDiskPageId(fileId, testPageId));
+        } catch(HyracksDataException e) {
+            exceptionThrown = true;
+        }
+        Assert.assertTrue(exceptionThrown);
+        
+        // pin should fail since file is not open
+        exceptionThrown = false;
+        try {
+            page = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, testPageId), false);
+        } catch(HyracksDataException e) {
+            exceptionThrown = true;
+        }
+        Assert.assertTrue(exceptionThrown);
+        
+        
+        // open file again
+        bufferCache.openFile(fileId);
+        
+        // tryPin should succeed because page should still be cached        
+        page = bufferCache.tryPin(BufferedFileHandle.getDiskPageId(fileId, testPageId));        
+        Assert.assertNotNull(page);
+        page.acquireReadLatch();
+        try {
+            // verify contents of page
+            for(int i = 0; i < num; i++) {
+                Assert.assertEquals(page.getBuffer().getInt(i * 4), i);
+            }
+        } finally {
+            page.releaseReadLatch();
+            bufferCache.unpin(page);
+        }                
+        
+        bufferCache.closeFile(fileId);        
+        bufferCache.close();
+    }
+        
+    @Test
+    public void simpleMaxOpenFilesTest() throws HyracksDataException {
+        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
+        IBufferCache bufferCache = TestStorageManagerComponentHolder.getBufferCache(ctx);
+        IFileMapProvider fmp = TestStorageManagerComponentHolder.getFileMapProvider(ctx);
+        
+        List<Integer> fileIds = new ArrayList<Integer>();
+        
+        for(int i = 0; i < MAX_OPEN_FILES; i++) {
+            String fileName = getFileName();
+            FileReference file = new FileReference(new File(fileName));
+            bufferCache.createFile(file);
+            int fileId = fmp.lookupFileId(file);
+            bufferCache.openFile(fileId);
+            fileIds.add(fileId);
+        }
+        
+        boolean exceptionThrown = false;
+        
+        // since all files are open, next open should fail
+        try {
+            String fileName = getFileName();
+            FileReference file = new FileReference(new File(fileName));
+            bufferCache.createFile(file);
+            int fileId = fmp.lookupFileId(file);
+            bufferCache.openFile(fileId);
+        } catch(HyracksDataException e) {
+            exceptionThrown = true;
+        }
+        Assert.assertTrue(exceptionThrown);
+        
+        // close a random file
+        int ix = Math.abs(rnd.nextInt()) % fileIds.size();
+        bufferCache.closeFile(fileIds.get(ix));
+        fileIds.remove(ix);
+        
+        // now open should succeed again
+        exceptionThrown = false;
+        try {
+            String fileName = getFileName();
+            FileReference file = new FileReference(new File(fileName));
+            bufferCache.createFile(file);
+            int fileId = fmp.lookupFileId(file);
+            bufferCache.openFile(fileId);
+            fileIds.add(fileId);
+            
+        } catch(HyracksDataException e) {
+            exceptionThrown = true;
+        }
+        Assert.assertFalse(exceptionThrown);
+        
+        for(Integer i : fileIds) {
+            bufferCache.closeFile(i.intValue());
+        }
+        
+        bufferCache.close();
+    }
+    
+    @Test
+    public void contentCheckingMaxOpenFilesTest() throws HyracksDataException {
+        TestStorageManagerComponentHolder.init(PAGE_SIZE, NUM_PAGES, MAX_OPEN_FILES);
+        IBufferCache bufferCache = TestStorageManagerComponentHolder.getBufferCache(ctx);
+        IFileMapProvider fmp = TestStorageManagerComponentHolder.getFileMapProvider(ctx);
+        
+        List<Integer> fileIds = new ArrayList<Integer>();
+        Map<Integer, ArrayList<Integer>> pageContents = new HashMap<Integer, ArrayList<Integer>>();        
+        int num = 10;
+        int testPageId = 0;        
+        
+        // open max number of files and write some stuff into their first page
+        for(int i = 0; i < MAX_OPEN_FILES; i++) {
+            String fileName = getFileName();
+            FileReference file = new FileReference(new File(fileName));
+            bufferCache.createFile(file);
+            int fileId = fmp.lookupFileId(file);
+            bufferCache.openFile(fileId);
+            fileIds.add(fileId);
+            
+            ICachedPage page = null;            
+            page = bufferCache.pin(BufferedFileHandle.getDiskPageId(fileId, testPageId), true);
+            page.acquireWriteLatch();
+            try {            
+                ArrayList<Integer> values = new ArrayList<Integer>();                
+                for(int j = 0; j < num; j++) {
+                    int x = Math.abs(rnd.nextInt());
+                    page.getBuffer().putInt(j * 4, x);
+                    values.add(x);
+                }
+                pageContents.put(fileId, values);                
+            } finally {
+                page.releaseWriteLatch();
+                bufferCache.unpin(page);
+            }            
+        }        
+        
+        boolean exceptionThrown = false;
+        
+        // since all files are open, next open should fail
+        try {
+            String fileName = getFileName();
+            FileReference file = new FileReference(new File(fileName));
+            bufferCache.createFile(file);
+            int fileId = fmp.lookupFileId(file);
+            bufferCache.openFile(fileId);
+        } catch(HyracksDataException e) {
+            exceptionThrown = true;
+        }
+        Assert.assertTrue(exceptionThrown);        
+        
+        // close a few random files
+        ArrayList<Integer> closedFileIds = new ArrayList<Integer>();
+        int filesToClose = 5;
+        for(int i = 0; i < filesToClose; i++) {
+            int ix = Math.abs(rnd.nextInt()) % fileIds.size();            
+            bufferCache.closeFile(fileIds.get(ix));
+            closedFileIds.add(fileIds.get(ix));
+            fileIds.remove(ix);
+        }        
+        
+        // now open a few new files
+        for(int i = 0; i < filesToClose; i++) {
+            String fileName = getFileName();
+            FileReference file = new FileReference(new File(fileName));
+            bufferCache.createFile(file);
+            int fileId = fmp.lookupFileId(file);
+            bufferCache.openFile(fileId);
+            fileIds.add(fileId);
+        }        
+        
+        // since all files are open, next open should fail
+        try {
+            String fileName = getFileName();
+            FileReference file = new FileReference(new File(fileName));
+            bufferCache.createFile(file);
+            int fileId = fmp.lookupFileId(file);
+            bufferCache.openFile(fileId);            
+        } catch(HyracksDataException e) {
+            exceptionThrown = true;
+        }
+        Assert.assertTrue(exceptionThrown);       
+        
+        // close a few random files again        
+        for(int i = 0; i < filesToClose; i++) {
+            int ix = Math.abs(rnd.nextInt()) % fileIds.size();            
+            bufferCache.closeFile(fileIds.get(ix));
+            closedFileIds.add(fileIds.get(ix));
+            fileIds.remove(ix);
+        }
+        
+        // now open those closed files again and verify their contents
+        for(int i = 0; i < filesToClose; i++) {
+            int closedFileId = closedFileIds.get(i);
+            bufferCache.openFile(closedFileId);
+            fileIds.add(closedFileId);
+            
+            // pin first page and verify contents
+            ICachedPage page = null;            
+            page = bufferCache.pin(BufferedFileHandle.getDiskPageId(closedFileId, testPageId), false);
+            page.acquireReadLatch();
+            try {            
+                ArrayList<Integer> values = pageContents.get(closedFileId);                
+                for(int j = 0; j < values.size(); j++) {
+                    Assert.assertEquals(values.get(j).intValue(), page.getBuffer().getInt(j * 4));                    
+                }      
+            } finally {
+                page.releaseReadLatch();
+                bufferCache.unpin(page);
+            }            
+        }         
+        
+        for(Integer i : fileIds) {
+            bufferCache.closeFile(i.intValue());
+        }
+        
+        bufferCache.close();
+    }
+    
+    @AfterClass
+    public static void cleanup() throws Exception {
+        for(String s : openedFiles) {
+            File f = new File(s);
+            f.deleteOnExit();
+        }
+    }
+}
diff --git a/hyracks-tests/pom.xml b/hyracks-tests/pom.xml
index a4d2c04..adca473 100644
--- a/hyracks-tests/pom.xml
+++ b/hyracks-tests/pom.xml
@@ -12,6 +12,7 @@
   </parent>
 
   <modules>
+    <module>hyracks-storage-common-test</module>
     <module>hyracks-storage-am-btree-test</module>
     <module>hyracks-storage-am-invertedindex-test</module>
     <module>hyracks-storage-am-rtree-test</module>