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