[Java] New Java actor API (#7414)

This commit is contained in:
Hao Chen
2020-03-04 22:39:23 +08:00
committed by GitHub
parent 4198db5038
commit fe7820fec9
46 changed files with 1576 additions and 753 deletions
@@ -98,7 +98,7 @@ public abstract class AbstractRayRuntime implements RayRuntime {
}
@Override
public RayObject call(RayFunc func, RayActor<?> actor, Object[] args) {
public RayObject callActor(RayFunc func, RayActor<?> actor, Object[] args) {
FunctionDescriptor functionDescriptor =
functionManager.getFunction(workerContext.getCurrentJobId(), func)
.functionDescriptor;
@@ -149,8 +149,8 @@ public class RayMultiWorkerNativeRuntime implements RayRuntime {
}
@Override
public RayObject call(RayFunc func, RayActor<?> actor, Object[] args) {
return getCurrentRuntime().call(func, actor, args);
public RayObject callActor(RayFunc func, RayActor<?> actor, Object[] args) {
return getCurrentRuntime().callActor(func, actor, args);
}
@Override
@@ -3,7 +3,6 @@ package org.ray.runtime.functionmanager;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import org.ray.api.annotation.RayRemote;
/**
* Represents a Ray function (either a Method or a Constructor in Java) and its metadata.
@@ -57,21 +56,6 @@ public class RayFunction {
return functionDescriptor;
}
public RayRemote getRayRemoteAnnotation() {
RayRemote rayRemote;
// If this method is a constructor, the task of it should be a actorCreationTask.
// And the annotation of actorCreationTask should inherit from class.
// Otherwise, it's a normal method, and it shouldn't inherit annotation from class.
if (isConstructor()) {
rayRemote = executable.getDeclaringClass().getAnnotation(RayRemote.class);
} else {
rayRemote = executable.getAnnotation(RayRemote.class);
}
return rayRemote;
}
/**
* @return Whether this function has a return value.
*/
@@ -8,18 +8,18 @@ import java.util.List;
import org.apache.commons.io.FileUtils;
/**
* A util class that generates `RayCall.java`, which provides type-safe interfaces for `Ray.call`
* and `Ray.createActor`.
* A util class that generates `RayCall.java` and `ActorCall.java`, which provide type-safe
* interfaces for `Ray.call`, `Ray.createActor` and `actor.call`.
*/
public class RayCallGenerator extends BaseGenerator {
/**
* @return Whole file content of `RayCall.java`.
*/
private String build() {
private String generateRayCallDotJava() {
sb = new StringBuilder();
newLine("// generated automatically, do not modify.");
newLine("// Generated by `RayCallGenerator.java`. DO NOT EDIT.");
newLine("");
newLine("package org.ray.api;");
newLine("");
@@ -48,13 +48,6 @@ public class RayCallGenerator extends BaseGenerator {
buildCalls(i, false, false, false, true);
}
newLine(1, "// ===========================================");
newLine(1, "// Methods for remote actor method invocation.");
newLine(1, "// ===========================================");
for (int i = 0; i <= MAX_PARAMETERS - 1; i++) {
buildCalls(i, true, false, true, false);
buildCalls(i, true, false, false, false);
}
newLine(1, "// ===========================");
newLine(1, "// Methods for actor creation.");
newLine(1, "// ===========================");
@@ -70,6 +63,7 @@ public class RayCallGenerator extends BaseGenerator {
buildPyCalls(i, false, false, false);
buildPyCalls(i, false, false, true);
}
// TODO(hchen): move Python actor call API to `RayPyActor` class.
for (int i = 0; i <= MAX_PARAMETERS - 1; i++) {
buildPyCalls(i, true, false, false);
}
@@ -82,30 +76,61 @@ public class RayCallGenerator extends BaseGenerator {
}
/**
* Build the `Ray.call` or `Ray.createActor` methods with the given number of parameters.
* @return Whole file content of `ActorCall.java`.
*/
private String generateActorCallDotJava() {
sb = new StringBuilder();
newLine("// Generated by `RayCallGenerator.java`. DO NOT EDIT.");
newLine("");
newLine("package org.ray.api;");
newLine("");
for (int i = 1; i <= MAX_PARAMETERS; i++) {
newLine("import org.ray.api.function.RayFunc" + i + ";");
}
for (int i = 1; i <= MAX_PARAMETERS; i++) {
newLine("import org.ray.api.function.RayFuncVoid" + i + ";");
}
newLine("");
newLine("/**");
newLine(" * This class provides type-safe interfaces for remote actor calls.");
newLine(" **/");
newLine("@SuppressWarnings({\"rawtypes\", \"unchecked\"})");
newLine("interface ActorCall<A> {");
newLine("");
for (int i = 0; i <= MAX_PARAMETERS - 1; i++) {
buildCalls(i, true, false, true, false);
buildCalls(i, true, false, false, false);
}
newLine("}");
return sb.toString();
}
/**
* Build `Ray.call`, `Ray.createActor` and `actor.call` methods with
* the given number of parameters.
*
* @param numParameters the number of parameters
* @param forActor build actor api when true, otherwise build task api.
* @param hasReturn if true, build api for functions with return.
* @param forActorCreation build `Ray.createActor` when true, otherwise build `Ray.call`.
* @param forActor Build `actor.call` when true, otherwise build `Ray.call`.
* @param hasReturn if true, Build api for functions with return.
* @param forActorCreation Build `Ray.createActor` when true, otherwise build `Ray.call`.
*/
private void buildCalls(int numParameters, boolean forActor,
boolean forActorCreation, boolean hasReturn, boolean hasOptionsParam) {
// Template of the generated function:
// public static [genericTypes] [returnType] [callFunc]([argsDeclaration]) {
// [modifiers] [genericTypes] [returnType] [callFunc]([argsDeclaration]) {
// Objects[] args = new Object[]{[args]};
// return Ray.internal().[callFunc](f[, actor], args[, options]);
// return Ray.internal().[callFunc](f[, getThis()], args[, options]);
// }
String modifiers = forActor ? "default" : "public static";
// 1) Construct the `genericTypes` part, e.g. `<T0, T1, T2, R>`.
String genericTypes = "";
for (int i = 0; i < numParameters; i++) {
genericTypes += "T" + i + ", ";
}
if (forActor) {
// Actor generic type.
genericTypes = "A, " + genericTypes;
}
// Return generic type.
if (forActorCreation) {
genericTypes += "A, ";
@@ -129,15 +154,21 @@ public class RayCallGenerator extends BaseGenerator {
}
// 3) Construct the `argsDeclaration` part.
String rayFuncGenericTypes = genericTypes;
if (forActor) {
if (rayFuncGenericTypes.isEmpty()) {
rayFuncGenericTypes = "<A>";
} else {
rayFuncGenericTypes = rayFuncGenericTypes.replace("<", "<A, ");
}
}
String argsDeclarationPrefix = String.format("RayFunc%s%d%s f, ",
hasReturn ? "" : "Void",
!forActor ? numParameters : numParameters + 1,
genericTypes);
if (forActor) {
argsDeclarationPrefix += "RayActor<A> actor, ";
}
rayFuncGenericTypes);
String callFunc = forActorCreation ? "createActor" : "call";
String internalCallFunc = forActorCreation ? "createActor" : forActor ? "callActor" : "call";
// Enumerate all combinations of the parameters.
for (String param : generateParameters(numParameters)) {
@@ -150,7 +181,7 @@ public class RayCallGenerator extends BaseGenerator {
argsDeclaration = argsDeclaration.substring(0, argsDeclaration.length() - 2);
// Print the first line (method signature).
newLine(1, String.format(
"public static%s %s %s(%s) {",
"%s%s %s %s(%s) {", modifiers,
genericTypes.isEmpty() ? "" : " " + genericTypes, returnType, callFunc, argsDeclaration
));
@@ -169,22 +200,23 @@ public class RayCallGenerator extends BaseGenerator {
// 5) Construct the third line.
String callFuncArgs = "f, ";
if (forActor) {
callFuncArgs += "actor, ";
callFuncArgs += "(RayActor) this, ";
}
callFuncArgs += "args, ";
callFuncArgs += forActor ? "" : hasOptionsParam ? "options, " : "null, ";
callFuncArgs = callFuncArgs.substring(0, callFuncArgs.length() - 2);
newLine(2, String.format("%sRay.internal().%s(%s);",
hasReturn ? "return " : "", callFunc, callFuncArgs));
hasReturn ? "return " : "", internalCallFunc, callFuncArgs));
newLine(1, "}");
newLine("");
}
}
/**
* Build the `Ray.callPy` or `Ray.createPyActor` methods.
*
* @param forActor build actor api when true, otherwise build task api.
* @param forActorCreation build `Ray.createPyActor` when true, otherwise build `Ray.callPy`.
* @param forActor Build actor api when true, otherwise build task api.
* @param forActorCreation Build `Ray.createPyActor` when true, otherwise build `Ray.callPy`.
*/
private void buildPyCalls(int numParameters, boolean forActor,
boolean forActorCreation, boolean hasOptionsParam) {
@@ -269,7 +301,12 @@ public class RayCallGenerator extends BaseGenerator {
public static void main(String[] args) throws IOException {
String path = System.getProperty("user.dir")
+ "/api/src/main/java/org/ray/api/RayCall.java";
FileUtils.write(new File(path), new RayCallGenerator().build(), Charset.defaultCharset());
FileUtils.write(new File(path), new RayCallGenerator().generateRayCallDotJava(),
Charset.defaultCharset());
path = System.getProperty("user.dir")
+ "/api/src/main/java/org/ray/api/ActorCall.java";
FileUtils.write(new File(path), new RayCallGenerator().generateActorCallDotJava(),
Charset.defaultCharset());
}
}
@@ -9,7 +9,6 @@ import javax.tools.ToolProvider;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.ray.api.annotation.RayRemote;
import org.ray.api.function.RayFunc0;
import org.ray.api.function.RayFunc1;
import org.ray.api.id.JobId;
@@ -23,12 +22,10 @@ import org.testng.annotations.Test;
*/
public class FunctionManagerTest {
@RayRemote
public static Object foo() {
return null;
}
@RayRemote
public static class Bar {
public Bar() {
@@ -81,19 +78,16 @@ public class FunctionManagerTest {
RayFunction func = functionManager.getFunction(JobId.NIL, fooFunc);
Assert.assertFalse(func.isConstructor());
Assert.assertEquals(func.getFunctionDescriptor(), fooDescriptor);
Assert.assertNotNull(func.getRayRemoteAnnotation());
// Test actor method
func = functionManager.getFunction(JobId.NIL, barFunc);
Assert.assertFalse(func.isConstructor());
Assert.assertEquals(func.getFunctionDescriptor(), barDescriptor);
Assert.assertNull(func.getRayRemoteAnnotation());
// Test actor constructor
func = functionManager.getFunction(JobId.NIL, barConstructor);
Assert.assertTrue(func.isConstructor());
Assert.assertEquals(func.getFunctionDescriptor(), barConstructorDescriptor);
Assert.assertNotNull(func.getRayRemoteAnnotation());
}
@Test
@@ -103,19 +97,16 @@ public class FunctionManagerTest {
RayFunction func = functionManager.getFunction(JobId.NIL, fooDescriptor);
Assert.assertFalse(func.isConstructor());
Assert.assertEquals(func.getFunctionDescriptor(), fooDescriptor);
Assert.assertNotNull(func.getRayRemoteAnnotation());
// Test actor method
func = functionManager.getFunction(JobId.NIL, barDescriptor);
Assert.assertFalse(func.isConstructor());
Assert.assertEquals(func.getFunctionDescriptor(), barDescriptor);
Assert.assertNull(func.getRayRemoteAnnotation());
// Test actor constructor
func = functionManager.getFunction(JobId.NIL, barConstructorDescriptor);
Assert.assertTrue(func.isConstructor());
Assert.assertEquals(func.getFunctionDescriptor(), barConstructorDescriptor);
Assert.assertNotNull(func.getRayRemoteAnnotation());
// Test raise overload exception
Assert.expectThrows(RuntimeException.class, () -> {