diff --git a/cloudspanner/dependency-reduced-pom.xml b/cloudspanner/dependency-reduced-pom.xml
new file mode 100644
index 0000000000..c52b90b3f9
--- /dev/null
+++ b/cloudspanner/dependency-reduced-pom.xml
@@ -0,0 +1,53 @@
+
+
+
+ binding-parent
+ site.ycsb
+ 0.18.0-SNAPSHOT
+ ../binding-parent/pom.xml
+
+ 4.0.0
+ cloudspanner-binding
+ Cloud Spanner DB Binding
+
+
+
+ maven-shade-plugin
+
+
+ package
+
+ shade
+
+
+
+
+ *:*
+
+ META-INF/*.SF
+ META-INF/*.DSA
+ META-INF/*.RSA
+
+
+
+
+
+ org.example.Main
+
+
+
+
+
+
+
+
+
+
+
+ site.ycsb
+ core
+ 0.18.0-SNAPSHOT
+ provided
+
+
+
diff --git a/mapdb/file.db b/mapdb/file.db
new file mode 100644
index 0000000000..125a9698d0
Binary files /dev/null and b/mapdb/file.db differ
diff --git a/mapdb/pom.xml b/mapdb/pom.xml
new file mode 100644
index 0000000000..c11380bb28
--- /dev/null
+++ b/mapdb/pom.xml
@@ -0,0 +1,42 @@
+
+
+ 4.0.0
+
+ site.ycsb
+ root
+ 0.18.0-SNAPSHOT
+
+
+ mapdb-binding
+ MapDB Binding
+ jar
+
+
+ 17
+ 17
+ UTF-8
+
+
+
+
+ org.mapdb
+ mapdb
+ 3.1.0
+
+
+ site.ycsb
+ core
+ 0.18.0-SNAPSHOT
+ compile
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+
+
\ No newline at end of file
diff --git a/mapdb/src/main/java/site/ycsb/MapDBClient.java b/mapdb/src/main/java/site/ycsb/MapDBClient.java
new file mode 100644
index 0000000000..110911a21f
--- /dev/null
+++ b/mapdb/src/main/java/site/ycsb/MapDBClient.java
@@ -0,0 +1,132 @@
+package site.ycsb;
+
+import org.mapdb.*;
+import org.mapdb.DB;
+
+import java.util.*;
+
+/**
+ * MapDB client for YCSB framework.
+ *
+ */
+public class MapDBClient extends site.ycsb.DB {
+
+ private DB mapDB;
+ private HTreeMap>> db;
+
+ @Override
+ public void init() throws DBException {
+ this.mapDB = DBMaker
+ .fileDB("file.db")
+ .closeOnJvmShutdown()
+ .make();
+
+ db = mapDB.hashMap("db")
+ .keySerializer(Serializer.STRING)
+ .valueSerializer(Serializer.JAVA)
+ .createOrOpen();
+ }
+
+ public void cleanup() throws DBException {
+ db.clear();
+ db.close();
+ mapDB.close();
+ }
+
+ @Override
+ public Status read(String table, String key, Set fields, Map result) {
+ Map> collection = db.getOrDefault(table, new TreeMap<>());
+
+ Map map = collection.get(key);
+
+ if (map == null) {
+ return Status.NOT_FOUND;
+ }
+
+ for (String field : fields) {
+ result.put(field, new ByteArrayByteIterator(map.get(field)));
+ }
+
+ return Status.OK;
+ }
+
+ @Override
+ public Status scan(String table,
+ String startkey,
+ int recordcount,
+ Set fields,
+ Vector> result) {
+ TreeMap> collection = db.getOrDefault(table, new TreeMap<>());
+ SortedMap> map = collection.tailMap(startkey);
+
+ int counter = 0;
+ for (Map.Entry> entry : map.entrySet()) {
+ HashMap filteredMap = new HashMap<>();
+ if (fields == null) {
+ for (Map.Entry entry1 : entry.getValue().entrySet()) {
+ filteredMap.put(entry1.getKey(), new ByteArrayByteIterator(entry1.getValue()));
+ }
+ } else {
+ for (Map.Entry entry1 : entry.getValue().entrySet()) {
+ if (fields.contains(entry1.getKey())) {
+ filteredMap.put(entry1.getKey(), new ByteArrayByteIterator(entry1.getValue()));
+ }
+ }
+ }
+ result.add(filteredMap);
+
+ counter += 1;
+ if (counter == recordcount) {
+ break;
+ }
+ }
+
+ return Status.OK;
+ }
+
+ @Override
+ public Status update(String table, String key, Map values) {
+ TreeMap> collection = db.getOrDefault(table, new TreeMap<>());
+
+ HashMap map = collection.get(key);
+
+ if (map == null) {
+ return Status.NOT_FOUND;
+ }
+
+ for (Map.Entry entry : values.entrySet()) {
+ map.put(entry.getKey(), entry.getValue().toArray());
+ }
+ collection.put(key, map);
+ db.put(table, collection);
+
+ return Status.OK;
+ }
+
+ @Override
+ public Status insert(String table, String key, Map values) {
+ TreeMap> collection = db.getOrDefault(table, new TreeMap<>());
+
+ HashMap map = collection.getOrDefault(key, new HashMap<>());
+
+ for (Map.Entry entry : values.entrySet()) {
+ map.put(entry.getKey(), entry.getValue().toArray());
+ }
+ collection.put(key, map);
+ db.put(table, collection);
+
+ return Status.OK;
+ }
+
+ @Override
+ public Status delete(String table, String key) {
+ Map> collection = db.getOrDefault(table, new TreeMap<>());
+
+ Map removed = collection.remove(key);
+
+ if (removed == null) {
+ return Status.NOT_FOUND;
+ }
+ return Status.OK;
+ }
+}
\ No newline at end of file
diff --git a/mapdb/src/main/java/site/ycsb/package-info.java b/mapdb/src/main/java/site/ycsb/package-info.java
new file mode 100644
index 0000000000..a6d73c4f74
--- /dev/null
+++ b/mapdb/src/main/java/site/ycsb/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2017, Yahoo!, Inc. All rights reserved.
+ *
+ * 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. See accompanying
+ * LICENSE file.
+ */
+
+/**
+ * The YCSB binding for MapDB.
+ */
+package site.ycsb;
+
diff --git a/mapdb/src/test/java/site/ycsb/MapDBClientTest.java b/mapdb/src/test/java/site/ycsb/MapDBClientTest.java
new file mode 100644
index 0000000000..3c8319e4ea
--- /dev/null
+++ b/mapdb/src/test/java/site/ycsb/MapDBClientTest.java
@@ -0,0 +1,147 @@
+/**
+ * Copyright (c) 2012-2017 YCSB contributors. All rights reserved.
+ *
+ * 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. See accompanying
+ * LICENSE file.
+ */
+
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package site.ycsb;
+
+import site.ycsb.workloads.CoreWorkload;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.util.HashMap;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Vector;
+
+import static org.junit.Assert.assertEquals;
+
+public class MapDBClientTest {
+
+ @ClassRule public final static TemporaryFolder temp = new TemporaryFolder();
+ private static final MapDBClient instance = new MapDBClient();
+ private final static HashMap MOCK_DATA;
+ private final static String MOCK_TABLE = "MOCK_TABLE";
+ private final static String MOCK_KEY0 = "0";
+ private final static String MOCK_KEY1 = "1";
+ private final static String MOCK_KEY2 = "2";
+ private final static String FIELD_PREFIX = CoreWorkload.FIELD_NAME_PREFIX_DEFAULT;
+
+ static {
+ MOCK_DATA = new HashMap<>(10);
+ for (int i = 1; i <= 10; i++) {
+ MOCK_DATA.put(FIELD_PREFIX + i, new StringByteIterator("value" + i));
+ }
+ }
+
+ @BeforeClass
+ public static void setUpClass() throws DBException {
+ final Properties props = new Properties();
+ props.put("path.home", temp.getRoot().toString());
+ instance.setProperties(props);
+ instance.init();
+ }
+
+ @AfterClass
+ public static void tearDownClass() throws DBException {
+ instance.cleanup();
+ }
+
+ @Before
+ public void setUp() {
+ instance.insert(MOCK_TABLE, MOCK_KEY1, MOCK_DATA);
+ instance.insert(MOCK_TABLE, MOCK_KEY2, MOCK_DATA);
+ }
+
+ @After
+ public void tearDown() {
+ instance.delete(MOCK_TABLE, MOCK_KEY1);
+ instance.delete(MOCK_TABLE, MOCK_KEY2);
+ }
+
+ /**
+ * Test of insert method, of class MapDBClient.
+ */
+ @Test
+ public void testInsert() {
+ Status result = instance.insert(MOCK_TABLE, MOCK_KEY0, MOCK_DATA);
+ assertEquals(Status.OK, result);
+ }
+
+ /**
+ * Test of delete method, of class MapDBClient.
+ */
+ @Test
+ public void testDelete() {
+ Status result = instance.delete(MOCK_TABLE, MOCK_KEY1);
+ assertEquals(Status.OK, result);
+ }
+
+ /**
+ * Test of read method, of class MapDBClient.
+ */
+ @Test
+ public void testRead() {
+ Set fields = MOCK_DATA.keySet();
+ HashMap resultParam = new HashMap<>(10);
+ Status result = instance.read(MOCK_TABLE, MOCK_KEY1, fields, resultParam);
+ assertEquals(Status.OK, result);
+ }
+
+ /**
+ * Test of update method, of class MapDBClient.
+ */
+ @Test
+ public void testUpdate() {
+ int i;
+ HashMap newValues = new HashMap<>(10);
+
+ for (i = 1; i <= 10; i++) {
+ newValues.put(FIELD_PREFIX + i, new StringByteIterator("newvalue" + i));
+ }
+
+ Status result = instance.update(MOCK_TABLE, MOCK_KEY1, newValues);
+ assertEquals(Status.OK, result);
+
+ //validate that the values changed
+ HashMap resultParam = new HashMap<>(10);
+ instance.read(MOCK_TABLE, MOCK_KEY1, MOCK_DATA.keySet(), resultParam);
+
+ for (i = 1; i <= 10; i++) {
+ assertEquals("newvalue" + i, resultParam.get(FIELD_PREFIX + i).toString());
+ }
+ }
+
+ /**
+ * Test of scan method, of class MapDBClient.
+ */
+ @Test
+ public void testScan() {
+ int recordcount = 10;
+ Set fields = MOCK_DATA.keySet();
+ Vector> resultParam = new Vector<>(10);
+ Status result = instance.scan(MOCK_TABLE, MOCK_KEY1, recordcount, fields, resultParam);
+ assertEquals(Status.OK, result);
+ }
+}
diff --git a/pom.xml b/pom.xml
index 7a24d43d4f..4e3ba9ad69 100644
--- a/pom.xml
+++ b/pom.xml
@@ -203,6 +203,7 @@ LICENSE file.
tablestore
voltdb
zookeeper
+ mapdb