diff --git a/arangodb/.gitignore b/arangodb/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..ae3c1726048cd06b9a143e0376ed46dd9b9a8d53
--- /dev/null
+++ b/arangodb/.gitignore
@@ -0,0 +1 @@
+/bin/
diff --git a/arangodb/README.md b/arangodb/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..001892fd912ac6dcfe8f134272a52c3c91caf109
--- /dev/null
+++ b/arangodb/README.md
@@ -0,0 +1,93 @@
+<!--
+Copyright (c) 2012 - 2015 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.
+-->
+
+## Quick Start
+
+This section describes how to run YCSB on ArangoDB. 
+
+### 1. Start ArangoDB
+See https://docs.arangodb.com/Installing/index.html
+
+### 2. Install Java and Maven
+
+Go to http://www.oracle.com/technetwork/java/javase/downloads/index.html
+
+and get the url to download the rpm into your server. For example:
+
+    wget http://download.oracle.com/otn-pub/java/jdk/7u40-b43/jdk-7u40-linux-x64.rpm?AuthParam=11232426132 -o jdk-7u40-linux-x64.rpm
+    rpm -Uvh jdk-7u40-linux-x64.rpm
+    
+Or install via yum/apt-get
+
+    sudo yum install java-devel
+
+Download MVN from http://maven.apache.org/download.cgi
+
+    wget http://ftp.heanet.ie/mirrors/www.apache.org/dist/maven/maven-3/3.1.1/binaries/apache-maven-3.1.1-bin.tar.gz
+    sudo tar xzf apache-maven-*-bin.tar.gz -C /usr/local
+    cd /usr/local
+    sudo ln -s apache-maven-* maven
+    sudo vi /etc/profile.d/maven.sh
+
+Add the following to `maven.sh`
+
+    export M2_HOME=/usr/local/maven
+    export PATH=${M2_HOME}/bin:${PATH}
+
+Reload bash and test mvn
+
+    bash
+    mvn -version
+
+### 3. Set Up YCSB
+
+Clone this YCSB source code:
+
+    git clone https://github.com/brianfrankcooper/YCSB.git
+
+### 4. Run YCSB
+
+Now you are ready to run! First, drop the existing collection: "usertable" under database "ycsb":
+	
+	db._collection("usertable").drop()
+
+Then, load the data:
+
+    ./bin/ycsb load arangodb -s -P workloads/workloada -p arangodb.ip=xxx -p arangodb.port=xxx
+
+Then, run the workload:
+
+    ./bin/ycsb run arangodb -s -P workloads/workloada -p arangodb.ip=xxx -p arangodb.port=xxx
+
+See the next section for the list of configuration parameters for ArangoDB.
+
+## ArangoDB Configuration Parameters
+
+- `arangodb.ip`
+  - Default value is `localhost`
+
+- `arangodb.port`
+  - Default value is `8529`.
+  
+- `arangodb.waitForSync`
+  - Default value is `true`.
+  
+- `arangodb.transactionUpdate`
+  - Default value is `false`.
+
+- `arangodb.dropDBBeforeRun`
+  - Default value is `false`.
diff --git a/arangodb/conf/logback.xml b/arangodb/conf/logback.xml
new file mode 100644
index 0000000000000000000000000000000000000000..95668c700c6c7850bf3294d49fb12e2601c1441d
--- /dev/null
+++ b/arangodb/conf/logback.xml
@@ -0,0 +1,31 @@
+<!-- 
+Copyright (c) 2012 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.
+-->
+
+<configuration>
+
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <!-- encoders are assigned the type
+         ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
+    <encoder>
+      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
+    </encoder>
+  </appender>
+
+  <root level="info">
+    <appender-ref ref="STDOUT" />
+  </root>
+</configuration>
diff --git a/arangodb/pom.xml b/arangodb/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..717224d69338bdd4d3d92aa2472c7da6d1c91ca0
--- /dev/null
+++ b/arangodb/pom.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+Copyright (c) 2012 - 2016 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.
+-->
+
+<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>
+  <parent>
+    <groupId>com.yahoo.ycsb</groupId>
+    <artifactId>binding-parent</artifactId>
+    <version>0.12.0-SNAPSHOT</version>
+    <relativePath>../binding-parent</relativePath>
+  </parent>
+
+  <artifactId>arangodb-binding</artifactId>
+  <name>ArangoDB Binding</name>
+  <packaging>jar</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>com.arangodb</groupId>
+      <artifactId>arangodb-java-driver</artifactId>
+      <version>${arangodb.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.yahoo.ycsb</groupId>
+      <artifactId>core</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+	<dependency>
+		<groupId>org.slf4j</groupId>
+		<artifactId>slf4j-api</artifactId>
+		<version>1.7.13</version>
+		<type>jar</type>
+		<scope>compile</scope>
+	</dependency>
+	<dependency>
+		<groupId>ch.qos.logback</groupId>
+		<artifactId>logback-classic</artifactId>
+		<version>1.1.3</version>
+		<type>jar</type>
+		<scope>provided</scope>
+	</dependency>
+	<dependency>
+		<groupId>ch.qos.logback</groupId>
+		<artifactId>logback-core</artifactId>
+		<version>1.1.3</version>
+		<type>jar</type>
+		<scope>provided</scope>
+	</dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/arangodb/src/main/java/com/yahoo/ycsb/db/ArangoDBClient.java b/arangodb/src/main/java/com/yahoo/ycsb/db/ArangoDBClient.java
new file mode 100644
index 0000000000000000000000000000000000000000..1a9d185f53009ddceee5e841ca779c7201cba86e
--- /dev/null
+++ b/arangodb/src/main/java/com/yahoo/ycsb/db/ArangoDBClient.java
@@ -0,0 +1,466 @@
+/**
+ * Copyright (c) 2012 - 2015 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.
+ */
+package com.yahoo.ycsb.db;
+
+import com.arangodb.ArangoConfigure;
+import com.arangodb.ArangoDriver;
+import com.arangodb.ArangoException;
+import com.arangodb.ArangoHost;
+import com.arangodb.DocumentCursor;
+import com.arangodb.ErrorNums;
+import com.arangodb.entity.BaseDocument;
+import com.arangodb.entity.DocumentEntity;
+import com.arangodb.entity.EntityFactory;
+import com.arangodb.entity.TransactionEntity;
+import com.arangodb.util.MapBuilder;
+
+import com.yahoo.ycsb.DB;
+import com.yahoo.ycsb.Status;
+import com.yahoo.ycsb.DBException;
+import com.yahoo.ycsb.ByteIterator;
+import com.yahoo.ycsb.StringByteIterator;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Vector;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ArangoDB binding for YCSB framework using the ArangoDB Inc. <a
+ * href="https://github.com/arangodb/arangodb-java-driver">driver</a>
+ * <p>
+ * See the <code>README.md</code> for configuration information.
+ * </p>
+ * 
+ * @see <a href="https://github.com/arangodb/arangodb-java-driver">ArangoDB Inc.
+ *      driver</a>
+ */
+public class ArangoDBClient extends DB {
+
+  private static Logger logger = LoggerFactory.getLogger(ArangoDBClient.class);
+  
+  /**
+   * The database name to access.
+   */
+  private static String databaseName = "ycsb";
+
+  /**
+   * Count the number of times initialized to teardown on the last
+   * {@link #cleanup()}.
+   */
+  private static final AtomicInteger INIT_COUNT = new AtomicInteger(0);
+
+  /** ArangoDB Driver related, Singleton. */
+  private static ArangoDriver arangoDriver;
+  private static Boolean dropDBBeforeRun;
+  private static Boolean waitForSync = true;
+  private static Boolean transactionUpdate = false;
+
+  /**
+   * Initialize any state for this DB. Called once per DB instance; there is
+   * one DB instance per client thread.
+   * 
+   * Actually, one client process will share one DB instance here.(Coincide to
+   * mongoDB driver)
+   */
+  @Override
+  public void init() throws DBException {
+    INIT_COUNT.incrementAndGet();
+    synchronized (ArangoDBClient.class) {
+      if (arangoDriver != null) {
+        return;
+      }
+
+      Properties props = getProperties();
+
+      // Set the DB address
+      String ip = props.getProperty("arangodb.ip", "localhost");
+      String portStr = props.getProperty("arangodb.port", "8529");
+      int port = Integer.parseInt(portStr);
+
+      // If clear db before run
+      String dropDBBeforeRunStr = props.getProperty("arangodb.dropDBBeforeRun", "false");
+      dropDBBeforeRun = Boolean.parseBoolean(dropDBBeforeRunStr);
+      
+      // Set the sync mode
+      String waitForSyncStr = props.getProperty("arangodb.waitForSync", "false");
+      waitForSync = Boolean.parseBoolean(waitForSyncStr);
+      
+      // Set if transaction for update
+      String transactionUpdateStr = props.getProperty("arangodb.transactionUpdate", "false");
+      transactionUpdate = Boolean.parseBoolean(transactionUpdateStr);
+      
+      // Init ArangoDB connection
+      try {
+        ArangoConfigure arangoConfigure = new ArangoConfigure();
+        arangoConfigure.setArangoHost(new ArangoHost(ip, port));
+        arangoConfigure.init();
+        arangoDriver = new ArangoDriver(arangoConfigure);
+      } catch (Exception e) {
+        logger.error("Failed to initialize ArangoDB", e);
+        System.exit(-1);
+      }
+
+      // Init the database
+      if (dropDBBeforeRun) {
+        // Try delete first
+        try {
+          arangoDriver.deleteDatabase(databaseName);
+        } catch (ArangoException e) {
+          if (e.getErrorNumber() != ErrorNums.ERROR_ARANGO_DATABASE_NOT_FOUND) {
+            logger.error("Failed to delete database: {} with ex: {}", databaseName, e.toString());
+            System.exit(-1);
+          } else {
+            logger.info("Fail to delete DB, already deleted: {}", databaseName);
+          }
+        }
+      }
+      try {
+        arangoDriver.createDatabase(databaseName);
+        logger.info("Database created: " + databaseName);
+      } catch (ArangoException e) {
+        if (e.getErrorNumber() != ErrorNums.ERROR_ARANGO_DUPLICATE_NAME) {
+          logger.error("Failed to create database: {} with ex: {}", databaseName, e.toString());
+          System.exit(-1);
+        } else {
+          logger.info("DB already exists: {}", databaseName);
+        }
+      }
+      // Always set the default db
+      arangoDriver.setDefaultDatabase(databaseName);
+      logger.info("ArangoDB client connection created to {}:{}", ip, port);
+      
+      // Log the configuration
+      logger.info("Arango Configuration: dropDBBeforeRun: {}; address: {}:{}; databaseName: {};"
+                  + " waitForSync: {}; transactionUpdate: {};",
+                  dropDBBeforeRun, ip, port, databaseName, waitForSync, transactionUpdate);
+    }
+  }
+
+  /**
+   * Cleanup any state for this DB. Called once per DB instance; there is one
+   * DB instance per client thread.
+   * 
+   * Actually, one client process will share one DB instance here.(Coincide to
+   * mongoDB driver)
+   */
+  @Override
+  public void cleanup() throws DBException {
+    if (INIT_COUNT.decrementAndGet() == 0) {
+      arangoDriver = null;
+      logger.info("Local cleaned up.");
+    }
+  }
+
+  /**
+   * Insert a record in the database. Any field/value pairs in the specified
+   * values HashMap will be written into the record with the specified record
+   * key.
+   * 
+   * @param table
+   *      The name of the table
+   * @param key
+   *      The record key of the record to insert.
+   * @param values
+   *      A HashMap of field/value pairs to insert in the record
+   * @return Zero on success, a non-zero error code on error. See the
+   *     {@link DB} class's description for a discussion of error codes.
+   */
+  @Override
+  public Status insert(String table, String key, HashMap<String, ByteIterator> values) {
+    try {
+      BaseDocument toInsert = new BaseDocument(key);
+      for (Map.Entry<String, ByteIterator> entry : values.entrySet()) {
+        toInsert.addAttribute(entry.getKey(), byteIteratorToString(entry.getValue()));
+      }
+      arangoDriver.createDocument(table, toInsert, true/*create collection if not exist*/,
+                                  waitForSync);
+      return Status.OK;
+    } catch (ArangoException e) {
+      if (e.getErrorNumber() != ErrorNums.ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED) {
+        logger.error("Fail to insert: {} {} with ex {}", table, key, e.toString());
+      } else {
+        logger.debug("Trying to create document with duplicate key: {} {}", table, key);
+        return Status.BAD_REQUEST;
+      }
+    }  catch (RuntimeException e) {
+      logger.error("Exception while trying insert {} {} with ex {}", table, key, e.toString());
+    }
+    return Status.ERROR;
+  }
+
+  /**
+   * Read a record from the database. Each field/value pair from the result
+   * will be stored in a HashMap.
+   * 
+   * @param table
+   *      The name of the table
+   * @param key
+   *      The record key of the record to read.
+   * @param fields
+   *      The list of fields to read, or null for all of them
+   * @param result
+   *      A HashMap of field/value pairs for the result
+   * @return Zero on success, a non-zero error code on error or "not found".
+   */
+  @SuppressWarnings("unchecked")
+  @Override
+  public Status read(String table, String key, Set<String> fields, HashMap<String, ByteIterator> result) {
+    try {
+      DocumentEntity<BaseDocument> targetDoc = arangoDriver.getDocument(table, key, BaseDocument.class);
+      BaseDocument aDocument = targetDoc.getEntity();
+      if (!this.fillMap(result, aDocument.getProperties(), fields)) {
+        return Status.ERROR;
+      }
+      return Status.OK;
+    } catch (ArangoException e) {
+      if (e.getErrorNumber() != ErrorNums.ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
+        logger.error("Fail to read: {} {} with ex {}", table, key, e.toString());
+      } else {
+        logger.debug("Trying to read document not exist: {} {}", table, key);
+        return Status.NOT_FOUND;
+      }
+    } catch (RuntimeException e) {
+      logger.error("Exception while trying read {} {} with ex {}", table, key, e.toString());
+    }
+    return Status.ERROR;
+  }
+
+  /**
+   * Update a record in the database. Any field/value pairs in the specified
+   * values HashMap will be written into the record with the specified record
+   * key, overwriting any existing values with the same field name.
+   * 
+   * @param table
+   *      The name of the table
+   * @param key
+   *      The record key of the record to write.
+   * @param values
+   *      A HashMap of field/value pairs to update in the record
+   * @return Zero on success, a non-zero error code on error. See this class's
+   *     description for a discussion of error codes.
+   */
+  @Override
+  public Status update(String table, String key, HashMap<String, ByteIterator> values) {
+    try {
+      
+      if (!transactionUpdate) {
+        BaseDocument updateDoc = new BaseDocument();
+        for (String field : values.keySet()) {
+          updateDoc.addAttribute(field, byteIteratorToString(values.get(field)));
+        }
+        arangoDriver.updateDocument(table, key, updateDoc);
+        return Status.OK;
+      } else {
+        // id for documentHandle
+        String transactionAction = "function (id) {"
+               // use internal database functions
+            + "var db = require('internal').db;"
+              // collection.update(document, data, overwrite, keepNull, waitForSync)
+            + String.format("db._update(id, %s, true, false, %s);}",
+                mapToJson(values), Boolean.toString(waitForSync).toLowerCase());
+        TransactionEntity transaction = arangoDriver.createTransaction(transactionAction);
+        transaction.addWriteCollection(table);
+        transaction.setParams(createDocumentHandle(table, key));
+        arangoDriver.executeTransaction(transaction);
+        return Status.OK;
+      }
+    } catch (ArangoException e) {
+      if (e.getErrorNumber() != ErrorNums.ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
+        logger.error("Fail to update: {} {} with ex {}", table, key, e.toString());
+      } else {
+        logger.debug("Trying to update document not exist: {} {}", table, key);
+        return Status.NOT_FOUND;
+      }
+    } catch (RuntimeException e) {
+      logger.error("Exception while trying update {} {} with ex {}", table, key, e.toString());
+    }
+    return Status.ERROR;
+  }
+
+  /**
+   * Delete a record from the database.
+   * 
+   * @param table
+   *      The name of the table
+   * @param key
+   *      The record key of the record to delete.
+   * @return Zero on success, a non-zero error code on error. See the
+   *     {@link DB} class's description for a discussion of error codes.
+   */
+  @Override
+  public Status delete(String table, String key) {
+    try {
+      arangoDriver.deleteDocument(table, key);
+      return Status.OK;
+    } catch (ArangoException e) {
+      if (e.getErrorNumber() != ErrorNums.ERROR_ARANGO_DOCUMENT_NOT_FOUND) {
+        logger.error("Fail to delete: {} {} with ex {}", table, key, e.toString());
+      } else {
+        logger.debug("Trying to delete document not exist: {} {}", table, key);
+        return Status.NOT_FOUND;
+      }
+    } catch (RuntimeException e) {
+      logger.error("Exception while trying delete {} {} with ex {}", table, key, e.toString());
+    }
+    return Status.ERROR;
+  }
+
+  /**
+   * Perform a range scan for a set of records in the database. Each
+   * field/value pair from the result will be stored in a HashMap.
+   * 
+   * @param table
+   *      The name of the table
+   * @param startkey
+   *      The record key of the first record to read.
+   * @param recordcount
+   *      The number of records to read
+   * @param fields
+   *      The list of fields to read, or null for all of them
+   * @param result
+   *      A Vector of HashMaps, where each HashMap is a set field/value
+   *      pairs for one record
+   * @return Zero on success, a non-zero error code on error. See the
+   *     {@link DB} class's description for a discussion of error codes.
+   */
+  @Override
+  public Status scan(String table, String startkey, int recordcount, Set<String> fields,
+      Vector<HashMap<String, ByteIterator>> result) {
+    DocumentCursor<BaseDocument> cursor = null;
+    try {
+      String aqlQuery = String.format(
+          "FOR target IN %s FILTER target._key >= @key SORT target._key ASC LIMIT %d RETURN %s ", table,
+          recordcount, constructReturnForAQL(fields, "target"));
+
+      Map<String, Object> bindVars = new MapBuilder().put("key", startkey).get();
+      cursor = arangoDriver.executeDocumentQuery(aqlQuery, bindVars, null, BaseDocument.class);
+      Iterator<BaseDocument> iterator = cursor.entityIterator();
+      while (iterator.hasNext()) {
+        BaseDocument aDocument = iterator.next();
+        HashMap<String, ByteIterator> aMap = new HashMap<String, ByteIterator>(aDocument.getProperties().size());
+        if (!this.fillMap(aMap, aDocument.getProperties())) {
+          return Status.ERROR;
+        }
+        result.add(aMap);
+      }
+      return Status.OK;
+    } catch (Exception e) {
+      logger.error("Exception while trying scan {} {} {} with ex {}", table, startkey, recordcount, e.toString());
+    } finally {
+      if (cursor != null) {
+        try {
+          cursor.close();
+        } catch (ArangoException e) {
+          logger.error("Fail to close cursor", e);
+        }
+      }
+    }
+    return Status.ERROR;
+  }
+
+  private String createDocumentHandle(String collectionName, String documentKey) throws ArangoException {
+    validateCollectionName(collectionName);
+    return collectionName + "/" + documentKey;
+  }
+
+  private void validateCollectionName(String name) throws ArangoException {
+    if (name.indexOf('/') != -1) {
+      throw new ArangoException("does not allow '/' in name.");
+    }
+  }
+
+  
+  private String constructReturnForAQL(Set<String> fields, String targetName) {
+    // Construct the AQL query string.
+    String resultDes = targetName;
+    if (fields != null && fields.size() != 0) {
+      StringBuilder builder = new StringBuilder("{");
+      for (String field : fields) {
+        builder.append(String.format("\n\"%s\" : %s.%s,", field, targetName, field));
+      }
+      //Replace last ',' to newline.
+      builder.setCharAt(builder.length() - 1, '\n');
+      builder.append("}");
+      resultDes = builder.toString();
+    }
+    return resultDes;
+  }
+  
+  private boolean fillMap(Map<String, ByteIterator> resultMap, Map<String, Object> properties) {
+    return fillMap(resultMap, properties, null);
+  }
+  
+  /**
+   * Fills the map with the properties from the BaseDocument.
+   * 
+   * @param resultMap
+   *      The map to fill/
+   * @param obj
+   *      The object to copy values from.
+   * @return isSuccess
+   */
+  @SuppressWarnings("unchecked")
+  private boolean fillMap(Map<String, ByteIterator> resultMap, Map<String, Object> properties, Set<String> fields) {
+    if (fields == null || fields.size() == 0) {
+      for (Map.Entry<String, Object> entry : properties.entrySet()) {
+        if (entry.getValue() instanceof String) {
+          resultMap.put(entry.getKey(),
+              stringToByteIterator((String)(entry.getValue())));
+        } else {
+          logger.error("Error! Not the format expected! Actually is {}",
+              entry.getValue().getClass().getName());
+          return false;
+        }
+      }
+    } else {
+      for (String field : fields) {
+        if (properties.get(field) instanceof String) {
+          resultMap.put(field, stringToByteIterator((String)(properties.get(field))));
+        } else {
+          logger.error("Error! Not the format expected! Actually is {}",
+              properties.get(field).getClass().getName());
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+  
+  private String byteIteratorToString(ByteIterator byteIter) {
+    return new String(byteIter.toArray());
+  }
+
+  private ByteIterator stringToByteIterator(String content) {
+    return new StringByteIterator(content);
+  }
+  
+  private String mapToJson(HashMap<String, ByteIterator> values) {
+    HashMap<String, String> intervalRst = new HashMap<String, String>();
+    for (Map.Entry<String, ByteIterator> entry : values.entrySet()) {
+      intervalRst.put(entry.getKey(), byteIteratorToString(entry.getValue()));
+    }
+    return EntityFactory.toJsonString(intervalRst);
+  }
+  
+}
diff --git a/arangodb/src/main/java/com/yahoo/ycsb/db/package-info.java b/arangodb/src/main/java/com/yahoo/ycsb/db/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..0f3c7e78773f780f08d8c15c8242296c374bacff
--- /dev/null
+++ b/arangodb/src/main/java/com/yahoo/ycsb/db/package-info.java
@@ -0,0 +1,22 @@
+/**
+ * Copyright (c) 2012 - 2015 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.
+ */
+
+/**
+ * The YCSB binding for <a href="https://www.arangodb.com/">ArangoDB</a>.
+ */
+package com.yahoo.ycsb.db;
+
diff --git a/cassandra/pom.xml b/cassandra/pom.xml
index c922bbc2678d7753e3ee4b280e1f493d5b34c84c..570e010f1f6da2381df92e13b62643f95197fb8c 100644
--- a/cassandra/pom.xml
+++ b/cassandra/pom.xml
@@ -63,13 +63,13 @@ LICENSE file.
       <scope>test</scope>
     </dependency>
     <!-- only for Cassandra test (Cassandra 2.2+ uses Sigar for collecting system information, and Sigar requires some native lib files) -->
-	<dependency>
+	  <dependency>
 	    <groupId>org.hyperic</groupId>
 	    <artifactId>sigar-dist</artifactId>
 	    <version>1.6.4.129</version>
 	    <type>zip</type>
 	    <scope>test</scope>
-	</dependency>
+	  </dependency>
   </dependencies>
 
   <profiles>
diff --git a/cassandra/src/main/java/com/yahoo/ycsb/db/CassandraCQLClient.java b/cassandra/src/main/java/com/yahoo/ycsb/db/CassandraCQLClient.java
old mode 100755
new mode 100644
diff --git a/cassandra/src/test/java/com/yahoo/ycsb/db/CassandraCQLClientTest.java b/cassandra/src/test/java/com/yahoo/ycsb/db/CassandraCQLClientTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..60b7e2f33f392d68265f89352b17d62fc261e297
--- /dev/null
+++ b/cassandra/src/test/java/com/yahoo/ycsb/db/CassandraCQLClientTest.java
@@ -0,0 +1,177 @@
+/**
+ * Copyright (c) 2015 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.
+ */
+
+package com.yahoo.ycsb.db;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+
+import com.google.common.collect.Sets;
+
+import com.datastax.driver.core.ResultSet;
+import com.datastax.driver.core.Row;
+import com.datastax.driver.core.Session;
+import com.datastax.driver.core.Statement;
+import com.datastax.driver.core.querybuilder.Insert;
+import com.datastax.driver.core.querybuilder.QueryBuilder;
+import com.datastax.driver.core.querybuilder.Select;
+import com.yahoo.ycsb.ByteIterator;
+import com.yahoo.ycsb.Status;
+import com.yahoo.ycsb.StringByteIterator;
+import com.yahoo.ycsb.measurements.Measurements;
+import com.yahoo.ycsb.workloads.CoreWorkload;
+
+import org.cassandraunit.CassandraCQLUnit;
+import org.cassandraunit.dataset.cql.ClassPathCQLDataSet;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * Integration tests for the Cassandra client
+ */
+public class CassandraCQLClientTest {
+  private final static String TABLE = "usertable";
+  private final static String HOST = "localhost";
+  private final static int PORT = 9142;
+  private final static String DEFAULT_ROW_KEY = "user1";
+
+  private CassandraCQLClient client;
+  private Session session;
+
+  @ClassRule
+  public static CassandraCQLUnit cassandraUnit = new CassandraCQLUnit(new ClassPathCQLDataSet("ycsb.cql", "ycsb"));
+
+  @Before
+  public void setUp() throws Exception {
+    session = cassandraUnit.getSession();
+
+    Properties p = new Properties();
+    p.setProperty("hosts", HOST);
+    p.setProperty("port", Integer.toString(PORT));
+    p.setProperty("table", TABLE);
+
+    Measurements.setProperties(p);
+    final CoreWorkload workload = new CoreWorkload();
+    workload.init(p);
+    client = new CassandraCQLClient();
+    client.setProperties(p);
+    client.init();
+  }
+
+  @After
+  public void tearDownClient() throws Exception {
+    if (client != null) {
+      client.cleanup();
+    }
+    client = null;
+  }
+
+  @After
+  public void clearTable() throws Exception {
+    // Clear the table so that each test starts fresh.
+    final Statement truncate = QueryBuilder.truncate(TABLE);
+    if (cassandraUnit != null) {
+      cassandraUnit.getSession().execute(truncate);
+    }
+  }
+
+  @Test
+  public void testReadMissingRow() throws Exception {
+    final HashMap<String, ByteIterator> result = new HashMap<String, ByteIterator>();
+    final Status status = client.read(TABLE, "Missing row", null, result);
+    assertThat(result.size(), is(0));
+    assertThat(status, is(Status.NOT_FOUND));
+  }
+
+  private void insertRow() {
+    final String rowKey = DEFAULT_ROW_KEY;
+    Insert insertStmt = QueryBuilder.insertInto(TABLE);
+    insertStmt.value(CassandraCQLClient.YCSB_KEY, rowKey);
+
+    insertStmt.value("field0", "value1");
+    insertStmt.value("field1", "value2");
+    session.execute(insertStmt);
+  }
+
+  @Test
+  public void testRead() throws Exception {
+    insertRow();
+
+    final HashMap<String, ByteIterator> result = new HashMap<String, ByteIterator>();
+    final Status status = client.read(CoreWorkload.table, DEFAULT_ROW_KEY, null, result);
+    assertThat(status, is(Status.OK));
+    assertThat(result.entrySet(), hasSize(11));
+    assertThat(result, hasEntry("field2", null));
+
+    final HashMap<String, String> strResult = new HashMap<String, String>();
+    for (final Map.Entry<String, ByteIterator> e : result.entrySet()) {
+      if (e.getValue() != null) {
+        strResult.put(e.getKey(), e.getValue().toString());
+      }
+    }
+    assertThat(strResult, hasEntry(CassandraCQLClient.YCSB_KEY, DEFAULT_ROW_KEY));
+    assertThat(strResult, hasEntry("field0", "value1"));
+    assertThat(strResult, hasEntry("field1", "value2"));
+  }
+
+  @Test
+  public void testReadSingleColumn() throws Exception {
+    insertRow();
+    final HashMap<String, ByteIterator> result = new HashMap<String, ByteIterator>();
+    final Set<String> fields = Sets.newHashSet("field1");
+    final Status status = client.read(CoreWorkload.table, DEFAULT_ROW_KEY, fields, result);
+    assertThat(status, is(Status.OK));
+    assertThat(result.entrySet(), hasSize(1));
+    final Map<String, String> strResult = StringByteIterator.getStringMap(result);
+    assertThat(strResult, hasEntry("field1", "value2"));
+  }
+
+  @Test
+  public void testUpdate() throws Exception {
+    final String key = "key";
+    final HashMap<String, String> input = new HashMap<String, String>();
+    input.put("field0", "value1");
+    input.put("field1", "value2");
+
+    final Status status = client.insert(TABLE, key, StringByteIterator.getByteIteratorMap(input));
+    assertThat(status, is(Status.OK));
+
+    // Verify result
+    final Select selectStmt =
+        QueryBuilder.select("field0", "field1")
+            .from(TABLE)
+            .where(QueryBuilder.eq(CassandraCQLClient.YCSB_KEY, key))
+            .limit(1);
+
+    final ResultSet rs = session.execute(selectStmt);
+    final Row row = rs.one();
+    assertThat(row, notNullValue());
+    assertThat(rs.isExhausted(), is(true));
+    assertThat(row.getString("field0"), is("value1"));
+    assertThat(row.getString("field1"), is("value2"));
+  }
+}
diff --git a/cassandra/src/test/resources/ycsb.cql b/cassandra/src/test/resources/ycsb.cql
new file mode 100644
index 0000000000000000000000000000000000000000..c52ab787b21a251a5a899b3163e9540e8af0c082
--- /dev/null
+++ b/cassandra/src/test/resources/ycsb.cql
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2015 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.
+ */
+
+CREATE TABLE usertable (
+  y_id varchar primary key,
+  field0 varchar,
+  field1 varchar,
+  field2 varchar,
+  field3 varchar,
+  field4 varchar,
+  field5 varchar,
+  field6 varchar,
+  field7 varchar,
+  field8 varchar,
+  field9 varchar);