Skip to content
Snippets Groups Projects
Commit 28703c74 authored by Sean Busbey's avatar Sean Busbey Committed by GitHub
Browse files

[rados] Merge pull request #670 from jaemyoun/dev-ceph-rados

Development of RADOS binding of Ceph FS
parents 56b5fa16 5d3464fe
No related branches found
No related tags found
No related merge requests found
...@@ -81,6 +81,7 @@ DATABASES = { ...@@ -81,6 +81,7 @@ DATABASES = {
"mongodb-async": "com.yahoo.ycsb.db.AsyncMongoDbClient", "mongodb-async": "com.yahoo.ycsb.db.AsyncMongoDbClient",
"nosqldb" : "com.yahoo.ycsb.db.NoSqlDbClient", "nosqldb" : "com.yahoo.ycsb.db.NoSqlDbClient",
"orientdb" : "com.yahoo.ycsb.db.OrientDBClient", "orientdb" : "com.yahoo.ycsb.db.OrientDBClient",
"rados" : "com.yahoo.ycsb.db.RadosClient",
"redis" : "com.yahoo.ycsb.db.RedisClient", "redis" : "com.yahoo.ycsb.db.RedisClient",
"riak" : "com.yahoo.ycsb.db.riak.RiakKVClient", "riak" : "com.yahoo.ycsb.db.riak.RiakKVClient",
"s3" : "com.yahoo.ycsb.db.S3Client", "s3" : "com.yahoo.ycsb.db.S3Client",
......
...@@ -149,6 +149,11 @@ LICENSE file. ...@@ -149,6 +149,11 @@ LICENSE file.
<artifactId>orientdb-binding</artifactId> <artifactId>orientdb-binding</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.yahoo.ycsb</groupId>
<artifactId>rados-binding</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.yahoo.ycsb</groupId> <groupId>com.yahoo.ycsb</groupId>
<artifactId>redis-binding</artifactId> <artifactId>redis-binding</artifactId>
......
...@@ -129,6 +129,7 @@ LICENSE file. ...@@ -129,6 +129,7 @@ LICENSE file.
<module>mongodb</module> <module>mongodb</module>
<module>nosqldb</module> <module>nosqldb</module>
<module>orientdb</module> <module>orientdb</module>
<module>rados</module>
<module>redis</module> <module>redis</module>
<module>riak</module> <module>riak</module>
<module>s3</module> <module>s3</module>
......
<!--
Copyright (c) 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.
-->
## Quick Start
This section describes how to run YCSB on RADOS of Ceph.
### 1. Start RADOS
After you start your Ceph cluster, check your cluster’s health first. You can check on the health of your cluster with the following:
ceph health
### 2. Install Java and Maven
### 3. Set Up YCSB
Git clone YCSB and compile:
git clone http://github.com/brianfrankcooper/YCSB.git
cd YCSB
mvn clean package
You can compile only RADOS-binding, EG:
mvn -pl com.yahoo.ycsb:rados-binding -am clean package
You can skip the test, EG:
mvn -pl com.yahoo.ycsb:rados-binding -am clean package -DskipTests
### 4. Configuration Parameters
- `rados.configfile`
- The path of the Ceph configuration file
- Default value is '/etc/ceph/ceph.conf'
- `rados.id`
- The user id to access the RADOS service
- Default value is 'admin'
- `rados.pool`
- The pool name to be used for benchmark
- Default value is 'data'
You can set configurations with the shell command, EG:
./bin/ycsb load rados -s -P workloads/workloada -p "rados.configfile=/etc/ceph/ceph.conf" -p "rados.id=admin" -p "rados.pool=data" > outputLoad.txt
### 5. Load data and run tests
Load the data:
./bin/ycsb load rados -s -P workloads/workloada > outputLoad.txt
Run the workload test:
./bin/ycsb run rados -s -P workloads/workloada > outputRun.txt
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 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.10.0-SNAPSHOT</version>
<relativePath>../binding-parent</relativePath>
</parent>
<artifactId>rados-binding</artifactId>
<name>rados of Ceph FS binding</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.ceph</groupId>
<artifactId>rados</artifactId>
<version>${rados.version}</version>
</dependency>
<dependency>
<groupId>com.yahoo.ycsb</groupId>
<artifactId>core</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>${json.version}</version>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.2.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<rados.version>0.2.0</rados.version>
<json.version>20160212</json.version>
</properties>
</project>
/**
* Copyright (c) 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.
*/
package com.yahoo.ycsb.db;
import com.ceph.rados.Rados;
import com.ceph.rados.IoCTX;
import com.ceph.rados.jna.RadosObjectInfo;
import com.ceph.rados.ReadOp;
import com.ceph.rados.ReadOp.ReadResult;
import com.ceph.rados.exceptions.RadosException;
import com.yahoo.ycsb.ByteIterator;
import com.yahoo.ycsb.DB;
import com.yahoo.ycsb.DBException;
import com.yahoo.ycsb.Status;
import com.yahoo.ycsb.StringByteIterator;
import java.io.File;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.Vector;
import org.json.JSONObject;
/**
* YCSB binding for <a href="http://ceph.org/">RADOS of Ceph</a>.
*
* See {@code rados/README.md} for details.
*/
public class RadosClient extends DB {
private Rados rados;
private IoCTX ioctx;
public static final String CONFIG_FILE_PROPERTY = "rados.configfile";
public static final String CONFIG_FILE_DEFAULT = "/etc/ceph/ceph.conf";
public static final String ID_PROPERTY = "rados.id";
public static final String ID_DEFAULT = "admin";
public static final String POOL_PROPERTY = "rados.pool";
public static final String POOL_DEFAULT = "data";
private boolean isInited = false;
public void init() throws DBException {
Properties props = getProperties();
String configfile = props.getProperty(CONFIG_FILE_PROPERTY);
if (configfile == null) {
configfile = CONFIG_FILE_DEFAULT;
}
String id = props.getProperty(ID_PROPERTY);
if (id == null) {
id = ID_DEFAULT;
}
String pool = props.getProperty(POOL_PROPERTY);
if (pool == null) {
pool = POOL_DEFAULT;
}
// try {
// } catch (UnsatisfiedLinkError e) {
// throw new DBException("RADOS library is not loaded.");
// }
rados = new Rados(id);
try {
rados.confReadFile(new File(configfile));
rados.connect();
ioctx = rados.ioCtxCreate(pool);
} catch (RadosException e) {
throw new DBException(e.getMessage() + ": " + e.getReturnValue());
}
isInited = true;
}
public void cleanup() throws DBException {
if (isInited) {
rados.shutDown();
rados.ioCtxDestroy(ioctx);
isInited = false;
}
}
@Override
public Status read(String table, String key, Set<String> fields, HashMap<String, ByteIterator> result) {
byte[] buffer;
try {
RadosObjectInfo info = ioctx.stat(key);
buffer = new byte[(int)info.getSize()];
ReadOp rop = ioctx.readOpCreate();
ReadResult readResult = rop.queueRead(0, info.getSize());
// TODO: more size than byte length possible;
// rop.operate(key, Rados.OPERATION_NOFLAG); // for rados-java 0.3.0
rop.operate(key, 0);
// readResult.raiseExceptionOnError("Error ReadOP(%d)", readResult.getRVal()); // for rados-java 0.3.0
if (readResult.getRVal() < 0) {
throw new RadosException("Error ReadOP", readResult.getRVal());
}
if (info.getSize() != readResult.getBytesRead()) {
return new Status("ERROR", "Error the object size read");
}
readResult.getBuffer().get(buffer);
} catch (RadosException e) {
return new Status("ERROR-" + e.getReturnValue(), e.getMessage());
}
JSONObject json = new JSONObject(new String(buffer, java.nio.charset.StandardCharsets.UTF_8));
Set<String> fieldsToReturn = (fields == null ? json.keySet() : fields);
for (String name : fieldsToReturn) {
result.put(name, new StringByteIterator(json.getString(name)));
}
return result.isEmpty() ? Status.ERROR : Status.OK;
}
@Override
public Status insert(String table, String key, HashMap<String, ByteIterator> values) {
JSONObject json = new JSONObject();
for (final Entry<String, ByteIterator> e : values.entrySet()) {
json.put(e.getKey(), e.getValue().toString());
}
try {
ioctx.write(key, json.toString());
} catch (RadosException e) {
return new Status("ERROR-" + e.getReturnValue(), e.getMessage());
}
return Status.OK;
}
@Override
public Status delete(String table, String key) {
try {
ioctx.remove(key);
} catch (RadosException e) {
return new Status("ERROR-" + e.getReturnValue(), e.getMessage());
}
return Status.OK;
}
@Override
public Status update(String table, String key, HashMap<String, ByteIterator> values) {
Status rtn = delete(table, key);
if (rtn.equals(Status.OK)) {
return insert(table, key, values);
}
return rtn;
}
@Override
public Status scan(String table, String startkey, int recordcount, Set<String> fields,
Vector<HashMap<String, ByteIterator>> result) {
return Status.NOT_IMPLEMENTED;
}
}
/**
* Copyright (c) 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.
*/
/**
* YCSB binding for RADOS of Ceph.
*/
package com.yahoo.ycsb.db;
/**
* Copyright (c) 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.
*/
package com.yahoo.ycsb.db;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeNoException;
import com.yahoo.ycsb.ByteIterator;
import com.yahoo.ycsb.DBException;
import com.yahoo.ycsb.Status;
import com.yahoo.ycsb.StringByteIterator;
import org.junit.AfterClass;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Before;
import org.junit.Test;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.UUID;
/**
* Test for the binding of <a href="http://ceph.org/">RADOS of Ceph</a>.
*
* See {@code rados/README.md} for details.
*/
public class RadosClientTest {
private static RadosClient radosclient;
public static final String POOL_PROPERTY = "rados.pool";
public static final String POOL_TEST = "rbd";
private static final String TABLE_NAME = "table0";
private static final String KEY0 = "key0";
private static final String KEY1 = "key1";
private static final String KEY2 = "key2";
private static final HashMap<String, ByteIterator> DATA;
private static final HashMap<String, ByteIterator> DATA_UPDATED;
static {
DATA = new HashMap<String, ByteIterator>(10);
DATA_UPDATED = new HashMap<String, ByteIterator>(10);
for (int i = 0; i < 10; i++) {
String key = "key" + UUID.randomUUID();
DATA.put(key, new StringByteIterator("data" + UUID.randomUUID()));
DATA_UPDATED.put(key, new StringByteIterator("data" + UUID.randomUUID()));
}
}
@BeforeClass
public static void setupClass() throws DBException {
radosclient = new RadosClient();
Properties p = new Properties();
p.setProperty(POOL_PROPERTY, POOL_TEST);
try {
radosclient.setProperties(p);
radosclient.init();
}
catch (DBException|UnsatisfiedLinkError e) {
assumeNoException("Ceph cluster is not running. Skipping tests.", e);
}
}
@AfterClass
public static void teardownClass() throws DBException {
if (radosclient != null) {
radosclient.cleanup();
}
}
@Before
public void setUp() {
radosclient.insert(TABLE_NAME, KEY0, DATA);
}
@After
public void tearDown() {
radosclient.delete(TABLE_NAME, KEY0);
}
@Test
public void insertTest() {
Status result = radosclient.insert(TABLE_NAME, KEY1, DATA);
assertEquals(Status.OK, result);
}
@Test
public void updateTest() {
radosclient.insert(TABLE_NAME, KEY2, DATA);
Status result = radosclient.update(TABLE_NAME, KEY2, DATA_UPDATED);
assertEquals(Status.OK, result);
HashMap<String, ByteIterator> ret = new HashMap<String, ByteIterator>(10);
radosclient.read(TABLE_NAME, KEY2, DATA.keySet(), ret);
compareMap(DATA_UPDATED, ret);
radosclient.delete(TABLE_NAME, KEY2);
}
@Test
public void readTest() {
HashMap<String, ByteIterator> ret = new HashMap<String, ByteIterator>(10);
Status result = radosclient.read(TABLE_NAME, KEY0, DATA.keySet(), ret);
assertEquals(Status.OK, result);
compareMap(DATA, ret);
}
private void compareMap(HashMap<String, ByteIterator> src, HashMap<String, ByteIterator> dest) {
assertEquals(src.size(), dest.size());
Set setSrc = src.entrySet();
Iterator<Map.Entry> itSrc = setSrc.iterator();
for (int i = 0; i < 10; i++) {
Map.Entry<String, ByteIterator> entrySrc = itSrc.next();
assertEquals(entrySrc.getValue().toString(), dest.get(entrySrc.getKey()).toString());
}
}
@Test
public void deleteTest() {
Status result = radosclient.delete(TABLE_NAME, KEY0);
assertEquals(Status.OK, result);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment