
com.nesscomputing.service.discovery.client.internal.ConsistentRingGroup Maven / Gradle / Ivy
/**
* Copyright (C) 2012 Ness Computing, Inc.
*
* 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 com.nesscomputing.service.discovery.client.internal;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import org.apache.commons.lang3.StringUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.nesscomputing.service.discovery.client.ServiceInformation;
/** A group of servers, partitioned into rings by their service type, which provide a particular service.
*
* @author christopher
*
*/
public class ConsistentRingGroup extends AbstractCollection {
private final Map rings = Maps.newHashMap();
private final Random rand = new Random();
private final int totalServers;
public ConsistentRingGroup(Collection servers) {
totalServers = servers.size();
Map> serverGroups = Maps.newHashMap();
String serviceName = null;
//Sort the servers by type
for (ServiceInformation info: servers) {
Preconditions.checkArgument(serviceName == null || StringUtils.equals(serviceName, info.getServiceName()),
"All services must have the same name: " + servers);
serviceName = info.getServiceName();
//Hashmaps allow null keys, so null service types should map correctly.
if (!serverGroups.containsKey(info.getServiceType())) {
serverGroups.put(info.getServiceType(), new ArrayList());
}
serverGroups.get(info.getServiceType()).add(info);
}
for (Map.Entry> entry: serverGroups.entrySet()) {
rings.put(entry.getKey(), new ConsistentHashRing(entry.getValue()));
}
}
/** Get the server ring for a particular type.
*
* Notes on running time:
* if type != null: O(1)
* if type == null and there is at least 1 service with null type: O(1)
* otherwise: O(N) where N is the number of types
*
* @param type
* @return
*/
public ConsistentHashRing getRing(String type) {
ConsistentHashRing ring = rings.get(type);
if (ring != null) {
return ring;
}
if (type == null) {
//If there's no ring without a type, then any type will do
//Use weighted random among the types, based on how many servers are serving each type
int selection = rand.nextInt() % totalServers;
for (ConsistentHashRing candidateRing: rings.values()) {
if (selection <= 0) {
return candidateRing;
} else {
selection -= candidateRing.size();
}
}
//It's possible there are no rings
Preconditions.checkState(totalServers == 0, "It shouldn't be possible to get here, " +
"unless there are no rings");
return null;
} else {
//If there's no server for this type, then pick one without a type
return rings.get(null);
}
}
public List getAll() {
List result = Lists.newArrayList();
for (Collection info: this) {
result.addAll(info);
}
return result;
}
@Override
public Iterator iterator() {
return rings.values().iterator();
}
@Override
public int size() {
return rings.size();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy