[java] support creating an actor with parameters (#2817)

Previously `Ray.createActor` only support creating an actor without any parameter. This PR adds the support for creating an actor with parameters. Moreover, besides using a constructor, it's now also allowed to create an actor with a factory method. For more usage, prefer refer to `ActorTest.java`.
This commit is contained in:
Hao Chen
2018-09-04 00:53:03 +08:00
committed by Robert Nishihara
parent b37a283053
commit 9d655721e5
27 changed files with 1131 additions and 680 deletions
@@ -14,9 +14,7 @@ import org.ray.api.Ray;
import org.ray.api.RayActor;
import org.ray.api.RayObject;
import org.ray.api.WaitResult;
import org.ray.api.annotation.RayRemote;
import org.ray.api.function.RayFunc;
import org.ray.api.function.RayFunc2;
import org.ray.api.id.UniqueId;
import org.ray.api.runtime.RayRuntime;
import org.ray.core.model.RayParameters;
@@ -50,9 +48,9 @@ public abstract class AbstractRayRuntime implements RayRuntime {
protected PathConfig pathConfig;
/**
* Actor ID -> actor instance.
* Actor ID -> local actor instance.
*/
private Map<UniqueId, Object> actors = new HashMap<>();
Map<UniqueId, Object> localActors = new HashMap<>();
// app level Ray.init()
// make it private so there is no direct usage but only from Ray.init
@@ -137,7 +135,7 @@ public abstract class AbstractRayRuntime implements RayRuntime {
objectStoreProxy = new ObjectStoreProxy(plink, slink);
}
worker = new Worker(localSchedulerClient, functions);
worker = new Worker(this);
}
private static AbstractRayRuntime instantiate(RayParameters params) {
@@ -195,13 +193,15 @@ public abstract class AbstractRayRuntime implements RayRuntime {
@Override
public <T> RayObject<T> put(T obj) {
UniqueId objectId = getCurrentTaskNextPutId();
UniqueId objectId = UniqueIdHelper.computePutId(
WorkerContext.currentTask().taskId, WorkerContext.nextPutIndex());
put(objectId, obj);
return new RayObjectImpl<>(objectId);
}
public <T> void put(UniqueId objectId, T obj) {
UniqueId taskId = getCurrentTaskId();
UniqueId taskId = WorkerContext.currentTask().taskId;
RayLog.core.info("Putting object {}, for task {} ", objectId, taskId);
if (!params.use_raylet) {
localSchedulerClient.markTaskPutDependency(taskId, objectId);
@@ -209,21 +209,6 @@ public abstract class AbstractRayRuntime implements RayRuntime {
objectStoreProxy.put(objectId, obj, null);
}
/**
* get the task identity of the currently running task, UniqueId.NIL if not inside any
*/
public UniqueId getCurrentTaskId() {
return worker.getCurrentTaskId();
}
/**
* get the to-be-returned objects identities of the currently running task, empty array if not
* inside any.
*/
public UniqueId getCurrentTaskNextPutId() {
return worker.getCurrentTaskNextPutId();
}
@Override
public <T> T get(UniqueId objectId) throws TaskExecutionException {
List<T> ret = get(ImmutableList.of(objectId));
@@ -233,7 +218,7 @@ public abstract class AbstractRayRuntime implements RayRuntime {
@Override
public <T> List<T> get(List<UniqueId> objectIds) {
boolean wasBlocked = false;
UniqueId taskId = getCurrentTaskId();
UniqueId taskId = WorkerContext.currentTask().taskId;
try {
int numObjectIds = objectIds.size();
@@ -343,7 +328,7 @@ public abstract class AbstractRayRuntime implements RayRuntime {
@Override
public RayObject call(RayFunc func, Object[] args) {
TaskSpec spec = createTaskSpec(func, RayActorImpl.NIL, args, null);
TaskSpec spec = createTaskSpec(func, RayActorImpl.NIL, args, false);
localSchedulerClient.submitTask(spec);
return new RayObjectImpl(spec.returnIds[0]);
}
@@ -354,7 +339,7 @@ public abstract class AbstractRayRuntime implements RayRuntime {
throw new IllegalArgumentException("Unsupported actor type: " + actor.getClass().getName());
}
RayActorImpl actorImpl = (RayActorImpl)actor;
TaskSpec spec = createTaskSpec(func, actorImpl, args, null);
TaskSpec spec = createTaskSpec(func, actorImpl, args, false);
actorImpl.setTaskCursor(spec.returnIds[1]);
localSchedulerClient.submitTask(spec);
return new RayObjectImpl(spec.returnIds[0]);
@@ -362,30 +347,13 @@ public abstract class AbstractRayRuntime implements RayRuntime {
@Override
@SuppressWarnings("unchecked")
public <T> RayActor<T> createActor(Class<T> actorClass) {
RayFunc2<UniqueId, String, Object> func = AbstractRayRuntime::createLocalActor;
TaskSpec spec = createTaskSpec(func, RayActorImpl.NIL, null, actorClass);
RayActorImpl actor = new RayActorImpl(spec.returnIds[0]);
public <T> RayActor<T> createActor(RayFunc actorFactoryFunc, Object[] args) {
TaskSpec spec = createTaskSpec(actorFactoryFunc, RayActorImpl.NIL, args, true);
RayActorImpl<?> actor = new RayActorImpl(spec.returnIds[0]);
actor.increaseTaskCounter();
actor.setTaskCursor(spec.returnIds[0]);
localSchedulerClient.submitTask(spec);
return actor;
}
@RayRemote
private static Object createLocalActor(UniqueId actorId, String className) {
try {
Class<?> cls = Class.forName(className, true, Thread.currentThread().getContextClassLoader());
Object actor = cls.getConstructor().newInstance();
getInstance().actors.put(actorId, actor);
RayLog.core.info("Created actor: {}, actor id: {}", className, actorId);
return null;
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException | NoSuchMethodException
| SecurityException e) {
RayLog.core.error("Failed to create actor {}", className, e);
throw new TaskExecutionException(e);
}
return (RayActor<T>) actor;
}
/**
@@ -404,12 +372,11 @@ public abstract class AbstractRayRuntime implements RayRuntime {
* @param func The target remote function.
* @param actor The actor handle. If the task is not an actor task, actor id must be NIL.
* @param args The arguments for the remote function.
* @param actorClassForCreation If the task is a actor creation task, the argument should be
* the actor class. Otherwise, it should be null.
* @param isActorCreationTask Whether this task is an actor creation task.
* @return A TaskSpec object.
*/
private TaskSpec createTaskSpec(RayFunc func, RayActorImpl actor, Object[] args,
Class actorClassForCreation) {
boolean isActorCreationTask) {
final TaskSpec current = WorkerContext.currentTask();
UniqueId taskId = localSchedulerClient.generateTaskId(current.driverId,
current.taskId,
@@ -418,8 +385,7 @@ public abstract class AbstractRayRuntime implements RayRuntime {
UniqueId[] returnIds = genReturnIds(taskId, numReturns);
UniqueId actorCreationId = UniqueId.NIL;
if (actorClassForCreation != null) {
args = new Object[] {returnIds[0], actorClassForCreation.getName()};
if (isActorCreationTask) {
actorCreationId = returnIds[0];
}
@@ -448,24 +414,25 @@ public abstract class AbstractRayRuntime implements RayRuntime {
returnIds,
actor.getHandleId(),
actorCreationId,
ResourceUtil.getResourcesMapFromArray(rayMethod.remoteAnnotation.resources()),
ResourceUtil.getResourcesMapFromArray(rayMethod.remoteAnnotation),
actor.getTaskCursor()
);
}
/***********
* Internal Methods.
***********/
public void loop() {
worker.loop();
}
/**
* get actor with given id.
*/
public Object getLocalActor(UniqueId id) {
return actors.get(id);
public Worker getWorker() {
return worker;
}
}
public LocalSchedulerLink getLocalSchedulerClient() {
return localSchedulerClient;
}
public LocalFunctionManager getLocalFunctionManager() {
return functions;
}
}
@@ -9,12 +9,16 @@ import org.ray.api.id.UniqueId;
import org.ray.spi.model.FunctionArg;
import org.ray.spi.model.TaskSpec;
/**
* arguments wrap and unwrap.
*/
public class ArgumentsBuilder {
@SuppressWarnings({"rawtypes", "unchecked"})
private static boolean checkSimpleValue(Object o) {
// TODO(raulchen): implement this.
return true;
}
/**
* Convert real function arguments to task spec arguments.
*/
public static FunctionArg[] wrap(Object[] args) {
FunctionArg[] ret = new FunctionArg[args.length];
for (int i = 0; i < ret.length; i++) {
@@ -38,13 +42,11 @@ public class ArgumentsBuilder {
return ret;
}
private static boolean checkSimpleValue(Object o) {
return true;//TODO I think Ray don't want to pass big parameter
}
@SuppressWarnings({"rawtypes", "unchecked"})
public static Pair<Object, Object[]> unwrap(TaskSpec task, Method m, ClassLoader classLoader) {
// the last arg is className
/**
* Convert task spec arguments to real function arguments.
*/
public static Object[] unwrap(TaskSpec task, ClassLoader classLoader) {
// Ignore the last arg, which is the class name
Object[] realArgs = new Object[task.args.length - 1];
for (int i = 0; i < task.args.length - 1; i++) {
FunctionArg arg = task.args[i];
@@ -57,8 +59,6 @@ public class ArgumentsBuilder {
realArgs[i] = Ray.get(arg.id);
}
}
Object actor = task.actorId.isNil()
? null : AbstractRayRuntime.getInstance().getLocalActor(task.actorId);
return Pair.of(actor, realArgs);
return realArgs;
}
}
@@ -1,94 +0,0 @@
package org.ray.core;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.commons.lang3.tuple.Pair;
import org.ray.api.id.UniqueId;
import org.ray.spi.model.RayMethod;
import org.ray.spi.model.TaskSpec;
import org.ray.util.exception.TaskExecutionException;
import org.ray.util.logger.RayLog;
/**
* how to execute a invocation.
*/
public class InvocationExecutor {
public static void execute(TaskSpec task, Pair<ClassLoader, RayMethod> pr)
throws TaskExecutionException {
String taskdesc =
"[" + pr.getRight().fullName + "_" + task.taskId.toString() + " actorId = " + task.actorId
+ "]";
TaskExecutionException ex = null;
// switch to current driver's loader
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
if (pr.getLeft() != null) {
Thread.currentThread().setContextClassLoader(pr.getLeft());
}
// execute
try {
executeInternal(task, pr);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
if (!task.actorId.isNil()
&& AbstractRayRuntime.getInstance().getLocalActor(task.actorId) == null) {
ex = new TaskExecutionException("Task " + taskdesc + " execution on actor " + task.actorId
+ " failed as the actor is not present ", e);
RayLog.core.error("Task " + taskdesc + " execution on actor " + task.actorId
+ " failed as the actor is not present ", e);
} else {
ex = new TaskExecutionException(
formatTaskExecutionExceptionMsg(task, pr.getRight().fullName), e);
RayLog.core.error("Task " + taskdesc + " execution failed ", e);
}
RayLog.core.error(e.getMessage());
RayLog.core.error("task info: \n" + task.toString());
} catch (Throwable e) {
ex = new TaskExecutionException(formatTaskExecutionExceptionMsg(task, pr.getRight().fullName),
e);
RayLog.core.error("Task " + taskdesc + " execution with unknown error ", e);
RayLog.core.error(e.getMessage());
}
// recover loader
if (pr.getLeft() != null) {
Thread.currentThread().setContextClassLoader(oldLoader);
}
// set exception as the output results
if (ex != null) {
throw ex;
}
}
private static void executeInternal(TaskSpec task, Pair<ClassLoader, RayMethod> pr)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method m = pr.getRight().invokable;
Pair<Object, Object[]> realArgs = ArgumentsBuilder.unwrap(task, m, pr.getLeft());
// execute
Object result = null;
try {
result = m.invoke(realArgs.getLeft(), realArgs.getRight());
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
RayLog.core.error("invoke failed:" + m);
throw e;
}
if (task.returnIds == null || task.returnIds.length == 0) {
return;
}
AbstractRayRuntime.getInstance().put(task.returnIds[0], result);
}
private static String formatTaskExecutionExceptionMsg(TaskSpec task, String funcName) {
return "Execute task " + task.taskId
+ " failed with function name = " + funcName;
}
private static void safePut(UniqueId objectId, Object obj) {
AbstractRayRuntime.getInstance().put(objectId, obj);
}
}
@@ -62,8 +62,7 @@ public class LocalFunctionManager {
* it may block for a while if the related resources (e.g., jars) are not ready on local machine
*/
public Pair<ClassLoader, RayMethod> getMethod(UniqueId driverId, UniqueId actorId,
UniqueId methodId,
FunctionArg[] args) throws NoSuchMethodException, SecurityException, ClassNotFoundException {
UniqueId methodId, FunctionArg[] args) {
Preconditions.checkArgument(args.length >= 1, "method's args len %s<=1", args.length);
String className = (String) Serializer.decode(args[args.length - 1].data);
return getMethod(driverId, actorId, methodId, className);
@@ -84,20 +83,20 @@ public class LocalFunctionManager {
final ClassLoader classLoader;
final ConcurrentHashMap<String, RayTaskMethods> taskMethods = new ConcurrentHashMap<>();
final ConcurrentHashMap<String, RayActorMethods> actors = new ConcurrentHashMap<>();
final ConcurrentHashMap<String, RayActorMethods> actorMethods = new ConcurrentHashMap<>();
FunctionTable(ClassLoader classLoader) {
this.classLoader = classLoader;
}
RayMethod getTaskMethod(UniqueId methodId, String className) {
RayTaskMethods tasks = taskMethods.get(className);
if (tasks == null) {
tasks = RayTaskMethods.fromClass(className, classLoader);
RayLog.core.info("create RayTaskMethods:" + tasks);
taskMethods.put(className, tasks);
RayTaskMethods taskMethods = this.taskMethods.get(className);
if (taskMethods == null) {
taskMethods = RayTaskMethods.fromClass(className, classLoader);
RayLog.core.info("create RayTaskMethods: {}", taskMethods);
this.taskMethods.put(className, taskMethods);
}
RayMethod m = tasks.functions.get(methodId);
RayMethod m = taskMethods.functions.get(methodId);
if (m != null) {
return m;
}
@@ -110,13 +109,14 @@ public class LocalFunctionManager {
}
private RayMethod getActorMethod(UniqueId methodId, String className, boolean isStatic) {
RayActorMethods actor = actors.get(className);
if (actor == null) {
actor = RayActorMethods.fromClass(className, classLoader);
RayLog.core.info("create RayActorMethods:" + actor);
actors.put(className, actor);
RayActorMethods actorMethods = this.actorMethods.get(className);
if (actorMethods == null) {
actorMethods = RayActorMethods.fromClass(className, classLoader);
RayLog.core.info("create RayActorMethods: {}", actorMethods);
this.actorMethods.put(className, actorMethods);
}
return isStatic ? actor.staticFunctions.get(methodId) : actor.functions.get(methodId);
return isStatic ? actorMethods.staticFunctions.get(methodId)
: actorMethods.functions.get(methodId);
}
}
}
}
@@ -68,5 +68,4 @@ public class UniqueIdHelper {
return new UniqueId(taskId);
}
}
@@ -1,9 +1,8 @@
package org.ray.core;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.ray.api.exception.RayException;
import org.ray.api.id.UniqueId;
import org.ray.spi.LocalSchedulerLink;
import org.ray.spi.model.RayMethod;
import org.ray.spi.model.TaskSpec;
import org.ray.util.logger.RayLog;
@@ -14,51 +13,58 @@ import org.ray.util.logger.RayLog;
*/
public class Worker {
private final LocalSchedulerLink scheduler;
private final LocalFunctionManager functions;
private final AbstractRayRuntime runtime;
public Worker(LocalSchedulerLink scheduler, LocalFunctionManager functions) {
this.scheduler = scheduler;
this.functions = functions;
public Worker(AbstractRayRuntime runtime) {
this.runtime = runtime;
}
public void loop() {
while (true) {
RayLog.core.info(Thread.currentThread().getName() + ":fetching new task...");
TaskSpec task = scheduler.getTask();
execute(task, functions);
TaskSpec task = runtime.getLocalSchedulerClient().getTask();
execute(task);
}
}
public static void execute(TaskSpec task, LocalFunctionManager funcs) {
RayLog.core.info("Executing task {}", task.taskId);
if (!task.actorId.isNil() || (task.createActorId != null && !task.createActorId.isNil())) {
task.returnIds = ArrayUtils.subarray(task.returnIds, 0, task.returnIds.length - 1);
}
/**
* Execute a task.
*/
public void execute(TaskSpec spec) {
RayLog.core.info("Executing task {}", spec.taskId);
UniqueId returnId = spec.returnIds[0];
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
try {
Pair<ClassLoader, RayMethod> pr = funcs
.getMethod(task.driverId, task.actorId, task.functionId, task.args);
WorkerContext.prepare(task, pr.getLeft());
InvocationExecutor.execute(task, pr);
RayLog.core.info("Finished executing task {}", task.taskId);
// Get method
Pair<ClassLoader, RayMethod> pair = runtime.getLocalFunctionManager().getMethod(
spec.driverId, spec.actorId, spec.functionId, spec.args);
ClassLoader classLoader = pair.getLeft();
RayMethod method = pair.getRight();
// Set context
WorkerContext.prepare(spec, classLoader);
Thread.currentThread().setContextClassLoader(classLoader);
// Get local actor object and arguments.
Object actor = spec.isActorTask() ? runtime.localActors.get(spec.actorId) : null;
Object[] args = ArgumentsBuilder.unwrap(spec, classLoader);
// Execute the task.
Object result;
if (!method.isConstructor()) {
result = method.getMethod().invoke(actor, args);
} else {
result = method.getConstructor().newInstance(args);
}
// Set result
if (!spec.isActorCreationTask()) {
runtime.put(returnId, result);
} else {
runtime.localActors.put(returnId, result);
}
RayLog.core.info("Finished executing task {}", spec.taskId);
} catch (Exception e) {
RayLog.core.error("Failed to execute task " + task.taskId, e);
AbstractRayRuntime.getInstance().put(task.returnIds[0], e);
RayLog.core.error("Error executing task " + spec, e);
runtime.put(returnId, new RayException("Error executing task " + spec, e));
} finally {
Thread.currentThread().setContextClassLoader(oldLoader);
}
}
public UniqueId getCurrentTaskId() {
return WorkerContext.currentTask().taskId;
}
public UniqueId getCurrentTaskNextPutId() {
return UniqueIdHelper.computePutId(
WorkerContext.currentTask().taskId, WorkerContext.nextPutIndex());
}
public UniqueId[] getCurrentTaskReturnIDs() {
return WorkerContext.currentTask().returnIds;
}
}
@@ -1,10 +1,15 @@
package org.ray.spi.model;
import com.google.common.base.Preconditions;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.ray.api.annotation.RayRemote;
import org.ray.api.id.UniqueId;
@@ -28,22 +33,21 @@ public final class RayActorMethods {
this.staticFunctions = Collections.unmodifiableMap(new HashMap<>(staticFunctions));
}
public static RayActorMethods fromClass(String clazzName, ClassLoader classLoader) {
public static RayActorMethods fromClass(String className, ClassLoader classLoader) {
try {
Class clazz = Class.forName(clazzName, true, classLoader);
Class clazz = Class.forName(className, true, classLoader);
RayRemote remoteAnnotation = (RayRemote) clazz.getAnnotation(RayRemote.class);
Preconditions
.checkNotNull(remoteAnnotation, "%s must declare @RayRemote", clazzName);
Method[] methods = clazz.getDeclaredMethods();
Map<UniqueId, RayMethod> functions = new HashMap<>(methods.length * 2);
Map<UniqueId, RayMethod> staticFunctions = new HashMap<>(methods.length * 2);
Preconditions.checkNotNull(remoteAnnotation,
"%s must be annotated with @RayRemote", className);
for (Method m : methods) {
if (!Modifier.isPublic(m.getModifiers())) {
continue;
}
RayMethod rayMethod = RayMethod.from(m, remoteAnnotation);
if (Modifier.isStatic(m.getModifiers())) {
List<Executable> executables = new ArrayList<>(Arrays.asList(clazz.getDeclaredMethods()));
Map<UniqueId, RayMethod> functions = new HashMap<>();
Map<UniqueId, RayMethod> staticFunctions = new HashMap<>();
for (Executable e : executables) {
RayMethod rayMethod = RayMethod.from(e, remoteAnnotation);
if (Modifier.isStatic(e.getModifiers())) {
staticFunctions.put(rayMethod.getFuncId(), rayMethod);
} else {
functions.put(rayMethod.getFuncId(), rayMethod);
@@ -51,7 +55,7 @@ public final class RayActorMethods {
}
return new RayActorMethods(clazz, remoteAnnotation, functions, staticFunctions);
} catch (Exception e) {
throw new RuntimeException("failed to get RayActorMethods from " + clazzName, e);
throw new RuntimeException("failed to get RayActorMethods from " + className, e);
}
}
@@ -1,5 +1,7 @@
package org.ray.spi.model;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import org.ray.api.annotation.RayRemote;
import org.ray.api.id.UniqueId;
@@ -10,29 +12,40 @@ import org.ray.util.MethodId;
*/
public class RayMethod {
public final Method invokable;
public final Executable invokable;
public final String fullName;
public final RayRemote remoteAnnotation;
private final UniqueId funcId;
private RayMethod(Method m, RayRemote remoteAnnotation, UniqueId funcId) {
this.invokable = m;
private RayMethod(Executable e, RayRemote remoteAnnotation, UniqueId funcId) {
this.invokable = e;
this.remoteAnnotation = remoteAnnotation;
this.funcId = funcId;
fullName = m.getDeclaringClass().getName() + "." + m.getName();
fullName = e.getDeclaringClass().getName() + "." + e.getName();
}
public static RayMethod from(Method m, RayRemote parentRemoteAnnotation) {
Class<?> clazz = m.getDeclaringClass();
RayRemote remoteAnnotation = m.getAnnotation(RayRemote.class);
MethodId mid = MethodId.fromMethod(m);
public static RayMethod from(Executable e, RayRemote parentRemoteAnnotation) {
RayRemote remoteAnnotation = e.getAnnotation(RayRemote.class);
MethodId mid = MethodId.fromExecutable(e);
UniqueId funcId = new UniqueId(mid.getSha1Hash());
RayMethod method = new RayMethod(m,
RayMethod method = new RayMethod(e,
remoteAnnotation != null ? remoteAnnotation : parentRemoteAnnotation,
funcId);
return method;
}
public boolean isConstructor() {
return invokable instanceof Constructor;
}
public Constructor<?> getConstructor() {
return (Constructor<?>) invokable;
}
public Method getMethod() {
return (Method) invokable;
}
@Override
public String toString() {
return fullName;
@@ -1,9 +1,14 @@
package org.ray.spi.model;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.ray.api.annotation.RayRemote;
import org.ray.api.id.UniqueId;
@@ -23,20 +28,19 @@ public final class RayTaskMethods {
public static RayTaskMethods fromClass(String clazzName, ClassLoader classLoader) {
try {
Class clazz = Class.forName(clazzName, true, classLoader);
Method[] methods = clazz.getDeclaredMethods();
Map<UniqueId, RayMethod> functions = new HashMap<>(methods.length * 2);
List<Executable> executables = new ArrayList<>();
executables.addAll(Arrays.asList(clazz.getDeclaredMethods()));
executables.addAll(Arrays.asList(clazz.getConstructors()));
Map<UniqueId, RayMethod> functions = new HashMap<>(executables.size());
for (Method m : methods) {
if (!Modifier.isStatic(m.getModifiers())) {
for (Executable e : executables) {
// This executable must be either a constructor or a static method.
if (!(e instanceof Constructor)
&& !Modifier.isStatic(e.getModifiers())) {
continue;
}
//task method only for static.
RayRemote remoteAnnotation = m.getAnnotation(RayRemote.class);
if (remoteAnnotation == null) {
continue;
}
m.setAccessible(true);
RayMethod rayMethod = RayMethod.from(m, null);
e.setAccessible(true);
RayMethod rayMethod = RayMethod.from(e, null);
functions.put(rayMethod.getFuncId(), rayMethod);
}
return new RayTaskMethods(clazz, functions);
@@ -94,4 +94,11 @@ public class TaskSpec {
return builder.toString();
}
public boolean isActorTask() {
return !actorId.isNil();
}
public boolean isActorCreationTask() {
return !createActorId.isNil();
}
}