package org.hackreduce.storm.example.riak;
import backtype.storm.task.IMetricsContext;
import com.basho.riak.client.IRiakClient;
import com.basho.riak.client.RiakFactory;
import com.basho.riak.client.bucket.Bucket;
import com.basho.riak.client.cap.DefaultRetrier;
import com.basho.riak.client.query.MultiFetchFuture;
import com.basho.riak.client.raw.pbc.PBClientConfig;
import com.basho.riak.client.raw.pbc.PBClusterConfig;
import com.google.common.base.Joiner;
import storm.trident.state.State;
import storm.trident.state.map.IBackingMap;
import storm.trident.state.map.NonTransactionalMap;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class RiakBackingMap<T> implements IBackingMap<T> {
private static final char KEY_JOIN_CHAR = ':';
private final Class<T> clazz;
private final Bucket bucket;
public RiakBackingMap(String bucketName, List<String> hosts, int port, Class<T> clazz) {
this.clazz = clazz;
try {
PBClusterConfig clusterConfig = new PBClusterConfig(5);
PBClientConfig clientConfig = new PBClientConfig.Builder()
.withPort(port)
.build();
clusterConfig.addHosts(clientConfig, hosts.toArray(new String[hosts.size()]));
IRiakClient riakClient = RiakFactory.newClient(clusterConfig);
bucket = riakClient.createBucket(bucketName)
.withRetrier(DefaultRetrier.attempts(3))
.execute();
} catch (Exception e) {
throw new RuntimeException("Exception while talking to Riak!", e);
}
}
@Override
public List<T> multiGet(List<List<Object>> lists) {
try {
ArrayList<String> keys = new ArrayList<String>();
for (List<Object> keyList : lists) {
String key = Joiner.on(KEY_JOIN_CHAR).join(keyList);
keys.add(key);
}
List<MultiFetchFuture<T>> futureResults = bucket.multiFetch(keys, clazz)
.withRetrier(DefaultRetrier.attempts(3))
.execute();
ArrayList<T> results = new ArrayList<T>();
for (MultiFetchFuture<T> result : futureResults) {
results.add(result.get());
}
return results;
} catch (Exception e) {
throw new RuntimeException("Exception while talking to Riak!", e);
}
}
@Override
public void multiPut(List<List<Object>> lists, List<T> ts) {
Iterator<List<Object>> keyIterator = lists.iterator();
Iterator<T> valueIterator = ts.iterator();
try {
while (keyIterator.hasNext() && valueIterator.hasNext()) {
String key = Joiner.on(KEY_JOIN_CHAR).join(keyIterator.next());
T value = valueIterator.next();
bucket.store(key, value)
.withRetrier(DefaultRetrier.attempts(3))
.execute();
}
} catch (Exception e) {
throw new RuntimeException("Exception while talking to Riak!", e);
}
}
/**
* Creates a nontransactional state using Riak as the backing store.
*
* This is nontransactional for two reasons: it makes it friendlier to users of the HTTP client
*/
public static class Factory<T> implements storm.trident.state.StateFactory {
private final String bucket;
private List<String> hosts;
private int port;
private Class<T> clazz;
public Factory(String bucket, List<String> hosts, int port, Class<T> clazz) {
this.bucket = bucket;
this.hosts = hosts;
this.port = port;
this.clazz = clazz;
}
@Override public State makeState(Map map, IMetricsContext iMetricsContext, int i, int i2) {
return NonTransactionalMap.build(new RiakBackingMap<T>(bucket, hosts, port, clazz));
}
}
}