* @param receiver the receiver to notify when the second job completes, not null
*/
private static DispatchableJob splitJob(final WatchedJob creator, final CalculationJob job) {
final List<CalculationJobItem> items = job.getJobItems();
s_logger.debug("Splitting {} for resubmission ", job);
final CacheSelectHint hint = job.getCacheSelectHint();
// Build the head job items
final int headItemCount = items.size() >> 1;
final List<CalculationJobItem> headItems = new ArrayList<CalculationJobItem>(headItemCount);
final Set<ValueSpecification> headShared = new HashSet<ValueSpecification>();
final Set<ValueSpecification> headPrivate = new HashSet<ValueSpecification>();
final int tailItemCount = (items.size() + 1) >> 1;
for (int i = 0; i < headItemCount; i++) {
final CalculationJobItem item = items.get(i);
headItems.add(item);
for (ValueSpecification input : item.getInputs()) {
if (hint.isPrivateValue(input)) {
headPrivate.add(input);
} else {
headShared.add(input);
}
}
for (ValueSpecification output : item.getOutputs()) {
if (hint.isPrivateValue(output)) {
headPrivate.add(output);
} else {
headShared.add(output);
}
}
}
// Build the tail job items and adjust the cache hint for head private values
final List<CalculationJobItem> tailItems = new ArrayList<CalculationJobItem>(tailItemCount);
final Set<ValueSpecification> tailShared = new HashSet<ValueSpecification>();
final Set<ValueSpecification> tailPrivate = new HashSet<ValueSpecification>();
for (int i = 0; i < tailItemCount; i++) {
final CalculationJobItem item = items.get(headItemCount + i);
tailItems.add(item);
for (ValueSpecification input : item.getInputs()) {
if (hint.isPrivateValue(input)) {
// If the head had this as private, make shared
if (headPrivate.remove(input)) {
headShared.add(input);
tailShared.add(input);
}
} else {
tailShared.add(input);
}
}
for (ValueSpecification output : item.getOutputs()) {
if (hint.isPrivateValue(output)) {
tailPrivate.add(output);
} else {
tailShared.add(output);
}
}
}
// Construct the head cache hint, job specification (synthetic ID) and job
final CacheSelectHint headHint;
if (headPrivate.size() > headShared.size()) {
headHint = CacheSelectHint.sharedValues(headShared);
} else {
headHint = CacheSelectHint.privateValues(headPrivate);
}
final CalculationJob head = new CalculationJob(job.getSpecification().withJobId(JobIdSource.getId()), job.getFunctionInitializationIdentifier(), job.getResolverVersionCorrection(), null,
headItems, headHint);
// Construct the tail cache hint, job specification (using original ID) and job
final CacheSelectHint tailHint;
if (tailPrivate.size() > tailShared.size()) {
tailHint = CacheSelectHint.sharedValues(tailShared);
} else {
tailHint = CacheSelectHint.privateValues(tailPrivate);
}