diff --git a/src/HashMap.h b/src/HashMap.h
new file mode 100644
index 0000000000000000000000000000000000000000..dae8012b958f71591de9b4ce3367c7d47bdca275
--- /dev/null
+++ b/src/HashMap.h
@@ -0,0 +1,150 @@
+#pragma once
+
+/**
+ * Copyright 2017 HashMap Development Team
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "HashNode.h"
+#include <cstddef>
+#include "Key.h"
+#include "Buffer.h"
+#define TABLE_SIZE 50000
+
+namespace RAMCloud
+{
+    class HashMap
+    {
+    public:
+        HashMap() : table()
+        {}
+
+        ~HashMap()
+        {
+            // destroy all buckets one by one
+            for (size_t i = 0; i < TABLE_SIZE; ++i)
+            {
+                HashNode *entry = table[i];
+
+                while (entry != NULL)
+                {
+                    HashNode *prev = entry;
+                    entry = entry->getNext();
+                    delete prev;
+                }
+
+                table[i] = NULL;
+            }
+        }
+
+        bool get(Key &key, Buffer &value)
+        {
+            unsigned long hashValue = hashFunc(key);
+            // HashNode *entry = table[hashValue];
+            HashNode *entry = table[hashValue];
+
+            while (entry != NULL)
+            {
+                if (entry->getKey() == key)
+                {
+                    void **ptr;
+                    entry->getValue().peek(0,ptr);
+                    value.appendCopy(*ptr, entry->getValue().size()); // verify if should be dereferenced
+                    return true;
+                }
+
+                entry = entry->getNext();
+            }
+
+            return false;
+        }
+
+        void put(Key &key, const Buffer &value)
+        {
+            unsigned long hashValue = hashFunc(key);
+            HashNode *prev = NULL;
+            HashNode *entry = table[hashValue];
+
+            while (entry != NULL && entry->getKey() != key)
+            {
+                prev = entry;
+                entry = entry->getNext();
+            }
+
+            if (entry == NULL)
+            {
+                entry = new HashNode(key, value);
+
+                if (prev == NULL)
+                {
+                    // insert as first bucket
+                    table[hashValue] = entry;
+                }
+                else
+                {
+                    prev->setNext(entry);
+                }
+            }
+            else
+            {
+                // just update the value
+                entry->setValue(value);
+            }
+        }
+
+        void remove(Key &key)
+        {
+            unsigned long hashValue = hashFunc(key);
+            HashNode *prev = NULL;
+            HashNode *entry = table[hashValue];
+
+            while (entry != NULL && entry->getKey() != key)
+            {
+                prev = entry;
+                entry = entry->getNext();
+            }
+
+            if (entry == NULL)
+            {
+                // key not found
+                return;
+            }
+            else
+            {
+                if (prev == NULL)
+                {
+                    // remove first bucket of the list
+                    table[hashValue] = entry->getNext();
+                }
+                else
+                {
+                    prev->setNext(entry->getNext());
+                }
+
+                delete entry;
+            }
+        }
+
+    private:
+        HashMap(const HashMap &other);
+        const HashMap &operator=(const HashMap &other);
+        // hash table
+        HashNode *table[TABLE_SIZE];
+        unsigned long hashFunc(Key &k) const
+        {
+            return k.getHash();
+        }
+    };
+
+}
diff --git a/src/HashNode.h b/src/HashNode.h
new file mode 100644
index 0000000000000000000000000000000000000000..dbd8262bf7652ec147a076148b528ecfdf8b537c
--- /dev/null
+++ b/src/HashNode.h
@@ -0,0 +1,84 @@
+#pragma once
+
+/**
+ * Copyright 2017 HashMap Development Team
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <cstddef>
+#include "Key.h"
+#include "Buffer.h"
+
+namespace RAMCloud
+{
+    // Hash node class template
+    // template <typename Key, typename Buffer>
+    class HashNode
+    {
+    private:
+        // key-value pair
+        // next bucket with the same key
+    public:
+        Key _key;
+        Buffer _value;
+        HashNode *_next;
+        // disallow copy and assignment
+        HashNode(const HashNode &);
+        HashNode &operator=(const HashNode &);
+        HashNode(const Key &key, Buffer &value) : 
+            _key(
+                key.getTableId(),
+                key.getStringKey(),
+                key.getStringKeyLength()
+            ), 
+            _value(), 
+            _next(NULL)
+        {
+            void **ptr;
+            value.peek(0,ptr);
+            _value.appendCopy(*ptr, value.size());
+        }
+
+        Key getKey() const
+        {
+            return _key;
+        }
+
+        Buffer getValue() const
+        {
+            return _value;
+        }
+
+        void setValue(Buffer& value)
+        {
+            void **ptr;
+            value.peek(0, ptr);
+            _value.appendCopy(*ptr, value.size());
+            // _value = value;
+        }
+
+        HashNode *getNext() const
+        {
+            return _next;
+        }
+
+        void setNext(HashNode *next)
+        {
+            _next = next;
+        }
+
+
+    };
+
+}
diff --git a/src/ObjectManager.cc b/src/ObjectManager.cc
index 6089ae0ab52585d30c41c460cfe7bd504077eaf3..c6011e0c50872ce58f5c33dbdfa9f634a53aa051 100644
--- a/src/ObjectManager.cc
+++ b/src/ObjectManager.cc
@@ -34,6 +34,7 @@
 #include "WallTime.h"
 #include "MasterService.h"
 #include <emmintrin.h> // _mm_clflush and _mm_mfence
+#include "HashMap.h"
 
 namespace RAMCloud {
 
diff --git a/src/ObjectManager.h b/src/ObjectManager.h
index d1ccb2914fe7057e88e44343d4f32f2232614c6f..fec745da5578ce090d2e81ee22ecd16506d4a073 100644
--- a/src/ObjectManager.h
+++ b/src/ObjectManager.h
@@ -38,6 +38,7 @@
 #include "MasterTableMetadata.h"
 #include "UnackedRpcResults.h"
 #include "LockTable.h"
+#include "HashMap.h"
 
 namespace RAMCloud {
 
@@ -416,6 +417,14 @@ class ObjectManager : public LogEntryHandlers,
      */
     int tombstoneProtectorCount;
 
+
+    /**
+     * This hash table maps the key to a pointer to the value in DRAM.
+     * 
+     */
+    HashMap cacheTable;
+
+
     friend class CleanerCompactionBenchmark;
     friend class ObjectManagerBenchmark;