throw new IllegalStateException("Reduce phase of MapReduceTask " + taskId + " on node " + cdl.getAddress()
+ " executed with empty input keys");
} else {
final Reducer<KOut, VOut> reducer = reduceCommand.getReducer();
final boolean useIntermediateKeys = reduceCommand.isEmitCompositeIntermediateKeys();
MapReduceTaskLifecycleService taskLifecycleService = MapReduceTaskLifecycleService.getInstance();
log.tracef("For m/r task %s invoking %s at %s", taskId, reduceCommand, cdl.getAddress());
long start = log.isTraceEnabled() ? timeService.time() : 0;
try {
//first hook into lifecycle
Cache<?, ?> cache = cacheManager.getCache(reduceCommand.getCacheName());
taskLifecycleService.onPreExecute(reducer, cache);
//assume dedicated tmp cache, all keys belong to this task
AdvancedCacheLoader.KeyFilter<?> filter = AdvancedCacheLoader.KeyFilter.LOAD_ALL_FILTER;
if (useIntermediateKeys) {
//shared tmp cache, filter keys that belong to this task
filter = new IntermediateKeyFilter<KOut>(taskId);
}
//iterate all tmp cache entries in memory, do it in parallel
DataContainer dc = cache.getAdvancedCache().getDataContainer();
dc.executeTask(filter, new StatelessDataContainerTask<KOut, List<VOut>>() {
@Override
public void apply(Object k, InternalCacheEntry v) {
KOut key = null;
if (useIntermediateKeys) {
IntermediateCompositeKey<KOut> intKey = (IntermediateCompositeKey<KOut>) k;
key = intKey.getKey();
} else {
key = (KOut) k;
}
//resolve List<VOut> for iterated key stored in tmp cache
List<VOut> value = getValue(v);
if (value != null) {
// and reduce it
VOut reduced = reducer.reduce(key, value.iterator());
result.put(key, reduced);
log.tracef("For m/r task %s reduced %s to %s at %s ", taskId, key, reduced, cdl.getAddress());
}
}
});
} finally {
if (log.isTraceEnabled()) {
log.tracef("Reduce for task %s took %s milliseconds", reduceCommand.getTaskId(),
timeService.timeDuration(start, TimeUnit.MILLISECONDS));
}
taskLifecycleService.onPostExecute(reducer);
}
}
return result;
}