Added test for StorageManagerInterface containing BufferCache and FileMapManager.

git-svn-id: https://hyracks.googlecode.com/svn/branches/hyracks_storage_cleanup@258 123451ca-8445-de46-9d55-352943316053
diff --git a/hyracks-storage-am-btree/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java b/hyracks-storage-am-btree/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java
new file mode 100644
index 0000000..be63c1e
--- /dev/null
+++ b/hyracks-storage-am-btree/src/test/java/edu/uci/ics/hyracks/storage/am/btree/StorageManagerTest.java
@@ -0,0 +1,238 @@
+package edu.uci.ics.hyracks.storage.am.btree;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+
+import org.junit.Test;
+
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+import edu.uci.ics.hyracks.storage.am.btree.api.DummySMI;
+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.FileHandle;
+import edu.uci.ics.hyracks.storage.common.file.IFileMapProvider;
+import edu.uci.ics.hyracks.storage.common.sync.LatchType;
+
+public class StorageManagerTest {
+	private static final int PAGE_SIZE = 256;
+	private static final int NUM_PAGES = 10;
+
+	private String tmpDir = System.getProperty("java.io.tmpdir");
+
+	public class PinnedLatchedPage {
+		public final ICachedPage page;
+		public final LatchType latch;
+		public final int pageId;
+		
+		public PinnedLatchedPage(ICachedPage page, int pageId, LatchType latch) {
+			this.page = page;
+			this.pageId = pageId;
+			this.latch = latch;
+		}
+	}
+	
+	public enum FileAccessType {
+		FTA_READONLY,
+		FTA_WRITEONLY,
+		FTA_MIXED,
+		FTA_UNLATCHED
+	}
+	
+	public class FileAccessWorker implements Runnable {		
+		private int workerId;
+		private final IBufferCache bufferCache;
+		private final int maxPages;
+		private final int fileId;
+		private final long thinkTime;
+		private final int maxLoopCount;
+		private final int maxPinnedPages;
+		private final int closeFileChance;
+		private final FileAccessType fta;
+		private int loopCount = 0;
+		private boolean fileIsOpen = false;
+		private Random rnd = new Random(50);
+		private List<PinnedLatchedPage> pinnedPages = new LinkedList<PinnedLatchedPage>();
+		
+		public FileAccessWorker(int workerId, IBufferCache bufferCache, FileAccessType fta, int fileId, int maxPages, int maxPinnedPages, int maxLoopCount, int closeFileChance, long thinkTime) {
+			this.bufferCache = bufferCache;
+			this.fileId = fileId;
+			this.maxPages = maxPages;  
+			this.maxLoopCount = maxLoopCount;
+			this.maxPinnedPages = maxPinnedPages;
+			this.thinkTime = thinkTime;
+			this.closeFileChance = closeFileChance;
+			this.workerId = workerId;
+			this.fta = fta;
+		}
+		
+		private void pinRandomPage() {
+			int pageId = Math.abs(rnd.nextInt() % maxPages);
+			
+			System.out.println(workerId + " PINNING PAGE: " + pageId);
+			
+			try {
+				ICachedPage page = bufferCache.pin(FileHandle.getDiskPageId(fileId, pageId), false);
+				LatchType latch = null;
+				
+				switch(fta) {
+				
+				case FTA_UNLATCHED: {
+					latch = null;
+				} break;
+				
+				case FTA_READONLY: {
+					System.out.println(workerId + " S LATCHING: " + pageId);
+					page.acquireReadLatch();
+					latch = LatchType.LATCH_S;
+				} break;
+				
+				case FTA_WRITEONLY: {
+					System.out.println(workerId + " X LATCHING: " + pageId);
+					page.acquireWriteLatch();
+					latch = LatchType.LATCH_X;
+				} break;
+				
+				case FTA_MIXED: {
+					if(rnd.nextInt() % 2 == 0) {
+						System.out.println(workerId + " S LATCHING: " + pageId);
+						page.acquireReadLatch();
+						latch = LatchType.LATCH_S;
+					}
+					else {
+						System.out.println(workerId + " X LATCHING: " + pageId);
+						page.acquireWriteLatch();
+						latch = LatchType.LATCH_X;
+					}
+				} break;
+								
+				}
+				
+				PinnedLatchedPage plPage = new PinnedLatchedPage(page, pageId, latch);
+				pinnedPages.add(plPage);				
+			} catch (HyracksDataException e) {
+				e.printStackTrace();
+			}
+		}
+		
+		private void unpinRandomPage() {
+			int index = Math.abs(rnd.nextInt() % pinnedPages.size());
+			try {
+				PinnedLatchedPage plPage = pinnedPages.get(index);
+				System.out.println(workerId + " UNPINNING PAGE: " + plPage.pageId);
+				
+				if(plPage.latch != null) {
+					if(plPage.latch == LatchType.LATCH_S) {
+						System.out.println(workerId + " S UNLATCHING: " + plPage.pageId);
+						plPage.page.releaseReadLatch();
+					}
+					else {
+						System.out.println(workerId + " X UNLATCHING: " + plPage.pageId);
+						plPage.page.releaseWriteLatch();
+					}
+				}								
+				bufferCache.unpin(plPage.page);				
+				pinnedPages.remove(index);				
+			} catch (HyracksDataException e) {
+				e.printStackTrace();
+			}
+		}
+
+		private void openFile() {
+			System.out.println(workerId + " OPENING FILE: " + fileId);
+			try {
+				bufferCache.openFile(fileId);
+				fileIsOpen = true;
+			} catch (HyracksDataException e) {
+				e.printStackTrace();
+			}
+		}
+		
+		private void closeFile() {
+			System.out.println(workerId + " CLOSING FILE: " + fileId);
+			try {
+				bufferCache.closeFile(fileId);
+				fileIsOpen = false;
+			} catch (HyracksDataException e) {
+				e.printStackTrace();
+			}
+		}
+		
+		@Override
+		public void run() {
+
+			openFile();
+						
+			while(loopCount < maxLoopCount) {		
+				loopCount++;
+							
+				System.out.println(workerId + " LOOP: " + loopCount + "/" + maxLoopCount);
+				
+				if(fileIsOpen) {					
+					
+					// pin some pages
+					int pagesToPin = Math.abs(rnd.nextInt()) % (maxPinnedPages - pinnedPages.size());
+					for(int i = 0; i < pagesToPin; i++) {
+						pinRandomPage();
+					}
+					
+					// do some thinking
+					try {
+						Thread.sleep(thinkTime);
+					} catch (InterruptedException e) {
+						e.printStackTrace();
+					}					
+					
+					// unpin some pages
+					if(!pinnedPages.isEmpty()) {
+						int pagesToUnpin = Math.abs(rnd.nextInt()) % pinnedPages.size();
+						for(int i = 0; i < pagesToUnpin; i++) {
+							unpinRandomPage();
+						}
+					}
+					
+					// possibly close file
+					int closeFileCheck = Math.abs(rnd.nextInt()) % closeFileChance;
+					if(pinnedPages.isEmpty() || closeFileCheck == 0) {						
+						int numPinnedPages = pinnedPages.size();
+						for(int i = 0; i < numPinnedPages; i++) {
+							unpinRandomPage();
+						}						
+						closeFile();						
+					}
+				}
+				else {
+					openFile();		
+				}
+			}
+			
+			if(fileIsOpen) {
+				int numPinnedPages = pinnedPages.size();
+				for(int i = 0; i < numPinnedPages; i++) {
+					unpinRandomPage();
+				}
+				closeFile();
+			}			
+		}
+	}
+
+
+	@Test
+	public void oneThreadOneFileTest() throws Exception {
+		DummySMI smi = new DummySMI(PAGE_SIZE, NUM_PAGES);    	
+		IBufferCache bufferCache = smi.getBufferCache();
+		IFileMapProvider fmp = smi.getFileMapProvider();
+		String fileName = tmpDir + "/" + "testfile01.bin";
+		bufferCache.createFile(fileName);    	
+		int fileId = fmp.lookupFileId(fileName);
+		
+		Thread worker = new Thread(new FileAccessWorker(0, bufferCache, FileAccessType.FTA_READONLY, fileId, 10, 10, 100, 10, 0));		
+		
+		worker.start();		
+
+		worker.join();
+		
+		bufferCache.close();    	
+	}
+
+}