SubPartitionInfo[] newSpliting = null;
ArrayList newSubParts = new ArrayList ();
for (int i=0; i<splitingInfo.partitions.length; i++)
{
SubPartitionInfo currentSubPart = splitingInfo.partitions[i];
SubPartitionInfo newCurrent = null;
Iterator iter = currentSubPart.memberNodeNames.iterator ();
while (iter.hasNext ())
{
String node = (String)iter.next ();
if (replicants.contains (node))
{
if (newCurrent == null)
{
newCurrent = (SubPartitionInfo)currentSubPart.clone ();
newCurrent.memberNodeNames.clear ();
}
newCurrent.memberNodeNames.add (node);
}
}
if (newCurrent != null)
newSubParts.add (newCurrent);
}
// we now create a list of new nodes that are not yet part of any group
//
Iterator iter = replicants.iterator ();
ArrayList newMembersNotInAGroup = new ArrayList ();
while (iter.hasNext ())
{
boolean found = false;
String aMember = (String)iter.next ();
Iterator iterNewSubPart = newSubParts.iterator ();
while (iterNewSubPart.hasNext () && !found)
if (((SubPartitionInfo)iterNewSubPart.next ()).memberNodeNames.contains (aMember))
found = true;
if (!found)
newMembersNotInAGroup.add (aMember);
}
iter = null;
// we now have purged our current sub-partition structure from its dead members
// we now check if some sub-partitions need to be merged to remove singleton groups
// or if there is a group with n>(nodesPerSubPartition) that may be reduced to its ideal size
//
// we remove elements that are less than the group size and put them in a new sorted list
//
ArrayList smallerGroups = new ArrayList ();
ArrayList correctlySizedGroups = new ArrayList ();
ArrayList biggerGroups = new ArrayList ();
for (int i=0; i<newSubParts.size (); i++)
{
int groupSize = ((SubPartitionInfo)newSubParts.get (i)).memberNodeNames.size ();
if (groupSize < this.nodesPerSubPartition)
smallerGroups.add (newSubParts.get (i));
else if (groupSize > this.nodesPerSubPartition)
biggerGroups.add (newSubParts.get (i));
else
correctlySizedGroups.add (newSubParts.get (i));
}
// for our algo, we need to sort smallerGroups
//
java.util.Collections.sort (smallerGroups);
//
// Our algo is not perfect and could, for example, take in account, the actual group load in order to minimize
// the synchronization time
//
// 1st step: we place newly started nodes (not yet part of a group) in smallerGroups
// by first feeding small groups
//
iter = newMembersNotInAGroup.iterator ();
while (iter.hasNext ())
{
String member = (String)iter.next ();
SubPartitionInfo target = null;
if (smallerGroups.size () > 0)
{
target = (SubPartitionInfo)smallerGroups.get (0); // array is sorted
target.memberNodeNames.add (member);
if (target.memberNodeNames.size () == this.nodesPerSubPartition)
{
// we have a complete sub-partition, we change its owning group
//
smallerGroups.remove (0);
correctlySizedGroups.add (target);
}
}
else
{
// we create an singleton group
//
target = new SubPartitionInfo ();
target.setIsNewGroup ();
target.subPartitionName = getSubPartitionName (splitingInfo);
target.memberNodeNames.add (member);
smallerGroups.add (target);
java.util.Collections.sort (smallerGroups);
}
}
// 2nd step: we reduce the size of any too-big sub-partition (biggerGroups)
// by removing the last component and feeding elements in smallerGroups
// If smallerGroups is empty, we don't modify biggerGroups (minimize
// involved state transfer)
//
iter = biggerGroups.iterator ();
while (iter.hasNext ())
{
SubPartitionInfo big = (SubPartitionInfo)iter.next ();
if (smallerGroups.size () > 0)
{
String member = (String)big.memberNodeNames.get (big.memberNodeNames.size ()-1); // get last one
SubPartitionInfo target = null;
target = (SubPartitionInfo)smallerGroups.get (0); // array is sorted
target.memberNodeNames.add (member);
big.memberNodeNames.remove (big.memberNodeNames.size () -1);
if (target.memberNodeNames.size () == this.nodesPerSubPartition)
{
// we have a complete sub-partition, we change its owning group
//
smallerGroups.remove (0);
correctlySizedGroups.add (target);
}
}
}
// biggerGroups is now processed, we can move it to the correctly sized group
//
correctlySizedGroups.addAll (biggerGroups);
// 3rd step: we now try to merge sub-partitions belonging to smallerGroups to form bigger groups (up to the
// max size of a sub-partition). We travel in descending order to keep max granularity when forming groups
//
boolean thirdStepFinished = (smallerGroups.size () == 0);
while (!thirdStepFinished)
{
//thirdStepFinished = (smallerGroups.size () == 0);
SubPartitionInfo current = (SubPartitionInfo)smallerGroups.get (smallerGroups.size ()-1);
for (int i = smallerGroups.size ()-2; i >= 0; i--)
{
// test if the merge is possible
//
SubPartitionInfo merger = (SubPartitionInfo)smallerGroups.get (i);
if ((merger.memberNodeNames.size () + current.memberNodeNames.size ()) <= this.nodesPerSubPartition)
{
// it is possible to merge both
//
current.merge (merger);
smallerGroups.remove (i);
}
// we check if we need to go further or not
//
if (current.memberNodeNames.size () == this.nodesPerSubPartition)
break;
}
if (current.memberNodeNames.size () > 1)
{
// we only move non-singleton groups
//
smallerGroups.remove (smallerGroups.size ()-1);
correctlySizedGroups.add (current);
}
thirdStepFinished = ( (smallerGroups.size () == 0) ||
((smallerGroups.size () == 1) && ( ((SubPartitionInfo)smallerGroups.get (0)).memberNodeNames.size () == 1)) );
}
// 4th step: if smallerGroups is not empty, it means that we have a singleton. In that case,
// we merge it with the smallest group we can find.
//
if (smallerGroups.size () > 0)
{
if (correctlySizedGroups.size ()>0)
{
java.util.Collections.sort (correctlySizedGroups);
SubPartitionInfo merger = (SubPartitionInfo)smallerGroups.get (0);
SubPartitionInfo master = (SubPartitionInfo)correctlySizedGroups.get (0);
master.merge (merger);
}
else
{
// we have a single singleton group!
//