/* * Copyright 2007-2010 Sun Microsystems, Inc. * * This file is part of Project Darkstar Server. * * Project Darkstar Server is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation and * distributed hereunder to you. * * Project Darkstar Server 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, see <http://www.gnu.org/licenses/>. * * -- */ package com.sun.sgs.impl.service.nodemap.affinity; import com.sun.sgs.auth.Identity; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; /** * Stub, to be replaced by Keith's version (used for testing until we merge). * <p> * An affinity group which can relocate its member identities to other nodes. * Key ideas swiped from Keith's branch to help us with merging. * <p> * These affinity groups can span multiple nodes and will eventually * relocate their members to a single node. There probably needs to be * some external control of the relocation in case we merge affinity groups * or find that an algorithm run returns a single group. */ public class RelocatingAffinityGroup implements AffinityGroup, Comparable { // The group id private final long agid; // Map Identity -> nodeId private final Map<Identity, Long> identities; // The node id that most Identities seem to be on private final long targetNodeId; // Generation number private final long generation; // hashcode, lazily computed private volatile int hashcode; /** * Creates a new affinity group containing node information. * @param agid the group id * @param identities the identities and their nodes in the group * @param generation the generation number of this group * @throws IllegalArgumentException if {@code identities} is empty */ public RelocatingAffinityGroup(long agid, Map<Identity, Long> identities, long generation) { if (identities.size() == 0) { throw new IllegalArgumentException("Identities must not be empty"); } this.agid = agid; this.identities = identities; this.generation = generation; targetNodeId = calcMostUsedNode(); } /** * Calculate the node that the most number of identities is on. * @return the node id of the most used node */ private long calcMostUsedNode() { Map<Long, Integer> nodeCountMap = new HashMap<Long, Integer>(); for (Long nodeId : identities.values()) { if (nodeId == -1) { // Node id was unknown, so don't count it continue; } Integer count = nodeCountMap.get(nodeId); int val = (count == null) ? 0 : count.intValue(); val++; nodeCountMap.put(nodeId, Integer.valueOf(val)); } long retNode = -1; int highestCount = -1; for (Entry<Long, Integer> entry : nodeCountMap.entrySet()) { int count = entry.getValue(); if (highestCount < count) { highestCount = count; retNode = entry.getKey(); } } return retNode; } /** * {@inheritDoc} * <p> * Sorts based on the number of identities in the groups. */ @Override public int compareTo(Object obj) { if (obj == null) { throw new NullPointerException(); } if (this.equals(obj)) { return 0; } int mySize = identities.size(); int otherSize = ((RelocatingAffinityGroup) obj).identities.size(); if (mySize == otherSize) { return 0; } else if (mySize < otherSize) { return -1; } else { return 1; } } /** {@inheritDoc} */ @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof RelocatingAffinityGroup)) { return false; } RelocatingAffinityGroup other = (RelocatingAffinityGroup) obj; return (agid == other.agid) && (generation == other.generation) && (identities.equals(other.identities)); } /** {@inheritDoc} */ @Override public int hashCode() { if (hashcode == 0) { int result = 17; result = result * 37 + (int) (agid ^ agid >>> 32); result = result * 37 + (int) (generation ^ generation >>> 32); result = result * 37 + identities.hashCode(); hashcode = result; } return hashcode; } /** {@inheritDoc} */ @Override public String toString() { return "AffinityGroup: " + agid + " targetNodeId: " + targetNodeId + " #identities: " + identities.size(); } /** {@inheritDoc} */ public long getId() { return agid; } /** {@inheritDoc} */ public Set<Identity> getIdentities() { return Collections.unmodifiableSet(identities.keySet()); } /** {@inheritDoc} */ public long getGeneration() { return generation; } }