/* * 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.peers; import java.io.IOException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.NavigableSet; import java.util.Random; import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.atomic.AtomicInteger; import net.tomp2p.Utils2; import net.tomp2p.utils.Timings; import net.tomp2p.utils.Utils; import org.junit.Assert; import org.junit.Test; public class TestPeerMap { private static final Number160 ID = new Number160("0x1"); @Test public void testDifference() throws UnknownHostException { // setup Collection<PeerAddress> newC = new ArrayList<PeerAddress>(); newC.add(Utils2.createAddress(12)); newC.add(Utils2.createAddress(15)); newC.add(Utils2.createAddress(88)); newC.add(Utils2.createAddress(90)); newC.add(Utils2.createAddress(91)); SortedSet<PeerAddress> result = new TreeSet<PeerAddress>(PeerMap.createComparator(new Number160(88))); SortedSet<PeerAddress> already = new TreeSet<PeerAddress>(PeerMap.createComparator(new Number160(88))); already.add(Utils2.createAddress(90)); already.add(Utils2.createAddress(15)); // do testing Utils.difference(newC, result, already); // verification Assert.assertEquals(3, result.size()); Assert.assertEquals(Utils2.createAddress(88), result.first()); } @Test public void testAdd1() { PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(4).bagSizeOverflow(4); conf.offlineCount(1000).offlineTimeout(60); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); PeerMap peerMap = new PeerMap(conf); Number160 id1 = new Number160("0x2"); Number160 id2 = new Number160("0x3"); Number160 id3 = new Number160("0x4"); Number160 id4 = new Number160("0x5"); Number160 id5 = new Number160("0x6"); Number160 id6 = new Number160("0x7"); Number160 id11 = id1.xor(ID); Number160 id22 = id2.xor(ID); Number160 id33 = id3.xor(ID); Assert.assertEquals(2, id11.bitLength()); Assert.assertEquals(2, id22.bitLength()); Assert.assertEquals(3, id33.bitLength()); Assert.assertEquals(0, PeerMap.classMember(Number160.ZERO, ID)); Assert.assertEquals(1, PeerMap.classMember(Number160.ZERO, id1)); Assert.assertEquals(159, PeerMap.classMember(Number160.ZERO, Number160.MAX_VALUE)); // PeerAddress pa1 = new PeerAddress(id1); PeerAddress pa2 = new PeerAddress(id2); PeerAddress pa3 = new PeerAddress(id3); PeerAddress pa4 = new PeerAddress(id4); PeerAddress pa5 = new PeerAddress(id5); PeerAddress pa6 = new PeerAddress(id6); peerMap.peerFound(pa1, null); peerMap.peerFound(pa2, null); peerMap.peerFound(pa3, null); peerMap.peerFound(pa4, null); peerMap.peerFound(pa5, null); peerMap.peerFound(pa6, null); SortedSet<PeerAddress> pa = peerMap.closePeers(ID, 2); Assert.assertEquals(2, pa.size()); Iterator<PeerAddress> iterator = pa.iterator(); Assert.assertEquals("0x3", iterator.next().getPeerId().toString()); Assert.assertEquals("0x2", iterator.next().getPeerId().toString()); pa = peerMap.closePeers(id3, 3); Assert.assertEquals(4, pa.size()); iterator = pa.iterator(); Assert.assertEquals("0x4", iterator.next().getPeerId().toString()); Assert.assertEquals("0x5", iterator.next().getPeerId().toString()); Assert.assertEquals("0x6", iterator.next().getPeerId().toString()); Assert.assertEquals("0x7", iterator.next().getPeerId().toString()); } @Test public void testAdd2() { PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(3).bagSizeOverflow(3); conf.offlineCount(1000).offlineTimeout(60); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); PeerMap peerMap = new PeerMap(conf); Number160 id1 = new Number160("0x2"); Number160 id2 = new Number160("0x3"); Number160 id3 = new Number160("0x4"); Number160 id4 = new Number160("0x5"); Number160 id5 = new Number160("0x6"); Number160 id6 = new Number160("0x7"); // PeerAddress pa1 = new PeerAddress(id1); PeerAddress pa2 = new PeerAddress(id2); PeerAddress pa3 = new PeerAddress(id3); PeerAddress pa4 = new PeerAddress(id4); PeerAddress pa5 = new PeerAddress(id5); PeerAddress pa6 = new PeerAddress(id6); peerMap.peerFound(pa1, null); peerMap.peerFound(pa2, null); peerMap.peerFound(pa3, null); peerMap.peerFound(pa4, null); peerMap.peerFound(pa5, null); peerMap.peerFound(pa6, null); SortedSet<PeerAddress> pa = peerMap.closePeers(ID, 2); Assert.assertEquals(2, pa.size()); Iterator<PeerAddress> iterator = pa.iterator(); Assert.assertEquals("0x3", iterator.next().getPeerId().toString()); Assert.assertEquals("0x2", iterator.next().getPeerId().toString()); pa = peerMap.closePeers(id3, 3); Assert.assertEquals(3, pa.size()); iterator = pa.iterator(); Assert.assertEquals("0x4", iterator.next().getPeerId().toString()); Assert.assertEquals("0x5", iterator.next().getPeerId().toString()); Assert.assertEquals("0x6", iterator.next().getPeerId().toString()); // 0x7 is in the non-verified / overflow map List<PeerAddress> list = peerMap.getAllOverflow(); Assert.assertEquals("0x7", list.iterator().next().getPeerId().toString()); } @Test public void testLength() { Number160 bi1 = new Number160("0x127"); Number160 bi2 = new Number160("0x128"); Number160 bi3 = new Number160("0x255"); Number160 rr = PeerMap.distance(bi1, bi2); Assert.assertFalse(bi3.equals(rr)); bi1 = new Number160("0x7f"); bi2 = new Number160("0x80"); bi3 = new Number160("0xff"); rr = PeerMap.distance(bi1, bi2); Assert.assertTrue(bi3.equals(rr)); Assert.assertEquals(7, PeerMap.classMember(bi1, bi2)); Assert.assertEquals(6, PeerMap.classMember(bi2, bi3)); } @Test public void testCloser() throws UnknownHostException { PeerAddress rn1 = new PeerAddress(new Number160("0x7f")); PeerAddress rn2 = new PeerAddress(new Number160("0x40")); Number160 key = new Number160("0xff"); Assert.assertEquals(-1, PeerMap.isCloser(key, rn1, rn2)); // rn1 = new PeerAddress(new Number160("0x10")); rn2 = new PeerAddress(new Number160("0x11")); key = new Number160("0xff"); System.err.println("0x7f xor 0xff " + rn1.getPeerId().xor(key)); System.err.println("0x40 xor 0xff " + rn2.getPeerId().xor(key)); Assert.assertEquals(1, PeerMap.isCloser(key, rn1, rn2)); } @Test public void testCloser2() throws UnknownHostException { PeerAddress rn1 = new PeerAddress(new Number160(98)); PeerAddress rn2 = new PeerAddress(new Number160(66)); PeerAddress rn3 = new PeerAddress(new Number160(67)); PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(3).bagSizeOverflow(3); conf.offlineCount(1000).offlineTimeout(60); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); PeerMap peerMap = new PeerMap(conf); SortedSet<PeerAddress> rc = peerMap.closePeers(new Number160(98), 3); rc.add(rn2); rc.add(rn1); rc.add(rn3); Assert.assertTrue(rc.first().equals(rn1)); } @Test public void testAddNode() throws UnknownHostException { PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(4).bagSizeOverflow(4); conf.offlineCount(1000).offlineTimeout(60); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); PeerMap peerMap = new PeerMap(conf); for (int i = 1; i < 12; i++) { PeerAddress r1 = new PeerAddress(new Number160(i)); peerMap.peerFound(r1, null); } SortedSet<PeerAddress> close = peerMap.closePeers(new Number160(2), 2); Assert.assertEquals(2, close.size()); close = peerMap.closePeers(new Number160(6), 4); Assert.assertEquals(4, close.size()); } @Test public void testAddNode2() throws UnknownHostException { PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(3).bagSizeOverflow(3); conf.offlineCount(1000).offlineTimeout(60); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); PeerMap peerMap = new PeerMap(conf); for (int i = 1; i < 12; i++) { PeerAddress r1 = new PeerAddress(new Number160((i % 6) + 1)); peerMap.peerFound(r1, null); } SortedSet<PeerAddress> close = peerMap.closePeers(new Number160(2), 2); Assert.assertEquals(2, close.size()); close = peerMap.closePeers(new Number160(6), 1); Assert.assertEquals(3, close.size()); } @Test public void testRemove() throws UnknownHostException, InterruptedException { PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(3).bagSizeOverflow(3); conf.offlineCount(1000).offlineTimeout(1); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); PeerMap peerMap = new PeerMap(conf); for (int i = 1; i <= 200; i++) { PeerAddress r1 = new PeerAddress(new Number160(i + 1)); peerMap.peerFound(r1, null); } Assert.assertEquals(20, peerMap.size()); peerMap.peerFailed(new PeerAddress(new Number160(100)), true); Assert.assertTrue(peerMap.isPeerRemovedTemporarly(new PeerAddress(new Number160(100)))); Assert.assertEquals(20, peerMap.size()); peerMap.peerFailed(new PeerAddress(new Number160(2)), true); Assert.assertEquals(19, peerMap.size()); Assert.assertTrue(peerMap.isPeerRemovedTemporarly(new PeerAddress(new Number160(2)))); Timings.sleep(1000); Assert.assertFalse(peerMap.isPeerRemovedTemporarly(new PeerAddress(new Number160(2)))); Assert.assertFalse(peerMap.isPeerRemovedTemporarly(new PeerAddress(new Number160(100)))); } @Test public void testRemoveConcurrent() throws UnknownHostException, InterruptedException { PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(3).bagSizeOverflow(3); conf.offlineCount(1000).offlineTimeout(1); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); final PeerMap peerMap = new PeerMap(conf); for (int i = 1; i <= 200; i++) { PeerAddress r1 = new PeerAddress(new Number160(i + 1)); peerMap.peerFound(r1, null); } Assert.assertEquals(20, peerMap.size()); Thread t1 = new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 50; i++) { peerMap.peerFailed(new PeerAddress(new Number160(i + 1)), true); } } }); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 100; i++) { peerMap.peerFailed(new PeerAddress(new Number160(i + 1)), true); } } }); t2.start(); t1.join(); t2.join(); Assert.assertTrue(peerMap.isPeerRemovedTemporarly(new PeerAddress(new Number160(100)))); Assert.assertEquals(3, peerMap.size()); } @Test public void testAddConcurrent() throws UnknownHostException, InterruptedException { PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(3).bagSizeOverflow(3); conf.offlineCount(1000).offlineTimeout(1); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); final PeerMap peerMap = new PeerMap(conf); Thread t1 = new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 50; i++) { peerMap.peerFound(new PeerAddress(new Number160(i + 1)), null); } } }); t1.start(); Thread t2 = new Thread(new Runnable() { @Override public void run() { for (int i = 1; i <= 100; i++) { peerMap.peerFound(new PeerAddress(new Number160(i + 1)), null); } } }); t2.start(); t1.join(); t2.join(); Assert.assertEquals(17, peerMap.size()); } /** * Repeating test of testRandomAddRemove() to test for concurrency issues. * * @throws InterruptedException . */ @Test public void testMultiRandomAddRemove() throws InterruptedException { final int rounds = 100; for (int i = 0; i < rounds; i++) { testRandomAddRemove(); } } /** * Tests the peermap and concurrent adds and puts. There will be two times 5000 inserts and 4989 removes. That means * the resulting peer count needs to be 11. * * @throws InterruptedException . */ @Test public void testRandomAddRemove() throws InterruptedException { for (int j = 0; j < 50; j++) { PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(j + 1).bagSizeOverflow(j + 1); conf.offlineCount(1000).offlineTimeout(1); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); final PeerMap peerMap = new PeerMap(conf); final AtomicInteger add = new AtomicInteger(); final AtomicInteger del = new AtomicInteger(); final int rounds = 500; final int diff = 10; Runnable runnable = new Runnable() { @Override public void run() { for (int i = 1; i <= rounds + diff; i++) { if (i + diff < rounds) { boolean retVal = peerMap.peerFound(new PeerAddress(new Number160(i + 1)), null); if (retVal) { add.incrementAndGet(); } } if (i - diff > 1) { boolean retVal = peerMap.peerFailed(new PeerAddress(new Number160(i - diff)), true); if (retVal) { del.incrementAndGet(); } } } } }; Thread t1 = new Thread(runnable); Thread t2 = new Thread(runnable); t1.start(); t2.start(); t1.join(); t2.join(); System.err.println("inserted: " + add.get() + ", removed: " + del.get()); Assert.assertEquals(0, peerMap.size()); } } @Test public void testPerformance() throws IOException { PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(3).bagSizeOverflow(3); conf.offlineCount(1000).offlineTimeout(100); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); final PeerMap peerMap = new PeerMap(conf); final Random random = new Random(42L); final List<PeerAddress> listAdded = new ArrayList<PeerAddress>(); final List<PeerAddress> listRemoved = new ArrayList<PeerAddress>(); long start = System.currentTimeMillis(); int size = 500000; for (int i = 1; i <= size; i++) { PeerAddress r1 = new PeerAddress(new Number160(random)); listAdded.add(r1); } for (PeerAddress r1 : listAdded) { peerMap.peerFound(r1, null); } for (PeerAddress r1 : listAdded) { peerMap.peerFound(r1, null); } for (int i = 0; i < 100; i++) { PeerAddress removed = listAdded.get(random.nextInt(i + 1)); if (peerMap.peerFailed(removed, true)) { listRemoved.add(removed); } } for (PeerAddress r1 : listAdded) { peerMap.peerFound(r1, r1); } Assert.assertEquals(47, peerMap.size()); for (PeerAddress r1 : listRemoved) { Assert.assertTrue(peerMap.isPeerRemovedTemporarly(r1)); } // for (PeerAddress r1 : listRemoved) { listAdded.remove(r1); } for (int i = 0; i < 300; i++) { PeerAddress removed = listAdded.get(random.nextInt(i + 1)); peerMap.peerFailed(removed, true); } for (PeerAddress r1 : listRemoved) { Assert.assertTrue(peerMap.isPeerRemovedTemporarly(r1)); } System.err.println("Time used: " + (System.currentTimeMillis() - start) + " ms. (time to beat ~5100ms, now ~1800ms)"); } @Test public void testOrder() { Number160 b1 = new Number160("0x5"); Number160 b2 = new Number160("0x32"); Number160 b3 = new Number160("0x1F4"); Number160 b4 = new Number160("0x1388"); PeerAddress n1 = new PeerAddress(b1); PeerAddress n2 = new PeerAddress(b2); PeerAddress n3 = new PeerAddress(b3); PeerAddress n4 = new PeerAddress(b4); PeerMapConfiguration pm = new PeerMapConfiguration(b1); PeerMap routingMap = new PeerMap(pm); final NavigableSet<PeerAddress> queue = new TreeSet<PeerAddress>(routingMap.createComparator(b3)); queue.add(n1); queue.add(n2); queue.add(n3); queue.add(n4); Assert.assertEquals(queue.pollFirst(), n3); Assert.assertEquals(queue.pollFirst(), n2); Assert.assertEquals(queue.pollLast(), n4); } @Test public void testMaintenance() throws UnknownHostException, InterruptedException { PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(10).bagSizeOverflow(10); conf.offlineCount(1000).offlineTimeout(100); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); conf.maintenance(new DefaultMaintenance(4, new int[] { 1, 1 })); final PeerMap peerMap = new PeerMap(conf); PeerAddress pa1 = Utils2.createAddress(Number160.createHash("peer 1")); PeerAddress pa2 = Utils2.createAddress(Number160.createHash("peer 2")); peerMap.peerFound(pa2, pa1); List<PeerAddress> notInterested = new ArrayList<PeerAddress>(); PeerStatatistic peerStatatistic = peerMap.nextForMaintenance(notInterested); notInterested.add(peerStatatistic.getPeerAddress()); Assert.assertEquals(peerStatatistic.getPeerAddress(), pa2); peerStatatistic = peerMap.nextForMaintenance(notInterested); Assert.assertEquals(true, peerStatatistic == null); PeerAddress pa3 = Utils2.createAddress(Number160.createHash("peer 3")); peerMap.peerFound(pa3, null); peerStatatistic = peerMap.nextForMaintenance(notInterested); Assert.assertEquals(true, peerStatatistic == null); Thread.sleep(1000); peerStatatistic = peerMap.nextForMaintenance(notInterested); Assert.assertEquals(peerStatatistic.getPeerAddress(), pa3); } @Test public void testClose() throws UnknownHostException { for (int i = 1; i < 30; i++) { testClose(i); } } private void testClose(int round) throws UnknownHostException { Random rnd = new Random(round); for (int j = 0; j < 1000; j++) { Number160 key = new Number160(rnd); PeerMapConfiguration conf = new PeerMapConfiguration(ID); conf.bagSizeVerified(10).bagSizeOverflow(10); conf.offlineCount(1000).offlineTimeout(100); conf.peerFilter(new DefaultPeerFilter()).maintenance(new DefaultMaintenance(0, new int[] {})); final PeerMap peerMap = new PeerMap(conf); List<PeerAddress> peers = new ArrayList<PeerAddress>(); for (int i = 0; i < round; i++) { PeerAddress r1 = new PeerAddress(new Number160(rnd)); peers.add(r1); peerMap.peerFound(r1, null); } TreeSet<PeerAddress> set = new TreeSet<PeerAddress>(PeerMap.createComparator(key)); set.addAll(peers); PeerAddress closest1 = set.iterator().next(); PeerAddress closest2 = peerMap.closePeers(key, 1).iterator().next(); if (peerMap.getAllOverflow().size() == 0) { Assert.assertEquals(closest1, closest2); } } } }