Introduce usage of key/val data source as abstraction

Implement Redis  key/val datasource
Implement LevelDb key/val datasource
This commit is contained in:
Roman Mandeleil 2015-01-18 23:32:30 +02:00
parent 5ead5a5da0
commit 38cf19015b
6 changed files with 287 additions and 7 deletions

View File

@ -75,6 +75,8 @@ dependencies {
compile "org.hibernate:hibernate-core:${hibernateVersion}"
compile "org.hibernate:hibernate-entitymanager:${hibernateVersion}"
compile "commons-dbcp:commons-dbcp:1.4"
compile "redis.clients:jedis:2.6.0"
compile("com.googlecode.json-simple:json-simple:1.1.1") {
exclude group:'junit', module:'junit'
}

View File

@ -0,0 +1,25 @@
package org.ethereum.datasource;
import java.util.Map;
import java.util.Set;
/**
*
* @author: Roman Mandeleil
* Created on: 18/01/2015 21:40
*/
public interface KeyValueDataSource {
public void init();
public void setName(String name);
public byte[] get(byte[] key);
public void put(byte[] key, byte[] value);
public void delete(byte[] key);
public Set<byte[]> keys();
public void setBatch( Map<byte[], byte[]> rows);
}

View File

@ -0,0 +1,60 @@
package org.ethereum.datasource;
import org.ethereum.db.Database;
import org.ethereum.db.DatabaseImpl;
import org.iq80.leveldb.DB;
import java.util.Map;
import java.util.Set;
/**
*
* @author: Roman Mandeleil
* Created on: 18/01/2015 21:48
*/
public class LevelDbDataSource implements KeyValueDataSource{
String name;
Database db;
@Override
public void init() {
if (name == null) throw new NullPointerException("no name set to the db");
db = new DatabaseImpl(name);
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public byte[] get(byte[] key) {
return db.get(key);
}
@Override
public void put(byte[] key, byte[] value) {
db.put(key, value);
}
@Override
public void delete(byte[] key) {
db.delete(key);
}
@Override
public Set<byte[]> keys() {
// todo: re-modelling DataBase for that
throw new UnsupportedOperationException();
}
@Override
public void setBatch(Map<byte[], byte[]> rows) {
// todo: re-modelling DataBase for that
throw new UnsupportedOperationException();
}
}

View File

@ -0,0 +1,91 @@
package org.ethereum.datasource;
import org.ethereum.db.Database;
import org.ethereum.db.DatabaseImpl;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
*
* @author: Roman Mandeleil
* Created on: 18/01/2015 21:48
*/
public class RedisDataSource implements KeyValueDataSource{
String name;
int index;
Jedis jedis;
@Override
public void init() {
if (name == null) throw new NullPointerException("no name set to the db");
this.jedis = new Jedis("localhost"); // todo: config.redisHost, config.redisPort
this.jedis.flushAll(); // todo: if config.reset so reset.
}
@Override
public void setName(String name) {
this.name = name;
index = nameToIndex(name);
}
@Override
public byte[] get(byte[] key) {
jedis.select(index);
return jedis.get(key);
}
@Override
public void put(byte[] key, byte[] value) {
jedis.select(index);
jedis.set(key, value);
}
@Override
public void delete(byte[] key) {
jedis.select(index);
jedis.del(key);
}
@Override
public Set<byte[]> keys() {
return jedis.keys("*".getBytes());
}
@Override
public void setBatch(Map<byte[], byte[]> rows) {
jedis.select(index);
Pipeline pipeline = jedis.pipelined();
Iterator<Map.Entry<byte[], byte[]>> iterator = rows.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry<byte[], byte[]> row = iterator.next();
byte[] key = row.getKey();
byte[] val = row.getValue();
pipeline.set(key, val);
}
pipeline.sync();
}
private static Integer nameToIndex(String name) {
Integer index = DBNameScheme.get(name);
if (index == null) {
index = indexCounter.getAndIncrement();
DBNameScheme.put(name, index);
indexCounter.intValue();
}
return index;
}
private static Map<String, Integer> DBNameScheme = new HashMap<>();
private static AtomicInteger indexCounter = new AtomicInteger(1);
}

View File

@ -0,0 +1,67 @@
package test.ethereum.datasource;
import org.ethereum.datasource.RedisDataSource;
import org.junit.Assert;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
import redis.clients.jedis.exceptions.JedisConnectionException;
/**
* @author: Roman Mandeleil
* Created on: 18/01/2015 22:40
*/
public class RedisDataSourceTest {
@Test
public void testSet1(){
try {
RedisDataSource redis = new RedisDataSource();
redis.setName("state");
redis.init();
byte[] key = Hex.decode("a1a2a3");
byte[] val = Hex.decode("b1b2b3");
redis.put(key, val);
byte[] val2 = redis.get(key);
Assert.assertEquals(Hex.toHexString(val), Hex.toHexString(val2));
} catch (JedisConnectionException e) {
// no redis server consider test as pass
}
}
@Test
public void testSet2(){
try {
RedisDataSource redis1 = new RedisDataSource();
redis1.setName("state");
redis1.init();
RedisDataSource redis2 = new RedisDataSource();
redis2.setName("details");
redis2.init();
byte[] key = Hex.decode("a1a2a3");
byte[] val1 = Hex.decode("b1b2b3");
byte[] val2 = Hex.decode("c1c2c3");
redis1.put(key, val1);
redis2.put(key, val2);
byte[] res1 = redis1.get(key);
byte[] res2 = redis2.get(key);
Assert.assertEquals(Hex.toHexString(val1), Hex.toHexString(res1));
Assert.assertEquals(Hex.toHexString(val2), Hex.toHexString(res2));
} catch (JedisConnectionException e) {
// no redis server consider test as pass
}
}
}

View File

@ -1,5 +1,7 @@
package test.ethereum.trie;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;
import test.ethereum.db.MockDB;
import org.ethereum.core.AccountState;
@ -32,13 +34,7 @@ import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.*;
import static org.ethereum.crypto.HashUtil.EMPTY_TRIE_HASH;
import static org.junit.Assert.*;
@ -590,6 +586,45 @@ public class TrieTest {
}
@Ignore
@Test
public void reddisTest() throws URISyntaxException, IOException {
URL massiveUpload_1 = ClassLoader
.getSystemResource("trie/massive-upload.dmp");
File file = new File(massiveUpload_1.toURI());
List<String> strData = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
String dbName = "state";
long startTime = System.currentTimeMillis();
Jedis jedis = new Jedis("localhost");
jedis.flushAll();
Pipeline pipeline = jedis.pipelined();
Set<String> keys = jedis.keys("*");
System.out.println("before: all " + keys.size());
for (String aStrData : strData) {
String[] keyVal = aStrData.split("=");
if (keyVal[0].equals("*"))
pipeline.del(keyVal[1].getBytes());
else
pipeline.set(keyVal[0].getBytes(), keyVal[1].getBytes());
}
pipeline.sync();
keys = jedis.keys("*");
System.out.println("all " + keys.size());
for (String key : keys)
System.out.println(key + " -> " + jedis.get(key));
System.out.println("time: " + (System.currentTimeMillis() - startTime));
}
@Ignore
@Test
public void testMasiveDetermenisticUpdate() throws IOException, URISyntaxException {