/* * Mojito Distributed Hash Table (Mojito DHT) * Copyright (C) 2006-2007 LimeWire LLC * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ package org.limewire.mojito.routing; import java.io.Serializable; import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.limewire.collection.IntHashMap; import org.limewire.mojito.settings.RouteTableSettings; import org.limewire.mojito.util.ContactUtils; /** * Keeps track of the number of Contacts * that have the same Class C Network address in a Bucket. */ public class ClassfulNetworkCounter implements Serializable { private static final long serialVersionUID = -6603762323364585225L; private static final Log LOG = LogFactory.getLog(ClassfulNetworkCounter.class); private final IntHashMap<AtomicInteger> nodesPerNetwork = new IntHashMap<AtomicInteger>(); private final Bucket bucket; public ClassfulNetworkCounter(Bucket bucket) { this.bucket = bucket; } /** * Returns the Bucket of this ClassfulNetworkCounter. */ public Bucket getBucket() { return bucket; } /** * Returns the current number of Contacts that * are from the same Class C Network. */ public synchronized int get(Contact node) { if (bucket.isLocalNode(node)) { return 0; } if (!ContactUtils.isIPv4Address(node)) { if (LOG.isInfoEnabled()) { LOG.info(node + " has not an IPv4 Address"); } return 0; } int masked = ContactUtils.getClassC(node); AtomicInteger counter = nodesPerNetwork.get(masked); if (counter != null) { return counter.get(); } return 0; } /** * Increments and returns the current number of Contacts * that are from the same Class C Network as the given * Contact. */ public synchronized int incrementAndGet(Contact node) { if (bucket.isLocalNode(node)) { return 0; } if (!ContactUtils.isIPv4Address(node)) { if (LOG.isInfoEnabled()) { LOG.info(node + " has not an IPv4 Address"); } return 0; } int masked = ContactUtils.getClassC(node); AtomicInteger counter = nodesPerNetwork.get(masked); if (counter == null) { assert (nodesPerNetwork.size() < bucket.getMaxActiveSize()) : nodesPerNetwork.size() + " < " + bucket.getMaxActiveSize() + node + ", " + nodesPerNetwork + ", " + bucket; counter = new AtomicInteger(0); nodesPerNetwork.put(masked, counter); } return counter.incrementAndGet(); } /** * Decrements and returns the current number of Contacts * that are from the same Class C Network as the given * Contact. */ public synchronized int decrementAndGet(Contact node) { if (bucket.isLocalNode(node)) { return 0; } if (!ContactUtils.isIPv4Address(node)) { if (LOG.isInfoEnabled()) { LOG.info(node + " has not an IPv4 Address"); } return 0; } int masked = ContactUtils.getClassC(node); AtomicInteger counter = nodesPerNetwork.get(masked); if (counter != null) { int count = counter.decrementAndGet(); if (count <= 0) { nodesPerNetwork.remove(masked); assert (!nodesPerNetwork.containsKey(masked)); } return count; } return 0; } /** * Returns the number of Elements. */ public synchronized int size() { return nodesPerNetwork.size(); } /** * Clears the ClassfulNetworkCounter. */ public synchronized void clear() { nodesPerNetwork.clear(); } /** * Returns true if it's Okay to add the given Contact to the Bucket. * * @see RouteTableSettings#MAX_CONTACTS_PER_NETWORK_CLASS_RATIO */ public synchronized boolean isOkayToAdd(Contact node) { // We rely on the fact that get() returns 0 for // the local Node and for non IPv4 Contacts! float count = get(node); if (count == 0.0f) { return true; } assert (!bucket.isLocalNode(node)); assert (ContactUtils.isIPv4Address(node)); // If it's 1.0f then allow float maxRatio = RouteTableSettings.MAX_CONTACTS_PER_NETWORK_CLASS_RATIO.getValue(); if (maxRatio >= 1.0f) { return true; } float k = bucket.getMaxActiveSize(); float ratio = count/k; return (ratio < maxRatio); } @Override public synchronized String toString() { return nodesPerNetwork.toString();// + ", " + bucket; } }