/**
* Copyright 2013-2015 Seagate Technology LLC.
*
* This Source Code Form is subject to the terms of the Mozilla
* Public License, v. 2.0. If a copy of the MPL was not
* distributed with this file, You can obtain one at
* https://mozilla.org/MP:/2.0/.
*
* This program is distributed in the hope that it will be useful,
* but is provided AS-IS, WITHOUT ANY WARRANTY; including without
* the implied warranty of MERCHANTABILITY, NON-INFRINGEMENT or
* FITNESS FOR A PARTICULAR PURPOSE. See the Mozilla Public
* License for more details.
*
* See www.openkinetic.org for more project information
*/
package com.seagate.kinetic.usage.p2p;
import java.io.UnsupportedEncodingException;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.logging.Handler;
import java.util.logging.Logger;
import kinetic.client.AsyncKineticException;
import kinetic.client.CallbackHandler;
import kinetic.client.CallbackResult;
import kinetic.client.ClientConfiguration;
import kinetic.client.Entry;
import kinetic.client.KineticClient;
import kinetic.client.KineticClientFactory;
import kinetic.client.KineticException;
import kinetic.simulator.KineticSimulator;
import kinetic.simulator.SimulatorConfiguration;
public class KineticP2PUsageExample {
private final Logger logger = Logger.getLogger(this.getClass().getName());
KineticSimulator newSimulator(int port) throws KineticException {
SimulatorConfiguration sConfig = new SimulatorConfiguration();
sConfig.setPort(port);
sConfig.setStartSsl(false);
sConfig.put(SimulatorConfiguration.PERSIST_HOME, "instance_" + port);
return new KineticSimulator(sConfig);
}
KineticClient newClient(KineticSimulator s) throws KineticException {
SimulatorConfiguration sc = s.getServerConfiguration();
ClientConfiguration cConfig = new ClientConfiguration();
cConfig.setHost("localhost");
cConfig.setPort(sc.getPort());
return KineticClientFactory.createInstance(cConfig);
}
@SuppressWarnings("rawtypes")
List<Event> running = Collections.synchronizedList(new LinkedList<Event>());
// List<Event> events = new LinkedList<Event>();
synchronized void allComplete() throws AsyncKineticException {
try {
logger.fine("waitingAll");
while (!running.isEmpty()) {
logger.fine("allComplete waiting");
synchronized (running) {
running.wait(5000);
}
}
logger.fine("waitedAll");
} catch (InterruptedException e) {
throw new AsyncKineticException("Timed out [2]");
}
}
// this can be either a named event that can be waited on or an
// anonymous event that will automatically be a part of the "running"
// event list and can be waited on with a call to "completeAll()".
public class Event<T> implements CallbackHandler<T> {
T result = null;
private AsyncKineticException exception = null;
private boolean success = false;
private boolean complete = false;
void done() {
complete = true;
this.notifyAll();
synchronized (running) {
int i = running.indexOf(this);
if (i >= 0) {
running.remove(i);
}
if (running.isEmpty()) {
running.notifyAll();
}
}
}
@Override
synchronized public void onSuccess(CallbackResult<T> result) {
logger.fine("onSuccess");
if (!complete) {
this.result = result.getResult();
success = true;
}
done();
}
@Override
synchronized public void onError(AsyncKineticException exception) {
logger.warning("onError");
if (!complete) {
this.exception = exception;
logger.warning(exception.toString());
success = false;
}
done();
}
void completed() throws AsyncKineticException {
try {
logger.fine("waitingOne");
synchronized (this) {
while (!complete) {
this.wait(1000);
}
}
} catch (InterruptedException e) {
throw new AsyncKineticException("Timed out");
}
logger.fine("waitedOne");
if (!success)
throw this.exception;
}
Event() {
running.add(this);
}
}
Entry myEntry(String k) {
return myEntry(k, null);
}
Entry myEntry(String k, String v) {
Entry e = new Entry();
e.setKey(k.getBytes());
if (v != null)
e.setValue(v.getBytes());
return e;
}
@SuppressWarnings({ "rawtypes", "unchecked" })
List shuffle(List l) {
LinkedList l1 = new LinkedList();
Random r = new Random();
while (!l.isEmpty()) {
int i = r.nextInt(l.size());
l1.add(l.get(i));
l.remove(i);
}
return l1;
}
static enum Command {
PUSH
};
public class RemoteOp {
Command command;
boolean started = false;
boolean success = false;
KineticException exception;
byte[] key = null;
byte[] newKey = null;
byte[] version = null;
boolean force = false;
RemoteOp(Command c, byte[] key) {
this.command = c;
this.key = key;
}
}
// this is the interface to the library and a thing that is supposed to be
// similar
// to what is actually done in the drive. Imagine that this was really
// local.P2POperation(....) and that the local parameter is not there.
List<RemoteOp> P2POperation(KineticClient local, List<RemoteOp> l,
String peer, int port, boolean ssl) throws KineticException {
ClientConfiguration cConfig = new ClientConfiguration();
cConfig.setHost(peer);
cConfig.setPort(port);
cConfig.setUseSsl(ssl);
KineticClient remote = KineticClientFactory.createInstance(cConfig);
LinkedList<RemoteOp> lout = new LinkedList<RemoteOp>();
for (RemoteOp op : l) {
try {
op.started = true;
switch (op.command) {
case PUSH:
// we get the data
Entry e = local.get(op.key);
if (op.newKey != null)
e.setKey(op.newKey);
// TODO: Chiaming: How does "force" put implemented in the
// api? Is it? Maybe not?
if (op.force)
throw new KineticException(
"P2POperation.force not implemented");
// and if no options, just put it...
if (op.version != null) {
remote.putForced(e);
} else /* (op.version != null) */{
// in this case, we need to put the old version in the
// new
// data to the put with version works and then
// mark the new version as what we read.
byte[] newVersion = e.getEntryMetadata().getVersion();
byte[] oldVersion = op.version;
e.getEntryMetadata().setVersion(oldVersion);
remote.put(e, newVersion);
}
break;
default:
throw new KineticException("unknown P2P command");
}
// if we get here without an exception, we were successful.
op.success = true;
} catch (KineticException e) {
op.exception = e;
op.success = false;
}
lout.add(op);
}
return lout;
}
@SuppressWarnings("unchecked")
KineticP2PUsageExample() throws KineticException {
logger.warning("new");
KineticSimulator s1 = newSimulator(8123);
KineticSimulator s2 = newSimulator(8224);
KineticClient c1 = newClient(s1);
KineticClient c2 = newClient(s2);
logger.warning("started");
try {
List<Entry> keys = new LinkedList<Entry>();
for (int i = 0; i < 256; i++) {
byte[] bs = new byte[1];
bs[0] = (byte) i;
keys.add(new Entry(bs, bs));
}
keys = shuffle(keys);
for (Entry e : keys) {
c1.deleteForcedAsync(e.getKey(), new Event<Boolean>());
}
// allComplete();
logger.warning("deleted");
for (Entry e : keys) {
c1.putForcedAsync(e, new Event<Entry>());
}
// allComplete();
logger.warning("written");
List<byte[]> l = c1.getKeyRange(new byte[] {}, true, new byte[] {
-1, -1 }, false, 500);
List<RemoteOp> ops = new LinkedList<RemoteOp>();
for (Entry e : keys) {
ops.add(new RemoteOp(Command.PUSH, e.getKey()));
}
logger.warning("total operations out: " + ops.size());
ops = P2POperation(c1, ops, "localhost", 8224, false);
logger.warning("total operations in: " + ops.size());
for (RemoteOp op : ops) {
if (op.success)
System.out.printf("Success, key %02x\n", op.key[0]);
else
System.out.printf("Failed, key %02x\n%s\n", op.key[0],
op.exception.toString());
}
logger.warning("total running: " + running.size());
for (byte[] ba : l) {
System.out.printf("%04d %02x \n", ba[0], ba[0]);
}
logger.warning("complete");
} catch (Exception e) {
e.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
logger.warning("done");
c1.close();
c2.close();
s1.close();
s2.close();
logger.warning("Finished!");
Handler[] handlers = logger.getHandlers();
for (Handler handler : handlers) {
handler.close();
}
}
public static byte[] toByteArray(String s)
throws UnsupportedEncodingException {
return s.getBytes("utf8");
}
public static void main(String[] args) throws Exception {
@SuppressWarnings("unused")
KineticP2PUsageExample xx = new KineticP2PUsageExample();
}
}