/**
Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved.
Contact:
SYSTAP, LLC DBA Blazegraph
2501 Calvert ST NW #106
Washington, DC 20008
licenses@blazegraph.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.bigdata.btree.proc;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.bigdata.btree.proc.SplitValuePair.PairComparator;
import com.bigdata.service.Split;
/**
* Aggregator base class collects the individual results in an internal ordered
* map and assembles the final result when it is requested from the individual
* results. With this approach there is no overhead or contention when the
* results are being produced in parallel and they can be combined efficiently
* within a single thread in {@link #getResult()}.
* <p>
* Note: This implementation assumes that there is one element of the result for
* each key in the original request. It places the {@link Split}-wise results
* into a total ordering over the {@link Split}s and then delegates to a
* concrete implementation to build the aggregated results out of the ordered
* pairs of ({@link Split}, partial-result).
*
* @author bryan
*/
abstract public class AbstractLocalSplitResultAggregator<R> implements IResultHandler<R, R> {
/**
* The #of elements in the request (which is the must be the same as the
* cardinality of the aggregated result).
*/
private final int size;
/**
* Map for collecting the piece wise results.
*/
private final ConcurrentHashMap<Split, R> map = new ConcurrentHashMap<Split, R>();
/**
*
* @param size
* The #of elements in the request (which is the same as the
* cardinality of the aggregated result).
*/
public AbstractLocalSplitResultAggregator(final int size) {
if (size < 0)
throw new IllegalArgumentException();
this.size = size;
}
@Override
public void aggregate(final R result, final Split split) {
map.put(split, result);
}
@Override
public R getResult() {
/*
* Extract the results into a key/value array.
*/
final int nresults = map.size();
@SuppressWarnings("unchecked")
final SplitValuePair<Split, R>[] a = new SplitValuePair[nresults];
{
int i = 0;
for (Map.Entry<Split, R> e : map.entrySet()) {
a[i++] = new SplitValuePair<Split, R>(e.getKey(), e.getValue());
}
if (a.length == 1) {
// Do not bother aggregating a single result.
return a[0].val;
}
}
/*
* Sort the array by Split. This imposes a total ordering and makes the
* counters[] 1:1 with the original keys[][] and vals[][] provided to
* the index procedure.
*/
Arrays.sort(a, 0/* fromIndex */, a.length/* toIndex */, new PairComparator<Split, R>());
return newResult(size, a);
}
/**
* Build the aggregated result by aggregate the individual results in the
* given order.
*
* @param size
* The number of keys in the original request.
* @param a
* An array of {@link SplitValuePair}s that is ordered on
* {@link Split#fromIndex}.
*
* @return The aggregated result.
*/
abstract protected R newResult(final int size, final SplitValuePair<Split, R>[] a);
}