org.infinispan.distexec.DistributedExecutionCompletionService Maven / Gradle / Ivy
package org.infinispan.distexec;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;
import org.infinispan.remoting.transport.Address;
/**
* A {@link CompletionService} that uses a supplied {@link DistributedExecutorService} to execute
* tasks. This class arranges that submitted tasks are, upon completion, placed on a queue
* accessible using take. The class is lightweight enough to be suitable for transient use
* when processing groups of tasks.
*
* This class must be used instead of a {@link ExecutorCompletionService} provided from
* java.util.concurrent package. The {@link ExecutorCompletionService} may not be used since it
* requires the use of a non serializable RunnableFuture object.
*
* @author William Burns
* @author Vladimir Blagojevic
*/
public class DistributedExecutionCompletionService implements CompletionService {
protected final DistributedExecutorService executor;
protected final BlockingQueue> completionQueue;
/**
* Creates an ExecutorCompletionService using the supplied executor for base task execution and a
* {@link LinkedBlockingQueue} as a completion queue.
*
* @param executor
* the executor to use
* @throws NullPointerException
* if executor is null
*/
public DistributedExecutionCompletionService(DistributedExecutorService executor) {
this(executor, null);
}
/**
* Creates an ExecutorCompletionService using the supplied executor for base task execution and
* the supplied queue as its completion queue.
*
* Note: {@link PriorityBlockingQueue} for completionQueue can only be used with accompanying
* {@link Comparator} as our internal implementation of {@link Future} for each subtask does not
* implement Comparable interface. Note that we do not provide any guarantees about which
* particular internal class implements Future interface and these APIs will remain internal.
*
* @param executor
* the executor to use
* @param completionQueue
* the queue to use as the completion queue normally one dedicated for use by this
* service
* @throws NullPointerException
* if executor is null
*/
public DistributedExecutionCompletionService(DistributedExecutorService executor,
BlockingQueue> completionQueue) {
if (executor == null)
throw new NullPointerException();
this.executor = executor;
if (completionQueue == null) {
this.completionQueue = new LinkedBlockingQueue>();
}
else {
this.completionQueue = completionQueue;
}
}
/**
* {@inheritDoc CompletionService}
*/
@Override
public CompletableFuture submit(Callable task) {
if (task == null) throw new NullPointerException();
CompletableFuture f = (CompletableFuture) executor.submit(task);
return f.whenComplete((v, t) -> completionQueue.add(f));
}
/**
* {@inheritDoc CompletionService}
*/
@Override
public CompletableFuture submit(Runnable task, V result) {
if (task == null) throw new NullPointerException();
CompletableFuture f = (CompletableFuture) executor.submit(task, result);
return f.whenComplete((v, t) -> completionQueue.add(f));
}
/**
* {@inheritDoc CompletionService}
*/
@Override
public CompletableFuture take() throws InterruptedException {
return completionQueue.take();
}
/**
* {@inheritDoc CompletionService}
*/
@Override
public CompletableFuture poll() {
return completionQueue.poll();
}
/**
* {@inheritDoc CompletionService}
*/
@Override
public CompletableFuture poll(long timeout, TimeUnit unit) throws InterruptedException {
return completionQueue.poll(timeout, unit);
}
public Future submit(Callable task, K... input) {
CompletableFuture f = executor.submit(task, input);
return f.whenComplete((v, t) -> completionQueue.add(f));
}
public List> submitEverywhere(Callable task) {
List> fl = executor.submitEverywhere(task);
for (Future f : fl) {
((CompletableFuture) f).whenComplete((v, t) -> completionQueue.add((CompletableFuture) f));
}
return fl;
}
public List> submitEverywhere(Callable task, K... input) {
List> fl = executor.submitEverywhere(task, input);
for (CompletableFuture f : fl) {
f.whenComplete((v, t) -> completionQueue.add(f));
}
return fl;
}
public CompletableFuture submit(Address target, Callable task) {
CompletableFuture f = executor.submit(target, task);
return f.whenComplete((v, t) -> completionQueue.add(f));
}
}