diff --git a/.gitignore b/.gitignore
index aa65bacfc8..21647c4629 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,6 +19,7 @@ output*
# ignore standard Vim and Emacs temp files
*.swp
*~
+.vim/
# ignore standard Mac OS X files/dirs
.DS_Store
diff --git a/basictcp/pom.xml b/basictcp/pom.xml
new file mode 100644
index 0000000000..432cdd2d9c
--- /dev/null
+++ b/basictcp/pom.xml
@@ -0,0 +1,38 @@
+
+
+
+
+ 4.0.0
+
+ site.ycsb
+ binding-parent
+ 0.18.0-SNAPSHOT
+ ../binding-parent
+
+
+ basictcp-binding
+ BasicTCP Binding
+ jar
+
+
+
+ site.ycsb
+ core
+ ${project.version}
+ provided
+
+
+
diff --git a/basictcp/src/main/java/site/ycsb/db/BasicTcpDB.java b/basictcp/src/main/java/site/ycsb/db/BasicTcpDB.java
new file mode 100644
index 0000000000..60bcd77509
--- /dev/null
+++ b/basictcp/src/main/java/site/ycsb/db/BasicTcpDB.java
@@ -0,0 +1,201 @@
+/**
+ * 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.
+ *
+ * Basic TCP based DB client binding for YCSB.
+ *
+ * Based off of the S3 client.
+ */
+package site.ycsb.db;
+
+import java.util.HashMap;
+import java.util.Set;
+import java.util.Vector;
+import java.io.*;
+import java.util.*;
+import java.net.*;
+
+import site.ycsb.ByteIterator;
+import site.ycsb.DB;
+import site.ycsb.DBException;
+import site.ycsb.Status;
+
+/**
+ * Basic TCP based DB client for YCSB framework.
+ *
+ */
+public class BasicTcpDB extends DB {
+ public static final String HOST = "basictcpdb.host";
+ public static final String HOST_DEFAULT = "127.0.0.1";
+
+ public static final String PORT = "basictcpdb.port";
+ public static final String PORT_DEFAULT = "54321";
+
+ private Socket socket;
+ private String host;
+ private Integer port;
+ private PrintWriter outStream;
+ private BufferedReader inStream;
+
+ protected static final ThreadLocal TL_STRING_BUILDER =
+ new ThreadLocal() {
+ @Override
+ protected StringBuilder initialValue() {
+ return new StringBuilder();
+ }
+ };
+
+ protected StringBuilder getStringBuilder() {
+ StringBuilder sb = TL_STRING_BUILDER.get();
+ sb.setLength(0);
+ return sb;
+ }
+
+ /**
+ * Initialize.
+ */
+ @Override
+ public void init() throws DBException {
+ host = getProperties().getProperty(HOST, HOST_DEFAULT);
+ port = Integer.parseInt(getProperties().getProperty(PORT, PORT_DEFAULT));
+
+ try {
+ this.socket = new Socket(host, port);
+ this.outStream = new PrintWriter(socket.getOutputStream(), true);
+ this.inStream =
+ new BufferedReader(new InputStreamReader(socket.getInputStream()));
+ } catch (IOException e) {
+ throw new DBException(e);
+ }
+ }
+
+ /**
+ * Cleanup.
+ */
+ @Override
+ public void cleanup() throws DBException {
+ try {
+ this.socket.close();
+ } catch (IOException e) {
+ throw new DBException(e);
+ }
+ }
+
+ /**
+ * Insert.
+ */
+ @Override
+ public Status insert(String table, String key,
+ Map values) {
+
+ StringBuilder sb = this.getStringBuilder();
+ sb.append("INSERT ").append(table).append(" ").append(key).append(" [ ");
+ if (values != null) {
+ for (Map.Entry entry : values.entrySet()) {
+ sb.append(entry.getKey()).append("=").append(entry.getValue())
+ .append(" ");
+ }
+ }
+
+ sb.append("]");
+
+ this.outStream.write(sb.toString());
+
+ return Status.OK;
+ }
+
+ /**
+ * Read.
+ */
+ @Override
+ public Status read(String table, String key, Set fields,
+ Map result) {
+
+ StringBuilder sb = this.getStringBuilder();
+ sb.append("READ ").append(table).append(" ").append(key).append(" [ ");
+ if (fields != null) {
+ for (String f : fields) {
+ sb.append(f).append(" ");
+ }
+ } else {
+ sb.append("");
+ }
+
+ sb.append("]");
+
+ this.outStream.write(sb.toString());
+
+ return Status.OK;
+ }
+
+ /**
+ * Update.
+ */
+ @Override
+ public Status update(String table, String key,
+ Map values) {
+
+ StringBuilder sb = this.getStringBuilder();
+ sb.append("UPDATE ").append(table).append(" ").append(key).append(" [ ");
+ if (values != null) {
+ for (Map.Entry entry : values.entrySet()) {
+ sb.append(entry.getKey()).append("=").append(entry.getValue())
+ .append(" ");
+ }
+ }
+ sb.append("]");
+
+ this.outStream.write(sb.toString());
+
+ return Status.OK;
+ }
+
+ /**
+ * Delete.
+ */
+ @Override
+ public Status delete(String table, String key) {
+ StringBuilder sb = this.getStringBuilder();
+ sb.append("DELETE ").append(table).append(" ").append(key);
+
+ this.outStream.write(sb.toString());
+
+ return Status.OK;
+ }
+
+ /**
+ * Scan.
+ */
+ @Override
+ public Status scan(String table, String startkey, int recordcount,
+ Set fields, Vector> result) {
+
+ StringBuilder sb = this.getStringBuilder();
+ sb.append("SCAN ").append(table).append(" ").append(startkey).append(" ")
+ .append(recordcount).append(" [ ");
+ if (fields != null) {
+ for (String f : fields) {
+ sb.append(f).append(" ");
+ }
+ } else {
+ sb.append("");
+ }
+
+ sb.append("]");
+
+ this.outStream.write(sb.toString());
+
+ return Status.OK;
+ }
+}
diff --git a/basictcp/src/main/java/site/ycsb/db/package-info.java b/basictcp/src/main/java/site/ycsb/db/package-info.java
new file mode 100644
index 0000000000..2e2ea23ec5
--- /dev/null
+++ b/basictcp/src/main/java/site/ycsb/db/package-info.java
@@ -0,0 +1,19 @@
+/**
+ * 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.
+ *
+ * Basic TCP based DB client binding for YCSB.
+ */
+
+package site.ycsb.db;
diff --git a/bin/bindings.properties b/bin/bindings.properties
index 5c767c7599..041ed1df61 100755
--- a/bin/bindings.properties
+++ b/bin/bindings.properties
@@ -33,6 +33,7 @@ arangodb3:site.ycsb.db.arangodb.ArangoDBClient
azurecosmos:site.ycsb.db.AzureCosmosClient
azuretablestorage:site.ycsb.db.azuretablestorage.AzureClient
basic:site.ycsb.BasicDB
+basictcp:site.ycsb.db.BasicTcpDB
basicts:site.ycsb.BasicTSDB
cassandra-cql:site.ycsb.db.CassandraCQLClient
cassandra2-cql:site.ycsb.db.CassandraCQLClient
@@ -73,4 +74,4 @@ solr7:site.ycsb.db.solr7.SolrClient
tarantool:site.ycsb.db.TarantoolClient
tablestore:site.ycsb.db.tablestore.TableStoreClient
voltdb:site.ycsb.db.voltdb.VoltClient4
-zookeeper:site.ycsb.db.zookeeper.ZKClient
\ No newline at end of file
+zookeeper:site.ycsb.db.zookeeper.ZKClient
diff --git a/bin/ycsb b/bin/ycsb
index b5c85e35bb..3e12a79402 100755
--- a/bin/ycsb
+++ b/bin/ycsb
@@ -59,6 +59,7 @@ DATABASES = {
"azurecosmos" : "site.ycsb.db.AzureCosmosClient",
"azuretablestorage" : "site.ycsb.db.azuretablestorage.AzureClient",
"basic" : "site.ycsb.BasicDB",
+ "basictcp" : "site.ycsb.db.BasicTcpDB",
"basicts" : "site.ycsb.BasicTSDB",
"cassandra-cql": "site.ycsb.db.CassandraCQLClient",
"cassandra2-cql": "site.ycsb.db.CassandraCQLClient",
diff --git a/pom.xml b/pom.xml
index de2d5eea23..8ee84d52af 100644
--- a/pom.xml
+++ b/pom.xml
@@ -164,6 +164,7 @@ LICENSE file.
asynchbase
azurecosmos
azuretablestorage
+ basictcp
cassandra
cloudspanner
couchbase