From e4de1c9711f1cd980c102ca7fd2e55c9314d14c8 Mon Sep 17 00:00:00 2001 From: Yuta Namiki <y.namiki@gmail.com> Date: Thu, 9 Feb 2012 19:30:15 +0900 Subject: [PATCH] Oracle NoSQL Database client --- Makefile | 8 + build.xml | 5 + db/nosqldb/lib/README | 38 +++ db/nosqldb/nosqldb.properties | 28 +++ db/nosqldb/script.txt | 9 + .../src/com/yahoo/ycsb/db/NoSqlDbClient.java | 221 ++++++++++++++++++ 6 files changed, 309 insertions(+) create mode 100644 db/nosqldb/lib/README create mode 100644 db/nosqldb/nosqldb.properties create mode 100644 db/nosqldb/script.txt create mode 100644 db/nosqldb/src/com/yahoo/ycsb/db/NoSqlDbClient.java diff --git a/Makefile b/Makefile index c24b9739..5970c512 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,8 @@ MAPKEEPER_DIR=db/mapkeeper/lib MAPKEEPER_FILE=mapkeeper.jar GEMFIRE_DIR=db/gemfire/lib GEMFIRE_FILE=gemfire-6.6.1.jar +NOSQLDB_DIR=db/nosqldb/lib +NOSQLDB_FILE=kv-ce-1.2.123.tar.gz .PHONY: build build: download-database-deps @@ -46,6 +48,7 @@ download-database-deps: $(CASSANDRA_5_DIR)/$(CASSANDRA_5_FILE) \ $(VOLDEMORT_DIR)/$(VOLDEMORT_FILE) \ $(MAPKEEPER_DIR)/$(MAPKEEPER_FILE) \ $(GEMFIRE_DIR)/$(GEMFIRE_FILE) \ + $(NOSQLDB_DIR)/$(NOSQLDB_FILE) \ $(CASSANDRA_5_DIR)/$(CASSANDRA_5_FILE) : wget http://archive.apache.org/dist/cassandra/0.5.1/$(CASSANDRA_5_FILE)\ @@ -105,5 +108,10 @@ $(GEMFIRE_DIR)/$(GEMFIRE_FILE) : wget http://dist.gemstone.com.s3.amazonaws.com/maven/release/com/gemstone/gemfire/gemfire/6.6.1/$(GEMFIRE_FILE) \ -O $(GEMFIRE_DIR)/$(GEMFIRE_FILE) +$(NOSQLDB_DIR)/$(NOSQLDB_FILE) : + wget http://download.oracle.com/otn/nosql-database/$(NOSQLDB_FILE) \ + -O $(NOSQLDB_DIR)/$(NOSQLDB_FILE) + tar -C $(NOSQLDB_DIR) -zxf $(NOSQLDB_DIR)/$(NOSQLDB_FILE) + diff --git a/build.xml b/build.xml index e5bb6cc3..7d3d974f 100644 --- a/build.xml +++ b/build.xml @@ -80,6 +80,11 @@ <antcall target="dbcompile"/> </target> + <target name="dbcompile-nosqldb" depends="compile"> + <property name="db.dir" value="db/nosqldb"/> + <antcall target="dbcompile"/> + </target> + <target name="compile"> <mkdir dir="${classes.dir}"/> <javac includeantruntime="false" srcdir="${src.dir}" destdir="${classes.dir}" classpathref="build.classpath" deprecation="on"> diff --git a/db/nosqldb/lib/README b/db/nosqldb/lib/README new file mode 100644 index 00000000..83586631 --- /dev/null +++ b/db/nosqldb/lib/README @@ -0,0 +1,38 @@ +This directory should contain kvclient-1.2.123.jar for building +and running Oracle NoSQL Database client. + +BUILD + +Oracle NoSQL Database client can be compiled using target: +$ ant dbcompile-nosqldb + +CONFIGURE + +$KVHOME is Oracle NoSQL Database package files. +$KVROOT is a data directory. + +$ mkdir $KVROOT +$ java -jar $KVHOME/lib/kvstore-1.2.123.jar makebootconfig \ + -root $KVROOT -port 5000 -admin 5001 -host localhost \ + -harange 5010,5020 +$ java -jar $KVHOME/lib/kvstore-1.2.123.jar start -root $KVROOT +$ java -jar $KVHOME/lib/kvstore-1.2.123.jar runadmin \ + -port 5000 -host localhost -script ../script.txt + +BENCHMARK + +$ java -cp build/ycsb.jar:db/nosqldb/lib/kvclient-1.2.123.jar \ + com.yahoo.ycsb.Client -db com.yahoo.ycsb.db.NoSqlDbClient \ + -P workloads/workloada + +PROPERTIES + +See nosqldb.properties. + +STOP + +$ java -jar $KVHOME/lib/kvstore-1.2.123.jar stop -root $KVROOT + + +Please refer to Oracle NoSQL Database docs here: +http://docs.oracle.com/cd/NOSQL/html/index.html diff --git a/db/nosqldb/nosqldb.properties b/db/nosqldb/nosqldb.properties new file mode 100644 index 00000000..22f2504e --- /dev/null +++ b/db/nosqldb/nosqldb.properties @@ -0,0 +1,28 @@ +# +# Sample property file for Oracle NoSQL Database client +# +# Refer to the Javadoc of oracle.kv.KVStoreConfig class +# for more details. +# + +# Store name +#storeName=kvstore + +# Comma-separated list of helper host/port pairs +#helperHost=localhost:5000 + +# Read consistency +# "ABSOLUTE" or "NONE_REQUIRED" +#consistency=NONE_REQUIRED + +# Write durability +# "COMMIT_NO_SYNC", "COMMIT_SYNC" or "COMMIT_WRITE_NO_SYNC" +#durability=COMMIT_NO_SYNC + +# Limitations on the number of active requests to a node +#requestLimit.maxActiveRequests=100 +#requestLimit.requestThresholdPercent=90 +#requestLimit.nodeLimitPercent=80 + +# Request timeout in seconds (positive integer) +#requestTimeout=5 diff --git a/db/nosqldb/script.txt b/db/nosqldb/script.txt new file mode 100644 index 00000000..87f1c8af --- /dev/null +++ b/db/nosqldb/script.txt @@ -0,0 +1,9 @@ +# Simple configuration file; only one node in a system +configure kvstore +plan -execute -name "Deploy DC" deploy-datacenter "Local" +plan -execute -name "Deploy n01" deploy-sn 1 localhost 5000 +plan -execute -name "Deploy admin" deploy-admin 1 5001 +addpool LocalPool +joinpool LocalPool 1 +plan -execute -name "Deploy the store" deploy-store LocalPool 1 100 +quit diff --git a/db/nosqldb/src/com/yahoo/ycsb/db/NoSqlDbClient.java b/db/nosqldb/src/com/yahoo/ycsb/db/NoSqlDbClient.java new file mode 100644 index 00000000..a19d8f8f --- /dev/null +++ b/db/nosqldb/src/com/yahoo/ycsb/db/NoSqlDbClient.java @@ -0,0 +1,221 @@ +package com.yahoo.ycsb.db; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.SortedMap; +import java.util.Vector; +import java.util.concurrent.TimeUnit; + +import oracle.kv.Consistency; +import oracle.kv.Durability; +import oracle.kv.FaultException; +import oracle.kv.KVStore; +import oracle.kv.KVStoreConfig; +import oracle.kv.KVStoreFactory; +import oracle.kv.Key; +import oracle.kv.RequestLimitConfig; +import oracle.kv.Value; +import oracle.kv.ValueVersion; + +import com.yahoo.ycsb.ByteArrayByteIterator; +import com.yahoo.ycsb.ByteIterator; +import com.yahoo.ycsb.DB; +import com.yahoo.ycsb.DBException; + +/** + * A database interface layer for Oracle NoSQL Database. + */ +public class NoSqlDbClient extends DB { + + public static final int OK = 0; + public static final int ERROR = -1; + + KVStore store; + + private int getPropertyInt(Properties properties, String key, int defaultValue) throws DBException { + String p = properties.getProperty(key); + int i = defaultValue; + if (p != null) { + try { + i = Integer.parseInt(p); + } catch (NumberFormatException e) { + throw new DBException("Illegal number format in " + key + " property"); + } + } + return i; + } + + @Override + public void init() throws DBException { + Properties properties = getProperties(); + + /* Mandatory properties */ + String storeName = properties.getProperty("storeName", "kvstore"); + String[] helperHosts = properties.getProperty("helperHost", "localhost:5000").split(","); + + KVStoreConfig config = new KVStoreConfig(storeName, helperHosts); + + /* Optional properties */ + String p; + + p = properties.getProperty("consistency"); + if (p != null) { + if (p.equalsIgnoreCase("ABSOLUTE")) { + config.setConsistency(Consistency.ABSOLUTE); + } else if (p.equalsIgnoreCase("NONE_REQUIRED")) { + config.setConsistency(Consistency.NONE_REQUIRED); + } else { + throw new DBException("Illegal value in consistency property"); + } + } + + p = properties.getProperty("durability"); + if (p != null) { + if (p.equalsIgnoreCase("COMMIT_NO_SYNC")) { + config.setDurability(Durability.COMMIT_NO_SYNC); + } else if (p.equalsIgnoreCase("COMMIT_SYNC")) { + config.setDurability(Durability.COMMIT_SYNC); + } else if (p.equalsIgnoreCase("COMMIT_WRITE_NO_SYNC")) { + config.setDurability(Durability.COMMIT_WRITE_NO_SYNC); + } else { + throw new DBException("Illegal value in durability property"); + } + } + + int maxActiveRequests = getPropertyInt(properties, + "requestLimit.maxActiveRequests", RequestLimitConfig.DEFAULT_MAX_ACTIVE_REQUESTS); + int requestThresholdPercent = getPropertyInt(properties, + "requestLimit.requestThresholdPercent", RequestLimitConfig.DEFAULT_REQUEST_THRESHOLD_PERCENT); + int nodeLimitPercent = getPropertyInt(properties, + "requestLimit.nodeLimitPercent", RequestLimitConfig.DEFAULT_NODE_LIMIT_PERCENT); + RequestLimitConfig requestLimitConfig; + /* It is said that the constructor could throw NodeRequestLimitException in Javadoc, the exception is not provided */ +// try { + requestLimitConfig = new RequestLimitConfig(maxActiveRequests, requestThresholdPercent, nodeLimitPercent); +// } catch (NodeRequestLimitException e) { +// throw new DBException(e); +// } + config.setRequestLimit(requestLimitConfig); + + p = properties.getProperty("requestTimeout"); + if (p != null) { + long timeout = 1; + try { + timeout = Long.parseLong(p); + } catch (NumberFormatException e) { + throw new DBException("Illegal number format in requestTimeout property"); + } + try { + // TODO Support other TimeUnit + config.setRequestTimeout(timeout, TimeUnit.SECONDS); + } catch (IllegalArgumentException e) { + throw new DBException(e); + } + } + + try { + store = KVStoreFactory.getStore(config); + } catch (FaultException e) { + throw new DBException(e); + } + } + + @Override + public void cleanup() throws DBException { + store.close(); + } + + /** + * Create a key object. + * We map "table" and (YCSB's) "key" to a major component of the oracle.kv.Key, + * and "field" to a minor component. + * + * @return An oracle.kv.Key object. + */ + private static Key createKey(String table, String key, String field) { + List<String> majorPath = new ArrayList<String>(); + majorPath.add(table); + majorPath.add(key); + if (field == null) { + return Key.createKey(majorPath); + } + + return Key.createKey(majorPath, field); + } + + private static Key createKey(String table, String key) { + return createKey(table, key, null); + } + + private static String getFieldFromKey(Key key) { + return key.getMinorPath().get(0); + } + + @Override + public int read(String table, String key, Set<String> fields, HashMap<String, ByteIterator> result) { + Key kvKey = createKey(table, key); + SortedMap<Key, ValueVersion> kvResult; + try { + kvResult = store.multiGet(kvKey, null, null); + } catch (FaultException e) { + System.err.println(e); + return ERROR; + } + + for (Map.Entry<Key, ValueVersion> entry : kvResult.entrySet()) { + /* If fields is null, read all fields */ + String field = getFieldFromKey(entry.getKey()); + if (fields != null && !fields.contains(field)) { + continue; + } + result.put(field, new ByteArrayByteIterator(entry.getValue().getValue().getValue())); + } + + return OK; + } + + @Override + public int scan(String table, String startkey, int recordcount, Set<String> fields, Vector<HashMap<String, ByteIterator>> result) { + System.err.println("Oracle NoSQL Database does not support Scan semantics"); + return ERROR; + } + + @Override + public int update(String table, String key, HashMap<String, ByteIterator> values) { + for (Map.Entry<String, ByteIterator> entry : values.entrySet()) { + Key kvKey = createKey(table, key, entry.getKey()); + Value kvValue = Value.createValue(entry.getValue().toArray()); + try { + store.put(kvKey, kvValue); + } catch (FaultException e) { + System.err.println(e); + return ERROR; + } + } + + return OK; + } + + @Override + public int insert(String table, String key, HashMap<String, ByteIterator> values) { + return update(table, key, values); + } + + @Override + public int delete(String table, String key) { + Key kvKey = createKey(table, key); + try { + store.multiDelete(kvKey, null, null); + } catch (FaultException e) { + System.err.println(e); + return ERROR; + } + + return OK; + } + +} -- GitLab