Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package com.cloudhopper.commons.util;
/*
* #%L
* ch-commons-util
* %%
* Copyright (C) 2012 Cloudhopper by Twitter
* %%
* 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.
* #L%
*/
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implementation of a load balanced list that returns items using a weighted,
* round-robin algorithm. If "A" is added with weight 2 and "B" is added with
* weight 1, then getNext() will return the items in this order:
*
* A, B, A, A, B, A, A, B, A, ....
*
* NOTE: This class does not synchronize access. Any concurrent access to this
* object MUST be externally synchronized.
*
* NOTE: This class only works for small lists. You need to assume every
* call to get the next selection is O(n).
*
* @author joelauer (twitter: @jjlauer or http://twitter.com/jjlauer)
*/
public class RoundRobinLoadBalancedList implements LoadBalancedList {
private static final Logger logger = LoggerFactory.getLogger(RoundRobinLoadBalancedList.class);
private final ArrayList> allItems;
private final ArrayList> remainingItems;
private int currentIndex;
public RoundRobinLoadBalancedList() {
this.allItems = new ArrayList>();
this.remainingItems = new ArrayList>();
this.currentIndex = 0; // index of remaining item to return
}
@Override
public List> getValues() {
return this.allItems;
}
@Override
public void clear() {
// remove all items from allitems
allItems.clear();
remainingItems.clear();
this.currentIndex = 0;
}
@Override
public boolean contains(E item) {
Node newNode = new Node(item);
return this.allItems.contains(newNode);
}
@Override
public void set(E item, int weight) {
// if weight of zero, acts just like removing
if (weight <= 0) {
remove(item);
return;
}
// create a new node we'll use for searching and/or adding
Node newNode = new Node(item, weight);
// try to find item in list 0(N)
int i = allItems.indexOf(newNode);
// this is a new item -- add it
if (i < 0) {
// add to all of our items
this.allItems.add(newNode);
// add to remainingItems as well
this.remainingItems.add(newNode);
// this is a current item -- update weight
} else {
// this is just an update of the weight (to something non-zero) - get the current node
Node currentNode = allItems.get(i);
// update it's weight to its new value
currentNode.setWeight(weight);
// if the new weight >= count, remove it from remaining items
if (currentNode.getCount() >= currentNode.getWeight()) {
// remove this node from remaining items if it already exists...
// MUST reset count back to zero (otherwise we'll never add it back in)
currentNode.setCount(0);
// remove from remaining items
this.remainingItems.remove(currentNode);
// bug fix: if the node just removed was the only node in our
// *remaining* items list, then we have a problem. we need to
// check if we should rebuild our remaining items array
if (this.remainingItems.isEmpty() && this.allItems.size() > 0) {
this.rebuildRemainingItems();
}
}
}
}
@Override
public void remove(E item) {
// create a new node we'll use for searching and/or adding
Node newNode = new Node(item);
// try to find item in list 0(N)
int i = allItems.indexOf(newNode);
if (i < 0) {
// item not in our list, don't do anything
//logger.debug("Item is not in list");
} else {
// remove from all items and possible items
this.allItems.remove(i);
this.remainingItems.remove(newNode);
}
// safety check -- if there are no more remaining items, but we still
// have items in our list, rebuild our "remaining items"
if (this.remainingItems.isEmpty() && this.allItems.size() > 0) {
this.rebuildRemainingItems();
}
}
protected void rebuildRemainingItems() {
// clear any previous items
this.remainingItems.clear();
// loop thru all items
for (Node node : allItems) {
// if the nodes weight is greater than count add it
if (node.getWeight() > node.getCount()) {
this.remainingItems.add(node);
}
}
}
protected void resetCountsAndRebuildRemainingItems() {
// reset all counts back to zero
for (Node node : allItems) {
node.setCount(0);
}
// now rebuild the whole thing
this.rebuildRemainingItems();
}
@Override
public int getSize() {
return this.allItems.size();
}
public int getRemainingSize() {
return this.remainingItems.size();
}
@Override
public E getNext() {
// hmm... actually, this is a good safety check to do now -- if allitems
// is zero, then there is no way we could have a next item
if (allItems.isEmpty()) {
return null;
}
// if there are items in "allItems", but remainingItems is still zero
// then this means some sort of bug occurred since this should be impossible
if (remainingItems.isEmpty()) {
logger.error("Impossible bug occurred with RoundRobinLoadBalancedList where allItems > 0, but remainingItems == 0, going to completely internally rebuild everything");
resetCountsAndRebuildRemainingItems();
}
// saftey check -- see if we need to reset the index back to zero
if (this.currentIndex >= remainingItems.size()) {
// reset back to zero
this.currentIndex = 0;
}
// get the item at this index
Node node = this.remainingItems.get(this.currentIndex);
// increment count
node.incrementCount();
// is the max count reached?
if (node.getCount() >= node.getWeight()) {
// reset count back to zero
node.setCount(0);
//logger.debug("Removing node " + node.getValue());
// remove this node from possible items
this.remainingItems.remove(this.currentIndex);
// don't increment index since the current index actually would
// be the next item we want to return
} else {
// keep the current node and increment the index
// always increment currentIndex first
this.currentIndex++;
}
// if there aren't any more remaining items, rebuid it
if (remainingItems.isEmpty()) {
// rebuild a new remainingItems array
rebuildRemainingItems();
}
// see if we need to reset the index back to zero for next getNext call
if (this.currentIndex >= remainingItems.size()) {
// reset back to zero
this.currentIndex = 0;
}
return node.getValue();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(200);
buf.append("curIdx=");
buf.append(this.currentIndex);
buf.append(" [");
int i = 0;
for (Node node : remainingItems) {
if (i != 0) buf.append(", ");
buf.append(node);
i++;
}
buf.append("]");
return buf.toString();
}
}