package ibis.ipl.impl.stacking.lrmc.util;
import ibis.ipl.IbisIdentifier;
import ibis.ipl.Location;
import java.util.Arrays;
import java.util.Comparator;
public class IbisSorter implements Comparator<IbisIdentifier> {
// General sorter to use when no cluster order is preferred.
private static final IbisSorter sorter = new IbisSorter("unknown", null);
private final String preferredCluster;
private final String preferredName;
private IbisSorter(String preferredCluster, String preferredName) {
this.preferredCluster = preferredCluster;
this.preferredName = preferredName;
}
public static void sort(IbisIdentifier[] ids) {
sort(ids, 0, ids.length);
}
public static void sort(IbisIdentifier local, IbisIdentifier[] ids) {
sort(local, ids, 0, ids.length);
}
public static void sort(IbisIdentifier[] ids, int from, int to) {
Arrays.sort(ids, from, to, sorter);
}
public static void sort(IbisIdentifier local, IbisIdentifier[] ids,
int from, int to) {
/*
* IbisSorter tmp = sorter;
*
* if (!local.equals(sorter.preferredName) ||
* !local.getLocation().cluster().equals(sorter.preferredCluster)) { tmp =
* new IbisSorter(local.getLocation().cluster(), local); }
*
* Arrays.sort(ids, from, to, tmp);
*/
IbisIdentifier[] tmp = new IbisIdentifier[(to - from) + 1];
tmp[0] = local;
System.arraycopy(ids, from, tmp, 1, to - from);
Arrays.sort(tmp, sorter);
int index = 0;
for (int i = 0; i < tmp.length; i++) {
if (tmp[i].equals(local)) {
index = i;
break;
}
}
System.arraycopy(tmp, index + 1, ids, from, tmp.length - (index + 1));
System.arraycopy(tmp, 0, ids, from + tmp.length - index - 1, index);
}
// Returns the index of the first character that is different in the two
// Strings. Thus, the higher the number returned, the longer the prefix that
// the two Strings share.
private static int firstDifference(String s1, String s2) {
// first, make sure that we s1 is the shortest string.
if (s1.length() > s2.length()) {
String tmp = s1;
s1 = s2;
s2 = tmp;
}
for (int i = 0; i < s1.length(); i++) {
if (s1.charAt(i) != s2.charAt(i)) {
return i;
}
}
return s1.length();
}
public int compare(IbisIdentifier id1, IbisIdentifier id2) {
Location cluster1 = id1.location().getParent();
Location cluster2 = id2.location().getParent();
if (cluster1.equals(cluster2)) {
// The clusters are identical, so the order depends completely
// on the names.
//
// For SMP awareness, we assume that the identifiers of two ibises
// on an SMP machine are 'closer' that the identifiers of two ibises
// on different machines. This way, the identifiers will
// automatically be sorted 'pair-wise' (or quad/oct/etc, depending
// on the number of ibises that share the SMP machines).
//
// One aditional problem is that we want the ibises that share the
// machine with the sender to be first (which isn't that simple!).
if (preferredName == null) {
return id1.location().toString().compareTo(
id2.location().toString());
} else {
// Figure out if one of the two strings has a longer prefix
// in common with 'preferredName'. Note that this will result
// in the lenght of the string only if the IbisIdentifier
// actually contains the 'preferredName'. Therefore, this
// IbisIdentifier will end up at the first position of the
// array, which is exactly what we want.
int d1 = firstDifference(preferredName, id1.location()
.toString());
int d2 = firstDifference(preferredName, id2.location()
.toString());
// If both have the same distance, we sort them alphabetically.
// Otherwise, we prefer the one that is closest to
// 'preferredName', since these may actually be located on the
// same machine.
if (d1 == d2) {
return id1.location().toString().compareTo(
id2.location().toString());
} else if (d1 <= d2) {
return 1;
} else {
return -1;
}
}
}
// The clusters are different. If one of the two is equal to the
// preferredCluster, we want that one to win. Otherwise, we just return
// the 'natural order'.
if (cluster1.equals(preferredCluster)) {
return -1;
}
if (cluster2.equals(preferredCluster)) {
return 1;
}
return cluster1.compareTo(cluster2);
}
}