/*
* Copyright 2013 Thomas Bocek
*
* 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.
*/
package net.tomp2p.p2p;
import java.io.IOException;
import java.security.PublicKey;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicInteger;
import net.tomp2p.Utils2;
import net.tomp2p.connection2.ChannelCreator;
import net.tomp2p.futures.BaseFuture;
import net.tomp2p.futures.FutureBootstrap;
import net.tomp2p.futures.FutureChannelCreator;
import net.tomp2p.futures.FutureCreate;
import net.tomp2p.futures.FutureDHT;
import net.tomp2p.futures.FutureResponse;
import net.tomp2p.p2p.builder.DHTBuilder;
import net.tomp2p.peers.Number160;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.storage.Data;
import net.tomp2p.storage.StorageMemory;
import net.tomp2p.utils.Timings;
import net.tomp2p.utils.Utils;
import org.junit.Assert;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Thomas Bocek
*
*/
public class TestReplication {
private static final Random RND = new Random(42L);
private static final Random RND2 = new Random(42L);
private static final int PORT = 4001;
private static final int SECOND = 1000;
private static final Logger LOG = LoggerFactory.getLogger(TestReplication.class);
private static final int NR_PEERS = 100;
private static final int NINE_SECONDS = 9000;
/**
* Test the direct replication, where the initiator is also the responsible peer.
*
* @throws Exception .
*/
/*@Test
public void testDirectReplication() throws Exception {
Peer master = null;
try {
// setup
Peer[] peers = Utils2.createNodes(NR_PEERS, RND, PORT);
master = peers[0];
List<FutureBootstrap> tmp = new ArrayList<FutureBootstrap>();
for (int i = 0; i < peers.length; i++) {
if (peers[i] != master) {
FutureBootstrap res = peers[i].bootstrap().setPeerAddress(master.getPeerAddress()).start();
tmp.add(res);
}
}
int i = 0;
for (FutureBootstrap fm : tmp) {
fm.awaitUninterruptibly();
if (fm.isFailed()) {
System.err.println(fm.getFailedReason());
}
Assert.assertEquals(true, fm.isSuccess());
System.err.println("i:" + (++i));
}
final AtomicInteger counter = new AtomicInteger(0);
// New storage class to count the puts.
final class MyStorageMemory extends StorageMemory {
@Override
public PutStatus put(final Number160 locationKey, final Number160 domainKey,
final Number160 contentKey, final Data newData, final PublicKey publicKey,
final boolean putIfAbsent, final boolean domainProtection) {
System.err.println("here");
counter.incrementAndGet();
return super.put(locationKey, domainKey, contentKey, newData, publicKey, putIfAbsent,
domainProtection);
}
}
final int peerNr = 50;
final int repetitions = 5;
peers[peerNr].getPeerBean().setStorage(new MyStorageMemory());
FutureCreate<FutureDHT> futureCreate = new FutureCreate<FutureDHT>() {
@Override
public void repeated(final FutureDHT future) {
System.err.println("chain1...");
}
};
FutureDHT fdht = peers[1].put(peers[peerNr].getPeerID()).setData(new Data("test")).setRefreshSeconds(2)
.setDirectReplication().setFutureCreate(futureCreate).start();
Timings.sleep(NINE_SECONDS);
Assert.assertEquals(repetitions, counter.get());
fdht.shutdown();
System.err.println("stop chain1");
final AtomicInteger counter2 = new AtomicInteger(0);
futureCreate = new FutureCreate<FutureDHT>() {
@Override
public void repeated(final FutureDHT future) {
System.err.println("chain2...");
counter2.incrementAndGet();
}
};
FutureDHT fdht2 = peers[2].remove(peers[peerNr].getPeerID()).setRefreshSeconds(1)
.setRepetitions(repetitions).setFutureCreate(futureCreate).setDirectReplication().start();
Timings.sleep(NINE_SECONDS);
Assert.assertEquals(repetitions, counter.get());
Assert.assertEquals(true, fdht2.isSuccess());
Assert.assertEquals(repetitions, counter2.get());
} finally {
if (master != null) {
master.halt();
}
}
}*/
/**
* Test the indirect replication where the closest peer is responsible for a location key.
*
* @throws Exception .
*/
/*@Test
public void testIndirectReplicationForward() throws Exception {
Peer master = null;
try {
// setup
Peer[] peers = Utils2.createNodes(NR_PEERS, RND2, PORT, 0, true);
master = peers[0];
Number160 locationKey = new Number160(RND2);
// closest
TreeSet<PeerAddress> tmp = new TreeSet<PeerAddress>(master.getPeerBean().getPeerMap()
.createPeerComparator(locationKey));
tmp.add(master.getPeerAddress());
for (int i = 0; i < peers.length; i++) {
tmp.add(peers[i].getPeerAddress());
}
PeerAddress closest = tmp.iterator().next();
System.err.println("closest to " + locationKey + " is " + closest);
// store
Data data = new Data("Test");
FutureDHT futureDHT = master.put(locationKey).setData(data).start();
futureDHT.awaitUninterruptibly();
futureDHT.getFutureRequests().awaitUninterruptibly();
Assert.assertEquals(true, futureDHT.isSuccess());
List<FutureBootstrap> tmp2 = new ArrayList<FutureBootstrap>();
for (int i = 0; i < peers.length; i++) {
if (peers[i] != master) {
tmp2.add(peers[i].bootstrap().setPeerAddress(master.getPeerAddress()).start());
}
}
for (FutureBootstrap fm : tmp2) {
fm.awaitUninterruptibly();
Assert.assertEquals(true, fm.isSuccess());
}
for (int i = 0; i < peers.length; i++) {
for (BaseFuture baseFuture : peers[i].getPendingFutures().keySet()) {
baseFuture.awaitUninterruptibly();
}
}
// wait for the replication
Peer peerClose = searchPeer(closest, peers);
int i = 0;
// wait for 2.5 sec
final int tests = 10;
final int wait = 2500;
while (!peerClose.getPeerBean().getStorage()
.contains(locationKey, DHTBuilder.DEFAULT_DOMAIN, Number160.ZERO)) {
Timings.sleep(wait / tests);
i++;
if (i > tests) {
break;
}
}
final FutureChannelCreator fcc = master.getConnectionBean().getConnectionReservation().reserve(1);
fcc.awaitUninterruptibly();
ChannelCreator cc = fcc.getChannelCreator();
final int peerNr = 76;
FutureResponse futureResponse = peers[peerNr].getStoreRPC().get(closest, locationKey,
DHTBuilder.DEFAULT_DOMAIN, null, null, null, false, false, false, false, cc, false);
Utils.addReleaseListenerAll(futureResponse, master.getConnectionBean().getConnectionReservation(), cc);
futureResponse.awaitUninterruptibly();
Assert.assertEquals(true, futureResponse.isSuccess());
Assert.assertEquals(1, futureResponse.getResponse().getDataMap().size());
// master.getConnectionBean().getConnectionReservation().release(cc);
} finally {
if (master != null) {
master.halt();
}
}
}*/
/**
* Test the replication with the following scenario: 2 peers online that store data, third peer joins. This means
* for indirect replication, that the content need to be stored on peer 3 as well.
*
* @throws IOException .
* @throws InterruptedException .
*/
/*@Test
public void testReplication() throws IOException, InterruptedException {
Peer p1 = null;
try {
p1 = new PeerMaker(Number160.createHash("1")).setEnableIndirectReplication(true).setPorts(PORT)
.makeAndListen();
Peer p2 = new PeerMaker(Number160.createHash("2")).setEnableIndirectReplication(true).setMasterPeer(p1)
.makeAndListen();
Peer p3 = new PeerMaker(Number160.createHash("3")).setEnableIndirectReplication(true).setMasterPeer(p1)
.makeAndListen();
LOG.info("p1 = " + p1.getPeerAddress());
LOG.info("p2 = " + p2.getPeerAddress());
LOG.info("p3 = " + p3.getPeerAddress());
p2.bootstrap().setPeerAddress(p1.getPeerAddress()).start().awaitUninterruptibly();
p2.put(Number160.createHash("key")).setData(new Data("test")).start().awaitUninterruptibly();
LOG.info("storage done");
Thread.sleep(SECOND);
LOG.info("new peer joins");
p3.bootstrap().setPeerAddress(p1.getPeerAddress()).start().awaitUninterruptibly();
Thread.sleep(SECOND);
Data test = p3.getPeerBean().getStorage()
.get(Number160.createHash("key"), DHTBuilder.DEFAULT_DOMAIN, Number160.ZERO);
Assert.assertNotNull(test);
} finally {
if (p1 != null) {
p1.halt();
}
}
}*/
/**
* Search a Peer in a list.
*
* @param peerAddress
* The peer to search for
* @param peers
* The list of peers
* @return The found peer or null if not found
*/
private static Peer searchPeer(final PeerAddress peerAddress, final Peer[] peers) {
for (Peer peer : peers) {
if (peer.getPeerAddress().equals(peerAddress)) {
return peer;
}
}
return null;
}
}