Added Hyracks storage
git-svn-id: https://hyracks.googlecode.com/svn/trunk/hyracks@74 123451ca-8445-de46-9d55-352943316053
diff --git a/hyracks-storage-common/.classpath b/hyracks-storage-common/.classpath
new file mode 100644
index 0000000..1f3c1ff
--- /dev/null
+++ b/hyracks-storage-common/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" output="target/classes" path="src/main/java"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/hyracks-storage-common/.project b/hyracks-storage-common/.project
new file mode 100644
index 0000000..d990298
--- /dev/null
+++ b/hyracks-storage-common/.project
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>hyracks-storage-common</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.maven.ide.eclipse.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.maven.ide.eclipse.maven2Nature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/hyracks-storage-common/.settings/org.eclipse.jdt.core.prefs b/hyracks-storage-common/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..33fff33
--- /dev/null
+++ b/hyracks-storage-common/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,6 @@
+#Tue Aug 24 14:59:46 PDT 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
diff --git a/hyracks-storage-common/.settings/org.maven.ide.eclipse.prefs b/hyracks-storage-common/.settings/org.maven.ide.eclipse.prefs
new file mode 100644
index 0000000..a91dbc3
--- /dev/null
+++ b/hyracks-storage-common/.settings/org.maven.ide.eclipse.prefs
@@ -0,0 +1,9 @@
+#Tue Aug 24 14:59:44 PDT 2010
+activeProfiles=
+eclipse.preferences.version=1
+fullBuildGoals=process-test-resources
+includeModules=false
+resolveWorkspaceProjects=true
+resourceFilterGoals=process-resources resources\:testResources
+skipCompilerPlugin=true
+version=1
diff --git a/hyracks-storage-common/pom.xml b/hyracks-storage-common/pom.xml
new file mode 100644
index 0000000..d359f11
--- /dev/null
+++ b/hyracks-storage-common/pom.xml
@@ -0,0 +1,35 @@
+<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</artifactId>
+ <version>0.1.1-SNAPSHOT</version>
+
+ <parent>
+ <groupId>edu.uci.ics.hyracks</groupId>
+ <artifactId>hyracks</artifactId>
+ <version>0.1.1-SNAPSHOT</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>edu.uci.ics.hyracks</groupId>
+ <artifactId>hyracks-api</artifactId>
+ <version>0.1.1-SNAPSHOT</version>
+ <type>jar</type>
+ <scope>compile</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/BufferCache.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/BufferCache.java
new file mode 100644
index 0000000..0ea76d9
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/BufferCache.java
@@ -0,0 +1,450 @@
+package edu.uci.ics.hyracks.storage.common.storage.buffercache;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+import edu.uci.ics.hyracks.storage.common.storage.file.FileInfo;
+import edu.uci.ics.hyracks.storage.common.storage.file.FileManager;
+
+public class BufferCache implements IBufferCacheInternal {
+ private static final int MAP_FACTOR = 2;
+
+ private static final int MAX_VICTIMIZATION_TRY_COUNT = 3;
+
+ private final int pageSize;
+ private final int numPages;
+ private final CachedPage[] cachedPages;
+ private final CacheBucket[] pageMap;
+ private final IPageReplacementStrategy pageReplacementStrategy;
+ private final FileManager fileManager;
+ private final CleanerThread cleanerThread;
+
+ private boolean closed;
+
+ public BufferCache(ICacheMemoryAllocator allocator, IPageReplacementStrategy pageReplacementStrategy,
+ FileManager fileManager, int pageSize, int numPages) {
+ this.pageSize = pageSize;
+ this.numPages = numPages;
+ pageReplacementStrategy.setBufferCache(this);
+ ByteBuffer[] buffers = allocator.allocate(pageSize, numPages);
+ cachedPages = new CachedPage[buffers.length];
+ for (int i = 0; i < buffers.length; ++i) {
+ cachedPages[i] = new CachedPage(i, buffers[i], pageReplacementStrategy);
+ }
+ pageMap = new CacheBucket[numPages * MAP_FACTOR];
+ for (int i = 0; i < pageMap.length; ++i) {
+ pageMap[i] = new CacheBucket();
+ }
+ this.pageReplacementStrategy = pageReplacementStrategy;
+ this.fileManager = fileManager;
+ cleanerThread = new CleanerThread();
+ cleanerThread.start();
+ closed = false;
+ }
+
+ @Override
+ public int getPageSize() {
+ return pageSize;
+ }
+
+ @Override
+ public int getNumPages() {
+ return numPages;
+ }
+
+ @Override
+ public ICachedPage pin(long dpid, boolean newPage) throws HyracksDataException {
+ if (closed) {
+ throw new HyracksDataException("pin called on a closed cache");
+ }
+ CachedPage cPage = findPage(dpid, newPage);
+ if (!newPage) {
+ if (!cPage.valid) {
+ /*
+ * We got a buffer and we have pinned it. But its invalid.
+ * If its a new page, we just mark it as valid and return. Or else,
+ * while we hold the page lock, we get a write latch on the
+ * data and start a read.
+ */
+ cPage.acquireWriteLatch(false);
+ try {
+ if (!cPage.valid) {
+ read(cPage);
+ }
+ cPage.valid = true;
+ } finally {
+ cPage.releaseWriteLatch();
+ }
+ }
+ } else {
+ cPage.valid = true;
+ }
+ pageReplacementStrategy.notifyCachePageAccess(cPage);
+ return cPage;
+ }
+
+ private CachedPage findPage(long dpid, boolean newPage) {
+ int victimizationTryCount = 0;
+ while (true) {
+ CachedPage cPage = null;
+ /*
+ * Hash dpid to get a bucket and then check if the page exists in the bucket.
+ */
+ 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();
+ return cPage;
+ }
+ cPage = cPage.next;
+ }
+ } finally {
+ bucket.bucketLock.unlock();
+ }
+ /*
+ * If we got here, the page was not in the hash table.
+ * Now we ask the page replacement strategy to find us a victim.
+ */
+ CachedPage victim = (CachedPage) pageReplacementStrategy.findVictim();
+ if (victim != null) {
+ /*
+ * We have a victim with the following invariants.
+ * 1. The dpid on the CachedPage may or may not be valid.
+ * 2. We have a pin on the CachedPage.
+ * We have to deal with three cases here.
+ * Case 1: The dpid on the CachedPage is invalid (-1). This indicates
+ * that this buffer has never been used. So we are the only ones holding
+ * it. Get a lock on the required dpid's hash bucket, check if someone inserted
+ * the page we want into the table. If so, decrement the pincount on the victim
+ * and return the winner page in the table. If such a winner does not exist,
+ * insert the victim and return it.
+ * Case 2: The dpid on the CachedPage is valid.
+ * Case 2a: The current dpid and required dpid hash to the same bucket.
+ * Get the bucket lock, check that the victim is still at pinCount == 1
+ * If so check if there is a winning CachedPage with the required dpid.
+ * If so, decrement the pinCount on the victim and return the winner.
+ * If not, update the contents of the CachedPage to hold the required dpid
+ * and return it. If the picCount on the victim was != 1 or CachedPage was dirty
+ * someone used the victim for its old contents -- Decrement the pinCount and
+ * retry.
+ * Case 2b: The current dpid and required dpid hash to different buckets.
+ * Get the two bucket locks in the order of the bucket indexes (Ordering prevents
+ * deadlocks). Check for the existence of a winner in the new bucket and for potential
+ * use of the victim (pinCount != 1). If everything looks good, remove
+ * the CachedPage from the old bucket, and add it to the new bucket and update its
+ * header with the new dpid.
+ */
+ if (victim.dpid < 0) {
+ /*
+ * Case 1.
+ */
+ bucket.bucketLock.lock();
+ try {
+ cPage = bucket.cachedPage;
+ while (cPage != null) {
+ if (cPage.dpid == dpid) {
+ cPage.pinCount.incrementAndGet();
+ victim.pinCount.decrementAndGet();
+ return cPage;
+ }
+ cPage = cPage.next;
+ }
+ victim.reset(dpid);
+ victim.next = bucket.cachedPage;
+ bucket.cachedPage = victim;
+ } finally {
+ bucket.bucketLock.unlock();
+ }
+ return victim;
+ }
+ int victimHash = hash(victim.dpid);
+ if (victimHash == hash) {
+ /*
+ * Case 2a.
+ */
+ bucket.bucketLock.lock();
+ try {
+ if (victim.pinCount.get() != 1) {
+ victim.pinCount.decrementAndGet();
+ continue;
+ }
+ cPage = bucket.cachedPage;
+ while (cPage != null) {
+ if (cPage.dpid == dpid) {
+ cPage.pinCount.incrementAndGet();
+ victim.pinCount.decrementAndGet();
+ return cPage;
+ }
+ cPage = cPage.next;
+ }
+ victim.reset(dpid);
+ } finally {
+ bucket.bucketLock.unlock();
+ }
+ return victim;
+ } else {
+ /*
+ * Case 2b.
+ */
+ CacheBucket victimBucket = pageMap[victimHash];
+ if (victimHash < hash) {
+ victimBucket.bucketLock.lock();
+ bucket.bucketLock.lock();
+ } else {
+ bucket.bucketLock.lock();
+ victimBucket.bucketLock.lock();
+ }
+ try {
+ if (victim.pinCount.get() != 1) {
+ victim.pinCount.decrementAndGet();
+ continue;
+ }
+ cPage = bucket.cachedPage;
+ while (cPage != null) {
+ if (cPage.dpid == dpid) {
+ cPage.pinCount.incrementAndGet();
+ victim.pinCount.decrementAndGet();
+ return cPage;
+ }
+ cPage = cPage.next;
+ }
+ if (victimBucket.cachedPage == victim) {
+ victimBucket.cachedPage = victim.next;
+ } else {
+ CachedPage victimPrev = victimBucket.cachedPage;
+ while (victimPrev != null && victimPrev.next != victim) {
+ victimPrev = victimPrev.next;
+ }
+ assert victimPrev != null;
+ victimPrev.next = victim.next;
+ }
+ victim.reset(dpid);
+ victim.next = bucket.cachedPage;
+ bucket.cachedPage = victim;
+ } finally {
+ victimBucket.bucketLock.unlock();
+ bucket.bucketLock.unlock();
+ }
+ return victim;
+ }
+ }
+ /*
+ * Victimization failed -- all pages pinned?
+ * wait a bit, increment victimizationTryCount and loop around.
+ * Give up after MAX_VICTIMIZATION_TRY_COUNT trys.
+ */
+ if (++victimizationTryCount >= MAX_VICTIMIZATION_TRY_COUNT) {
+ return null;
+ }
+ try {
+ synchronized (cleanerThread) {
+ cleanerThread.notifyAll();
+ }
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ // Do nothing
+ }
+ }
+ }
+
+ private void read(CachedPage cPage) throws HyracksDataException {
+ FileInfo fInfo = fileManager.getFileInfo(FileInfo.getFileId(cPage.dpid));
+ try {
+ cPage.buffer.clear();
+ fInfo.getFileChannel().read(cPage.buffer, FileInfo.getPageId(cPage.dpid) * pageSize);
+ } catch (IOException e) {
+ throw new HyracksDataException(e);
+ }
+ }
+
+ private void write(CachedPage cPage) throws HyracksDataException {
+ FileInfo fInfo = fileManager.getFileInfo(FileInfo.getFileId(cPage.dpid));
+ try {
+ cPage.buffer.position(0);
+ cPage.buffer.limit(pageSize);
+ fInfo.getFileChannel().write(cPage.buffer, FileInfo.getPageId(cPage.dpid) * pageSize);
+ } catch (IOException e) {
+ throw new HyracksDataException(e);
+ }
+ }
+
+ @Override
+ public void unpin(ICachedPage page) throws HyracksDataException {
+ if (closed) {
+ throw new HyracksDataException("unpin called on a closed cache");
+ }
+ ((CachedPage) page).pinCount.decrementAndGet();
+ }
+
+ private int hash(long dpid) {
+ return (int) (dpid % pageMap.length);
+ }
+
+ private static class CacheBucket {
+ private final Lock bucketLock;
+ private CachedPage cachedPage;
+
+ public CacheBucket() {
+ bucketLock = new ReentrantLock();
+ }
+ }
+
+ private class CachedPage implements ICachedPageInternal {
+ private final int cpid;
+ private final ByteBuffer buffer;
+ private final AtomicInteger pinCount;
+ private final AtomicBoolean dirty;
+ private final ReadWriteLock latch;
+ private final Object replacementStrategyObject;
+ volatile long dpid;
+ CachedPage next;
+ volatile boolean valid;
+
+ public CachedPage(int cpid, ByteBuffer buffer, IPageReplacementStrategy pageReplacementStrategy) {
+ this.cpid = cpid;
+ this.buffer = buffer;
+ pinCount = new AtomicInteger();
+ dirty = new AtomicBoolean();
+ latch = new ReentrantReadWriteLock(true);
+ replacementStrategyObject = pageReplacementStrategy.createPerPageStrategyObject(cpid);
+ dpid = -1;
+ valid = false;
+ }
+
+ public void reset(long dpid) {
+ this.dpid = dpid;
+ dirty.set(false);
+ valid = false;
+ pageReplacementStrategy.notifyCachePageReset(this);
+ }
+
+ @Override
+ public ByteBuffer getBuffer() {
+ return buffer;
+ }
+
+ @Override
+ public Object getReplacementStrategyObject() {
+ return replacementStrategyObject;
+ }
+
+ @Override
+ public boolean pinIfGoodVictim() {
+ return pinCount.compareAndSet(0, 1);
+ }
+
+ @Override
+ public int getCachedPageId() {
+ return cpid;
+ }
+
+ @Override
+ public void acquireReadLatch() {
+ latch.readLock().lock();
+ }
+
+ private void acquireWriteLatch(boolean markDirty) {
+ latch.writeLock().lock();
+ if (markDirty) {
+ if (dirty.compareAndSet(false, true)) {
+ pinCount.incrementAndGet();
+ }
+ }
+ }
+
+ @Override
+ public void acquireWriteLatch() {
+ acquireWriteLatch(true);
+ }
+
+ @Override
+ public void releaseReadLatch() {
+ latch.readLock().unlock();
+ }
+
+ @Override
+ public void releaseWriteLatch() {
+ latch.writeLock().unlock();
+ }
+ }
+
+ @Override
+ public ICachedPageInternal getPage(int cpid) {
+ return cachedPages[cpid];
+ }
+
+ private class CleanerThread extends Thread {
+ private boolean shutdownStart = false;
+ private boolean shutdownComplete = false;
+
+ @Override
+ public synchronized void run() {
+ try {
+ while (true) {
+ for (int i = 0; i < numPages; ++i) {
+ CachedPage cPage = cachedPages[i];
+ if (cPage.dirty.get()) {
+ if (cPage.latch.readLock().tryLock()) {
+ try {
+ boolean cleaned = true;
+ try {
+ write(cPage);
+ } catch (HyracksDataException e) {
+ cleaned = false;
+ }
+ if (cleaned) {
+ cPage.dirty.set(false);
+ cPage.pinCount.decrementAndGet();
+ }
+ } finally {
+ cPage.latch.readLock().unlock();
+ }
+ } else if (shutdownStart) {
+ throw new IllegalStateException(
+ "Cache closed, but unable to acquire read lock on dirty page: " + cPage.dpid);
+ }
+ }
+ }
+ if (shutdownStart) {
+ break;
+ }
+ try {
+ wait(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ } finally {
+ shutdownComplete = true;
+ notifyAll();
+ }
+ }
+ }
+
+ @Override
+ public void close() {
+ closed = true;
+ synchronized (cleanerThread) {
+ cleanerThread.shutdownStart = true;
+ cleanerThread.notifyAll();
+ while (!cleanerThread.shutdownComplete) {
+ try {
+ cleanerThread.wait();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ClockPageReplacementStrategy.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ClockPageReplacementStrategy.java
new file mode 100644
index 0000000..8d59c64
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ClockPageReplacementStrategy.java
@@ -0,0 +1,65 @@
+package edu.uci.ics.hyracks.storage.common.storage.buffercache;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class ClockPageReplacementStrategy implements IPageReplacementStrategy {
+ private final Lock lock;
+ private IBufferCacheInternal bufferCache;
+ private int clockPtr;
+
+ public ClockPageReplacementStrategy() {
+ this.lock = new ReentrantLock();
+ clockPtr = 0;
+ }
+
+ @Override
+ public Object createPerPageStrategyObject(int cpid) {
+ return new AtomicBoolean();
+ }
+
+ @Override
+ public void setBufferCache(IBufferCacheInternal bufferCache) {
+ this.bufferCache = bufferCache;
+ }
+
+ @Override
+ public void notifyCachePageReset(ICachedPageInternal cPage) {
+ getPerPageObject(cPage).set(false);
+ }
+
+ @Override
+ public void notifyCachePageAccess(ICachedPageInternal cPage) {
+ getPerPageObject(cPage).set(true);
+ }
+
+ @Override
+ public ICachedPageInternal findVictim() {
+ lock.lock();
+ try {
+ int startClockPtr = clockPtr;
+ do {
+ ICachedPageInternal cPage = bufferCache.getPage(clockPtr);
+
+ /*
+ * We do two things here: 1. If the page has been accessed, then we skip it -- The CAS would return false if the current value is false which makes the page a possible candidate for replacement. 2. We check with the buffer manager if it feels its a good idea to use this page as a victim.
+ */
+ AtomicBoolean accessedFlag = getPerPageObject(cPage);
+ if (!accessedFlag.compareAndSet(true, false)) {
+ if (cPage.pinIfGoodVictim()) {
+ return cPage;
+ }
+ }
+ clockPtr = (clockPtr + 1) % bufferCache.getNumPages();
+ } while (clockPtr != startClockPtr);
+ } finally {
+ lock.unlock();
+ }
+ return null;
+ }
+
+ private AtomicBoolean getPerPageObject(ICachedPageInternal cPage) {
+ return (AtomicBoolean) cPage.getReplacementStrategyObject();
+ }
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/DirectBufferAllocator.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/DirectBufferAllocator.java
new file mode 100644
index 0000000..ffe0356
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/DirectBufferAllocator.java
@@ -0,0 +1,14 @@
+package edu.uci.ics.hyracks.storage.common.storage.buffercache;
+
+import java.nio.ByteBuffer;
+
+public class DirectBufferAllocator 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.allocateDirect(pageSize);
+ }
+ return buffers;
+ }
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/IBufferCache.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/IBufferCache.java
new file mode 100644
index 0000000..cd8a576
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/IBufferCache.java
@@ -0,0 +1,15 @@
+package edu.uci.ics.hyracks.storage.common.storage.buffercache;
+
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+
+public interface IBufferCache {
+ public ICachedPage pin(long dpid, boolean newPage) throws HyracksDataException;
+
+ public void unpin(ICachedPage page) throws HyracksDataException;
+
+ public int getPageSize();
+
+ public int getNumPages();
+
+ public void close();
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/IBufferCacheInternal.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/IBufferCacheInternal.java
new file mode 100644
index 0000000..a517a55
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/IBufferCacheInternal.java
@@ -0,0 +1,5 @@
+package edu.uci.ics.hyracks.storage.common.storage.buffercache;
+
+public interface IBufferCacheInternal extends IBufferCache {
+ public ICachedPageInternal getPage(int cpid);
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ICacheMemoryAllocator.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ICacheMemoryAllocator.java
new file mode 100644
index 0000000..03be5b6
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ICacheMemoryAllocator.java
@@ -0,0 +1,7 @@
+package edu.uci.ics.hyracks.storage.common.storage.buffercache;
+
+import java.nio.ByteBuffer;
+
+public interface ICacheMemoryAllocator {
+ public ByteBuffer[] allocate(int pageSize, int numPages);
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ICachedPage.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ICachedPage.java
new file mode 100644
index 0000000..c5f60f1
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ICachedPage.java
@@ -0,0 +1,15 @@
+package edu.uci.ics.hyracks.storage.common.storage.buffercache;
+
+import java.nio.ByteBuffer;
+
+public interface ICachedPage {
+ public ByteBuffer getBuffer();
+
+ public void acquireReadLatch();
+
+ public void releaseReadLatch();
+
+ public void acquireWriteLatch();
+
+ public void releaseWriteLatch();
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ICachedPageInternal.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ICachedPageInternal.java
new file mode 100644
index 0000000..de97ad4
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/ICachedPageInternal.java
@@ -0,0 +1,9 @@
+package edu.uci.ics.hyracks.storage.common.storage.buffercache;
+
+public interface ICachedPageInternal extends ICachedPage {
+ public int getCachedPageId();
+
+ public Object getReplacementStrategyObject();
+
+ public boolean pinIfGoodVictim();
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/IPageReplacementStrategy.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/IPageReplacementStrategy.java
new file mode 100644
index 0000000..e4c1ab7
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/buffercache/IPageReplacementStrategy.java
@@ -0,0 +1,13 @@
+package edu.uci.ics.hyracks.storage.common.storage.buffercache;
+
+public interface IPageReplacementStrategy {
+ public Object createPerPageStrategyObject(int cpid);
+
+ public void setBufferCache(IBufferCacheInternal bufferCache);
+
+ public void notifyCachePageReset(ICachedPageInternal cPage);
+
+ public void notifyCachePageAccess(ICachedPageInternal cPage);
+
+ public ICachedPageInternal findVictim();
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/file/FileInfo.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/file/FileInfo.java
new file mode 100644
index 0000000..97b1b57
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/file/FileInfo.java
@@ -0,0 +1,44 @@
+package edu.uci.ics.hyracks.storage.common.storage.file;
+
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+
+public class FileInfo {
+ private final int fileId;
+ private final RandomAccessFile file;
+ private FileChannel channel;
+
+ public FileInfo(int fileId, RandomAccessFile file) {
+ this.fileId = fileId;
+ this.file = file;
+ channel = file.getChannel();
+ }
+
+ public int getFileId() {
+ return fileId;
+ }
+
+ public RandomAccessFile getFile() {
+ return file;
+ }
+
+ public FileChannel getFileChannel() {
+ return channel;
+ }
+
+ public long getDiskPageId(int pageId) {
+ return getDiskPageId(fileId, pageId);
+ }
+
+ public static long getDiskPageId(int fileId, int pageId) {
+ return (((long) fileId) << 32) + pageId;
+ }
+
+ public static int getFileId(long dpid) {
+ return (int) ((dpid >> 32) & 0xffffffff);
+ }
+
+ public static int getPageId(long dpid) {
+ return (int) (dpid & 0xffffffff);
+ }
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/file/FileManager.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/file/FileManager.java
new file mode 100644
index 0000000..b2f309b
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/file/FileManager.java
@@ -0,0 +1,47 @@
+package edu.uci.ics.hyracks.storage.common.storage.file;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import edu.uci.ics.hyracks.api.exceptions.HyracksDataException;
+
+public class FileManager {
+ private final Map<Integer, FileInfo> fileRegistry;
+
+ public FileManager() {
+ fileRegistry = new HashMap<Integer, FileInfo>();
+ }
+
+ public void registerFile(FileInfo fInfo) throws HyracksDataException {
+ if (fileRegistry.containsKey(fInfo.getFileId())) {
+ throw new HyracksDataException("File with id " + fInfo.getFileId() + " is already registered");
+ }
+ fileRegistry.put(fInfo.getFileId(), fInfo);
+ }
+
+ public FileInfo unregisterFile(int fileId) throws HyracksDataException {
+ if (!fileRegistry.containsKey(fileId)) {
+ throw new HyracksDataException("File with id " + fileId + " not in registry");
+ }
+ return fileRegistry.remove(fileId);
+ }
+
+ public FileInfo getFileInfo(int fileId) throws HyracksDataException {
+ FileInfo fInfo = fileRegistry.get(fileId);
+ if (fInfo == null) {
+ throw new HyracksDataException("File with id " + fileId + " not in registry");
+ }
+ return fInfo;
+ }
+
+ public void close() {
+ for (FileInfo fInfo : fileRegistry.values()) {
+ try {
+ fInfo.getFileChannel().close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/sync/LatchType.java b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/sync/LatchType.java
new file mode 100644
index 0000000..4772ae0
--- /dev/null
+++ b/hyracks-storage-common/src/main/java/edu/uci/ics/hyracks/storage/common/storage/sync/LatchType.java
@@ -0,0 +1,6 @@
+package edu.uci.ics.hyracks.storage.common.storage.sync;
+
+public enum LatchType {
+ LATCH_X,
+ LATCH_S
+}
\ No newline at end of file