|
|
|
@ -21,6 +21,9 @@ import java.util.List;
|
|
|
|
|
import java.util.UUID;
|
|
|
|
|
import java.util.concurrent.Callable;
|
|
|
|
|
import java.util.concurrent.CountDownLatch;
|
|
|
|
|
import java.util.concurrent.ExecutionException;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.concurrent.TimeoutException;
|
|
|
|
|
|
|
|
|
|
import org.redisson.api.RExecutorService;
|
|
|
|
|
import org.redisson.api.RFuture;
|
|
|
|
@ -74,6 +77,8 @@ public class CoordinatorTask<KOut, VOut> implements Callable<Object>, Serializab
|
|
|
|
|
protected Class<?> objectClass;
|
|
|
|
|
private Class<?> objectCodecClass;
|
|
|
|
|
private String resultMapName;
|
|
|
|
|
private long timeout;
|
|
|
|
|
private long startTime;
|
|
|
|
|
|
|
|
|
|
protected Codec codec;
|
|
|
|
|
|
|
|
|
@ -82,7 +87,7 @@ public class CoordinatorTask<KOut, VOut> implements Callable<Object>, Serializab
|
|
|
|
|
|
|
|
|
|
public CoordinatorTask(BaseMapperTask<KOut, VOut> mapperTask, RReducer<KOut, VOut> reducer,
|
|
|
|
|
String mapName, String resultMapName, Class<?> mapCodecClass, Class<?> objectClass,
|
|
|
|
|
RCollator<KOut, VOut, Object> collator) {
|
|
|
|
|
RCollator<KOut, VOut, Object> collator, long timeout, long startTime) {
|
|
|
|
|
super();
|
|
|
|
|
this.mapperTask = mapperTask;
|
|
|
|
|
this.reducer = reducer;
|
|
|
|
@ -91,49 +96,81 @@ public class CoordinatorTask<KOut, VOut> implements Callable<Object>, Serializab
|
|
|
|
|
this.objectClass = objectClass;
|
|
|
|
|
this.resultMapName = resultMapName;
|
|
|
|
|
this.collator = collator;
|
|
|
|
|
this.timeout = timeout;
|
|
|
|
|
this.startTime = startTime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Object call() throws Exception {
|
|
|
|
|
long timeSpent = System.currentTimeMillis() - startTime;
|
|
|
|
|
if (isTimeoutExpired(timeSpent)) {
|
|
|
|
|
throw new MapReduceTimeoutException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.codec = (Codec) objectCodecClass.getConstructor().newInstance();
|
|
|
|
|
|
|
|
|
|
RScheduledExecutorService executor = redisson.getExecutorService(RExecutorService.MAPREDUCE_NAME);
|
|
|
|
|
int workersAmount = executor.countActiveWorkers();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UUID id = UUID.randomUUID();
|
|
|
|
|
String collectorMapName = objectName + ":collector:" + id;
|
|
|
|
|
|
|
|
|
|
mapperTask.setCollectorMapName(collectorMapName);
|
|
|
|
|
mapperTask.setWorkersAmount(workersAmount);
|
|
|
|
|
executor.submit(mapperTask).get();
|
|
|
|
|
|
|
|
|
|
if (Thread.currentThread().isInterrupted()) {
|
|
|
|
|
return null;
|
|
|
|
|
timeSpent = System.currentTimeMillis() - startTime;
|
|
|
|
|
if (isTimeoutExpired(timeSpent)) {
|
|
|
|
|
throw new MapReduceTimeoutException();
|
|
|
|
|
}
|
|
|
|
|
if (timeout > 0) {
|
|
|
|
|
mapperTask.setTimeout(timeout - timeSpent);
|
|
|
|
|
}
|
|
|
|
|
RFuture<?> mapperFuture = executor.submit(mapperTask);
|
|
|
|
|
if (timeout > 0 && !mapperFuture.await(timeout - timeSpent)) {
|
|
|
|
|
mapperFuture.cancel(true);
|
|
|
|
|
throw new MapReduceTimeoutException();
|
|
|
|
|
}
|
|
|
|
|
if (timeout == 0) {
|
|
|
|
|
try {
|
|
|
|
|
mapperFuture.await();
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<RFuture<?>> futures = new ArrayList<RFuture<?>>();
|
|
|
|
|
final CountDownLatch latch = new CountDownLatch(workersAmount);
|
|
|
|
|
for (int i = 0; i < workersAmount; i++) {
|
|
|
|
|
String name = collectorMapName + ":" + i;
|
|
|
|
|
Runnable runnable = new ReducerTask<KOut, VOut>(name, reducer, objectCodecClass, resultMapName);
|
|
|
|
|
RFuture<?> future = executor.submit(runnable);
|
|
|
|
|
Runnable runnable = new ReducerTask<KOut, VOut>(name, reducer, objectCodecClass, resultMapName, timeout - timeSpent);
|
|
|
|
|
RFuture<?> future = executor.submitAsync(runnable);
|
|
|
|
|
future.addListener(new LatchListener(latch));
|
|
|
|
|
futures.add(future);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Thread.currentThread().isInterrupted()) {
|
|
|
|
|
for (RFuture<?> future : futures) {
|
|
|
|
|
future.cancel(true);
|
|
|
|
|
}
|
|
|
|
|
cancelReduce(futures);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
timeSpent = System.currentTimeMillis() - startTime;
|
|
|
|
|
if (isTimeoutExpired(timeSpent)) {
|
|
|
|
|
cancelReduce(futures);
|
|
|
|
|
throw new MapReduceTimeoutException();
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
latch.await();
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
for (RFuture<?> future : futures) {
|
|
|
|
|
future.cancel(true);
|
|
|
|
|
if (timeout > 0 && !latch.await(timeout - timeSpent, TimeUnit.MILLISECONDS)) {
|
|
|
|
|
cancelReduce(futures);
|
|
|
|
|
throw new MapReduceTimeoutException();
|
|
|
|
|
}
|
|
|
|
|
if (timeout == 0) {
|
|
|
|
|
try {
|
|
|
|
|
latch.await();
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
cancelReduce(futures);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
for (RFuture<?> rFuture : futures) {
|
|
|
|
@ -142,12 +179,46 @@ public class CoordinatorTask<KOut, VOut> implements Callable<Object>, Serializab
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return executeCollator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Object executeCollator() throws ExecutionException, Exception {
|
|
|
|
|
if (collator == null) {
|
|
|
|
|
if (timeout > 0) {
|
|
|
|
|
redisson.getMap(resultMapName).clearExpire();
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Callable<Object> collatorTask = new CollatorTask<KOut, VOut, Object>(redisson, collator, resultMapName, objectCodecClass);
|
|
|
|
|
return collatorTask.call();
|
|
|
|
|
long timeSpent = System.currentTimeMillis() - startTime;
|
|
|
|
|
if (isTimeoutExpired(timeSpent)) {
|
|
|
|
|
throw new MapReduceTimeoutException();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (timeout > 0) {
|
|
|
|
|
java.util.concurrent.Future<?> collatorFuture = redisson.getConfig().getExecutor().submit(collatorTask);
|
|
|
|
|
try {
|
|
|
|
|
return collatorFuture.get(timeout - timeSpent, TimeUnit.MILLISECONDS);
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
return null;
|
|
|
|
|
} catch (TimeoutException e) {
|
|
|
|
|
collatorFuture.cancel(true);
|
|
|
|
|
throw new MapReduceTimeoutException();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return collatorTask.call();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isTimeoutExpired(long timeSpent) {
|
|
|
|
|
return timeSpent > timeout && timeout > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void cancelReduce(List<RFuture<?>> futures) {
|
|
|
|
|
for (RFuture<?> future : futures) {
|
|
|
|
|
future.cancel(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|