| package edu.uci.ics.hyracks.storage.am.lsm.common; |
| |
| import static org.junit.Assert.assertTrue; |
| |
| import java.io.File; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Random; |
| import java.util.Set; |
| |
| import org.junit.Test; |
| |
| import edu.uci.ics.hyracks.api.io.FileReference; |
| import edu.uci.ics.hyracks.storage.am.lsm.common.impls.VirtualBufferCache; |
| import edu.uci.ics.hyracks.storage.common.buffercache.HeapBufferAllocator; |
| 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; |
| |
| public class VirtualBufferCacheTest { |
| private static final long SEED = 123456789L; |
| private static final int NUM_OVERPIN = 128; |
| private static final int PAGE_SIZE = 256; |
| private static final int NUM_FILES = 10; |
| private static final int NUM_PAGES = 1000; |
| |
| private final Random random; |
| private final FileState[] fileStates; |
| |
| private VirtualBufferCache vbc; |
| |
| public VirtualBufferCacheTest() { |
| fileStates = new FileState[NUM_FILES]; |
| for (int i = 0; i < NUM_FILES; i++) { |
| fileStates[i] = new FileState(); |
| } |
| random = new Random(SEED); |
| vbc = null; |
| } |
| |
| private static class FileState { |
| private int fileId; |
| private FileReference fileRef; |
| private int pinCount; |
| private Set<ICachedPage> pinnedPages; |
| |
| public FileState() { |
| fileId = -1; |
| fileRef = null; |
| pinCount = 0; |
| pinnedPages = new HashSet<ICachedPage>(); |
| } |
| } |
| |
| /** |
| * Pins NUM_PAGES randomly distributed across NUM_FILES and checks that each |
| * set of cached pages pinned on behalf of a file are disjoint from all other sets of |
| * cached pages pinned on behalf of other files. |
| * Additionally, the test perform the same test when pinning over soft cap (NUM_PAGES) |
| * of pages. |
| */ |
| @Test |
| public void test01() throws Exception { |
| ICacheMemoryAllocator allocator = new HeapBufferAllocator(); |
| vbc = new VirtualBufferCache(allocator, PAGE_SIZE, NUM_PAGES); |
| vbc.open(); |
| createFiles(); |
| |
| kPins(NUM_PAGES); |
| assertTrue(pagesDisjointed()); |
| |
| kPins(NUM_OVERPIN); |
| assertTrue(pagesDisjointed()); |
| |
| deleteFiles(); |
| vbc.close(); |
| } |
| |
| private boolean pagesDisjointed() { |
| boolean disjoint = true; |
| for (int i = 0; i < NUM_FILES; i++) { |
| FileState fi = fileStates[i]; |
| for (int j = i + 1; j < NUM_FILES; j++) { |
| FileState fj = fileStates[j]; |
| disjoint = disjoint && Collections.disjoint(fi.pinnedPages, fj.pinnedPages); |
| } |
| } |
| return disjoint; |
| } |
| |
| private void createFiles() throws Exception { |
| for (int i = 0; i < NUM_FILES; i++) { |
| FileState f = fileStates[i]; |
| String fName = String.format("f%d", i); |
| f.fileRef = new FileReference(new File(fName)); |
| vbc.createFile(f.fileRef); |
| f.fileId = vbc.getFileMapProvider().lookupFileId(f.fileRef); |
| } |
| } |
| |
| private void deleteFiles() throws Exception { |
| for (int i = 0; i < NUM_FILES; i++) { |
| vbc.deleteFile(fileStates[i].fileId, false); |
| } |
| } |
| |
| private void kPins(int k) throws Exception { |
| int numPinned = 0; |
| while (numPinned < k) { |
| int fsIdx = random.nextInt(NUM_FILES); |
| FileState f = fileStates[fsIdx]; |
| ICachedPage p = vbc.pin(BufferedFileHandle.getDiskPageId(f.fileId, f.pinCount), true); |
| f.pinnedPages.add(p); |
| ++f.pinCount; |
| ++numPinned; |
| } |
| } |
| } |