From bf4c4e579cec49c03cc2ebf507d8876dc16e6bd4 Mon Sep 17 00:00:00 2001 From: bigbes <bigbes@gmail.com> Date: Thu, 11 Jun 2015 16:29:37 +0300 Subject: [PATCH] Add Tarantool database http://tarantool.org and https://github.com/tarantool/tarantool In "mail.ru" we wrote and widely use Tarantool key-value database. It's key properties include: * Defferent index types with iterators: - HASH (the fastest) - TREE (range and ordered retreival) - BITSET (bit mask search) - RTREE (geo search) * multipart keys for HASH and TREE indexes * Data persistence with by Write Ahead Log (WAL) and snapshots. * asynchronous master-master replication, hot standby. * coroutines and async. IO are used to implement high-performance lock-free access to data. - socket-io/file-io with yeilds from lua * stored procedures in Lua (Using LuaJIT) * supports plugins written on C/C++ (Have two basic plugins for working with MySQL and PostgreSQL) * Authentication and access control Move 'distribution target' to the end (it's needed for .jar to be in the .tar.gz) --- bin/ycsb | 3 +- pom.xml | 4 +- tarantool/README.md | 62 +++++++ tarantool/config/tarantool-hash.lua | 12 ++ tarantool/config/tarantool-tree.lua | 12 ++ tarantool/pom.xml | 59 ++++++ .../com/yahoo/ycsb/db/TarantoolClient.java | 168 ++++++++++++++++++ 7 files changed, 318 insertions(+), 2 deletions(-) create mode 100644 tarantool/README.md create mode 100644 tarantool/config/tarantool-hash.lua create mode 100644 tarantool/config/tarantool-tree.lua create mode 100644 tarantool/pom.xml create mode 100644 tarantool/src/main/java/com/yahoo/ycsb/db/TarantoolClient.java diff --git a/bin/ycsb b/bin/ycsb index 5494c767..9c15be80 100755 --- a/bin/ycsb +++ b/bin/ycsb @@ -33,6 +33,7 @@ DATABASES = { "cassandra-8" : "com.yahoo.ycsb.db.CassandraClient8", "cassandra-10" : "com.yahoo.ycsb.db.CassandraClient10", "cassandra-cql": "com.yahoo.ycsb.db.CassandraCQLClient", + "couchbase" : "com.yahoo.ycsb.db.CouchbaseClient", "dynamodb" : "com.yahoo.ycsb.db.DynamoDBClient", "elasticsearch": "com.yahoo.ycsb.db.ElasticSearchClient", "gemfire" : "com.yahoo.ycsb.db.GemFireClient", @@ -47,8 +48,8 @@ DATABASES = { "nosqldb" : "com.yahoo.ycsb.db.NoSqlDbClient", "orientdb" : "com.yahoo.ycsb.db.OrientDBClient", "redis" : "com.yahoo.ycsb.db.RedisClient", + "tarantool" : "com.yahoo.ycsb.db.TarantoolClient" "voldemort" : "com.yahoo.ycsb.db.VoldemortClient", - "couchbase" : "com.yahoo.ycsb.db.CouchbaseClient" } OPTIONS = { diff --git a/pom.xml b/pom.xml index c0bf48cf..930f0672 100644 --- a/pom.xml +++ b/pom.xml @@ -67,6 +67,7 @@ <thrift.version>0.8.0</thrift.version> <hypertable.version>0.9.5.6</hypertable.version> <couchbase.version>1.1.8</couchbase.version> + <tarantool.version>1.6.1-SNAPSHOT</tarantool.version> </properties> <modules> @@ -85,10 +86,11 @@ <module>orientdb</module> <module>redis</module> <module>voldemort</module> - <module>distribution</module> <!--<module>mapkeeper</module>--> <!--module>nosqldb</module--> <module>couchbase</module> + <module>tarantool</module> + <module>distribution</module> </modules> <build> diff --git a/tarantool/README.md b/tarantool/README.md new file mode 100644 index 00000000..419c792a --- /dev/null +++ b/tarantool/README.md @@ -0,0 +1,62 @@ +# Tarantool + +## Introduction + +Tarantool is a NoSQL In-Memory database. +It's distributed under BSD licence and is hosted on [github][tarantool-github]. + +Tarantool features: + +* Defferent index types with iterators: + - HASH (the fastest) + - TREE (range and ordered retreival) + - BITSET (bit mask search) + - RTREE (geo search) +* multipart keys for HASH and TREE indexes +* Data persistence with by Write Ahead Log (WAL) and snapshots. +* asynchronous master-master replication, hot standby. +* coroutines and async. IO are used to implement high-performance lock-free access to data. + - socket-io/file-io with yeilds from lua +* stored procedures in Lua (Using LuaJIT) +* supports plugins written on C/C++ (Have two basic plugins for working with MySQL and PostgreSQL) +* Authentication and access control + +## Quick start + +This section descrives how to run YCSB against a local Tarantool instance + +### 1. Start Tarantool + +First, clone Tarantool from it's own git repo and build it (described in our [README.md][tarantool-readme]): + + cp YCSB/tarantool/config/tarantool-tree.lua <vardir>/tarantool.lua + cp TNT/src/box/tarantool_box <vardir> + cd <vardir> + ./tarantool_box tarantool.lua + +OR you can simply download ans install a binary package for your GNU/Linux or BSD distro from http://tarantool.org/download.html + +### 2. Run YCSB + +Now you are ready to run! First, load the data: + + ./bin/ycsb load tarantool -s -P workloads/workloada + +Then, run the workload: + + ./bin/ycsb run tarantool -s -P workloads/workloada + +See the next section for the list of configuration parameters for Tarantool. + +## Tarantool Configuration Parameters + +#### 'tarantool.host' (default : 'localhost') +Which host YCSB must use for connection with Tarantool +#### 'tarantool.port' (default : 3301) +Which port YCSB must use for connection with Tarantool +#### 'tarantool.space' (default : 1024) + (possible values: 0 .. 255) +Which space YCSB must use for benchmark Tarantool + +[tarantool-github]: https://github.com/tarantool/tarantool/ +[tarantool-readme]: https://github.com/tarantool/tarantool/blob/master/README.md diff --git a/tarantool/config/tarantool-hash.lua b/tarantool/config/tarantool-hash.lua new file mode 100644 index 00000000..256d93c6 --- /dev/null +++ b/tarantool/config/tarantool-hash.lua @@ -0,0 +1,12 @@ +box.cfg { + listen=3303, + logger="tarantool.log", + log_level=5, + logger_nonblock=true, + wal_mode="none", + pid_file="tarantool.pid" +} + +box.schema.space.create("ycsb", {id = 1024}) +box.space.ycsb:create_index('primary', {type = 'hash', parts = {1, 'STR'}}) +box.schema.user.grant('guest', 'read,write,execute', 'universe') diff --git a/tarantool/config/tarantool-tree.lua b/tarantool/config/tarantool-tree.lua new file mode 100644 index 00000000..1e2a90e3 --- /dev/null +++ b/tarantool/config/tarantool-tree.lua @@ -0,0 +1,12 @@ +box.cfg { + listen=3303, + logger="tarantool.log", + log_level=5, + logger_nonblock=true, + wal_mode="none", + pid_file="tarantool.pid" +} + +box.schema.space.create("ycsb", {id = 1024}) +box.space.ycsb:create_index('primary', {type = 'tree', parts = {1, 'STR'}}) +box.schema.user.grant('guest', 'read,write,execute', 'universe') diff --git a/tarantool/pom.xml b/tarantool/pom.xml new file mode 100644 index 00000000..90514f3e --- /dev/null +++ b/tarantool/pom.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<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>root</artifactId> + <version>0.2.0-SNAPSHOT</version> + </parent> + + <artifactId>tarantool-binding</artifactId> + <name>Tarantool DB Binding</name> + <packaging>jar</packaging> + + <dependencies> + <dependency> + <groupId>org.tarantool</groupId> + <artifactId>connector</artifactId> + <version>${tarantool.version}</version> + </dependency> + <dependency> + <groupId>com.yahoo.ycsb</groupId> + <artifactId>core</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> + + <repositories> + <repository> + <id>dgreenru-repo</id> + <name>dgreenru repository</name> + <url>http://dgreenru.github.com/repo/</url> + </repository> + </repositories> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-assembly-plugin</artifactId> + <version>${maven.assembly.version}</version> + <configuration> + <descriptorRefs> + <descriptorRef>jar-with-dependencies</descriptorRef> + </descriptorRefs> + <appendAssemblyId>false</appendAssemblyId> + </configuration> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>single</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> diff --git a/tarantool/src/main/java/com/yahoo/ycsb/db/TarantoolClient.java b/tarantool/src/main/java/com/yahoo/ycsb/db/TarantoolClient.java new file mode 100644 index 00000000..0bf54d88 --- /dev/null +++ b/tarantool/src/main/java/com/yahoo/ycsb/db/TarantoolClient.java @@ -0,0 +1,168 @@ +package com.yahoo.ycsb.db; + +import java.util.Map; +import java.util.Set; +import java.util.List; +import java.util.Arrays; +import java.util.Vector; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.HashMap; +import java.util.Properties; + +import java.io.IOException; + +import org.tarantool.TarantoolConnection16; +import org.tarantool.TarantoolConnection16Impl; +import org.tarantool.TarantoolException; +import org.tarantool.CommunicationException; + +import com.yahoo.ycsb.DB; +import com.yahoo.ycsb.DBException; +import com.yahoo.ycsb.ByteIterator; +import com.yahoo.ycsb.StringByteIterator; + +public class TarantoolClient extends DB { + + public static final String HOST_PROPERTY = "tarantool.host"; + public static final String PORT_PROPERTY = "tarantool.port"; + public static final String SPACE_PROPERTY = "tarantool.space"; + + public static final String DEFAULT_HOST = "localhost"; + public static final int DEFAULT_PORT = 3301; + public static final int DEFAULT_SPACE = 1024; + + private static final Logger log = Logger.getLogger(TarantoolClient.class.getName()); + private TarantoolConnection16Impl connection; + private int spaceNo; + + public void init() throws DBException { + Properties props = getProperties(); + + int port = DEFAULT_PORT; + String portString = props.getProperty(PORT_PROPERTY); + if (portString != null) { + port = Integer.parseInt(portString); + } + + String host = props.getProperty(HOST_PROPERTY); + if (host == null) { + host = DEFAULT_HOST; + } + + spaceNo = DEFAULT_SPACE; + String spaceString = props.getProperty(SPACE_PROPERTY); + if (spaceString != null) { + spaceNo = Integer.parseInt(spaceString); + } + + try { + this.connection = new TarantoolConnection16Impl(host, port); + } + catch (Exception exc) { + System.err.println("Can't init Tarantool connection:" + exc.toString()); + exc.printStackTrace(); + return; + } + } + + public void cleanup() throws DBException{ + this.connection.close(); + } + + @Override + public int insert(String table, String key, HashMap<String, ByteIterator> values) { + int j = 0; + String[] tuple = new String[1 + 2 * values.size()]; + tuple[0] = key; + for (Map.Entry<String, ByteIterator> i: values.entrySet()) { + tuple[j + 1] = i.getKey(); + tuple[j + 2] = i.getValue().toString(); + j += 2; + } + try { + this.connection.insert(this.spaceNo, tuple); + } catch (TarantoolException e) { + e.printStackTrace(); + return 1; + } + return 0; + } + + private HashMap<String, ByteIterator> tuple_convert_filter (List<String> input, + Set<String> fields) { + HashMap<String, ByteIterator> result = new HashMap<String, ByteIterator>(); + if (input == null) + return result; + for (int i = 1; i < input.toArray().length; i += 2) + if (fields == null || fields.contains(input.get(i))) + result.put(input.get(i), new StringByteIterator(input.get(i+1))); + return result; + } + + @Override + public int read(String table, String key, Set<String> fields, + HashMap<String, ByteIterator> result) { + try { + List<String> response; + response = this.connection.select(this.spaceNo, 0, Arrays.asList(key), 0, 1, 0); + result = tuple_convert_filter(response, fields); + return 0; + } catch (TarantoolException e) { + e.printStackTrace(); + return 1; + } catch (IndexOutOfBoundsException e) { + return 1; + } + } + + @Override + public int scan(String table, String startkey, + int recordcount, Set<String> fields, + Vector<HashMap<String, ByteIterator>> result) { + List<String> response; + try { + response = this.connection.select(this.spaceNo, 0, Arrays.asList(startkey), 0, recordcount, 6); + } catch (TarantoolException e) { + e.printStackTrace(); + return 1; + } + HashMap<String, ByteIterator> temp = tuple_convert_filter(response, fields); + if (!temp.isEmpty()) + result.add((HashMap<String, ByteIterator>) temp.clone()); + return 0; + } + + @Override + public int delete(String table, String key) { + try { + this.connection.delete(this.spaceNo, Arrays.asList(key)); + } catch (TarantoolException e) { + e.printStackTrace(); + return 1; + } catch (IndexOutOfBoundsException e) { + return 1; + } + return 0; + } + @Override + public int update(String table, String key, + HashMap<String, ByteIterator> values) { + int j = 0; + String[] tuple = new String[1 + 2 * values.size()]; + tuple[0] = key; + for (Map.Entry<String, ByteIterator> i: values.entrySet()) { + tuple[j + 1] = i.getKey(); + tuple[j + 2] = i.getValue().toString(); + j += 2; + } + try { + this.connection.replace(this.spaceNo, tuple); + } catch (TarantoolException e) { + e.printStackTrace(); + return 1; + } + return 0; + + } +} -- GitLab