package ibis.ipl.registry.central;
import ibis.ipl.impl.IbisIdentifier;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import java.util.Random;
import java.util.SortedSet;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class TreeMemberSet implements MemberSet, Serializable {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(TreeMemberSet.class);
private class Node implements Serializable, Comparable<Node> {
private static final long serialVersionUID = 1L;
Node[] children;
Member member;
int index;
Node() {
index = getNextIndex();
children = new Node[0];
member = null;
}
public String toString() {
return "node " + index + " member = " + member + " with "
+ children.length + " children";
}
public int compareTo(Node o) {
return index - o.index;
}
}
// root node
private ArrayList<Node> root;
// all nodes, as an array
private ArrayList<Node> list;
// list of not currently used nodes
private SortedSet<Node> spares;
private int nextNodeIndex;
private final Random random;
private Node lastSearchResult;
public TreeMemberSet() {
nextNodeIndex = 0;
root = new ArrayList<Node>();
list = new ArrayList<Node>();
spares = new TreeSet<Node>();
random = new Random();
}
@SuppressWarnings("unchecked")
public void init(DataInputStream in) throws IOException {
long start = System.currentTimeMillis();
logger.debug("initializing tree member set");
int size = in.readInt();
logger.debug("reading " + size + " bytes");
byte[] data = new byte[size];
in.readFully(data);
long read = System.currentTimeMillis();
ObjectInputStream objectInput =
new ObjectInputStream(new ByteArrayInputStream(data));
long stream = System.currentTimeMillis();
try {
root = (ArrayList<Node>) objectInput.readObject();
list = (ArrayList<Node>) objectInput.readObject();
spares = (SortedSet<Node>) objectInput.readObject();
nextNodeIndex = objectInput.readInt();
} catch (ClassNotFoundException e) {
throw new IOException("could not deserialize data for tree");
}
objectInput.close();
long done = System.currentTimeMillis();
logger.info("TreeMemberSet.init(): read = " + (read - start)
+ ", stream = " + (stream - read) + ", done = "
+ (done - stream));
if (logger.isDebugEnabled()) {
logger.debug("initialized tree member set, content:" + toString());
}
}
public void writeTo(DataOutputStream out) throws IOException {
logger.debug("writing tree member set to stream");
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutput = new ObjectOutputStream(byteStream);
objectOutput.writeObject(root);
objectOutput.writeObject(list);
objectOutput.writeObject(spares);
objectOutput.writeInt(nextNodeIndex);
objectOutput.flush();
objectOutput.close();
logger.debug("writing " + byteStream.size() + " bytes");
byte[] bytes = byteStream.toByteArray();
out.writeInt(bytes.length);
out.write(bytes);
}
private Node createTree(int order, SortedSet<Node> spares) {
logger.debug("creating tree of order " + order);
Node result = new Node();
spares.add(result);
result.children = new Node[order];
for (int i = 0; i < order; i++) {
result.children[i] = createTree(i, spares);
}
return result;
}
private int getNextIndex() {
return nextNodeIndex++;
}
private void expandTree() {
int order = root.size();
logger.debug("expanding tree with order " + order + " subtree");
Node newTree = createTree(order, spares);
root.add(newTree);
}
public void add(Member member) {
logger.debug("adding " + member + " to tree");
if (spares.isEmpty()) {
expandTree();
}
Node node = spares.first();
spares.remove(node);
node.member = member;
list.add(node);
if (logger.isDebugEnabled()) {
logger.debug("" + this);
}
}
public Member remove(IbisIdentifier identifier) {
logger.debug("removing " + identifier + " from tree");
for (int i = 0; i < list.size(); i++) {
Node node = list.get(i);
if (node.member.getIbis().equals(identifier)) {
Member result = node.member;
node.member = null;
list.remove(i);
spares.add(node);
if (logger.isDebugEnabled()) {
logger.debug("removed " + result + " from tree, result "
+ this);
}
return result;
}
}
logger.debug("could not remove " + identifier + ", not found in tree");
return null;
}
public Member[] asArray() {
Member[] result = new Member[list.size()];
for (int i = 0; i < result.length; i++) {
result[i] = list.get(i).member;
}
return result;
}
public boolean contains(IbisIdentifier identifier) {
for (Node node : list) {
if (node.member.getIbis().equals(identifier)) {
return true;
}
}
return false;
}
public boolean contains(Member member) {
for (Node node : list) {
if (node.member.getIbis().equals(member.getIbis())) {
return true;
}
}
return false;
}
public Member get(IbisIdentifier identifier) {
for (Node node : list) {
if (node.member.getIbis().equals(identifier)) {
return node.member;
}
}
return null;
}
public Member get(String name) {
for (Node node : list) {
if (node.member.getIbis().name().equals(name)) {
return node.member;
}
}
return null;
}
private Node getNode(IbisIdentifier identifier) {
for (Node node : list) {
if (node.member.getIbis().equals(identifier)) {
return node;
}
}
return null;
}
public Member get(int index) {
return list.get(index).member;
}
public List<Event> getJoinEvents() {
List<Event> result = new ArrayList<Event>();
for (Node node : list) {
result.add(node.member.getEvent());
}
return result;
}
public Member getLeastRecentlySeen() {
if (list.isEmpty()) {
return null;
}
Member oldest = list.get(0).member;
for (int i = 1; i < list.size(); i++) {
if (list.get(i).member.getTime() < oldest.getTime()) {
oldest = list.get(i).member;
}
}
return oldest;
}
public int getMinimumTime() {
if (list.isEmpty()) {
return -1;
}
int minimum = list.get(0).member.getCurrentTime();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).member.getCurrentTime() < minimum) {
minimum = list.get(i).member.getCurrentTime();
}
}
return minimum;
}
public Member getRandom() {
if (list.isEmpty()) {
return null;
}
return list.get(random.nextInt(size())).member;
}
public Member[] getRandom(int size) {
ArrayList<Member> result = new ArrayList<Member>();
BitSet added = new BitSet();
if (size > list.size()) {
for (Node node : list) {
result.add(node.member);
}
return result.toArray(new Member[0]);
}
while (result.size() < size) {
int next = random.nextInt(list.size());
if (!added.get(next)) {
// not added yet
result.add(list.get(next).member);
// remember we already added this member.
added.set(next);
}
}
return result.toArray(new Member[0]);
}
public int size() {
return list.size();
}
// add the member of this node to the list. If this node has
// no member, add it's children instead(recursive).
private void addMembers(Node node, List<Member> result) {
if (node == null) {
return;
}
if (node.member != null) {
result.add(node.member);
return;
}
// this node does not have a member, add all children
// in reverse order
for (int i = node.children.length - 1; i >= 0; i--) {
addMembers(node.children[i], result);
}
}
public Member[] getChildren(IbisIdentifier ibis) {
logger.debug("getting children of " + ibis);
if (lastSearchResult == null || lastSearchResult.member == null
|| !lastSearchResult.member.getIbis().equals(ibis)) {
lastSearchResult = getNode(ibis);
if (lastSearchResult == null) {
return new Member[0];
}
}
ArrayList<Member> result = new ArrayList<Member>();
// add all children (in reverse order)
for (int i = lastSearchResult.children.length - 1; i >= 0; i--) {
addMembers(lastSearchResult.children[i], result);
}
if (logger.isDebugEnabled()) {
String message = "children of " + ibis + ":\n";
for (Member member : result) {
message += member + "\n";
}
logger.debug(message);
}
return result.toArray(new Member[0]);
}
public Member[] getRootChildren() {
ArrayList<Member> result = new ArrayList<Member>();
// add all children (in reverse order)
for (int i = root.size() - 1; i >= 0; i--) {
addMembers(root.get(i), result);
}
return result.toArray(new Member[0]);
}
private String printTree(Node node, int level) {
if (node == null) {
return "";
}
String result = "";
for (int i = 0; i < level; i++) {
result += " ";
}
result += node + "\n";
for (Node child : node.children) {
result += printTree(child, level + 1);
}
return result;
}
public String toString() {
String result = "\nROOT:\n";
for (Node node : root) {
result += printTree(node, 1);
}
result += "LIST:\n";
for (Node node : list) {
result += node + "\n";
}
result += "SPARES:\n";
for (Node node : spares) {
result += node + "\n";
}
result += "Children of root:\n";
for (Member member : getRootChildren()) {
result += member + "\n";
}
return result;
}
}