package com.rubiconproject.oss.kv.tools;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Callable;
import org.kohsuke.args4j.CmdLineParser;
import org.kohsuke.args4j.Option;
import com.rubiconproject.oss.kv.KeyValueStore;
import com.rubiconproject.oss.kv.KeyValueStoreUnavailable;
import com.rubiconproject.oss.kv.backends.IterableKeyValueStore;
import com.rubiconproject.oss.kv.backends.KeyValueStoreIterator;
import com.rubiconproject.oss.kv.backends.UriConnectionFactory;
import com.rubiconproject.oss.kv.transcoder.ByteArrayTranscoder;
import com.rubiconproject.oss.kv.transcoder.Transcoder;
/**
* Copy from one kv store to another.
*
* Given an input node (by uri) and a destination node (by uri), will copy from
* input to output.
*
* Usage:
*
* - Run it: java -classpath oo-kv-storage.jar:...
* com.othersonline.kv.tools.NodeCopy --source "tyrant://dev-db:1978" --dest
* "tyrant://dev-db:1979" --sleep 2
*
* @author stingleff
*
*/
public class NodeCopy implements Runnable, Callable<Map<String, Long>> {
@Option(name = "--source", usage = "Source uri (default: none)", required = true)
private String source;
@Option(name = "--dest", usage = "Destination uri (default: none)", required = true)
private String dest;
@Option(name = "--sleep", usage = "Sleep time between keys (millis) (default: disabled)")
private long sleep = 0;
@Option(name = "--skip", usage = "Skip this many records first (default: 0)")
private int skip = 0;
@Option(name = "--max", usage = "Stop after x keys (default: disabled)")
private int max = -1;
@Option(name = "--delete", usage = "Delete from source (default: false")
private boolean delete = false;
private Transcoder byteTranscoder = new ByteArrayTranscoder();
public static void main(String[] args) throws Exception {
NodeCopy vr = new NodeCopy();
CmdLineParser parser = new CmdLineParser(vr);
parser.parseArgument(args);
Map<String, Long> stats = vr.call();
for (Map.Entry<String, Long> entry : stats.entrySet()) {
System.out.println(String.format("%1$s\t%2$d", entry.getKey(),
entry.getValue()));
}
System.out.println("Completed successfully. Exiting.");
System.exit(0);
}
public void run() {
try {
call();
} catch (Exception e) {
e.printStackTrace();
}
}
public Map<String, Long> call() throws Exception {
IterableKeyValueStore src = (IterableKeyValueStore) getKeyValueStore(source);
KeyValueStore kv = getKeyValueStore(dest);
long examined = 0, moved = 0, notMoved = 0, getFailures = 0, setFailures = 0, deleteFailures = 0;
KeyValueStoreIterator keyIterator = src.iterkeys();
try {
Iterator<String> iter = keyIterator.iterator();
while (iter.hasNext()) {
String key = iter.next();
++examined;
if (examined <= skip) {
++notMoved;
continue;
}
byte[] bytes = null;
try {
bytes = (byte[]) src.get(key, byteTranscoder);
} catch (Exception e) {
e.printStackTrace();
++getFailures;
}
boolean successfulMove = false;
try {
if (bytes != null) {
kv.set(key, bytes, byteTranscoder);
successfulMove = true;
++moved;
} else
++notMoved;
} catch (Exception e) {
e.printStackTrace();
++setFailures;
}
try {
if (successfulMove && delete) {
src.delete(key);
}
} catch (Exception e) {
e.printStackTrace();
++deleteFailures;
}
if (examined % 1000 == 0) {
System.out.println("Status");
System.out.println("examined: " + examined);
System.out.println("moved: " + moved);
System.out.println("getFailures: " + getFailures);
System.out.println("setFailures: " + setFailures);
System.out.println("deleteFailures: " + deleteFailures);
}
if ((max > 0) && (examined >= max))
break;
if (sleep > 0)
Thread.sleep(sleep);
}
} finally {
keyIterator.close();
src.stop();
kv.stop();
}
Map<String, Long> results = new HashMap<String, Long>();
results.put("examined", examined);
results.put("moved", moved);
results.put("not-moved", notMoved);
results.put("get-failures", getFailures);
results.put("set-failures", setFailures);
results.put("delete-failures", deleteFailures);
return results;
}
private KeyValueStore getKeyValueStore(String uri)
throws KeyValueStoreUnavailable, IOException {
UriConnectionFactory factory = new UriConnectionFactory();
KeyValueStore kv = factory.getStore(null, uri);
return kv;
}
}