chore: import upstream snapshot with attribution
This commit is contained in:
+480
@@ -0,0 +1,480 @@
|
||||
# Bazel build
|
||||
# C/C++ documentation: https://docs.bazel.build/versions/master/be/c-cpp.html
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")
|
||||
load("@rules_pkg//pkg:mappings.bzl", "pkg_attributes", "pkg_files")
|
||||
load("@rules_pkg//pkg:zip.bzl", "pkg_zip")
|
||||
load("@rules_python//python:defs.bzl", "py_binary", "py_test")
|
||||
load("//bazel:python.bzl", "py_test_module_list")
|
||||
load("//bazel:ray.bzl", "COPTS")
|
||||
|
||||
cc_binary(
|
||||
name = "libray_api.so",
|
||||
copts = COPTS,
|
||||
linkopts = select({
|
||||
"@platforms//os:osx": [
|
||||
#TODO(larry): Hide the symbols when we make it work on mac.
|
||||
],
|
||||
"@platforms//os:windows": [
|
||||
#TODO(larry): Hide the symbols when we make it work on Windows.
|
||||
],
|
||||
"//conditions:default": [
|
||||
"-Wl,--version-script,$(location :symbols/ray_api_exported_symbols_linux.lds)",
|
||||
],
|
||||
}),
|
||||
linkshared = 1,
|
||||
linkstatic = 1,
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":ray_api_lib",
|
||||
":symbols/ray_api_exported_symbols_linux.lds",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "ray_api_lib",
|
||||
srcs = glob([
|
||||
"src/ray/api/*.cc",
|
||||
"src/ray/api/*.h",
|
||||
"src/ray/app/*.cc",
|
||||
"src/ray/app/*.h",
|
||||
"src/ray/runtime/*.cc",
|
||||
"src/ray/runtime/*.h",
|
||||
"src/ray/runtime/**/*.cc",
|
||||
"src/ray/runtime/**/*.h",
|
||||
"src/ray/runtime/task/*.cc",
|
||||
"src/ray/runtime/task/*.h",
|
||||
"src/ray/util/*.cc",
|
||||
"src/ray/util/*.h",
|
||||
"src/ray/*.cc",
|
||||
"src/ray/*.h",
|
||||
]),
|
||||
hdrs = glob([
|
||||
"include/ray/*.h",
|
||||
"include/ray/**/*.h",
|
||||
"include/ray/**/**/*.h",
|
||||
]),
|
||||
copts = COPTS,
|
||||
linkopts = ["-ldl"],
|
||||
linkstatic = True,
|
||||
strip_include_prefix = "include",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//src/ray/asio:instrumented_io_context",
|
||||
"//src/ray/common:constants",
|
||||
"//src/ray/common:id",
|
||||
"//src/ray/common:ray_config",
|
||||
"//src/ray/common:task_common",
|
||||
"//src/ray/core_worker:core_worker_lib",
|
||||
"//src/ray/gcs_rpc_client:global_state_accessor_lib",
|
||||
"//src/ray/util:cmd_line_utils",
|
||||
"//src/ray/util:network_util",
|
||||
"//src/ray/util:process",
|
||||
"//src/ray/util:process_interface",
|
||||
"@boost//:callable_traits",
|
||||
"@boost//:dll",
|
||||
"@com_google_absl//absl/flags:flag",
|
||||
"@com_google_absl//absl/flags:parse",
|
||||
"@msgpack",
|
||||
"@nlohmann_json",
|
||||
],
|
||||
alwayslink = True,
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "ray_cpp_lib",
|
||||
srcs = [
|
||||
"libray_api.so",
|
||||
],
|
||||
hdrs = glob([
|
||||
"include/ray/*.h",
|
||||
"include/ray/**/*.h",
|
||||
"include/ray/**/**/*.h",
|
||||
]),
|
||||
strip_include_prefix = "include",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "default_worker",
|
||||
srcs = [
|
||||
"src/ray/worker/default_worker.cc",
|
||||
],
|
||||
copts = COPTS,
|
||||
linkstatic = True,
|
||||
deps = select({
|
||||
"@platforms//os:windows": [
|
||||
# TODO(SongGuyang): Change to use dynamic library
|
||||
# "ray_cpp_lib" when we make it work on Windows.
|
||||
"ray_api_lib",
|
||||
],
|
||||
"//conditions:default": [
|
||||
"ray_cpp_lib",
|
||||
"@boost//:callable_traits",
|
||||
"@boost//:optional",
|
||||
"@msgpack",
|
||||
"@nlohmann_json",
|
||||
],
|
||||
}),
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "ray_cpp_pkg_files",
|
||||
srcs = [
|
||||
"default_worker",
|
||||
"libray_api.so",
|
||||
],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "ray_cpp_hdrs",
|
||||
srcs = ["include/ray/api.h"] + glob([
|
||||
"include/ray/api/*.h",
|
||||
]),
|
||||
prefix = "ray/cpp/include/",
|
||||
strip_prefix = "include",
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "example_files",
|
||||
srcs = glob(["example/*"]),
|
||||
prefix = "ray/cpp/example/",
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "msgpack_hdrs_files",
|
||||
srcs = ["@msgpack//:msgpack_hdrs"],
|
||||
prefix = "ray/cpp/include/",
|
||||
strip_prefix = "include",
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "nlohmann_json_hdrs_files",
|
||||
srcs = ["@nlohmann_json//:nlohmann_json_hdrs"],
|
||||
prefix = "ray/cpp/include/",
|
||||
strip_prefix = "single_include",
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "boost_ray_hdrs_files",
|
||||
srcs = ["@boost//:boost_ray_hdrs"],
|
||||
prefix = "ray/cpp/include/boost/",
|
||||
strip_prefix = "boost",
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "default_worker_files",
|
||||
srcs = ["default_worker"],
|
||||
attributes = pkg_attributes(mode = "755"),
|
||||
prefix = "ray/cpp/",
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "libray_api_files",
|
||||
srcs = ["libray_api.so"],
|
||||
attributes = pkg_attributes(mode = "755"),
|
||||
prefix = "ray/cpp/lib/",
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
pkg_zip(
|
||||
name = "ray_cpp_pkg_zip",
|
||||
srcs = [
|
||||
":boost_ray_hdrs_files",
|
||||
":default_worker_files",
|
||||
":example_files",
|
||||
":libray_api_files",
|
||||
":msgpack_hdrs_files",
|
||||
":nlohmann_json_hdrs_files",
|
||||
":ray_cpp_hdrs",
|
||||
],
|
||||
out = "ray_cpp_pkg.zip",
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
py_binary(
|
||||
name = "gen_ray_cpp_pkg",
|
||||
srcs = ["gen_ray_cpp_pkg.py"],
|
||||
data = [
|
||||
":ray_cpp_pkg.zip",
|
||||
],
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//bazel:gen_extract",
|
||||
],
|
||||
)
|
||||
|
||||
# test
|
||||
cc_test(
|
||||
name = "api_test",
|
||||
srcs = glob([
|
||||
"src/ray/test/*.cc",
|
||||
]),
|
||||
copts = COPTS,
|
||||
linkstatic = True,
|
||||
tags = ["team:core"],
|
||||
deps = [
|
||||
"ray_api_lib",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "cluster_mode_test",
|
||||
srcs = glob(
|
||||
[
|
||||
"src/ray/test/cluster/*.cc",
|
||||
"src/ray/test/cluster/*.h",
|
||||
],
|
||||
exclude = [
|
||||
"src/ray/test/cluster/cluster_mode_xlang_test.cc",
|
||||
],
|
||||
),
|
||||
args = [
|
||||
"--ray_code_search_path=$(location plus.so):$(location counter.so):cpp/src/ray/test/cluster",
|
||||
"--ray_head_args '--include-dashboard false'",
|
||||
],
|
||||
copts = COPTS,
|
||||
data = [
|
||||
"counter.so",
|
||||
"plus.so",
|
||||
"src/ray/test/cluster/test_cross_language_invocation.py",
|
||||
":ray_cpp_pkg_files",
|
||||
],
|
||||
linkstatic = True,
|
||||
tags = ["team:core"],
|
||||
deps = [
|
||||
"ray_api_lib",
|
||||
"//src/ray/util:network_util",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "cluster_mode_xlang_test",
|
||||
srcs = [
|
||||
"src/ray/test/cluster/cluster_mode_xlang_test.cc",
|
||||
] + glob([
|
||||
"src/ray/test/cluster/*.h",
|
||||
]),
|
||||
args = [
|
||||
"--ray_code_search_path=$(location //java:libio_ray_ray_test.jar)",
|
||||
"--ray_head_args '--include-dashboard false'",
|
||||
],
|
||||
copts = COPTS,
|
||||
data = [
|
||||
":ray_cpp_pkg_files",
|
||||
"//java:libio_ray_ray_test.jar",
|
||||
],
|
||||
linkstatic = True,
|
||||
tags = [
|
||||
"no_macos",
|
||||
"team:core",
|
||||
],
|
||||
deps = [
|
||||
"ray_api_lib",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "plus.so",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"src/ray/test/cluster/plus.cc",
|
||||
"src/ray/test/cluster/plus.h",
|
||||
],
|
||||
copts = COPTS,
|
||||
linkopts = ["-shared"],
|
||||
linkstatic = True,
|
||||
# NOTE(WangTaoTheTonic): For java x-lang tests. See //java:all_tests
|
||||
# and `CrossLanguageInvocationTest.java`.
|
||||
visibility = ["//java:__subpackages__"],
|
||||
deps = [
|
||||
"ray_cpp_lib",
|
||||
"@boost//:callable_traits",
|
||||
"@boost//:optional",
|
||||
"@msgpack",
|
||||
"@nlohmann_json",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "counter.so",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"src/ray/test/cluster/counter.cc",
|
||||
"src/ray/test/cluster/counter.h",
|
||||
],
|
||||
copts = COPTS,
|
||||
linkopts = ["-shared"],
|
||||
linkstatic = True,
|
||||
# NOTE(WangTaoTheTonic): For java x-lang tests. See //java:all_tests
|
||||
# and `CrossLanguageInvocationTest.java`.
|
||||
visibility = ["//java:__subpackages__"],
|
||||
deps = [
|
||||
"ray_cpp_lib",
|
||||
"@boost//:callable_traits",
|
||||
"@boost//:optional",
|
||||
"@msgpack",
|
||||
"@nlohmann_json",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "simple_kv_store",
|
||||
srcs = [
|
||||
"src/ray/test/examples/simple_kv_store.cc",
|
||||
],
|
||||
args = [
|
||||
"--ray_code_search_path=$(location simple_kv_store.so)",
|
||||
"--ray_head_args '--include-dashboard false'",
|
||||
],
|
||||
copts = COPTS,
|
||||
data = [
|
||||
"simple_kv_store.so",
|
||||
],
|
||||
linkstatic = True,
|
||||
tags = ["team:core"],
|
||||
deps = [
|
||||
"ray_api_lib",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "simple_kv_store.so",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"src/ray/test/examples/simple_kv_store.cc",
|
||||
],
|
||||
copts = COPTS,
|
||||
linkopts = ["-shared"],
|
||||
linkstatic = True,
|
||||
deps = [
|
||||
"ray_cpp_lib",
|
||||
"@boost//:callable_traits",
|
||||
"@boost//:optional",
|
||||
"@msgpack",
|
||||
"@nlohmann_json",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "simple_job",
|
||||
srcs = [
|
||||
"src/ray/test/examples/simple_job.cc",
|
||||
],
|
||||
copts = COPTS,
|
||||
data = [
|
||||
"simple_job.so",
|
||||
],
|
||||
linkstatic = True,
|
||||
tags = ["team:core"],
|
||||
deps = [
|
||||
":ray_api_lib",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "simple_job.so",
|
||||
srcs = [
|
||||
"src/ray/test/examples/simple_job.cc",
|
||||
],
|
||||
copts = COPTS,
|
||||
linkopts = ["-shared"],
|
||||
linkstatic = True,
|
||||
deps = [
|
||||
"ray_cpp_lib",
|
||||
"@boost//:callable_traits",
|
||||
"@boost//:optional",
|
||||
"@msgpack",
|
||||
"@nlohmann_json",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "metric_example",
|
||||
srcs = [
|
||||
"src/ray/test/examples/metric_example.cc",
|
||||
],
|
||||
args = [
|
||||
"--ray_code_search_path $(location metric_example.so)",
|
||||
],
|
||||
data = [
|
||||
"metric_example.so",
|
||||
],
|
||||
linkstatic = True,
|
||||
tags = ["team:core"],
|
||||
deps = [
|
||||
"ray_cpp_lib",
|
||||
"@boost//:callable_traits",
|
||||
"@boost//:optional",
|
||||
"@com_google_absl//absl/flags:flag",
|
||||
"@com_google_absl//absl/flags:parse",
|
||||
"@msgpack",
|
||||
"@nlohmann_json",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "metric_example.so",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"src/ray/test/examples/metric_example.cc",
|
||||
],
|
||||
linkopts = ["-shared"],
|
||||
linkstatic = True,
|
||||
deps = [
|
||||
"ray_cpp_lib",
|
||||
"@boost//:callable_traits",
|
||||
"@boost//:optional",
|
||||
"@com_google_absl//absl/flags:flag",
|
||||
"@com_google_absl//absl/flags:parse",
|
||||
"@msgpack",
|
||||
"@nlohmann_json",
|
||||
],
|
||||
)
|
||||
|
||||
py_test_module_list(
|
||||
size = "medium",
|
||||
data = [
|
||||
"counter.so",
|
||||
"plus.so",
|
||||
],
|
||||
extra_srcs = [],
|
||||
files = [
|
||||
"test_python_call_cpp.py",
|
||||
],
|
||||
tags = [
|
||||
"exclusive",
|
||||
"medium_size_python_tests",
|
||||
"team:core",
|
||||
],
|
||||
deps = [],
|
||||
)
|
||||
|
||||
py_test(
|
||||
name = "test_submit_cpp_job",
|
||||
size = "medium",
|
||||
srcs = ["test_submit_cpp_job.py"],
|
||||
data = [
|
||||
"simple_job",
|
||||
"simple_job.so",
|
||||
],
|
||||
env = {
|
||||
"SIMPLE_DRIVER_SO_PATH": "$(location simple_job.so)",
|
||||
"SIMPLE_DRIVER_MAIN_PATH": "$(location simple_job)",
|
||||
},
|
||||
tags = [
|
||||
# TODO(ray-core): fix this test on apple silicon macos.
|
||||
"no_macos",
|
||||
"team:core",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,2 @@
|
||||
build --cxxopt="-std=c++17"
|
||||
build --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"
|
||||
@@ -0,0 +1,43 @@
|
||||
"""BUILD rules for Ray C++ examples."""
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
|
||||
|
||||
cc_binary(
|
||||
name = "example",
|
||||
srcs = glob([
|
||||
"*.cc",
|
||||
]),
|
||||
data = [
|
||||
"example.so",
|
||||
],
|
||||
linkstatic = True,
|
||||
deps = [
|
||||
":ray_api",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "example.so",
|
||||
srcs = glob([
|
||||
"*.cc",
|
||||
]),
|
||||
linkopts = ["-shared"],
|
||||
linkstatic = True,
|
||||
deps = [
|
||||
":ray_api",
|
||||
],
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "ray_api",
|
||||
srcs = [
|
||||
"thirdparty/lib/libray_api.so",
|
||||
],
|
||||
hdrs = glob([
|
||||
"thirdparty/include/**/*.h",
|
||||
"thirdparty/include/**/*.hpp",
|
||||
]),
|
||||
linkopts = ["-Wl,-rpath,./"],
|
||||
strip_include_prefix = "thirdparty/include",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
@@ -0,0 +1,59 @@
|
||||
/// This is an example of Ray C++ application. Please visit
|
||||
/// `https://docs.ray.io/en/master/ray-core/walkthrough.html#installation`
|
||||
/// for more details.
|
||||
|
||||
/// including the `<ray/api.h>` header
|
||||
#include <ray/api.h>
|
||||
|
||||
/// common function
|
||||
int Plus(int x, int y) { return x + y; }
|
||||
/// Declare remote function
|
||||
RAY_REMOTE(Plus);
|
||||
|
||||
/// class
|
||||
class Counter {
|
||||
public:
|
||||
int count;
|
||||
|
||||
Counter(int init) { count = init; }
|
||||
/// static factory method
|
||||
static Counter *FactoryCreate(int init) { return new Counter(init); }
|
||||
|
||||
/// non static function
|
||||
int Add(int x) {
|
||||
count += x;
|
||||
return count;
|
||||
}
|
||||
};
|
||||
/// Declare remote function
|
||||
RAY_REMOTE(Counter::FactoryCreate, &Counter::Add);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
/// initialization
|
||||
ray::Init();
|
||||
|
||||
/// put and get object
|
||||
auto object = ray::Put(100);
|
||||
auto put_get_result = *(ray::Get(object));
|
||||
std::cout << "put_get_result = " << put_get_result << std::endl;
|
||||
|
||||
/// common task
|
||||
auto task_object = ray::Task(Plus).Remote(1, 2);
|
||||
int task_result = *(ray::Get(task_object));
|
||||
std::cout << "task_result = " << task_result << std::endl;
|
||||
|
||||
/// actor
|
||||
ray::ActorHandle<Counter> actor = ray::Actor(Counter::FactoryCreate).Remote(0);
|
||||
/// actor task
|
||||
auto actor_object = actor.Task(&Counter::Add).Remote(3);
|
||||
int actor_task_result = *(ray::Get(actor_object));
|
||||
std::cout << "actor_task_result = " << actor_task_result << std::endl;
|
||||
/// actor task with reference argument
|
||||
auto actor_object2 = actor.Task(&Counter::Add).Remote(task_object);
|
||||
int actor_task_result2 = *(ray::Get(actor_object2));
|
||||
std::cout << "actor_task_result2 = " << actor_task_result2 << std::endl;
|
||||
|
||||
/// shutdown
|
||||
ray::Shutdown();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
#Cause the script to exit if a single command fails.
|
||||
set -e
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE:-$0}")" || exit; pwd)"
|
||||
|
||||
bazel --nosystem_rc --nohome_rc build //:example
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
DYLD_LIBRARY_PATH="$ROOT_DIR/thirdparty/lib" "${ROOT_DIR}"/bazel-bin/example
|
||||
else
|
||||
LD_LIBRARY_PATH="$ROOT_DIR/thirdparty/lib" "${ROOT_DIR}"/bazel-bin/example
|
||||
fi
|
||||
@@ -0,0 +1,11 @@
|
||||
from bazel.gen_extract import gen_extract
|
||||
|
||||
if __name__ == "__main__":
|
||||
gen_extract(
|
||||
[
|
||||
"cpp/ray_cpp_pkg.zip",
|
||||
],
|
||||
clear_dir_first=[
|
||||
"ray/cpp",
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,402 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/actor_creator.h>
|
||||
#include <ray/api/actor_handle.h>
|
||||
#include <ray/api/actor_task_caller.h>
|
||||
#include <ray/api/function_manager.h>
|
||||
#include <ray/api/logging.h>
|
||||
#include <ray/api/object_ref.h>
|
||||
#include <ray/api/ray_config.h>
|
||||
#include <ray/api/ray_remote.h>
|
||||
#include <ray/api/ray_runtime.h>
|
||||
#include <ray/api/ray_runtime_holder.h>
|
||||
#include <ray/api/runtime_env.h>
|
||||
#include <ray/api/task_caller.h>
|
||||
#include <ray/api/wait_result.h>
|
||||
|
||||
#include <boost/callable_traits.hpp>
|
||||
#include <memory>
|
||||
#include <msgpack.hpp>
|
||||
#include <mutex>
|
||||
|
||||
namespace ray {
|
||||
|
||||
/// Initialize Ray runtime with config.
|
||||
void Init(ray::RayConfig &config);
|
||||
|
||||
/// Initialize Ray runtime with config and command-line arguments.
|
||||
/// If a parameter is explicitly set in command-line arguments, the parameter value will
|
||||
/// be overwritten.
|
||||
void Init(ray::RayConfig &config, int argc, char **argv);
|
||||
|
||||
/// Initialize Ray runtime with default config.
|
||||
void Init();
|
||||
|
||||
/// Check if ray::Init has been called yet.
|
||||
bool IsInitialized();
|
||||
|
||||
/// Shutdown Ray runtime.
|
||||
void Shutdown();
|
||||
|
||||
/// Store an object in the object store.
|
||||
///
|
||||
/// \param[in] obj The object which should be stored.
|
||||
/// \return ObjectRef A reference to the object in the object store.
|
||||
template <typename T>
|
||||
ray::ObjectRef<T> Put(const T &obj);
|
||||
|
||||
/// Get a single object from the object store.
|
||||
/// This method will be blocked until the object is ready.
|
||||
///
|
||||
/// \param[in] object The object reference which should be returned.
|
||||
/// \return shared pointer of the result.
|
||||
template <typename T>
|
||||
std::shared_ptr<T> Get(const ray::ObjectRef<T> &object);
|
||||
|
||||
/// Get a list of objects from the object store.
|
||||
/// This method will be blocked until all the objects are ready.
|
||||
///
|
||||
/// \param[in] objects The object array which should be got.
|
||||
/// \return shared pointer array of the result.
|
||||
template <typename T>
|
||||
std::vector<std::shared_ptr<T>> Get(const std::vector<ray::ObjectRef<T>> &objects);
|
||||
|
||||
/// Get a single object from the object store.
|
||||
/// This method will be blocked until the object is ready.
|
||||
///
|
||||
/// \param[in] object The object reference which should be returned.
|
||||
/// \param[in] timeout_ms The maximum amount of time in milliseconds to wait before
|
||||
/// returning.
|
||||
/// \return shared pointer of the result.
|
||||
template <typename T>
|
||||
std::shared_ptr<T> Get(const ray::ObjectRef<T> &object, const int &timeout_ms);
|
||||
|
||||
/// Get a list of objects from the object store.
|
||||
/// This method will be blocked until all the objects are ready.
|
||||
///
|
||||
/// \param[in] objects The object array which should be got.
|
||||
/// \param[in] timeout_ms The maximum amount of time in milliseconds to wait before
|
||||
/// returning.
|
||||
/// \return shared pointer array of the result.
|
||||
template <typename T>
|
||||
std::vector<std::shared_ptr<T>> Get(const std::vector<ray::ObjectRef<T>> &objects,
|
||||
const int &timeout_ms);
|
||||
|
||||
/// Wait for a list of objects to be locally available,
|
||||
/// until specified number of objects are ready, or specified timeout has passed.
|
||||
///
|
||||
/// \param[in] objects The object array which should be waited.
|
||||
/// \param[in] num_objects The minimum number of objects to wait.
|
||||
/// \param[in] timeout_ms The maximum wait time in milliseconds.
|
||||
/// \return Two arrays, one containing locally available objects, one containing the
|
||||
/// rest.
|
||||
template <typename T>
|
||||
WaitResult<T> Wait(const std::vector<ray::ObjectRef<T>> &objects,
|
||||
int num_objects,
|
||||
int timeout_ms);
|
||||
|
||||
/// Create a `TaskCaller` for calling remote function.
|
||||
/// It is used for normal task, such as ray::Task(Plus1).Remote(1),
|
||||
/// ray::Task(Plus).Remote(1, 2).
|
||||
/// \param[in] func The function to be remote executed.
|
||||
/// \return TaskCaller.
|
||||
template <typename F>
|
||||
ray::internal::TaskCaller<F> Task(F func);
|
||||
|
||||
template <typename R>
|
||||
ray::internal::TaskCaller<PyFunction<R>> Task(PyFunction<R> func);
|
||||
|
||||
template <typename R>
|
||||
ray::internal::TaskCaller<JavaFunction<R>> Task(JavaFunction<R> func);
|
||||
|
||||
/// Generic version of creating an actor
|
||||
/// It is used for creating an actor, such as: ActorCreator<Counter> creator =
|
||||
/// ray::Actor(Counter::FactoryCreate<int>).Remote(1);
|
||||
template <typename F>
|
||||
ray::internal::ActorCreator<F> Actor(F create_func);
|
||||
|
||||
ray::internal::ActorCreator<PyActorClass> Actor(PyActorClass func);
|
||||
|
||||
ray::internal::ActorCreator<JavaActorClass> Actor(JavaActorClass func);
|
||||
|
||||
/// Get a handle to a named actor in current namespace.
|
||||
/// The actor must have been created with name specified.
|
||||
///
|
||||
/// \param[in] actor_name The name of the named actor.
|
||||
/// \return An ActorHandle to the actor if the actor of specified name exists or an
|
||||
/// empty optional object.
|
||||
template <typename T>
|
||||
boost::optional<ActorHandle<T>> GetActor(const std::string &actor_name);
|
||||
|
||||
/// Get a handle to a named actor in the given namespace.
|
||||
/// The actor must have been created with name specified.
|
||||
///
|
||||
/// \param[in] actor_name The name of the named actor.
|
||||
/// \param[in] namespace The namespace of the actor.
|
||||
/// \return An ActorHandle to the actor if the actor of specified name exists in
|
||||
/// specifiled namespace or an empty optional object.
|
||||
template <typename T>
|
||||
boost::optional<ActorHandle<T>> GetActor(const std::string &actor_name,
|
||||
const std::string &ray_namespace);
|
||||
|
||||
/// Intentionally exit the current actor.
|
||||
/// It is used to disconnect an actor and exit the worker.
|
||||
/// \Throws RayException if the current process is a driver or the current worker is not
|
||||
/// an actor.
|
||||
void ExitActor();
|
||||
|
||||
template <typename T>
|
||||
std::vector<std::shared_ptr<T>> Get(const std::vector<std::string> &ids);
|
||||
|
||||
template <typename T>
|
||||
std::vector<std::shared_ptr<T>> Get(const std::vector<std::string> &ids,
|
||||
const int &timeout_ms);
|
||||
|
||||
/// Create a placement group on remote nodes.
|
||||
///
|
||||
/// \param[in] create_options Creation options of the placement group.
|
||||
/// \return A PlacementGroup to the created placement group.
|
||||
PlacementGroup CreatePlacementGroup(
|
||||
const ray::PlacementGroupCreationOptions &create_options);
|
||||
|
||||
/// Remove a placement group by id.
|
||||
///
|
||||
/// \param[in] placement_group_id Id of the placement group.
|
||||
void RemovePlacementGroup(const std::string &placement_group_id);
|
||||
|
||||
std::vector<PlacementGroup> GetAllPlacementGroups();
|
||||
|
||||
/// Get a placement group by id.
|
||||
PlacementGroup GetPlacementGroupById(const std::string &id);
|
||||
|
||||
/// Get a placement group by name.
|
||||
PlacementGroup GetPlacementGroup(const std::string &name);
|
||||
|
||||
/// Returns true if the current actor was restarted, otherwise false.
|
||||
bool WasCurrentActorRestarted();
|
||||
|
||||
/// Get the namespace of this job.
|
||||
std::string GetNamespace();
|
||||
|
||||
// --------- inline implementation ------------
|
||||
|
||||
template <typename T>
|
||||
inline std::vector<std::string> ObjectRefsToObjectIDs(
|
||||
const std::vector<ray::ObjectRef<T>> &object_refs) {
|
||||
std::vector<std::string> object_ids;
|
||||
for (auto it = object_refs.begin(); it != object_refs.end(); it++) {
|
||||
object_ids.push_back(it->ID());
|
||||
}
|
||||
return object_ids;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ray::ObjectRef<T> Put(const T &obj) {
|
||||
auto buffer =
|
||||
std::make_shared<msgpack::sbuffer>(ray::internal::Serializer::Serialize(obj));
|
||||
auto id = ray::internal::GetRayRuntime()->Put(buffer);
|
||||
auto ref = ObjectRef<T>(id);
|
||||
// The core worker will add an initial ref to the put ID to
|
||||
// keep it in scope. Now that we've created the frontend
|
||||
// ObjectRef, remove this initial ref.
|
||||
ray::internal::GetRayRuntime()->RemoveLocalReference(id);
|
||||
return ref;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::shared_ptr<T> Get(const ray::ObjectRef<T> &object, const int &timeout_ms) {
|
||||
return GetFromRuntime(object, timeout_ms);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::vector<std::shared_ptr<T>> Get(const std::vector<std::string> &ids,
|
||||
const int &timeout_ms) {
|
||||
auto result = ray::internal::GetRayRuntime()->Get(ids, timeout_ms);
|
||||
std::vector<std::shared_ptr<T>> return_objects;
|
||||
return_objects.reserve(result.size());
|
||||
for (auto it = result.begin(); it != result.end(); it++) {
|
||||
auto obj = ray::internal::Serializer::Deserialize<std::shared_ptr<T>>((*it)->data(),
|
||||
(*it)->size());
|
||||
return_objects.push_back(std::move(obj));
|
||||
}
|
||||
return return_objects;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::vector<std::shared_ptr<T>> Get(const std::vector<ray::ObjectRef<T>> &ids,
|
||||
const int &timeout_ms) {
|
||||
auto object_ids = ObjectRefsToObjectIDs<T>(ids);
|
||||
return Get<T>(object_ids, timeout_ms);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::shared_ptr<T> Get(const ray::ObjectRef<T> &object) {
|
||||
return Get<T>(object, -1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::vector<std::shared_ptr<T>> Get(const std::vector<std::string> &ids) {
|
||||
return Get<T>(ids, -1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::vector<std::shared_ptr<T>> Get(const std::vector<ray::ObjectRef<T>> &ids) {
|
||||
return Get<T>(ids, -1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline WaitResult<T> Wait(const std::vector<ray::ObjectRef<T>> &objects,
|
||||
int num_objects,
|
||||
int timeout_ms) {
|
||||
auto object_ids = ObjectRefsToObjectIDs<T>(objects);
|
||||
auto results =
|
||||
ray::internal::GetRayRuntime()->Wait(object_ids, num_objects, timeout_ms);
|
||||
std::list<ray::ObjectRef<T>> readys;
|
||||
std::list<ray::ObjectRef<T>> unreadys;
|
||||
for (size_t i = 0; i < results.size(); i++) {
|
||||
if (results[i] == true) {
|
||||
readys.emplace_back(objects[i]);
|
||||
} else {
|
||||
unreadys.emplace_back(objects[i]);
|
||||
}
|
||||
}
|
||||
return WaitResult<T>(std::move(readys), std::move(unreadys));
|
||||
}
|
||||
|
||||
inline ray::internal::ActorCreator<PyActorClass> Actor(PyActorClass func) {
|
||||
ray::internal::RemoteFunctionHolder remote_func_holder(func.module_name,
|
||||
func.function_name,
|
||||
func.class_name,
|
||||
ray::internal::LangType::PYTHON);
|
||||
return {ray::internal::GetRayRuntime().get(), std::move(remote_func_holder)};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
inline ray::internal::TaskCaller<PyFunction<R>> Task(PyFunction<R> func) {
|
||||
ray::internal::RemoteFunctionHolder remote_func_holder(
|
||||
func.module_name, func.function_name, "", ray::internal::LangType::PYTHON);
|
||||
return {ray::internal::GetRayRuntime().get(), std::move(remote_func_holder)};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
inline ray::internal::TaskCaller<JavaFunction<R>> Task(JavaFunction<R> func) {
|
||||
ray::internal::RemoteFunctionHolder remote_func_holder(
|
||||
"", func.function_name, func.class_name, ray::internal::LangType::JAVA);
|
||||
return {ray::internal::GetRayRuntime().get(), std::move(remote_func_holder)};
|
||||
}
|
||||
|
||||
inline ray::internal::ActorCreator<JavaActorClass> Actor(JavaActorClass func) {
|
||||
ray::internal::RemoteFunctionHolder remote_func_holder(func.module_name,
|
||||
func.function_name,
|
||||
func.class_name,
|
||||
ray::internal::LangType::JAVA);
|
||||
return {ray::internal::GetRayRuntime().get(), std::move(remote_func_holder)};
|
||||
}
|
||||
|
||||
/// Normal task.
|
||||
template <typename F>
|
||||
inline ray::internal::TaskCaller<F> Task(F func) {
|
||||
static_assert(!ray::internal::is_python_v<F>, "Must be a cpp function.");
|
||||
static_assert(!std::is_member_function_pointer_v<F>,
|
||||
"Incompatible type: member function cannot be called with ray::Task.");
|
||||
auto func_name = internal::FunctionManager::Instance().GetFunctionName(func);
|
||||
ray::internal::RemoteFunctionHolder remote_func_holder(std::move(func_name));
|
||||
return ray::internal::TaskCaller<F>(ray::internal::GetRayRuntime().get(),
|
||||
std::move(remote_func_holder));
|
||||
}
|
||||
|
||||
/// Creating an actor.
|
||||
template <typename F>
|
||||
inline ray::internal::ActorCreator<F> Actor(F create_func) {
|
||||
auto func_name = internal::FunctionManager::Instance().GetFunctionName(create_func);
|
||||
// Cpp actor don't need class_name, But java/python calls cpp actor need class name
|
||||
// param.
|
||||
auto class_name = internal::FunctionManager::GetClassNameByFuncName(func_name);
|
||||
ray::internal::RemoteFunctionHolder remote_func_holder(
|
||||
"", std::move(func_name), std::move(class_name), internal::LangType::CPP);
|
||||
return ray::internal::ActorCreator<F>(ray::internal::GetRayRuntime().get(),
|
||||
std::move(remote_func_holder));
|
||||
}
|
||||
|
||||
// Get the cpp actor handle by name.
|
||||
template <typename T>
|
||||
boost::optional<ActorHandle<T>> GetActor(const std::string &actor_name) {
|
||||
return GetActor<T>(actor_name, "");
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
boost::optional<ActorHandle<T>> GetActor(const std::string &actor_name,
|
||||
const std::string &ray_namespace) {
|
||||
if (actor_name.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto actor_id = ray::internal::GetRayRuntime()->GetActorId(actor_name, ray_namespace);
|
||||
if (actor_id.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return ActorHandle<T>(actor_id);
|
||||
}
|
||||
|
||||
// Get the cross-language actor handle by name.
|
||||
inline boost::optional<ActorHandleXlang> GetActor(const std::string &actor_name,
|
||||
const std::string &ray_namespce = "") {
|
||||
if (actor_name.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto actor_id = ray::internal::GetRayRuntime()->GetActorId(actor_name, ray_namespce);
|
||||
if (actor_id.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return ActorHandleXlang(actor_id);
|
||||
}
|
||||
|
||||
inline void ExitActor() { ray::internal::GetRayRuntime()->ExitActor(); }
|
||||
|
||||
inline PlacementGroup CreatePlacementGroup(
|
||||
const ray::PlacementGroupCreationOptions &create_options) {
|
||||
return ray::internal::GetRayRuntime()->CreatePlacementGroup(create_options);
|
||||
}
|
||||
|
||||
inline void RemovePlacementGroup(const std::string &placement_group_id) {
|
||||
return ray::internal::GetRayRuntime()->RemovePlacementGroup(placement_group_id);
|
||||
}
|
||||
|
||||
inline std::vector<PlacementGroup> GetAllPlacementGroups() {
|
||||
return ray::internal::GetRayRuntime()->GetAllPlacementGroups();
|
||||
}
|
||||
|
||||
inline PlacementGroup GetPlacementGroupById(const std::string &id) {
|
||||
return ray::internal::GetRayRuntime()->GetPlacementGroupById(id);
|
||||
}
|
||||
|
||||
inline PlacementGroup GetPlacementGroup(const std::string &name) {
|
||||
return ray::internal::GetRayRuntime()->GetPlacementGroup(name);
|
||||
}
|
||||
|
||||
inline bool WasCurrentActorRestarted() {
|
||||
return ray::internal::GetRayRuntime()->WasCurrentActorRestarted();
|
||||
}
|
||||
|
||||
inline std::string GetNamespace() {
|
||||
return ray::internal::GetRayRuntime()->GetNamespace();
|
||||
}
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,113 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/actor_handle.h>
|
||||
#include <ray/api/runtime_env.h>
|
||||
#include <ray/api/task_options.h>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
template <typename F>
|
||||
using GetActorType = std::remove_pointer_t<boost::callable_traits::return_type_t<F>>;
|
||||
|
||||
template <typename F>
|
||||
class ActorCreator {
|
||||
public:
|
||||
ActorCreator() {}
|
||||
|
||||
ActorCreator(RayRuntime *runtime, RemoteFunctionHolder remote_function_holder)
|
||||
: runtime_(runtime), remote_function_holder_(std::move(remote_function_holder)) {}
|
||||
|
||||
template <typename... Args>
|
||||
ray::ActorHandle<GetActorType<F>, is_x_lang_v<F>> Remote(Args &&...args);
|
||||
|
||||
ActorCreator &SetName(std::string name) {
|
||||
create_options_.name = std::move(name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ActorCreator &SetName(std::string name, std::string ray_namespace) {
|
||||
create_options_.name = std::move(name);
|
||||
create_options_.ray_namespace = std::move(ray_namespace);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ActorCreator &SetResources(std::unordered_map<std::string, double> resources) {
|
||||
create_options_.resources = std::move(resources);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ActorCreator &SetResource(std::string name, double value) {
|
||||
create_options_.resources.emplace(std::move(name), value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ActorCreator &SetMaxRestarts(int max_restarts) {
|
||||
create_options_.max_restarts = max_restarts;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ActorCreator &SetMaxConcurrency(int max_concurrency) {
|
||||
create_options_.max_concurrency = max_concurrency;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ActorCreator &SetPlacementGroup(PlacementGroup group, int bundle_index) {
|
||||
create_options_.group = group;
|
||||
create_options_.bundle_index = bundle_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ActorCreator &SetRuntimeEnv(const ray::RuntimeEnv &runtime_env) {
|
||||
create_options_.serialized_runtime_env_info = runtime_env.SerializeToRuntimeEnvInfo();
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
RayRuntime *runtime_;
|
||||
RemoteFunctionHolder remote_function_holder_;
|
||||
std::vector<TaskArg> args_;
|
||||
ActorCreationOptions create_options_{};
|
||||
};
|
||||
|
||||
// ---------- implementation ----------
|
||||
template <typename F>
|
||||
template <typename... Args>
|
||||
ActorHandle<GetActorType<F>, is_x_lang_v<F>> ActorCreator<F>::Remote(Args &&...args) {
|
||||
CheckTaskOptions(create_options_.resources);
|
||||
|
||||
if constexpr (is_x_lang_v<F>) {
|
||||
using ArgsTuple = std::tuple<Args...>;
|
||||
Arguments::WrapArgs<ArgsTuple>(remote_function_holder_.lang_type_,
|
||||
&args_,
|
||||
std::make_index_sequence<sizeof...(Args)>{},
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
StaticCheck<F, Args...>();
|
||||
using ArgsTuple = RemoveReference_t<boost::callable_traits::args_t<F>>;
|
||||
Arguments::WrapArgs<ArgsTuple>(remote_function_holder_.lang_type_,
|
||||
&args_,
|
||||
std::make_index_sequence<sizeof...(Args)>{},
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
auto returned_actor_id =
|
||||
runtime_->CreateActor(remote_function_holder_, args_, create_options_);
|
||||
return ActorHandle<GetActorType<F>, is_x_lang_v<F>>(returned_actor_id);
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/actor_task_caller.h>
|
||||
#include <ray/api/function_manager.h>
|
||||
#include <ray/api/ray_runtime_holder.h>
|
||||
|
||||
namespace ray {
|
||||
|
||||
/// A handle to an actor which can be used to invoke a remote actor method, with the
|
||||
/// `Call` method.
|
||||
/// \param ActorType The type of the concrete actor class.
|
||||
/// Note, the `Call` method is defined in actor_call.generated.h.
|
||||
template <typename ActorType, bool IsXlang = false>
|
||||
class ActorHandle {
|
||||
public:
|
||||
ActorHandle() = default;
|
||||
|
||||
ActorHandle(const std::string &id) { id_ = id; }
|
||||
|
||||
// Used to identify its type.
|
||||
static bool IsActorHandle() { return true; }
|
||||
|
||||
/// Get a untyped ID of the actor
|
||||
const std::string &ID() const { return id_; }
|
||||
|
||||
/// Include the `Call` methods for calling remote functions.
|
||||
template <typename F>
|
||||
ray::internal::ActorTaskCaller<F> Task(F actor_func) {
|
||||
static_assert(!IsXlang && !ray::internal::is_python_v<F>,
|
||||
"Actor method is not a member function of actor class.");
|
||||
static_assert(std::is_member_function_pointer_v<F>,
|
||||
"Actor method is not a member function of actor class.");
|
||||
using Self = boost::callable_traits::class_of_t<F>;
|
||||
static_assert(
|
||||
std::is_same<ActorType, Self>::value || std::is_base_of<Self, ActorType>::value,
|
||||
"Class types must be same.");
|
||||
auto func_name = internal::FunctionManager::Instance().GetFunctionName(actor_func);
|
||||
ray::internal::RemoteFunctionHolder remote_func_holder(func_name);
|
||||
return ray::internal::ActorTaskCaller<F>(
|
||||
internal::GetRayRuntime().get(), id_, std::move(remote_func_holder));
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
ray::internal::ActorTaskCaller<PyActorMethod<R>> Task(PyActorMethod<R> func) {
|
||||
static_assert(IsXlang, "Actor function type does not match actor class");
|
||||
ray::internal::RemoteFunctionHolder remote_func_holder(
|
||||
"", func.function_name, "", ray::internal::LangType::PYTHON);
|
||||
return {ray::internal::GetRayRuntime().get(), id_, std::move(remote_func_holder)};
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
ray::internal::ActorTaskCaller<JavaActorMethod<R>> Task(JavaActorMethod<R> func) {
|
||||
static_assert(IsXlang, "Actor function type does not match actor class");
|
||||
ray::internal::RemoteFunctionHolder remote_func_holder(
|
||||
"", func.function_name, "", ray::internal::LangType::JAVA);
|
||||
return {ray::internal::GetRayRuntime().get(), id_, std::move(remote_func_holder)};
|
||||
}
|
||||
|
||||
void Kill() { Kill(true); }
|
||||
void Kill(bool no_restart) {
|
||||
ray::internal::GetRayRuntime()->KillActor(id_, no_restart);
|
||||
}
|
||||
|
||||
static ActorHandle FromBytes(const std::string &serialized_actor_handle) {
|
||||
std::string id = ray::internal::GetRayRuntime()->DeserializeAndRegisterActorHandle(
|
||||
serialized_actor_handle);
|
||||
return ActorHandle(id);
|
||||
}
|
||||
|
||||
/// Make ActorHandle serializable
|
||||
MSGPACK_DEFINE(id_);
|
||||
|
||||
private:
|
||||
std::string id_;
|
||||
};
|
||||
|
||||
typedef ActorHandle<void, true> ActorHandleXlang;
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/arguments.h>
|
||||
#include <ray/api/object_ref.h>
|
||||
#include <ray/api/static_check.h>
|
||||
#include <ray/api/task_options.h>
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
template <typename F>
|
||||
class ActorTaskCaller {
|
||||
public:
|
||||
ActorTaskCaller() = default;
|
||||
|
||||
ActorTaskCaller(RayRuntime *runtime,
|
||||
const std::string &id,
|
||||
RemoteFunctionHolder remote_function_holder)
|
||||
: runtime_(runtime),
|
||||
id_(id),
|
||||
remote_function_holder_(std::move(remote_function_holder)) {}
|
||||
|
||||
template <typename... Args>
|
||||
ObjectRef<boost::callable_traits::return_type_t<F>> Remote(Args &&...args);
|
||||
|
||||
ActorTaskCaller &SetName(std::string name) {
|
||||
task_options_.name = std::move(name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ActorTaskCaller &SetResources(std::unordered_map<std::string, double> resources) {
|
||||
task_options_.resources = std::move(resources);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ActorTaskCaller &SetResource(std::string name, double value) {
|
||||
task_options_.resources.emplace(std::move(name), value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
RayRuntime *runtime_;
|
||||
std::string id_;
|
||||
RemoteFunctionHolder remote_function_holder_;
|
||||
std::vector<TaskArg> args_;
|
||||
CallOptions task_options_;
|
||||
};
|
||||
|
||||
// ---------- implementation ----------
|
||||
|
||||
template <typename F>
|
||||
template <typename... Args>
|
||||
ObjectRef<boost::callable_traits::return_type_t<F>> ActorTaskCaller<F>::Remote(
|
||||
Args &&...args) {
|
||||
CheckTaskOptions(task_options_.resources);
|
||||
|
||||
if constexpr (is_x_lang_v<F>) {
|
||||
using ArgsTuple = std::tuple<Args...>;
|
||||
Arguments::WrapArgs<ArgsTuple>(remote_function_holder_.lang_type_,
|
||||
&args_,
|
||||
std::make_index_sequence<sizeof...(Args)>{},
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
StaticCheck<F, Args...>();
|
||||
using ArgsTuple = RemoveReference_t<RemoveFirst_t<boost::callable_traits::args_t<F>>>;
|
||||
Arguments::WrapArgs<ArgsTuple>(remote_function_holder_.lang_type_,
|
||||
&args_,
|
||||
std::make_index_sequence<sizeof...(Args)>{},
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
using ReturnType = boost::callable_traits::return_type_t<F>;
|
||||
auto returned_object_id =
|
||||
runtime_->CallActor(remote_function_holder_, id_, args_, task_options_);
|
||||
auto return_ref = ObjectRef<ReturnType>(returned_object_id);
|
||||
// The core worker will add an initial ref to each return ID to keep it in
|
||||
// scope. Now that we've created the frontend ObjectRef, remove this initial
|
||||
// ref.
|
||||
runtime_->RemoveLocalReference(returned_object_id);
|
||||
return return_ref;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,123 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/object_ref.h>
|
||||
#include <ray/api/serializer.h>
|
||||
#include <ray/api/type_traits.h>
|
||||
#include <ray/api/xlang_function.h>
|
||||
|
||||
#include <msgpack.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class Arguments {
|
||||
public:
|
||||
template <typename OriginArgType, typename InputArgTypes>
|
||||
static void WrapArgsImpl(LangType lang_type,
|
||||
std::vector<TaskArg> *task_args,
|
||||
InputArgTypes &&arg) {
|
||||
if constexpr (is_object_ref_v<OriginArgType>) {
|
||||
if (RayRuntimeHolder::Instance().Runtime()->IsLocalMode()) {
|
||||
PushReferenceArg(task_args, std::forward<InputArgTypes>(arg));
|
||||
} else {
|
||||
// After the Object Ref parameter is supported, this exception will be deleted.
|
||||
throw std::invalid_argument(
|
||||
"At present, the Ray C++ API does not support the passing of "
|
||||
"`ray::ObjectRef` parameters. Will support later.");
|
||||
}
|
||||
} else if constexpr (is_object_ref_v<InputArgTypes>) {
|
||||
// core_worker submitting task callback will get the value of an ObjectRef arg, but
|
||||
// local mode we don't call core_worker submit task, so we need get the value of an
|
||||
// ObjectRef arg only for local mode.
|
||||
if (RayRuntimeHolder::Instance().Runtime()->IsLocalMode()) {
|
||||
auto buffer = RayRuntimeHolder::Instance().Runtime()->Get(arg.ID());
|
||||
PushValueArg(task_args, std::move(*buffer));
|
||||
} else {
|
||||
PushReferenceArg(task_args, std::forward<InputArgTypes>(arg));
|
||||
}
|
||||
} else {
|
||||
if (lang_type == LangType::CPP) {
|
||||
if constexpr (is_actor_handle_v<InputArgTypes>) {
|
||||
auto serialized_actor_handle =
|
||||
RayRuntimeHolder::Instance().Runtime()->SerializeActorHandle(arg.ID());
|
||||
msgpack::sbuffer buffer = Serializer::Serialize(serialized_actor_handle);
|
||||
PushValueArg(task_args, std::move(buffer));
|
||||
} else {
|
||||
msgpack::sbuffer buffer =
|
||||
Serializer::Serialize(std::forward<InputArgTypes>(arg));
|
||||
PushValueArg(task_args, std::move(buffer));
|
||||
}
|
||||
} else {
|
||||
// Fill dummy field for handling kwargs.
|
||||
if (lang_type == LangType::PYTHON) {
|
||||
msgpack::sbuffer dummy_buf(METADATA_STR_DUMMY.size());
|
||||
dummy_buf.write(METADATA_STR_DUMMY.data(), METADATA_STR_DUMMY.size());
|
||||
PushValueArg(task_args, std::move(dummy_buf), METADATA_STR_RAW);
|
||||
}
|
||||
// Below applies to both PYTHON and JAVA.
|
||||
auto data_buf = Serializer::Serialize(std::forward<InputArgTypes>(arg));
|
||||
auto len_buf = Serializer::Serialize(data_buf.size());
|
||||
|
||||
msgpack::sbuffer buffer(XLANG_HEADER_LEN + data_buf.size());
|
||||
buffer.write(len_buf.data(), len_buf.size());
|
||||
for (size_t i = 0; i < XLANG_HEADER_LEN - len_buf.size(); ++i) {
|
||||
buffer.write("", 1);
|
||||
}
|
||||
buffer.write(data_buf.data(), data_buf.size());
|
||||
|
||||
PushValueArg(task_args, std::move(buffer), METADATA_STR_XLANG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename OriginArgsTuple, size_t... I, typename... InputArgTypes>
|
||||
static void WrapArgs(LangType lang_type,
|
||||
std::vector<TaskArg> *task_args,
|
||||
std::index_sequence<I...>,
|
||||
InputArgTypes &&...args) {
|
||||
(void)std::initializer_list<int>{
|
||||
(WrapArgsImpl<std::tuple_element_t<I, OriginArgsTuple>>(
|
||||
lang_type, task_args, std::forward<InputArgTypes>(args)),
|
||||
0)...};
|
||||
/// Silence gcc warning error.
|
||||
(void)task_args;
|
||||
(void)lang_type;
|
||||
}
|
||||
|
||||
private:
|
||||
static void PushValueArg(std::vector<TaskArg> *task_args,
|
||||
msgpack::sbuffer &&buffer,
|
||||
std::string_view meta_str = "") {
|
||||
/// Pass by value.
|
||||
TaskArg task_arg;
|
||||
task_arg.buf = std::move(buffer);
|
||||
if (!meta_str.empty()) task_arg.meta_str = std::move(meta_str);
|
||||
task_args->emplace_back(std::move(task_arg));
|
||||
}
|
||||
|
||||
template <typename TaskArg, typename T>
|
||||
static void PushReferenceArg(std::vector<TaskArg> *task_args, T &&arg) {
|
||||
/// Pass by reference.
|
||||
TaskArg task_arg{};
|
||||
task_arg.id = arg.ID();
|
||||
task_args->emplace_back(std::move(task_arg));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <msgpack.hpp>
|
||||
#include <string_view>
|
||||
|
||||
#include "boost/optional.hpp"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
struct TaskArg {
|
||||
TaskArg() = default;
|
||||
TaskArg(TaskArg &&rhs) {
|
||||
buf = std::move(rhs.buf);
|
||||
id = rhs.id;
|
||||
meta_str = std::move(rhs.meta_str);
|
||||
}
|
||||
|
||||
TaskArg(const TaskArg &) = delete;
|
||||
TaskArg &operator=(TaskArg const &) = delete;
|
||||
TaskArg &operator=(TaskArg &&) = delete;
|
||||
|
||||
/// If the buf is initialized shows it is a value argument.
|
||||
boost::optional<msgpack::sbuffer> buf;
|
||||
/// If the id is initialized shows it is a reference argument.
|
||||
boost::optional<std::string> id;
|
||||
|
||||
std::string_view meta_str;
|
||||
};
|
||||
|
||||
using ArgsBuffer = msgpack::sbuffer;
|
||||
using ArgsBufferList = std::vector<ArgsBuffer>;
|
||||
|
||||
using RemoteFunction = std::function<msgpack::sbuffer(const ArgsBufferList &)>;
|
||||
using RemoteFunctionMap_t = std::unordered_map<std::string, RemoteFunction>;
|
||||
|
||||
using RemoteMemberFunction =
|
||||
std::function<msgpack::sbuffer(msgpack::sbuffer *, const ArgsBufferList &)>;
|
||||
using RemoteMemberFunctionMap_t = std::unordered_map<std::string, RemoteMemberFunction>;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,354 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/common_types.h>
|
||||
#include <ray/api/ray_runtime_holder.h>
|
||||
#include <ray/api/serializer.h>
|
||||
#include <ray/api/type_traits.h>
|
||||
|
||||
#include <boost/callable_traits.hpp>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
inline static std::enable_if_t<!std::is_pointer<T>::value, msgpack::sbuffer>
|
||||
PackReturnValue(T result) {
|
||||
if constexpr (is_actor_handle_v<T>) {
|
||||
auto serialized_actor_handle =
|
||||
RayRuntimeHolder::Instance().Runtime()->SerializeActorHandle(result.ID());
|
||||
return Serializer::Serialize(serialized_actor_handle);
|
||||
}
|
||||
return Serializer::Serialize(std::move(result));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline static std::enable_if_t<std::is_pointer<T>::value, msgpack::sbuffer>
|
||||
PackReturnValue(T result) {
|
||||
return Serializer::Serialize((uint64_t)result);
|
||||
}
|
||||
|
||||
inline static msgpack::sbuffer PackVoid() {
|
||||
return Serializer::Serialize(msgpack::type::nil_t());
|
||||
}
|
||||
|
||||
msgpack::sbuffer PackError(std::string error_msg);
|
||||
|
||||
/// It's help to invoke functions and member functions, the class Invoker<Function> help
|
||||
/// do type erase.
|
||||
template <typename Function>
|
||||
struct Invoker {
|
||||
/// Invoke functions by networking stream, at first deserialize the binary data to a
|
||||
/// tuple, then call function with tuple.
|
||||
static inline msgpack::sbuffer Apply(const Function &func,
|
||||
const ArgsBufferList &args_buffer) {
|
||||
using RetrunType = boost::callable_traits::return_type_t<Function>;
|
||||
using ArgsTuple = RemoveReference_t<boost::callable_traits::args_t<Function>>;
|
||||
if (std::tuple_size<ArgsTuple>::value != args_buffer.size()) {
|
||||
throw std::invalid_argument("Arguments number not match");
|
||||
}
|
||||
|
||||
msgpack::sbuffer result;
|
||||
ArgsTuple tp{};
|
||||
bool is_ok = GetArgsTuple(
|
||||
tp, args_buffer, std::make_index_sequence<std::tuple_size<ArgsTuple>::value>{});
|
||||
if (!is_ok) {
|
||||
throw std::invalid_argument("Arguments error");
|
||||
}
|
||||
|
||||
result = Invoker<Function>::Call<RetrunType>(func, std::move(tp));
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline msgpack::sbuffer ApplyMember(const Function &func,
|
||||
msgpack::sbuffer *ptr,
|
||||
const ArgsBufferList &args_buffer) {
|
||||
using RetrunType = boost::callable_traits::return_type_t<Function>;
|
||||
using ArgsTuple =
|
||||
RemoveReference_t<RemoveFirst_t<boost::callable_traits::args_t<Function>>>;
|
||||
if (std::tuple_size<ArgsTuple>::value != args_buffer.size()) {
|
||||
throw std::invalid_argument("Arguments number not match");
|
||||
}
|
||||
|
||||
msgpack::sbuffer result;
|
||||
ArgsTuple tp{};
|
||||
bool is_ok = GetArgsTuple(
|
||||
tp, args_buffer, std::make_index_sequence<std::tuple_size<ArgsTuple>::value>{});
|
||||
if (!is_ok) {
|
||||
throw std::invalid_argument("Arguments error");
|
||||
}
|
||||
|
||||
uint64_t actor_ptr = Serializer::Deserialize<uint64_t>(ptr->data(), ptr->size());
|
||||
using Self = boost::callable_traits::class_of_t<Function>;
|
||||
Self *self = (Self *)actor_ptr;
|
||||
result = Invoker<Function>::CallMember<RetrunType>(func, self, std::move(tp));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
static inline T ParseArg(const ArgsBuffer &args_buffer, bool &is_ok) {
|
||||
is_ok = true;
|
||||
if constexpr (is_object_ref_v<T>) {
|
||||
// Construct an ObjectRef<T> by id.
|
||||
return T(std::string(args_buffer.data(), args_buffer.size()));
|
||||
} else if constexpr (is_actor_handle_v<T>) {
|
||||
auto actor_handle =
|
||||
Serializer::Deserialize<std::string>(args_buffer.data(), args_buffer.size());
|
||||
return T::FromBytes(actor_handle);
|
||||
} else {
|
||||
auto [success, value] =
|
||||
Serializer::DeserializeWhenNil<T>(args_buffer.data(), args_buffer.size());
|
||||
is_ok = success;
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool GetArgsTuple(std::tuple<> &tup,
|
||||
const ArgsBufferList &args_buffer,
|
||||
std::index_sequence<>) {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <size_t... I, typename... Args>
|
||||
static inline bool GetArgsTuple(std::tuple<Args...> &tp,
|
||||
const ArgsBufferList &args_buffer,
|
||||
std::index_sequence<I...>) {
|
||||
bool is_ok = true;
|
||||
(void)std::initializer_list<int>{
|
||||
(std::get<I>(tp) = ParseArg<Args>(args_buffer.at(I), is_ok), 0)...};
|
||||
return is_ok;
|
||||
}
|
||||
|
||||
template <typename R, typename F, typename... Args>
|
||||
static std::enable_if_t<std::is_void<R>::value, msgpack::sbuffer> Call(
|
||||
const F &f, std::tuple<Args...> args) {
|
||||
CallInternal<R>(f, std::make_index_sequence<sizeof...(Args)>{}, std::move(args));
|
||||
return PackVoid();
|
||||
}
|
||||
|
||||
template <typename R, typename F, typename... Args>
|
||||
static std::enable_if_t<!std::is_void<R>::value, msgpack::sbuffer> Call(
|
||||
const F &f, std::tuple<Args...> args) {
|
||||
auto r =
|
||||
CallInternal<R>(f, std::make_index_sequence<sizeof...(Args)>{}, std::move(args));
|
||||
return PackReturnValue(r);
|
||||
}
|
||||
|
||||
template <typename R, typename F, size_t... I, typename... Args>
|
||||
static R CallInternal(const F &f,
|
||||
const std::index_sequence<I...> &,
|
||||
std::tuple<Args...> args) {
|
||||
(void)args;
|
||||
using ArgsTuple = boost::callable_traits::args_t<F>;
|
||||
return f(((typename std::tuple_element<I, ArgsTuple>::type)std::get<I>(args))...);
|
||||
}
|
||||
|
||||
template <typename R, typename F, typename Self, typename... Args>
|
||||
static std::enable_if_t<std::is_void<R>::value, msgpack::sbuffer> CallMember(
|
||||
const F &f, Self *self, std::tuple<Args...> args) {
|
||||
CallMemberInternal<R>(
|
||||
f, self, std::make_index_sequence<sizeof...(Args)>{}, std::move(args));
|
||||
return PackVoid();
|
||||
}
|
||||
|
||||
template <typename R, typename F, typename Self, typename... Args>
|
||||
static std::enable_if_t<!std::is_void<R>::value, msgpack::sbuffer> CallMember(
|
||||
const F &f, Self *self, std::tuple<Args...> args) {
|
||||
auto r = CallMemberInternal<R>(
|
||||
f, self, std::make_index_sequence<sizeof...(Args)>{}, std::move(args));
|
||||
return PackReturnValue(r);
|
||||
}
|
||||
|
||||
template <typename R, typename F, typename Self, size_t... I, typename... Args>
|
||||
static R CallMemberInternal(const F &f,
|
||||
Self *self,
|
||||
const std::index_sequence<I...> &,
|
||||
std::tuple<Args...> args) {
|
||||
(void)args;
|
||||
using ArgsTuple = boost::callable_traits::args_t<F>;
|
||||
return (self->*f)(
|
||||
((typename std::tuple_element<I + 1, ArgsTuple>::type) std::get<I>(args))...);
|
||||
}
|
||||
};
|
||||
|
||||
/// Manage all ray remote functions, add remote functions by RAY_REMOTE, get functions by
|
||||
/// TaskExecutionHandler.
|
||||
class FunctionManager {
|
||||
public:
|
||||
static FunctionManager &Instance() {
|
||||
static FunctionManager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
std::pair<const RemoteFunctionMap_t &, const RemoteMemberFunctionMap_t &>
|
||||
GetRemoteFunctions() {
|
||||
return std::pair<const RemoteFunctionMap_t &, const RemoteMemberFunctionMap_t &>(
|
||||
map_invokers_, map_mem_func_invokers_);
|
||||
}
|
||||
|
||||
RemoteFunction *GetFunction(const std::string &func_name) {
|
||||
auto it = map_invokers_.find(func_name);
|
||||
if (it == map_invokers_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
std::enable_if_t<!std::is_member_function_pointer<Function>::value, bool>
|
||||
RegisterRemoteFunction(std::string const &name, const Function &f) {
|
||||
auto pair = func_ptr_to_key_map_.emplace(GetAddress(f), name);
|
||||
if (!pair.second) {
|
||||
throw RayException("Duplicate RAY_REMOTE function: " + name);
|
||||
}
|
||||
|
||||
bool ok = RegisterNonMemberFunc(name, f);
|
||||
if (!ok) {
|
||||
throw RayException("Duplicate RAY_REMOTE function: " + name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
std::enable_if_t<std::is_member_function_pointer<Function>::value, bool>
|
||||
RegisterRemoteFunction(std::string const &name, const Function &f) {
|
||||
using Self = boost::callable_traits::class_of_t<Function>;
|
||||
auto key = std::make_pair(typeid(Self).name(), GetAddress(f));
|
||||
auto pair = mem_func_to_key_map_.emplace(std::move(key), name);
|
||||
if (!pair.second) {
|
||||
throw RayException("Duplicate RAY_REMOTE function: " + name);
|
||||
}
|
||||
|
||||
bool ok = RegisterMemberFunc(name, f);
|
||||
if (!ok) {
|
||||
throw RayException("Duplicate RAY_REMOTE function: " + name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
std::enable_if_t<!std::is_member_function_pointer<Function>::value, std::string>
|
||||
GetFunctionName(const Function &f) {
|
||||
auto it = func_ptr_to_key_map_.find(GetAddress(f));
|
||||
if (it == func_ptr_to_key_map_.end()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
std::enable_if_t<std::is_member_function_pointer<Function>::value, std::string>
|
||||
GetFunctionName(const Function &f) {
|
||||
using Self = boost::callable_traits::class_of_t<Function>;
|
||||
auto key = std::make_pair(typeid(Self).name(), GetAddress(f));
|
||||
auto it = mem_func_to_key_map_.find(key);
|
||||
if (it == mem_func_to_key_map_.end()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
RemoteMemberFunction *GetMemberFunction(const std::string &func_name) {
|
||||
auto it = map_mem_func_invokers_.find(func_name);
|
||||
if (it == map_mem_func_invokers_.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
static std::string GetClassNameByFuncName(const std::string &func_name) {
|
||||
if (func_name.empty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const std::string &prefix = "RAY_FUNC(";
|
||||
size_t start_pos = 0;
|
||||
auto pos = func_name.find(prefix);
|
||||
if (pos != func_name.npos) {
|
||||
start_pos = pos + prefix.size();
|
||||
}
|
||||
auto end_pod = func_name.find_last_of("::");
|
||||
if (end_pod == func_name.npos || end_pod <= start_pos) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return func_name.substr(start_pos, (end_pod - start_pos - 1));
|
||||
}
|
||||
|
||||
private:
|
||||
FunctionManager() = default;
|
||||
~FunctionManager() = default;
|
||||
FunctionManager(const FunctionManager &) = delete;
|
||||
FunctionManager(FunctionManager &&) = delete;
|
||||
|
||||
template <typename Function>
|
||||
bool RegisterNonMemberFunc(std::string const &name, Function f) {
|
||||
return map_invokers_
|
||||
.emplace(
|
||||
name,
|
||||
std::bind(&Invoker<Function>::Apply, std::move(f), std::placeholders::_1))
|
||||
.second;
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
bool RegisterMemberFunc(std::string const &name, Function f) {
|
||||
return map_mem_func_invokers_
|
||||
.emplace(name,
|
||||
std::bind(&Invoker<Function>::ApplyMember,
|
||||
std::move(f),
|
||||
std::placeholders::_1,
|
||||
std::placeholders::_2))
|
||||
.second;
|
||||
}
|
||||
|
||||
template <class Dest, class Source>
|
||||
Dest BitCast(const Source &source) {
|
||||
static_assert(sizeof(Dest) == sizeof(Source),
|
||||
"BitCast requires source and destination to be the same size");
|
||||
|
||||
Dest dest;
|
||||
memcpy(&dest, &source, sizeof(dest));
|
||||
return dest;
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
std::string GetAddress(F f) {
|
||||
auto arr = BitCast<std::array<char, sizeof(F)>>(f);
|
||||
return std::string(arr.data(), arr.size());
|
||||
}
|
||||
|
||||
RemoteFunctionMap_t map_invokers_;
|
||||
RemoteMemberFunctionMap_t map_mem_func_invokers_;
|
||||
std::unordered_map<std::string, std::string> func_ptr_to_key_map_;
|
||||
std::map<std::pair<std::string, std::string>, std::string> mem_func_to_key_map_;
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,21 @@
|
||||
// Copyright 2022 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ray {
|
||||
|
||||
void RunTaskExecutionLoop();
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#ifndef _WINDOWS_
|
||||
// This is a public header that may be compiled outside of Ray's build system,
|
||||
// so we cannot rely on the -DWIN32_LEAN_AND_MEAN compiler flag from ray.bzl.
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN // Prevent Windows.h from including WinSock.h
|
||||
#endif
|
||||
#include <Windows.h> // Force inclusion of WinGDI here to resolve name conflict
|
||||
#endif
|
||||
#ifdef ERROR // Should be true unless someone else undef'd it already
|
||||
#undef ERROR // Windows GDI defines this macro; make it a global enum so it doesn't
|
||||
// conflict with our code
|
||||
enum { ERROR = 0 };
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(DEBUG) && DEBUG == 1
|
||||
// Bazel defines the DEBUG macro for historical reasons:
|
||||
// https://github.com/bazelbuild/bazel/issues/3513#issuecomment-323829248
|
||||
// Undefine the DEBUG macro to prevent conflicts with our usage below
|
||||
#undef DEBUG
|
||||
// Redefine DEBUG as itself to allow any '#ifdef DEBUG' to keep working regardless
|
||||
#define DEBUG DEBUG
|
||||
#endif
|
||||
|
||||
namespace ray {
|
||||
|
||||
enum class RayLoggerLevel { DEBUG = -1, INFO = 0, WARNING = 1, ERROR = 2, FATAL = 3 };
|
||||
|
||||
#define RAYLOG_INTERNAL(level) *CreateRayLogger(__FILE__, __LINE__, level)
|
||||
#define RAYLOG(level) \
|
||||
if (IsLevelEnabled(ray::RayLoggerLevel::level)) \
|
||||
RAYLOG_INTERNAL(ray::RayLoggerLevel::level)
|
||||
|
||||
// To make the logging lib pluggable with other logging libs and make
|
||||
// the implementation unaware by the user, RayLog is only a declaration
|
||||
// which hides the implementation into logging.cc file.
|
||||
// In logging.cc, we can choose different log libs using different macros.
|
||||
|
||||
// This is a log interface which does not output anything.
|
||||
class RayLogger {
|
||||
public:
|
||||
virtual ~RayLogger(){};
|
||||
|
||||
virtual bool IsEnabled() const = 0;
|
||||
|
||||
template <typename T>
|
||||
RayLogger &operator<<(const T &t) {
|
||||
if (IsEnabled()) {
|
||||
Stream() << t;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual std::ostream &Stream() = 0;
|
||||
};
|
||||
|
||||
std::unique_ptr<RayLogger> CreateRayLogger(const char *file_name,
|
||||
int line_number,
|
||||
RayLoggerLevel severity);
|
||||
bool IsLevelEnabled(RayLoggerLevel log_level);
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace ray {
|
||||
class Metric {
|
||||
public:
|
||||
virtual ~Metric() = 0;
|
||||
|
||||
/// Get the name of this metric.
|
||||
std::string GetName() const;
|
||||
|
||||
/// Record the value for this metric.
|
||||
///
|
||||
/// \param value The value that we record.
|
||||
/// \param tags The map tag values that we want to record for this metric record.
|
||||
void Record(double value, const std::unordered_map<std::string, std::string> &tags);
|
||||
|
||||
protected:
|
||||
void *metric_ = nullptr;
|
||||
}; // class Metric
|
||||
|
||||
class Gauge : public Metric {
|
||||
public:
|
||||
/// Gauges keep the last recorded value and drop everything before.
|
||||
/// Unlike counters, gauges can go up or down over time.
|
||||
///
|
||||
/// This corresponds to Prometheus' gauge metric:
|
||||
/// https://prometheus.io/docs/concepts/metric_types/#gauge
|
||||
///
|
||||
/// \param[in] name The Name of the metric.
|
||||
/// \param[in] description The Description of the metric.
|
||||
/// \param[in] unit The unit of the metric
|
||||
/// \param[in] tag_keys Tag keys of the metric.
|
||||
Gauge(const std::string &name,
|
||||
const std::string &description,
|
||||
const std::string &unit,
|
||||
const std::vector<std::string> &tag_keys = {});
|
||||
|
||||
/// Set the gauge to the given `value`.
|
||||
///
|
||||
/// Tags passed in will take precedence over the metric's default tags.
|
||||
///
|
||||
/// \param[in] value Value to set the gauge to.
|
||||
/// \param[in] tags Tags to set or override for this gauge.
|
||||
void Set(double value, const std::unordered_map<std::string, std::string> &tags);
|
||||
}; // class Gauge
|
||||
|
||||
class Histogram : public Metric {
|
||||
public:
|
||||
/// Tracks the size and number of events in buckets.
|
||||
///
|
||||
/// Histograms allow you to calculate aggregate quantiles
|
||||
/// such as 25, 50, 95, 99 percentile latency for an RPC.
|
||||
///
|
||||
/// This corresponds to Prometheus' histogram metric:
|
||||
/// https://prometheus.io/docs/concepts/metric_types/#histogram
|
||||
///
|
||||
/// \param[in] name The Name of the metric.
|
||||
/// \param[in] description The Description of the metric.
|
||||
/// \param[in] unit The unit of the metric
|
||||
/// \param[in] boundaries The Boundaries of histogram buckets.
|
||||
/// \param[in] tag_keys Tag keys of the metric.
|
||||
Histogram(const std::string &name,
|
||||
const std::string &description,
|
||||
const std::string &unit,
|
||||
const std::vector<double> boundaries,
|
||||
const std::vector<std::string> &tag_keys = {});
|
||||
|
||||
/// Observe a given `value` and add it to the appropriate bucket.
|
||||
///
|
||||
/// Tags passed in will take precedence over the metric's default tags.
|
||||
///
|
||||
/// \param[in] value The value that we record.
|
||||
/// \param[in] tags The map tag values that we want to record
|
||||
void Observe(double value, const std::unordered_map<std::string, std::string> &tags);
|
||||
}; // class Histogram
|
||||
|
||||
class Counter : public Metric {
|
||||
public:
|
||||
/// A cumulative metric that is monotonically increasing.
|
||||
///
|
||||
/// This corresponds to Prometheus' counter metric:
|
||||
/// https://prometheus.io/docs/concepts/metric_types/#counter
|
||||
///
|
||||
/// \param[in] name The Name of the metric.
|
||||
/// \param[in] description The Description of the metric.
|
||||
/// \param[in] unit The unit of the metric
|
||||
/// \param[in] tag_keys Tag keys of the metric.
|
||||
Counter(const std::string &name,
|
||||
const std::string &description,
|
||||
const std::string &unit,
|
||||
const std::vector<std::string> &tag_keys = {});
|
||||
|
||||
/// Increment the counter by `value` (defaults to 1).
|
||||
///
|
||||
/// Tags passed in will take precedence over the metric's default tags.
|
||||
///
|
||||
/// \param[in] value Value to increment the counter by (default=1).
|
||||
/// \param[in] tags The map tag values that we want to record
|
||||
void Inc(double value, const std::unordered_map<std::string, std::string> &tags);
|
||||
}; // class Counter
|
||||
|
||||
class Sum : public Metric {
|
||||
public:
|
||||
/// A sum up of the metric points.
|
||||
///
|
||||
/// \param[in] name The Name of the metric.
|
||||
/// \param[in] description The Description of the metric.
|
||||
/// \param[in] unit The unit of the metric
|
||||
/// \param[in] tag_keys Tag keys of the metric.
|
||||
Sum(const std::string &name,
|
||||
const std::string &description,
|
||||
const std::string &unit,
|
||||
const std::vector<std::string> &tag_keys = {});
|
||||
}; // class Sum
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright 2023 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <any>
|
||||
#include <msgpack.hpp>
|
||||
|
||||
// TODO(Larry Lian) Adapt on windows
|
||||
#ifndef _WIN32
|
||||
|
||||
namespace msgpack {
|
||||
namespace adaptor {
|
||||
|
||||
template <>
|
||||
struct pack<std::any> {
|
||||
template <typename Stream>
|
||||
msgpack::packer<Stream> &operator()(msgpack::packer<Stream> &o,
|
||||
const std::any &v) const {
|
||||
const auto &any_type = v.type();
|
||||
if (any_type == typeid(msgpack::type::nil_t)) {
|
||||
o.pack(std::any_cast<msgpack::type::nil_t>(v));
|
||||
} else if (any_type == typeid(bool)) {
|
||||
o.pack(std::any_cast<bool>(v));
|
||||
} else if (any_type == typeid(uint64_t)) {
|
||||
o.pack(std::any_cast<uint64_t>(v));
|
||||
} else if (any_type == typeid(int64_t)) {
|
||||
o.pack(std::any_cast<int64_t>(v));
|
||||
} else if (any_type == typeid(double)) {
|
||||
o.pack(std::any_cast<double>(v));
|
||||
} else if (any_type == typeid(std::string)) {
|
||||
o.pack(std::any_cast<std::string>(v));
|
||||
} else if (any_type == typeid(std::vector<char>)) {
|
||||
o.pack(std::any_cast<std::vector<char>>(v));
|
||||
} else {
|
||||
throw msgpack::type_error();
|
||||
}
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct convert<std::any> {
|
||||
msgpack::object const &operator()(msgpack::object const &o, std::any &v) const {
|
||||
switch (o.type) {
|
||||
case type::NIL:
|
||||
v = o.as<msgpack::type::nil_t>();
|
||||
break;
|
||||
case type::BOOLEAN:
|
||||
v = o.as<bool>();
|
||||
break;
|
||||
case type::POSITIVE_INTEGER:
|
||||
v = o.as<uint64_t>();
|
||||
break;
|
||||
case type::NEGATIVE_INTEGER:
|
||||
v = o.as<int64_t>();
|
||||
break;
|
||||
case type::FLOAT32:
|
||||
case type::FLOAT64:
|
||||
v = o.as<double>();
|
||||
break;
|
||||
case type::STR:
|
||||
v = o.as<std::string>();
|
||||
break;
|
||||
case type::BIN:
|
||||
v = o.as<std::vector<char>>();
|
||||
break;
|
||||
default:
|
||||
throw msgpack::type_error();
|
||||
}
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace adaptor
|
||||
} // namespace msgpack
|
||||
#endif
|
||||
@@ -0,0 +1,225 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/ray_runtime_holder.h>
|
||||
#include <ray/api/serializer.h>
|
||||
#include <ray/api/type_traits.h>
|
||||
|
||||
#include <memory>
|
||||
#include <msgpack.hpp>
|
||||
#include <utility>
|
||||
|
||||
namespace ray {
|
||||
|
||||
template <typename T>
|
||||
class ObjectRef;
|
||||
|
||||
/// Common helper functions used by ObjectRef<T> and ObjectRef<void>;
|
||||
inline void CheckResult(const std::shared_ptr<msgpack::sbuffer> &packed_object) {
|
||||
bool has_error =
|
||||
ray::internal::Serializer::HasError(packed_object->data(), packed_object->size());
|
||||
if (has_error) {
|
||||
auto tp = ray::internal::Serializer::Deserialize<std::tuple<int, std::string>>(
|
||||
packed_object->data(), packed_object->size(), 1);
|
||||
std::string err_msg = std::get<1>(tp);
|
||||
throw ray::internal::RayTaskException(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
inline void CopyAndAddReference(std::string &dest_id, const std::string &id) {
|
||||
dest_id = id;
|
||||
ray::internal::GetRayRuntime()->AddLocalReference(id);
|
||||
}
|
||||
|
||||
inline void SubReference(const std::string &id) {
|
||||
ray::internal::GetRayRuntime()->RemoveLocalReference(id);
|
||||
}
|
||||
|
||||
/// Represents an object in the object store..
|
||||
/// \param T The type of object.
|
||||
template <typename T>
|
||||
class ObjectRef {
|
||||
public:
|
||||
ObjectRef();
|
||||
~ObjectRef();
|
||||
// Used to identify its type.
|
||||
static bool IsObjectRef() { return true; }
|
||||
|
||||
ObjectRef(ObjectRef &&rhs) {
|
||||
SubReference(rhs.id_);
|
||||
CopyAndAddReference(id_, rhs.id_);
|
||||
rhs.id_ = {};
|
||||
}
|
||||
|
||||
ObjectRef &operator=(ObjectRef &&rhs) {
|
||||
if (rhs == *this) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
SubReference(id_);
|
||||
CopyAndAddReference(id_, rhs.id_);
|
||||
// Rvalues need to be sub after add. Otherwise, the reference_count will become 0 and
|
||||
// be deleted. Cause information such as owner to be deleted.
|
||||
SubReference(rhs.id_);
|
||||
rhs.id_ = {};
|
||||
return *this;
|
||||
}
|
||||
|
||||
ObjectRef(const ObjectRef &rhs) { CopyAndAddReference(id_, rhs.id_); }
|
||||
|
||||
ObjectRef &operator=(const ObjectRef &rhs) {
|
||||
if (rhs == *this) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
SubReference(id_);
|
||||
CopyAndAddReference(id_, rhs.id_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ObjectRef(const std::string &id);
|
||||
|
||||
bool operator==(const ObjectRef<T> &object) const;
|
||||
|
||||
/// Get a untyped ID of the object
|
||||
const std::string &ID() const;
|
||||
|
||||
/// Get the object from the object store.
|
||||
/// This method will be blocked until the object is ready.
|
||||
///
|
||||
/// \return shared pointer of the result.
|
||||
std::shared_ptr<T> Get() const;
|
||||
|
||||
/// Get the object from the object store.
|
||||
/// This method will be blocked until the object is ready.
|
||||
///
|
||||
/// \param timeout_ms The maximum amount of time in milliseconds to wait before
|
||||
/// returning.
|
||||
/// \return shared pointer of the result.
|
||||
std::shared_ptr<T> Get(const int &timeout_ms) const;
|
||||
|
||||
/// Make ObjectRef serializable
|
||||
MSGPACK_DEFINE(id_);
|
||||
|
||||
private:
|
||||
std::string id_;
|
||||
};
|
||||
|
||||
// ---------- implementation ----------
|
||||
template <typename T>
|
||||
inline static std::shared_ptr<T> GetFromRuntime(const ObjectRef<T> &object,
|
||||
const int &timeout_ms) {
|
||||
auto packed_object = internal::GetRayRuntime()->Get(object.ID(), timeout_ms);
|
||||
CheckResult(packed_object);
|
||||
|
||||
if (ray::internal::Serializer::IsXLang(packed_object->data(), packed_object->size())) {
|
||||
return ray::internal::Serializer::Deserialize<std::shared_ptr<T>>(
|
||||
packed_object->data(), packed_object->size(), internal::XLANG_HEADER_LEN);
|
||||
}
|
||||
|
||||
if constexpr (ray::internal::is_actor_handle_v<T>) {
|
||||
auto actor_handle = ray::internal::Serializer::Deserialize<std::string>(
|
||||
packed_object->data(), packed_object->size());
|
||||
return std::make_shared<T>(T::FromBytes(actor_handle));
|
||||
}
|
||||
|
||||
return ray::internal::Serializer::Deserialize<std::shared_ptr<T>>(
|
||||
packed_object->data(), packed_object->size());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ObjectRef<T>::ObjectRef() {}
|
||||
|
||||
template <typename T>
|
||||
ObjectRef<T>::ObjectRef(const std::string &id) {
|
||||
CopyAndAddReference(id_, id);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
ObjectRef<T>::~ObjectRef() {
|
||||
SubReference(id_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool ObjectRef<T>::operator==(const ObjectRef<T> &object) const {
|
||||
return id_ == object.id_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const std::string &ObjectRef<T>::ID() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::shared_ptr<T> ObjectRef<T>::Get() const {
|
||||
return GetFromRuntime(*this, -1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::shared_ptr<T> ObjectRef<T>::Get(const int &timeout_ms) const {
|
||||
return GetFromRuntime(*this, timeout_ms);
|
||||
}
|
||||
|
||||
template <>
|
||||
class ObjectRef<void> {
|
||||
public:
|
||||
ObjectRef() = default;
|
||||
~ObjectRef() { SubReference(id_); }
|
||||
// Used to identify its type.
|
||||
static bool IsObjectRef() { return true; }
|
||||
|
||||
ObjectRef(const ObjectRef &rhs) { CopyAndAddReference(id_, rhs.id_); }
|
||||
|
||||
ObjectRef &operator=(const ObjectRef &rhs) {
|
||||
CopyAndAddReference(id_, rhs.id_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ObjectRef(const std::string &id) { CopyAndAddReference(id_, id); }
|
||||
|
||||
bool operator==(const ObjectRef<void> &object) const { return id_ == object.id_; }
|
||||
|
||||
/// Get a untyped ID of the object
|
||||
const std::string &ID() const { return id_; }
|
||||
|
||||
/// Get the object from the object store.
|
||||
/// This method will be blocked until the object is ready.
|
||||
///
|
||||
/// \return shared pointer of the result.
|
||||
void Get() const {
|
||||
auto packed_object = internal::GetRayRuntime()->Get(id_);
|
||||
CheckResult(packed_object);
|
||||
}
|
||||
|
||||
/// Get the object from the object store.
|
||||
/// This method will be blocked until the object is ready.
|
||||
///
|
||||
/// \param timeout_ms The maximum amount of time in milliseconds to wait before
|
||||
/// returning.
|
||||
/// \return shared pointer of the result.
|
||||
void Get(const int &timeout_ms) const {
|
||||
auto packed_object = internal::GetRayRuntime()->Get(id_, timeout_ms);
|
||||
CheckResult(packed_object);
|
||||
}
|
||||
|
||||
/// Make ObjectRef serializable
|
||||
MSGPACK_DEFINE(id_);
|
||||
|
||||
private:
|
||||
std::string id_;
|
||||
};
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,200 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
struct cv_none {};
|
||||
struct cv_const {};
|
||||
struct cv_volatile {};
|
||||
struct cv_cv {};
|
||||
struct ref_none {};
|
||||
struct ref_rval {};
|
||||
struct ref_lval {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
//
|
||||
// underload for free functions
|
||||
//
|
||||
|
||||
template <typename... Ts>
|
||||
struct underload_free {
|
||||
template <typename R>
|
||||
constexpr auto operator()(R (*f)(Ts...)) const {
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// underload for member functions (also free functions for convenience)
|
||||
// unspecialized template accepts any cv qualifier, any reference qualifier
|
||||
// and therefore cannot resolve an overload that differs only in qualification
|
||||
//
|
||||
|
||||
template <typename... Ts>
|
||||
struct underload : underload_free<Ts...>,
|
||||
underload<cv_none, Ts...>,
|
||||
underload<cv_const, Ts...>,
|
||||
underload<cv_volatile, Ts...>,
|
||||
underload<cv_cv, Ts...> {
|
||||
using underload_free<Ts...>::operator();
|
||||
using underload<cv_none, Ts...>::operator();
|
||||
using underload<cv_const, Ts...>::operator();
|
||||
using underload<cv_volatile, Ts...>::operator();
|
||||
using underload<cv_cv, Ts...>::operator();
|
||||
static constexpr bool is_overload_v = true;
|
||||
};
|
||||
|
||||
//
|
||||
// specializations with cv tag
|
||||
// accept any reference qualifier
|
||||
// cannot resolve overload that differs only in reference qualification
|
||||
//
|
||||
|
||||
template <typename... Ts>
|
||||
struct underload<cv_none, Ts...> : underload<cv_none, ref_none, Ts...>,
|
||||
underload<cv_none, ref_rval, Ts...>,
|
||||
underload<cv_none, ref_lval, Ts...> {
|
||||
using underload<cv_none, ref_none, Ts...>::operator();
|
||||
using underload<cv_none, ref_rval, Ts...>::operator();
|
||||
using underload<cv_none, ref_lval, Ts...>::operator();
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct underload<cv_const, Ts...> : underload<cv_const, ref_none, Ts...>,
|
||||
underload<cv_const, ref_rval, Ts...>,
|
||||
underload<cv_const, ref_lval, Ts...> {
|
||||
using underload<cv_const, ref_none, Ts...>::operator();
|
||||
using underload<cv_const, ref_rval, Ts...>::operator();
|
||||
using underload<cv_const, ref_lval, Ts...>::operator();
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct underload<cv_volatile, Ts...> : underload<cv_volatile, ref_none, Ts...>,
|
||||
underload<cv_volatile, ref_rval, Ts...>,
|
||||
underload<cv_volatile, ref_lval, Ts...> {
|
||||
using underload<cv_volatile, ref_none, Ts...>::operator();
|
||||
using underload<cv_volatile, ref_rval, Ts...>::operator();
|
||||
using underload<cv_volatile, ref_lval, Ts...>::operator();
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct underload<cv_cv, Ts...> : underload<cv_cv, ref_none, Ts...>,
|
||||
underload<cv_cv, ref_rval, Ts...>,
|
||||
underload<cv_cv, ref_lval, Ts...> {
|
||||
using underload<cv_cv, ref_none, Ts...>::operator();
|
||||
using underload<cv_cv, ref_rval, Ts...>::operator();
|
||||
using underload<cv_cv, ref_lval, Ts...>::operator();
|
||||
};
|
||||
|
||||
//
|
||||
// specializations with reference tag
|
||||
// accept any cv qualifier
|
||||
// cannot resolve overload that differs only in cv qualification
|
||||
//
|
||||
|
||||
template <typename... Ts>
|
||||
struct underload<ref_none, Ts...> : underload<cv_none, ref_none, Ts...>,
|
||||
underload<cv_const, ref_none, Ts...>,
|
||||
underload<cv_volatile, ref_none, Ts...>,
|
||||
underload<cv_cv, ref_none, Ts...> {
|
||||
using underload<cv_none, ref_none, Ts...>::operator();
|
||||
using underload<cv_const, ref_none, Ts...>::operator();
|
||||
using underload<cv_volatile, ref_none, Ts...>::operator();
|
||||
using underload<cv_cv, ref_none, Ts...>::operator();
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct underload<ref_rval, Ts...> : underload<cv_none, ref_rval, Ts...>,
|
||||
underload<cv_const, ref_rval, Ts...>,
|
||||
underload<cv_volatile, ref_rval, Ts...>,
|
||||
underload<cv_cv, ref_rval, Ts...> {
|
||||
using underload<cv_none, ref_rval, Ts...>::operator();
|
||||
using underload<cv_const, ref_rval, Ts...>::operator();
|
||||
using underload<cv_volatile, ref_rval, Ts...>::operator();
|
||||
using underload<cv_cv, ref_rval, Ts...>::operator();
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
struct underload<ref_lval, Ts...> : underload<cv_none, ref_lval, Ts...>,
|
||||
underload<cv_const, ref_lval, Ts...>,
|
||||
underload<cv_volatile, ref_lval, Ts...>,
|
||||
underload<cv_cv, ref_lval, Ts...> {
|
||||
using underload<cv_none, ref_lval, Ts...>::operator();
|
||||
using underload<cv_const, ref_lval, Ts...>::operator();
|
||||
using underload<cv_volatile, ref_lval, Ts...>::operator();
|
||||
using underload<cv_cv, ref_lval, Ts...>::operator();
|
||||
};
|
||||
|
||||
//
|
||||
// specializations with cv tag followed by reference tag
|
||||
//
|
||||
|
||||
#define UNDERLOAD(CV_TAG, REF_TAG, QUALIFIER) \
|
||||
template <typename... Ts> \
|
||||
struct underload<CV_TAG, REF_TAG, Ts...> { \
|
||||
template <typename R, typename T> \
|
||||
constexpr auto operator()(R (T::*f)(Ts...) QUALIFIER) const { \
|
||||
return f; \
|
||||
} \
|
||||
static constexpr bool is_cv_v = true; \
|
||||
};
|
||||
UNDERLOAD(cv_none, ref_none, )
|
||||
UNDERLOAD(cv_const, ref_none, const)
|
||||
UNDERLOAD(cv_volatile, ref_none, volatile)
|
||||
UNDERLOAD(cv_cv, ref_none, const volatile)
|
||||
UNDERLOAD(cv_none, ref_rval, &&)
|
||||
UNDERLOAD(cv_const, ref_rval, const &&)
|
||||
UNDERLOAD(cv_volatile, ref_rval, volatile &&)
|
||||
UNDERLOAD(cv_cv, ref_rval, const volatile &&)
|
||||
UNDERLOAD(cv_none, ref_lval, &)
|
||||
UNDERLOAD(cv_const, ref_lval, const &)
|
||||
UNDERLOAD(cv_volatile, ref_lval, volatile &)
|
||||
UNDERLOAD(cv_cv, ref_lval, const volatile &)
|
||||
#undef UNDERLOAD
|
||||
|
||||
//
|
||||
// specializations with reference tag followed by cv tag
|
||||
//
|
||||
|
||||
#define UNDERLOAD(CV_TAG, REF_TAG) \
|
||||
template <typename... Ts> \
|
||||
struct underload<REF_TAG, CV_TAG, Ts...> : underload<CV_TAG, REF_TAG, Ts...> {};
|
||||
UNDERLOAD(cv_none, ref_none)
|
||||
UNDERLOAD(cv_const, ref_none)
|
||||
UNDERLOAD(cv_volatile, ref_none)
|
||||
UNDERLOAD(cv_cv, ref_none)
|
||||
UNDERLOAD(cv_none, ref_rval)
|
||||
UNDERLOAD(cv_const, ref_rval)
|
||||
UNDERLOAD(cv_volatile, ref_rval)
|
||||
UNDERLOAD(cv_cv, ref_rval)
|
||||
UNDERLOAD(cv_none, ref_lval)
|
||||
UNDERLOAD(cv_const, ref_lval)
|
||||
UNDERLOAD(cv_volatile, ref_lval)
|
||||
UNDERLOAD(cv_cv, ref_lval)
|
||||
#undef UNDERLOAD
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <typename... Ts>
|
||||
constexpr detail::underload_free<Ts...> underload_free{};
|
||||
|
||||
template <typename... Ts>
|
||||
constexpr detail::underload<Ts...> underload{};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <ray/api/ray_exception.h>
|
||||
#include <ray/api/runtime_env.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "boost/optional.hpp"
|
||||
|
||||
namespace ray {
|
||||
|
||||
enum class ActorLifetime {
|
||||
NON_DETACHED,
|
||||
DETACHED,
|
||||
};
|
||||
|
||||
class RayConfig {
|
||||
public:
|
||||
// The address of the Ray cluster to connect to.
|
||||
// If not provided, it will be initialized from environment variable "RAY_ADDRESS" by
|
||||
// default.
|
||||
std::string address = "";
|
||||
|
||||
// Whether or not to run this application in a local mode. This is used for debugging.
|
||||
bool local_mode = false;
|
||||
|
||||
// An array of directories or dynamic library files that specify the search path for
|
||||
// user code. This parameter is not used when the application runs in local mode.
|
||||
// Only searching the top level under a directory.
|
||||
std::vector<std::string> code_search_path;
|
||||
|
||||
// The command line args to be appended as parameters of the `ray start` command. It
|
||||
// takes effect only if Ray head is started by a driver. Run `ray start --help` for
|
||||
// details.
|
||||
std::vector<std::string> head_args = {};
|
||||
|
||||
// The default actor lifetime type, `DETACHED` or `NON_DETACHED`.
|
||||
ActorLifetime default_actor_lifetime = ActorLifetime::NON_DETACHED;
|
||||
|
||||
// The job level runtime environments.
|
||||
boost::optional<RuntimeEnv> runtime_env;
|
||||
|
||||
/* The following are unstable parameters and their use is discouraged. */
|
||||
|
||||
// Prevents external clients without the username from connecting to Redis if provided.
|
||||
boost::optional<std::string> redis_username_;
|
||||
|
||||
// Prevents external clients without the password from connecting to Redis if provided.
|
||||
boost::optional<std::string> redis_password_;
|
||||
|
||||
// A specific flag for internal `default_worker`. Please don't use it in user code.
|
||||
bool is_worker_ = false;
|
||||
|
||||
// A namespace is a logical grouping of jobs and named actors.
|
||||
std::string ray_namespace = "";
|
||||
};
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class RayException : public std::exception {
|
||||
public:
|
||||
RayException(const std::string &msg) : msg_(msg){};
|
||||
|
||||
const char *what() const noexcept override { return msg_.c_str(); };
|
||||
|
||||
std::string msg_;
|
||||
};
|
||||
|
||||
class RayActorException : public RayException {
|
||||
public:
|
||||
RayActorException(const std::string &msg) : RayException(msg){};
|
||||
};
|
||||
|
||||
class RayTaskException : public RayException {
|
||||
public:
|
||||
RayTaskException(const std::string &msg) : RayException(msg){};
|
||||
};
|
||||
|
||||
class RayWorkerException : public RayException {
|
||||
public:
|
||||
RayWorkerException(const std::string &msg) : RayException(msg){};
|
||||
};
|
||||
|
||||
class UnreconstructableException : public RayException {
|
||||
public:
|
||||
UnreconstructableException(const std::string &msg) : RayException(msg){};
|
||||
};
|
||||
|
||||
class RayFunctionNotFound : public RayException {
|
||||
public:
|
||||
RayFunctionNotFound(const std::string &msg) : RayException(msg){};
|
||||
};
|
||||
|
||||
class RayRuntimeEnvException : public RayException {
|
||||
public:
|
||||
RayRuntimeEnvException(const std::string &msg) : RayException(msg){};
|
||||
};
|
||||
|
||||
class RayTimeoutException : public RayException {
|
||||
public:
|
||||
RayTimeoutException(const std::string &msg) : RayException(msg){};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,83 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/function_manager.h>
|
||||
#include <ray/api/overload.h>
|
||||
|
||||
#include "boost/utility/string_view.hpp"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
inline static std::vector<boost::string_view> GetFunctionNames(boost::string_view str) {
|
||||
std::vector<boost::string_view> output;
|
||||
size_t first = 0;
|
||||
|
||||
while (first < str.size()) {
|
||||
auto second = str.find_first_of(",", first);
|
||||
|
||||
if (first != second) {
|
||||
auto sub_str = str.substr(first, second - first);
|
||||
if (sub_str.find_first_of('(') != boost::string_view::npos) {
|
||||
second = str.find_first_of(")", first) + 1;
|
||||
}
|
||||
if (str[first] == ' ') {
|
||||
first++;
|
||||
}
|
||||
|
||||
auto name = str.substr(first, second - first);
|
||||
if (name.back() == ' ') {
|
||||
name.remove_suffix(1);
|
||||
}
|
||||
output.emplace_back(name);
|
||||
}
|
||||
|
||||
if (second == boost::string_view::npos) break;
|
||||
|
||||
first = second + 1;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
template <typename T, typename... U>
|
||||
inline static int RegisterRemoteFunctions(const T &t, U... u) {
|
||||
int index = 0;
|
||||
const auto func_names = GetFunctionNames(t);
|
||||
(void)std::initializer_list<int>{
|
||||
(FunctionManager::Instance().RegisterRemoteFunction(
|
||||
std::string(func_names[index].data(), func_names[index].length()), u),
|
||||
index++,
|
||||
0)...};
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CONCATENATE_DIRECT(s1, s2) s1##s2
|
||||
#define CONCATENATE(s1, s2) CONCATENATE_DIRECT(s1, s2)
|
||||
#ifdef _MSC_VER
|
||||
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __COUNTER__)
|
||||
#else
|
||||
#define ANONYMOUS_VARIABLE(str) CONCATENATE(str, __LINE__)
|
||||
#endif
|
||||
} // namespace internal
|
||||
|
||||
#define RAY_REMOTE(...) \
|
||||
inline auto ANONYMOUS_VARIABLE(var) = \
|
||||
ray::internal::RegisterRemoteFunctions(#__VA_ARGS__, __VA_ARGS__);
|
||||
|
||||
#define RAY_FUNC(f, ...) ray::internal::underload<__VA_ARGS__>(f)
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,105 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/common_types.h>
|
||||
#include <ray/api/task_options.h>
|
||||
#include <ray/api/xlang_function.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <msgpack.hpp>
|
||||
#include <typeinfo>
|
||||
#include <vector>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
struct RemoteFunctionHolder {
|
||||
RemoteFunctionHolder() = default;
|
||||
RemoteFunctionHolder(const std::string &module_name,
|
||||
const std::string &function_name,
|
||||
const std::string &class_name = "",
|
||||
LangType lang_type = LangType::CPP)
|
||||
: module_name_(module_name),
|
||||
function_name_(function_name),
|
||||
class_name_(class_name),
|
||||
lang_type_(lang_type) {}
|
||||
|
||||
RemoteFunctionHolder(std::string func_name) {
|
||||
if (func_name.empty()) {
|
||||
throw RayException(
|
||||
"Function not found. Please use RAY_REMOTE to register this function.");
|
||||
}
|
||||
function_name_ = std::move(func_name);
|
||||
}
|
||||
|
||||
std::string module_name_;
|
||||
std::string function_name_;
|
||||
std::string class_name_;
|
||||
LangType lang_type_ = LangType::CPP;
|
||||
};
|
||||
|
||||
class RayRuntime {
|
||||
public:
|
||||
virtual std::string Put(std::shared_ptr<msgpack::sbuffer> data) = 0;
|
||||
virtual std::shared_ptr<msgpack::sbuffer> Get(const std::string &id) = 0;
|
||||
|
||||
virtual std::vector<std::shared_ptr<msgpack::sbuffer>> Get(
|
||||
const std::vector<std::string> &ids) = 0;
|
||||
|
||||
virtual std::shared_ptr<msgpack::sbuffer> Get(const std::string &object_id,
|
||||
const int &timeout_ms) = 0;
|
||||
|
||||
virtual std::vector<std::shared_ptr<msgpack::sbuffer>> Get(
|
||||
const std::vector<std::string> &ids, const int &timeout_ms) = 0;
|
||||
|
||||
virtual std::vector<bool> Wait(const std::vector<std::string> &ids,
|
||||
int num_objects,
|
||||
int timeout_ms) = 0;
|
||||
|
||||
virtual std::string Call(const RemoteFunctionHolder &remote_function_holder,
|
||||
std::vector<TaskArg> &args,
|
||||
const CallOptions &task_options) = 0;
|
||||
virtual std::string CreateActor(const RemoteFunctionHolder &remote_function_holder,
|
||||
std::vector<TaskArg> &args,
|
||||
const ActorCreationOptions &create_options) = 0;
|
||||
virtual std::string CallActor(const RemoteFunctionHolder &remote_function_holder,
|
||||
const std::string &actor,
|
||||
std::vector<TaskArg> &args,
|
||||
const CallOptions &call_options) = 0;
|
||||
virtual void AddLocalReference(const std::string &id) = 0;
|
||||
virtual void RemoveLocalReference(const std::string &id) = 0;
|
||||
virtual std::string GetActorId(const std::string &actor_name,
|
||||
const std::string &ray_namespace) = 0;
|
||||
virtual void KillActor(const std::string &str_actor_id, bool no_restart) = 0;
|
||||
virtual void ExitActor() = 0;
|
||||
virtual ray::PlacementGroup CreatePlacementGroup(
|
||||
const ray::PlacementGroupCreationOptions &create_options) = 0;
|
||||
virtual void RemovePlacementGroup(const std::string &group_id) = 0;
|
||||
virtual bool WaitPlacementGroupReady(const std::string &group_id,
|
||||
int64_t timeout_seconds) = 0;
|
||||
virtual bool WasCurrentActorRestarted() = 0;
|
||||
virtual std::vector<PlacementGroup> GetAllPlacementGroups() = 0;
|
||||
virtual PlacementGroup GetPlacementGroupById(const std::string &id) = 0;
|
||||
virtual PlacementGroup GetPlacementGroup(const std::string &name) = 0;
|
||||
virtual bool IsLocalMode() { return false; }
|
||||
virtual std::string GetNamespace() = 0;
|
||||
virtual std::string SerializeActorHandle(const std::string &actor_id) = 0;
|
||||
virtual std::string DeserializeAndRegisterActorHandle(
|
||||
const std::string &serialized_actor_handle) = 0;
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/ray_runtime.h>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
struct RayRuntimeHolder {
|
||||
static RayRuntimeHolder &Instance() {
|
||||
static RayRuntimeHolder instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Init(std::shared_ptr<RayRuntime> runtime) { runtime_ = runtime; }
|
||||
|
||||
std::shared_ptr<RayRuntime> Runtime() { return runtime_; }
|
||||
|
||||
private:
|
||||
RayRuntimeHolder() = default;
|
||||
~RayRuntimeHolder() = default;
|
||||
RayRuntimeHolder(RayRuntimeHolder const &) = delete;
|
||||
RayRuntimeHolder(RayRuntimeHolder &&) = delete;
|
||||
RayRuntimeHolder &operator=(RayRuntimeHolder const &) = delete;
|
||||
RayRuntimeHolder &operator=(RayRuntimeHolder &&) = delete;
|
||||
|
||||
std::shared_ptr<RayRuntime> runtime_;
|
||||
};
|
||||
|
||||
inline static std::shared_ptr<RayRuntime> GetRayRuntime() {
|
||||
return RayRuntimeHolder::Instance().Runtime();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright 2022 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <ray/api/ray_exception.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
namespace ray {
|
||||
|
||||
/// This class provides interfaces of setting runtime environments for job/actor/task.
|
||||
class RuntimeEnv {
|
||||
public:
|
||||
/// Set a runtime env field by name and Object.
|
||||
/// \param[in] name The runtime env plugin name.
|
||||
/// \param[in] value An object with primitive data type or jsonable type of
|
||||
/// nlohmann/json.
|
||||
template <typename T>
|
||||
void Set(const std::string &name, const T &value);
|
||||
|
||||
/// Get the object of a runtime env field.
|
||||
/// \param[in] name The runtime env plugin name.
|
||||
template <typename T>
|
||||
T Get(const std::string &name) const;
|
||||
|
||||
/// Set a runtime env field by name and json string.
|
||||
/// \param[in] name The runtime env plugin name.
|
||||
/// \param[in] json_str A json string represents the runtime env field.
|
||||
void SetJsonStr(const std::string &name, const std::string &json_str);
|
||||
|
||||
/// Get the json string of a runtime env field.
|
||||
/// \param[in] name The runtime env plugin name.
|
||||
std::string GetJsonStr(const std::string &name) const;
|
||||
|
||||
/// Whether a field is contained.
|
||||
/// \param[in] name The runtime env plugin name.
|
||||
bool Contains(const std::string &name) const;
|
||||
|
||||
/// Remove a field by name.
|
||||
/// \param[in] name The runtime env plugin name.
|
||||
/// \return true if remove an existing field, otherwise false.
|
||||
bool Remove(const std::string &name);
|
||||
|
||||
/// Whether the runtime env is empty.
|
||||
bool Empty() const;
|
||||
|
||||
/// Serialize the runtime env to string.
|
||||
std::string Serialize() const;
|
||||
|
||||
/// Serialize the runtime env to RuntimeEnvInfo.
|
||||
std::string SerializeToRuntimeEnvInfo() const;
|
||||
|
||||
/// Deserialize the runtime env from string.
|
||||
/// \return The deserialized RuntimeEnv instance.
|
||||
static RuntimeEnv Deserialize(const std::string &serialized_runtime_env);
|
||||
|
||||
private:
|
||||
nlohmann::json fields_;
|
||||
};
|
||||
|
||||
// --------- inline implementation ------------
|
||||
|
||||
template <typename T>
|
||||
inline void RuntimeEnv::Set(const std::string &name, const T &value) {
|
||||
try {
|
||||
nlohmann::json value_j = value;
|
||||
fields_[name] = value_j;
|
||||
} catch (std::exception &e) {
|
||||
throw ray::internal::RayRuntimeEnvException("Failed to set the field " + name + ": " +
|
||||
e.what());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T RuntimeEnv::Get(const std::string &name) const {
|
||||
if (!Contains(name)) {
|
||||
throw ray::internal::RayRuntimeEnvException("The field " + name + " not found.");
|
||||
}
|
||||
try {
|
||||
return fields_[name].get<T>();
|
||||
} catch (std::exception &e) {
|
||||
throw ray::internal::RayRuntimeEnvException("Failed to get the field " + name + ": " +
|
||||
e.what());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,86 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/msgpack_adaptor.h>
|
||||
#include <ray/api/ray_exception.h>
|
||||
#include <ray/api/xlang_function.h>
|
||||
|
||||
#include <msgpack.hpp>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class Serializer {
|
||||
public:
|
||||
template <typename T>
|
||||
static msgpack::sbuffer Serialize(const T &t) {
|
||||
msgpack::sbuffer buffer;
|
||||
msgpack::pack(buffer, t);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static msgpack::sbuffer Serialize(const char *data, size_t size) {
|
||||
msgpack::sbuffer buffer;
|
||||
msgpack::packer<msgpack::sbuffer> packer(&buffer);
|
||||
packer.pack_bin(size);
|
||||
packer.pack_bin_body(data, size);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T Deserialize(const char *data, size_t size) {
|
||||
msgpack::unpacked unpacked;
|
||||
msgpack::unpack(unpacked, data, size);
|
||||
return unpacked.get().as<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T Deserialize(const char *data, size_t size, size_t offset) {
|
||||
return Deserialize<T>(data + offset, size - offset);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T Deserialize(const char *data, size_t size, size_t *off) {
|
||||
msgpack::unpacked unpacked = msgpack::unpack(data, size, *off);
|
||||
return unpacked.get().as<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static std::pair<bool, T> DeserializeWhenNil(const char *data, size_t size) {
|
||||
T val;
|
||||
size_t off = 0;
|
||||
msgpack::unpacked unpacked = msgpack::unpack(data, size, off);
|
||||
if (!unpacked.get().convert_if_not_nil(val)) {
|
||||
return {false, {}};
|
||||
}
|
||||
|
||||
return {true, val};
|
||||
}
|
||||
|
||||
static bool HasError(char *data, size_t size) {
|
||||
msgpack::unpacked unpacked = msgpack::unpack(data, size);
|
||||
return unpacked.get().is_nil() && size > 1;
|
||||
}
|
||||
|
||||
static bool IsXLang(char *data, size_t size) {
|
||||
msgpack::unpacked unpacked = msgpack::unpack(data, size);
|
||||
return unpacked.get().type == msgpack::type::POSITIVE_INTEGER &&
|
||||
size >= XLANG_HEADER_LEN;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,73 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/object_ref.h>
|
||||
|
||||
#include <boost/callable_traits.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
template <typename T>
|
||||
struct FilterArgType {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FilterArgType<ObjectRef<T>> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FilterArgType<ObjectRef<T> &> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FilterArgType<ObjectRef<T> &&> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct FilterArgType<const ObjectRef<T> &> {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename F, typename... Args>
|
||||
struct is_invocable
|
||||
: std::is_constructible<
|
||||
std::function<void(Args...)>,
|
||||
std::reference_wrapper<typename std::remove_reference<F>::type>> {};
|
||||
|
||||
template <typename Function, typename... Args>
|
||||
inline std::enable_if_t<!std::is_member_function_pointer<Function>::value> StaticCheck() {
|
||||
static_assert(is_invocable<Function, typename FilterArgType<Args>::type...>::value ||
|
||||
is_invocable<Function, Args...>::value,
|
||||
"arguments not match");
|
||||
}
|
||||
|
||||
template <typename Function, typename... Args>
|
||||
inline std::enable_if_t<std::is_member_function_pointer<Function>::value> StaticCheck() {
|
||||
using ActorType = boost::callable_traits::class_of_t<Function>;
|
||||
static_assert(
|
||||
is_invocable<Function, ActorType &, typename FilterArgType<Args>::type...>::value ||
|
||||
is_invocable<Function, ActorType &, Args...>::value,
|
||||
"arguments not match");
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,109 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/runtime_env.h>
|
||||
#include <ray/api/static_check.h>
|
||||
#include <ray/api/task_options.h>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
template <typename F>
|
||||
class TaskCaller {
|
||||
public:
|
||||
TaskCaller();
|
||||
|
||||
TaskCaller(RayRuntime *runtime, RemoteFunctionHolder remote_function_holder);
|
||||
|
||||
template <typename... Args>
|
||||
ObjectRef<boost::callable_traits::return_type_t<F>> Remote(Args &&...args);
|
||||
|
||||
TaskCaller &SetName(std::string name) {
|
||||
task_options_.name = std::move(name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskCaller &SetResources(std::unordered_map<std::string, double> resources) {
|
||||
task_options_.resources = std::move(resources);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskCaller &SetResource(std::string name, double value) {
|
||||
task_options_.resources.emplace(std::move(name), value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskCaller &SetPlacementGroup(PlacementGroup group, int bundle_index) {
|
||||
task_options_.group = group;
|
||||
task_options_.bundle_index = bundle_index;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaskCaller &SetRuntimeEnv(const ray::RuntimeEnv &runtime_env) {
|
||||
task_options_.serialized_runtime_env_info = runtime_env.SerializeToRuntimeEnvInfo();
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
RayRuntime *runtime_;
|
||||
RemoteFunctionHolder remote_function_holder_{};
|
||||
std::string function_name_;
|
||||
std::vector<TaskArg> args_;
|
||||
CallOptions task_options_;
|
||||
};
|
||||
|
||||
// ---------- implementation ----------
|
||||
|
||||
template <typename F>
|
||||
TaskCaller<F>::TaskCaller() {}
|
||||
|
||||
template <typename F>
|
||||
TaskCaller<F>::TaskCaller(RayRuntime *runtime,
|
||||
RemoteFunctionHolder remote_function_holder)
|
||||
: runtime_(runtime), remote_function_holder_(std::move(remote_function_holder)) {}
|
||||
|
||||
template <typename F>
|
||||
template <typename... Args>
|
||||
ObjectRef<boost::callable_traits::return_type_t<F>> TaskCaller<F>::Remote(
|
||||
Args &&...args) {
|
||||
CheckTaskOptions(task_options_.resources);
|
||||
|
||||
if constexpr (is_x_lang_v<F>) {
|
||||
using ArgsTuple = std::tuple<Args...>;
|
||||
Arguments::WrapArgs<ArgsTuple>(remote_function_holder_.lang_type_,
|
||||
&args_,
|
||||
std::make_index_sequence<sizeof...(Args)>{},
|
||||
std::forward<Args>(args)...);
|
||||
} else {
|
||||
StaticCheck<F, Args...>();
|
||||
using ArgsTuple = RemoveReference_t<boost::callable_traits::args_t<F>>;
|
||||
Arguments::WrapArgs<ArgsTuple>(remote_function_holder_.lang_type_,
|
||||
&args_,
|
||||
std::make_index_sequence<sizeof...(Args)>{},
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
auto returned_object_id = runtime_->Call(remote_function_holder_, args_, task_options_);
|
||||
using ReturnType = boost::callable_traits::return_type_t<F>;
|
||||
auto return_ref = ObjectRef<ReturnType>(returned_object_id);
|
||||
// The core worker will add an initial ref to each return ID to keep it in
|
||||
// scope. Now that we've created the frontend ObjectRef, remove this initial
|
||||
// ref.
|
||||
runtime_->RemoveLocalReference(returned_object_id);
|
||||
return return_ref;
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/ray_exception.h>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
inline void CheckTaskOptions(const std::unordered_map<std::string, double> &resources) {
|
||||
for (auto &pair : resources) {
|
||||
if (pair.first.empty() || pair.second == 0) {
|
||||
throw RayException("Resource values should be positive. Specified resource: " +
|
||||
pair.first + " = " + std::to_string(pair.second) + ".");
|
||||
}
|
||||
// Note: A resource value should be an integer if it is greater than 1.0.
|
||||
// e.g. 3.0 is a valid resource value, but 3.5 is not.
|
||||
double intpart;
|
||||
if (pair.second > 1 && std::modf(pair.second, &intpart) != 0.0) {
|
||||
throw RayException(
|
||||
"A resource value should be an integer if it is greater than 1.0. Specified "
|
||||
"resource: " +
|
||||
pair.first + " = " + std::to_string(pair.second) + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
enum class PlacementStrategy {
|
||||
PACK = 0,
|
||||
SPREAD = 1,
|
||||
STRICT_PACK = 2,
|
||||
STRICT_SPREAD = 3,
|
||||
UNRECOGNIZED = -1
|
||||
};
|
||||
|
||||
enum PlacementGroupState {
|
||||
PENDING = 0,
|
||||
PREPARED = 1,
|
||||
CREATED = 2,
|
||||
REMOVED = 3,
|
||||
RESCHEDULING = 4,
|
||||
UNRECOGNIZED = -1,
|
||||
};
|
||||
|
||||
struct PlacementGroupCreationOptions {
|
||||
std::string name;
|
||||
std::vector<std::unordered_map<std::string, double>> bundles;
|
||||
PlacementStrategy strategy;
|
||||
};
|
||||
|
||||
class PlacementGroup {
|
||||
public:
|
||||
PlacementGroup() = default;
|
||||
PlacementGroup(std::string id,
|
||||
PlacementGroupCreationOptions options,
|
||||
PlacementGroupState state = PlacementGroupState::UNRECOGNIZED)
|
||||
: id_(std::move(id)), options_(std::move(options)), state_(state) {}
|
||||
std::string GetID() const { return id_; }
|
||||
std::string GetName() { return options_.name; }
|
||||
std::vector<std::unordered_map<std::string, double>> GetBundles() {
|
||||
return options_.bundles;
|
||||
}
|
||||
ray::PlacementGroupState GetState() { return state_; }
|
||||
PlacementStrategy GetStrategy() { return options_.strategy; }
|
||||
bool Wait(int timeout_seconds) { return callback_(id_, timeout_seconds); }
|
||||
void SetWaitCallbak(std::function<bool(const std::string &, int)> callback) {
|
||||
callback_ = std::move(callback);
|
||||
}
|
||||
bool Empty() const { return id_.empty(); }
|
||||
|
||||
private:
|
||||
std::string id_;
|
||||
PlacementGroupCreationOptions options_;
|
||||
PlacementGroupState state_;
|
||||
std::function<bool(const std::string &, int)> callback_;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
struct CallOptions {
|
||||
std::string name;
|
||||
std::unordered_map<std::string, double> resources;
|
||||
PlacementGroup group;
|
||||
int bundle_index;
|
||||
std::string serialized_runtime_env_info;
|
||||
};
|
||||
|
||||
struct ActorCreationOptions {
|
||||
std::string name;
|
||||
std::string ray_namespace;
|
||||
std::unordered_map<std::string, double> resources;
|
||||
int max_restarts = 0;
|
||||
int max_concurrency = 1;
|
||||
PlacementGroup group;
|
||||
int bundle_index;
|
||||
std::string serialized_runtime_env_info;
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
template <typename>
|
||||
struct RemoveFirst;
|
||||
|
||||
template <class First, class... Second>
|
||||
struct RemoveFirst<std::tuple<First, Second...>> {
|
||||
using type = std::tuple<Second...>;
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
using RemoveFirst_t = typename RemoveFirst<Tuple>::type;
|
||||
|
||||
template <typename>
|
||||
struct RemoveReference;
|
||||
|
||||
template <class... T>
|
||||
struct RemoveReference<std::tuple<T...>> {
|
||||
using type = std::tuple<std::remove_const_t<std::remove_reference_t<T>>...>;
|
||||
};
|
||||
|
||||
template <class Tuple>
|
||||
using RemoveReference_t = typename RemoveReference<Tuple>::type;
|
||||
|
||||
template <class, class = void>
|
||||
struct is_object_ref_t : std::false_type {};
|
||||
|
||||
template <class T>
|
||||
struct is_object_ref_t<T, std::void_t<decltype(std::declval<T>().IsObjectRef())>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
auto constexpr is_object_ref_v = is_object_ref_t<T>::value;
|
||||
|
||||
template <class, class = void>
|
||||
struct is_actor_handle_t : std::false_type {};
|
||||
|
||||
template <class T>
|
||||
struct is_actor_handle_t<T, std::void_t<decltype(std::declval<T>().IsActorHandle())>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
auto constexpr is_actor_handle_v = is_actor_handle_t<T>::value;
|
||||
|
||||
template <class, class = void>
|
||||
struct is_python_t : std::false_type {};
|
||||
|
||||
template <class T>
|
||||
struct is_python_t<T, std::void_t<decltype(std::declval<T>().IsPython())>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
auto constexpr is_python_v = is_python_t<T>::value;
|
||||
|
||||
template <class, class = void>
|
||||
struct is_java_t : std::false_type {};
|
||||
|
||||
template <class T>
|
||||
struct is_java_t<T, std::void_t<decltype(std::declval<T>().IsJava())>> : std::true_type {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
auto constexpr is_java_v = is_java_t<T>::value;
|
||||
|
||||
template <typename T>
|
||||
auto constexpr is_x_lang_v = is_java_v<T> || is_python_v<T>;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/object_ref.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace ray {
|
||||
|
||||
/// \param T The type of object.
|
||||
template <typename T>
|
||||
class WaitResult {
|
||||
public:
|
||||
/// The object id list of ready objects
|
||||
std::list<ObjectRef<T>> ready;
|
||||
/// The object id list of unready objects
|
||||
std::list<ObjectRef<T>> unready;
|
||||
WaitResult(){};
|
||||
WaitResult(std::list<ObjectRef<T>> &&ready_objects,
|
||||
std::list<ObjectRef<T>> &&unready_objects)
|
||||
: ready(ready_objects), unready(unready_objects){};
|
||||
};
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace ray {
|
||||
|
||||
template <typename R>
|
||||
struct PyFunction {
|
||||
bool IsPython() { return true; }
|
||||
R operator()() { return {}; }
|
||||
|
||||
std::string module_name;
|
||||
std::string function_name;
|
||||
};
|
||||
|
||||
struct PyActorClass {
|
||||
bool IsPython() { return true; }
|
||||
void operator()() {}
|
||||
|
||||
std::string module_name;
|
||||
std::string class_name;
|
||||
std::string function_name = "__init__";
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
struct PyActorMethod {
|
||||
bool IsPython() { return true; }
|
||||
R operator()() { return {}; }
|
||||
|
||||
std::string function_name;
|
||||
};
|
||||
|
||||
struct JavaActorClass {
|
||||
bool IsJava() { return true; }
|
||||
void operator()() {}
|
||||
std::string class_name;
|
||||
std::string module_name = "";
|
||||
std::string function_name = "<init>";
|
||||
};
|
||||
template <typename R>
|
||||
struct JavaActorMethod {
|
||||
bool IsJava() { return true; }
|
||||
R operator()() { return {}; }
|
||||
std::string function_name;
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
struct JavaFunction {
|
||||
bool IsJava() { return true; }
|
||||
R operator()() { return {}; }
|
||||
std::string class_name;
|
||||
std::string function_name;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
enum class LangType {
|
||||
CPP,
|
||||
PYTHON,
|
||||
JAVA,
|
||||
};
|
||||
|
||||
inline constexpr size_t XLANG_HEADER_LEN = 9;
|
||||
inline constexpr std::string_view METADATA_STR_DUMMY = "__RAY_DUMMY__";
|
||||
inline constexpr std::string_view METADATA_STR_RAW = "RAW";
|
||||
inline constexpr std::string_view METADATA_STR_XLANG = "XLANG";
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <ray/api.h>
|
||||
|
||||
#include "config_internal.h"
|
||||
#include "ray/core_worker/core_worker.h"
|
||||
#include "runtime/abstract_ray_runtime.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
static bool is_init_ = false;
|
||||
|
||||
void Init(ray::RayConfig &config, int argc, char **argv) {
|
||||
if (!IsInitialized()) {
|
||||
internal::ConfigInternal::Instance().Init(config, argc, argv);
|
||||
auto runtime = internal::AbstractRayRuntime::DoInit();
|
||||
is_init_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Init(ray::RayConfig &config) { Init(config, 0, nullptr); }
|
||||
|
||||
void Init() {
|
||||
RayConfig config;
|
||||
Init(config, 0, nullptr);
|
||||
}
|
||||
|
||||
bool IsInitialized() { return is_init_; }
|
||||
|
||||
void Shutdown() {
|
||||
// TODO(SongGuyang): Clean the ray runtime.
|
||||
internal::AbstractRayRuntime::DoShutdown();
|
||||
is_init_ = false;
|
||||
}
|
||||
|
||||
void RunTaskExecutionLoop() { ::ray::core::CoreWorkerProcess::RunTaskExecutionLoop(); }
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,273 @@
|
||||
// Copyright 2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "config_internal.h"
|
||||
|
||||
#include <boost/dll/runtime_symbol_info.hpp>
|
||||
#include <charconv>
|
||||
#include <filesystem>
|
||||
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/flags/parse.h"
|
||||
#include "absl/strings/str_split.h"
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "ray/common/id.h"
|
||||
#include "ray/util/network_util.h"
|
||||
|
||||
ABSL_FLAG(std::string, ray_address, "", "The address of the Ray cluster to connect to.");
|
||||
|
||||
/// absl::flags does not provide a IsDefaultValue method, so use a non-empty dummy default
|
||||
/// value to support an empty Redis username.
|
||||
ABSL_FLAG(std::string,
|
||||
ray_redis_username,
|
||||
"absl::flags dummy default value",
|
||||
"Prevents external clients without the username from connecting to Redis "
|
||||
"if provided.");
|
||||
|
||||
/// absl::flags does not provide a IsDefaultValue method, so use a non-empty dummy default
|
||||
/// value to support empty redis password.
|
||||
ABSL_FLAG(std::string,
|
||||
ray_redis_password,
|
||||
"absl::flags dummy default value",
|
||||
"Prevents external clients without the password from connecting to Redis "
|
||||
"if provided.");
|
||||
|
||||
ABSL_FLAG(std::string,
|
||||
ray_code_search_path,
|
||||
"",
|
||||
"A list of directories or files of dynamic libraries that specify the "
|
||||
"search path for user code. Only searching the top level under a directory. "
|
||||
"':' is used as the separator.");
|
||||
|
||||
ABSL_FLAG(std::string, ray_job_id, "", "Assigned job id.");
|
||||
|
||||
ABSL_FLAG(int32_t, ray_node_manager_port, 0, "The port to use for the node manager.");
|
||||
|
||||
ABSL_FLAG(std::string,
|
||||
ray_raylet_socket_name,
|
||||
"",
|
||||
"It will specify the socket name used by the raylet if provided.");
|
||||
|
||||
ABSL_FLAG(std::string,
|
||||
ray_plasma_store_socket_name,
|
||||
"",
|
||||
"It will specify the socket name used by the plasma store if provided.");
|
||||
|
||||
ABSL_FLAG(std::string, ray_session_dir, "", "The path of this session.");
|
||||
|
||||
ABSL_FLAG(std::string, ray_logs_dir, "", "Logs dir for workers.");
|
||||
|
||||
ABSL_FLAG(std::string, ray_node_ip_address, "", "The ip address for this node.");
|
||||
|
||||
ABSL_FLAG(std::string,
|
||||
ray_head_args,
|
||||
"",
|
||||
"The command line args to be appended as parameters of the `ray start` "
|
||||
"command. It takes effect only if Ray head is started by a driver. Run `ray "
|
||||
"start --help` for details.");
|
||||
|
||||
ABSL_FLAG(std::string,
|
||||
ray_worker_id,
|
||||
"",
|
||||
"The worker ID assigned to this worker process by the raylet (hex string).");
|
||||
|
||||
ABSL_FLAG(std::string,
|
||||
ray_default_actor_lifetime,
|
||||
"",
|
||||
"The default actor lifetime type, `detached` or `non_detached`.");
|
||||
|
||||
ABSL_FLAG(std::string, ray_runtime_env, "", "The serialized runtime env.");
|
||||
|
||||
ABSL_FLAG(int,
|
||||
ray_runtime_env_hash,
|
||||
-1,
|
||||
"The computed hash of the runtime env for this worker.");
|
||||
|
||||
ABSL_FLAG(std::string,
|
||||
ray_job_namespace,
|
||||
"",
|
||||
"The namespace of job. If not set,"
|
||||
" a unique value will be randomly generated.");
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
rpc::JobConfig_ActorLifetime ParseDefaultActorLifetimeType(
|
||||
const std::string &default_actor_lifetime_origin) {
|
||||
std::string default_actor_lifetime;
|
||||
default_actor_lifetime.resize(default_actor_lifetime_origin.size());
|
||||
transform(default_actor_lifetime_origin.begin(),
|
||||
default_actor_lifetime_origin.end(),
|
||||
default_actor_lifetime.begin(),
|
||||
::tolower);
|
||||
RAY_CHECK(default_actor_lifetime == "non_detached" ||
|
||||
default_actor_lifetime == "detached")
|
||||
<< "The default_actor_lifetime_string config must be `detached` or `non_detached`.";
|
||||
return default_actor_lifetime == "non_detached"
|
||||
? rpc::JobConfig_ActorLifetime_NON_DETACHED
|
||||
: rpc::JobConfig_ActorLifetime_DETACHED;
|
||||
}
|
||||
|
||||
void ConfigInternal::Init(RayConfig &config, int argc, char **argv) {
|
||||
if (!config.address.empty()) {
|
||||
SetBootstrapAddress(config.address);
|
||||
}
|
||||
run_mode = config.local_mode ? RunMode::SINGLE_PROCESS : RunMode::CLUSTER;
|
||||
if (!config.code_search_path.empty()) {
|
||||
code_search_path = config.code_search_path;
|
||||
}
|
||||
if (config.redis_username_) {
|
||||
redis_username = *config.redis_username_;
|
||||
}
|
||||
if (config.redis_password_) {
|
||||
redis_password = *config.redis_password_;
|
||||
}
|
||||
if (!config.head_args.empty()) {
|
||||
head_args = config.head_args;
|
||||
}
|
||||
if (config.default_actor_lifetime == ActorLifetime::DETACHED) {
|
||||
default_actor_lifetime = rpc::JobConfig_ActorLifetime_DETACHED;
|
||||
}
|
||||
if (config.runtime_env) {
|
||||
runtime_env = config.runtime_env;
|
||||
}
|
||||
|
||||
if (argc != 0 && argv != nullptr) {
|
||||
// Parse config from command line.
|
||||
absl::ParseCommandLine(argc, argv);
|
||||
|
||||
if (!FLAGS_ray_code_search_path.CurrentValue().empty()) {
|
||||
// Code search path like this "/path1/xxx.so:/path2".
|
||||
RAY_LOG(DEBUG) << "The code search path is "
|
||||
<< FLAGS_ray_code_search_path.CurrentValue();
|
||||
code_search_path = absl::StrSplit(
|
||||
FLAGS_ray_code_search_path.CurrentValue(), ':', absl::SkipEmpty());
|
||||
}
|
||||
if (!FLAGS_ray_address.CurrentValue().empty()) {
|
||||
SetBootstrapAddress(FLAGS_ray_address.CurrentValue());
|
||||
}
|
||||
// Don't rewrite `ray_redis_username` when it is not set in the command line.
|
||||
if (FLAGS_ray_redis_username.CurrentValue() !=
|
||||
FLAGS_ray_redis_username.DefaultValue()) {
|
||||
redis_username = FLAGS_ray_redis_username.CurrentValue();
|
||||
}
|
||||
// Don't rewrite `ray_redis_password` when it is not set in the command line.
|
||||
if (FLAGS_ray_redis_password.CurrentValue() !=
|
||||
FLAGS_ray_redis_password.DefaultValue()) {
|
||||
redis_password = FLAGS_ray_redis_password.CurrentValue();
|
||||
}
|
||||
if (!FLAGS_ray_job_id.CurrentValue().empty()) {
|
||||
job_id = FLAGS_ray_job_id.CurrentValue();
|
||||
}
|
||||
node_manager_port = absl::GetFlag<int32_t>(FLAGS_ray_node_manager_port);
|
||||
if (!FLAGS_ray_raylet_socket_name.CurrentValue().empty()) {
|
||||
raylet_socket_name = FLAGS_ray_raylet_socket_name.CurrentValue();
|
||||
}
|
||||
if (!FLAGS_ray_plasma_store_socket_name.CurrentValue().empty()) {
|
||||
plasma_store_socket_name = FLAGS_ray_plasma_store_socket_name.CurrentValue();
|
||||
}
|
||||
if (!FLAGS_ray_session_dir.CurrentValue().empty()) {
|
||||
session_dir = FLAGS_ray_session_dir.CurrentValue();
|
||||
}
|
||||
if (!FLAGS_ray_logs_dir.CurrentValue().empty()) {
|
||||
logs_dir = FLAGS_ray_logs_dir.CurrentValue();
|
||||
}
|
||||
if (!FLAGS_ray_node_ip_address.CurrentValue().empty()) {
|
||||
node_ip_address = FLAGS_ray_node_ip_address.CurrentValue();
|
||||
}
|
||||
if (!FLAGS_ray_head_args.CurrentValue().empty()) {
|
||||
std::vector<std::string> args =
|
||||
absl::StrSplit(FLAGS_ray_head_args.CurrentValue(), ' ', absl::SkipEmpty());
|
||||
head_args.insert(head_args.end(), args.begin(), args.end());
|
||||
}
|
||||
worker_id = absl::GetFlag<std::string>(FLAGS_ray_worker_id);
|
||||
if (!FLAGS_ray_default_actor_lifetime.CurrentValue().empty()) {
|
||||
default_actor_lifetime =
|
||||
ParseDefaultActorLifetimeType(FLAGS_ray_default_actor_lifetime.CurrentValue());
|
||||
}
|
||||
if (!FLAGS_ray_runtime_env.CurrentValue().empty()) {
|
||||
runtime_env = RuntimeEnv::Deserialize(FLAGS_ray_runtime_env.CurrentValue());
|
||||
}
|
||||
runtime_env_hash = absl::GetFlag<int>(FLAGS_ray_runtime_env_hash);
|
||||
}
|
||||
worker_type = config.is_worker_ ? WorkerType::WORKER : WorkerType::DRIVER;
|
||||
if (worker_type == WorkerType::DRIVER && run_mode == RunMode::CLUSTER) {
|
||||
if (bootstrap_ip.empty()) {
|
||||
auto ray_address_env = std::getenv("RAY_ADDRESS");
|
||||
if (ray_address_env) {
|
||||
RAY_LOG(DEBUG) << "Initialize Ray cluster address to \"" << ray_address_env
|
||||
<< "\" from environment variable \"RAY_ADDRESS\".";
|
||||
SetBootstrapAddress(ray_address_env);
|
||||
}
|
||||
}
|
||||
if (code_search_path.empty()) {
|
||||
auto program_path = boost::dll::program_location().parent_path();
|
||||
RAY_LOG(INFO) << "No code search path found yet. "
|
||||
<< "The program location path " << program_path
|
||||
<< " will be added for searching dynamic libraries by default."
|
||||
<< " And you can add some search paths by '--ray_code_search_path'";
|
||||
code_search_path.emplace_back(program_path.string());
|
||||
} else {
|
||||
// Convert all the paths to absolute path to support configuring relative paths in
|
||||
// driver.
|
||||
std::vector<std::string> absolute_path;
|
||||
for (const auto &path : code_search_path) {
|
||||
absolute_path.emplace_back(std::filesystem::absolute(path).string());
|
||||
}
|
||||
code_search_path = absolute_path;
|
||||
}
|
||||
}
|
||||
if (worker_type == WorkerType::DRIVER) {
|
||||
ray_namespace = config.ray_namespace;
|
||||
if (!FLAGS_ray_job_namespace.CurrentValue().empty()) {
|
||||
ray_namespace = FLAGS_ray_job_namespace.CurrentValue();
|
||||
}
|
||||
if (ray_namespace.empty()) {
|
||||
ray_namespace = UniqueID::FromRandom().Hex();
|
||||
}
|
||||
}
|
||||
|
||||
auto job_config_json_string = std::getenv("RAY_JOB_CONFIG_JSON_ENV_VAR");
|
||||
if (job_config_json_string) {
|
||||
json job_config_json = json::parse(job_config_json_string);
|
||||
runtime_env = RuntimeEnv::Deserialize(job_config_json.at("runtime_env").dump());
|
||||
job_config_metadata = job_config_json.at("metadata")
|
||||
.get<std::unordered_map<std::string, std::string>>();
|
||||
RAY_CHECK(job_config_json.size() == 2);
|
||||
}
|
||||
};
|
||||
|
||||
void ConfigInternal::SetBootstrapAddress(std::string_view bootstrap_address) {
|
||||
auto ip_and_port = ParseAddress(std::string(bootstrap_address));
|
||||
RAY_CHECK(ip_and_port.has_value());
|
||||
|
||||
bootstrap_ip = (*ip_and_port)[0];
|
||||
auto ret = std::from_chars((*ip_and_port)[1].data(),
|
||||
(*ip_and_port)[1].data() + (*ip_and_port)[1].size(),
|
||||
bootstrap_port);
|
||||
RAY_CHECK(ret.ec == std::errc());
|
||||
}
|
||||
|
||||
void ConfigInternal::UpdateSessionDir(const std::string dir) {
|
||||
if (session_dir.empty()) {
|
||||
session_dir = dir;
|
||||
}
|
||||
if (logs_dir.empty()) {
|
||||
logs_dir = session_dir + "/logs";
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,100 @@
|
||||
// Copyright 2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <ray/api/ray_config.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "ray/core_worker/common.h"
|
||||
#include "ray/util/process_interface.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
using ray::core::WorkerType;
|
||||
|
||||
enum class RunMode { SINGLE_PROCESS, CLUSTER };
|
||||
|
||||
class ConfigInternal {
|
||||
public:
|
||||
WorkerType worker_type = WorkerType::DRIVER;
|
||||
|
||||
RunMode run_mode = RunMode::SINGLE_PROCESS;
|
||||
|
||||
std::string bootstrap_ip;
|
||||
|
||||
int bootstrap_port = 6379;
|
||||
|
||||
std::string redis_username = "default";
|
||||
|
||||
std::string redis_password = "5241590000000000";
|
||||
|
||||
int node_manager_port = 0;
|
||||
|
||||
std::vector<std::string> code_search_path;
|
||||
|
||||
std::string plasma_store_socket_name = "";
|
||||
|
||||
std::string raylet_socket_name = "";
|
||||
|
||||
std::string session_dir = "";
|
||||
|
||||
std::string job_id = "";
|
||||
|
||||
std::string logs_dir = "";
|
||||
|
||||
std::string node_ip_address = "";
|
||||
|
||||
// Worker ID assigned by raylet when starting the worker process (hex string).
|
||||
std::string worker_id = "";
|
||||
|
||||
std::vector<std::string> head_args = {};
|
||||
|
||||
boost::optional<RuntimeEnv> runtime_env;
|
||||
|
||||
int runtime_env_hash = 0;
|
||||
|
||||
// The default actor lifetime type.
|
||||
rpc::JobConfig_ActorLifetime default_actor_lifetime =
|
||||
rpc::JobConfig_ActorLifetime_NON_DETACHED;
|
||||
|
||||
std::unordered_map<std::string, std::string> job_config_metadata;
|
||||
|
||||
std::string ray_namespace = "";
|
||||
|
||||
static ConfigInternal &Instance() {
|
||||
static ConfigInternal config;
|
||||
return config;
|
||||
};
|
||||
|
||||
void Init(RayConfig &config, int argc, char **argv);
|
||||
|
||||
void SetBootstrapAddress(std::string_view address);
|
||||
|
||||
void UpdateSessionDir(const std::string dir);
|
||||
|
||||
ConfigInternal(ConfigInternal const &) = delete;
|
||||
|
||||
void operator=(ConfigInternal const &) = delete;
|
||||
|
||||
private:
|
||||
ConfigInternal(){};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,399 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "abstract_ray_runtime.h"
|
||||
|
||||
#include <ray/api.h>
|
||||
#include <ray/api/ray_exception.h>
|
||||
#include <ray/util/logging.h>
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include "../config_internal.h"
|
||||
#include "../util/function_helper.h"
|
||||
#include "local_mode_ray_runtime.h"
|
||||
#include "native_ray_runtime.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
namespace internal {
|
||||
msgpack::sbuffer PackError(std::string error_msg) {
|
||||
msgpack::sbuffer sbuffer;
|
||||
msgpack::packer<msgpack::sbuffer> packer(sbuffer);
|
||||
packer.pack(msgpack::type::nil_t());
|
||||
packer.pack(std::make_tuple((int)ray::rpc::ErrorType::TASK_EXECUTION_EXCEPTION,
|
||||
std::move(error_msg)));
|
||||
|
||||
return sbuffer;
|
||||
}
|
||||
} // namespace internal
|
||||
namespace internal {
|
||||
|
||||
using ray::core::CoreWorkerProcess;
|
||||
using ray::core::WorkerType;
|
||||
|
||||
std::shared_ptr<AbstractRayRuntime> AbstractRayRuntime::abstract_ray_runtime_ = nullptr;
|
||||
|
||||
std::shared_ptr<AbstractRayRuntime> AbstractRayRuntime::DoInit() {
|
||||
std::shared_ptr<AbstractRayRuntime> runtime;
|
||||
if (ConfigInternal::Instance().run_mode == RunMode::SINGLE_PROCESS) {
|
||||
runtime = std::make_shared<LocalModeRayRuntime>();
|
||||
} else {
|
||||
ProcessHelper::GetInstance().RayStart(TaskExecutor::ExecuteTask);
|
||||
runtime = std::make_shared<NativeRayRuntime>();
|
||||
RAY_LOG(INFO) << "Native ray runtime started.";
|
||||
}
|
||||
RAY_CHECK(runtime);
|
||||
internal::RayRuntimeHolder::Instance().Init(runtime);
|
||||
if (ConfigInternal::Instance().worker_type == WorkerType::WORKER) {
|
||||
// Load functions from code search path.
|
||||
FunctionHelper::GetInstance().LoadFunctionsFromPaths(
|
||||
ConfigInternal::Instance().code_search_path);
|
||||
}
|
||||
abstract_ray_runtime_ = runtime;
|
||||
return runtime;
|
||||
}
|
||||
|
||||
std::shared_ptr<AbstractRayRuntime> AbstractRayRuntime::GetInstance() {
|
||||
return abstract_ray_runtime_;
|
||||
}
|
||||
|
||||
void AbstractRayRuntime::DoShutdown() {
|
||||
abstract_ray_runtime_ = nullptr;
|
||||
if (ConfigInternal::Instance().run_mode == RunMode::CLUSTER) {
|
||||
ProcessHelper::GetInstance().RayStop();
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractRayRuntime::Put(std::shared_ptr<msgpack::sbuffer> data,
|
||||
ObjectID *object_id) {
|
||||
object_store_->Put(data, object_id);
|
||||
}
|
||||
|
||||
void AbstractRayRuntime::Put(std::shared_ptr<msgpack::sbuffer> data,
|
||||
const ObjectID &object_id) {
|
||||
object_store_->Put(data, object_id);
|
||||
}
|
||||
|
||||
std::string AbstractRayRuntime::Put(std::shared_ptr<msgpack::sbuffer> data) {
|
||||
ObjectID object_id;
|
||||
object_store_->Put(data, &object_id);
|
||||
return object_id.Binary();
|
||||
}
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> AbstractRayRuntime::Get(const std::string &object_id) {
|
||||
return Get(object_id, -1);
|
||||
}
|
||||
|
||||
inline static std::vector<ObjectID> StringIDsToObjectIDs(
|
||||
const std::vector<std::string> &ids) {
|
||||
std::vector<ObjectID> object_ids;
|
||||
for (std::string id : ids) {
|
||||
object_ids.push_back(ObjectID::FromBinary(id));
|
||||
}
|
||||
return object_ids;
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> AbstractRayRuntime::Get(
|
||||
const std::vector<std::string> &ids) {
|
||||
return Get(ids, -1);
|
||||
}
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> AbstractRayRuntime::Get(const std::string &object_id,
|
||||
const int &timeout_ms) {
|
||||
return object_store_->Get(ObjectID::FromBinary(object_id), timeout_ms);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> AbstractRayRuntime::Get(
|
||||
const std::vector<std::string> &ids, const int &timeout_ms) {
|
||||
return object_store_->Get(StringIDsToObjectIDs(ids), timeout_ms);
|
||||
}
|
||||
|
||||
std::vector<bool> AbstractRayRuntime::Wait(const std::vector<std::string> &ids,
|
||||
int num_objects,
|
||||
int timeout_ms) {
|
||||
return object_store_->Wait(StringIDsToObjectIDs(ids), num_objects, timeout_ms);
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<::ray::TaskArg>> TransformArgs(
|
||||
std::vector<ray::internal::TaskArg> &args, bool cross_lang) {
|
||||
std::vector<std::unique_ptr<::ray::TaskArg>> ray_args;
|
||||
for (auto &arg : args) {
|
||||
std::unique_ptr<::ray::TaskArg> ray_arg = nullptr;
|
||||
if (arg.buf) {
|
||||
auto &buffer = *arg.buf;
|
||||
auto memory_buffer = std::make_shared<ray::LocalMemoryBuffer>(
|
||||
reinterpret_cast<uint8_t *>(buffer.data()), buffer.size(), true);
|
||||
std::shared_ptr<Buffer> metadata = nullptr;
|
||||
if (cross_lang) {
|
||||
auto meta_str = arg.meta_str;
|
||||
metadata = std::make_shared<ray::LocalMemoryBuffer>(
|
||||
reinterpret_cast<uint8_t *>(const_cast<char *>(meta_str.data())),
|
||||
meta_str.size(),
|
||||
true);
|
||||
}
|
||||
ray_arg = absl::make_unique<ray::TaskArgByValue>(std::make_shared<ray::RayObject>(
|
||||
memory_buffer, metadata, std::vector<rpc::ObjectReference>()));
|
||||
} else {
|
||||
RAY_CHECK(arg.id);
|
||||
auto id = ObjectID::FromBinary(*arg.id);
|
||||
auto owner_address = ray::rpc::Address{};
|
||||
if (ConfigInternal::Instance().run_mode == RunMode::CLUSTER) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
owner_address = core_worker.GetOwnerAddressOrDie(id);
|
||||
}
|
||||
ray_arg = absl::make_unique<ray::TaskArgByReference>(id,
|
||||
owner_address,
|
||||
/*call_site=*/"");
|
||||
}
|
||||
ray_args.push_back(std::move(ray_arg));
|
||||
}
|
||||
|
||||
return ray_args;
|
||||
}
|
||||
|
||||
InvocationSpec BuildInvocationSpec1(TaskType task_type,
|
||||
const RemoteFunctionHolder &remote_function_holder,
|
||||
std::vector<ray::internal::TaskArg> &args,
|
||||
const ActorID &actor) {
|
||||
InvocationSpec invocation_spec;
|
||||
invocation_spec.task_type = task_type;
|
||||
invocation_spec.remote_function_holder = remote_function_holder;
|
||||
invocation_spec.actor_id = actor;
|
||||
invocation_spec.args =
|
||||
TransformArgs(args, remote_function_holder.lang_type_ != LangType::CPP);
|
||||
return invocation_spec;
|
||||
}
|
||||
|
||||
std::string AbstractRayRuntime::Call(const RemoteFunctionHolder &remote_function_holder,
|
||||
std::vector<ray::internal::TaskArg> &args,
|
||||
const CallOptions &task_options) {
|
||||
auto invocation_spec = BuildInvocationSpec1(
|
||||
TaskType::NORMAL_TASK, remote_function_holder, args, ActorID::Nil());
|
||||
return task_submitter_->SubmitTask(invocation_spec, task_options).Binary();
|
||||
}
|
||||
|
||||
std::string AbstractRayRuntime::CreateActor(
|
||||
const RemoteFunctionHolder &remote_function_holder,
|
||||
std::vector<ray::internal::TaskArg> &args,
|
||||
const ActorCreationOptions &create_options) {
|
||||
auto invocation_spec = BuildInvocationSpec1(
|
||||
TaskType::ACTOR_CREATION_TASK, remote_function_holder, args, ActorID::Nil());
|
||||
return task_submitter_->CreateActor(invocation_spec, create_options).Binary();
|
||||
}
|
||||
|
||||
std::string AbstractRayRuntime::CallActor(
|
||||
const RemoteFunctionHolder &remote_function_holder,
|
||||
const std::string &actor,
|
||||
std::vector<ray::internal::TaskArg> &args,
|
||||
const CallOptions &call_options) {
|
||||
InvocationSpec invocation_spec{};
|
||||
if (remote_function_holder.lang_type_ == LangType::PYTHON) {
|
||||
const auto native_actor_handle = CoreWorkerProcess::GetCoreWorker().GetActorHandle(
|
||||
ray::ActorID::FromBinary(actor));
|
||||
auto function_descriptor = native_actor_handle->ActorCreationTaskFunctionDescriptor();
|
||||
auto typed_descriptor = function_descriptor->As<PythonFunctionDescriptor>();
|
||||
RemoteFunctionHolder func_holder = remote_function_holder;
|
||||
func_holder.module_name_ = typed_descriptor->ModuleName();
|
||||
func_holder.class_name_ = typed_descriptor->ClassName();
|
||||
invocation_spec = BuildInvocationSpec1(
|
||||
TaskType::ACTOR_TASK, func_holder, args, ActorID::FromBinary(actor));
|
||||
} else if (remote_function_holder.lang_type_ == LangType::JAVA) {
|
||||
const auto native_actor_handle = CoreWorkerProcess::GetCoreWorker().GetActorHandle(
|
||||
ray::ActorID::FromBinary(actor));
|
||||
auto function_descriptor = native_actor_handle->ActorCreationTaskFunctionDescriptor();
|
||||
auto typed_descriptor = function_descriptor->As<JavaFunctionDescriptor>();
|
||||
RemoteFunctionHolder func_holder = remote_function_holder;
|
||||
func_holder.class_name_ = typed_descriptor->ClassName();
|
||||
invocation_spec = BuildInvocationSpec1(
|
||||
TaskType::ACTOR_TASK, func_holder, args, ActorID::FromBinary(actor));
|
||||
} else {
|
||||
invocation_spec = BuildInvocationSpec1(
|
||||
TaskType::ACTOR_TASK, remote_function_holder, args, ActorID::FromBinary(actor));
|
||||
}
|
||||
|
||||
return task_submitter_->SubmitActorTask(invocation_spec, call_options).Binary();
|
||||
}
|
||||
|
||||
const TaskID &AbstractRayRuntime::GetCurrentTaskId() {
|
||||
return GetWorkerContext().GetCurrentTaskID();
|
||||
}
|
||||
|
||||
JobID AbstractRayRuntime::GetCurrentJobID() {
|
||||
return GetWorkerContext().GetCurrentJobID();
|
||||
}
|
||||
|
||||
const ActorID &AbstractRayRuntime::GetCurrentActorID() {
|
||||
return GetWorkerContext().GetCurrentActorID();
|
||||
}
|
||||
|
||||
void AbstractRayRuntime::AddLocalReference(const std::string &id) {
|
||||
if (CoreWorkerProcess::IsInitialized()) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
core_worker.AddLocalReference(ObjectID::FromBinary(id));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractRayRuntime::RemoveLocalReference(const std::string &id) {
|
||||
if (CoreWorkerProcess::IsInitialized()) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
core_worker.RemoveLocalReference(ObjectID::FromBinary(id));
|
||||
}
|
||||
}
|
||||
|
||||
std::string AbstractRayRuntime::GetActorId(const std::string &actor_name,
|
||||
const std::string &ray_namespace) {
|
||||
auto actor_id = task_submitter_->GetActor(actor_name, ray_namespace);
|
||||
if (actor_id.IsNil()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return actor_id.Binary();
|
||||
}
|
||||
|
||||
void AbstractRayRuntime::KillActor(const std::string &str_actor_id, bool no_restart) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
ray::ActorID actor_id = ray::ActorID::FromBinary(str_actor_id);
|
||||
Status status = core_worker.KillActor(actor_id, true, no_restart);
|
||||
if (!status.ok()) {
|
||||
throw RayException(status.message());
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractRayRuntime::ExitActor() {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
if (ConfigInternal::Instance().worker_type != WorkerType::WORKER ||
|
||||
core_worker.GetActorId().IsNil()) {
|
||||
throw std::logic_error("This shouldn't be called on a non-actor worker.");
|
||||
}
|
||||
throw RayIntentionalSystemExitException("SystemExit");
|
||||
}
|
||||
|
||||
const std::unique_ptr<ray::gcs::GlobalStateAccessor>
|
||||
&AbstractRayRuntime::GetGlobalStateAccessor() {
|
||||
return global_state_accessor_;
|
||||
}
|
||||
|
||||
bool AbstractRayRuntime::WasCurrentActorRestarted() {
|
||||
if (ConfigInternal::Instance().run_mode == RunMode::SINGLE_PROCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &actor_id = GetCurrentActorID();
|
||||
auto byte_ptr = global_state_accessor_->GetActorInfo(actor_id);
|
||||
if (byte_ptr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rpc::ActorTableData actor_table_data;
|
||||
bool r = actor_table_data.ParseFromString(*byte_ptr);
|
||||
if (!r) {
|
||||
throw RayException("Received invalid protobuf data from GCS.");
|
||||
}
|
||||
|
||||
return actor_table_data.num_restarts() != 0;
|
||||
}
|
||||
|
||||
ray::PlacementGroup AbstractRayRuntime::CreatePlacementGroup(
|
||||
const ray::PlacementGroupCreationOptions &create_options) {
|
||||
return task_submitter_->CreatePlacementGroup(create_options);
|
||||
}
|
||||
|
||||
void AbstractRayRuntime::RemovePlacementGroup(const std::string &group_id) {
|
||||
return task_submitter_->RemovePlacementGroup(group_id);
|
||||
}
|
||||
|
||||
bool AbstractRayRuntime::WaitPlacementGroupReady(const std::string &group_id,
|
||||
int64_t timeout_seconds) {
|
||||
return task_submitter_->WaitPlacementGroupReady(group_id, timeout_seconds);
|
||||
}
|
||||
|
||||
PlacementGroup AbstractRayRuntime::GeneratePlacementGroup(const std::string &str) {
|
||||
rpc::PlacementGroupTableData pg_table_data;
|
||||
bool r = pg_table_data.ParseFromString(str);
|
||||
if (!r) {
|
||||
throw RayException("Received invalid protobuf data from GCS.");
|
||||
}
|
||||
|
||||
PlacementGroupCreationOptions options;
|
||||
options.name = pg_table_data.name();
|
||||
auto &bundles = options.bundles;
|
||||
for (auto &bundle : bundles) {
|
||||
options.bundles.emplace_back(bundle);
|
||||
}
|
||||
options.strategy = PlacementStrategy(pg_table_data.strategy());
|
||||
PlacementGroup group(pg_table_data.placement_group_id(),
|
||||
std::move(options),
|
||||
PlacementGroupState(pg_table_data.state()));
|
||||
return group;
|
||||
}
|
||||
|
||||
std::vector<PlacementGroup> AbstractRayRuntime::GetAllPlacementGroups() {
|
||||
std::vector<std::string> list = global_state_accessor_->GetAllPlacementGroupInfo();
|
||||
std::vector<PlacementGroup> groups;
|
||||
for (auto &str : list) {
|
||||
PlacementGroup group = GeneratePlacementGroup(str);
|
||||
groups.push_back(std::move(group));
|
||||
}
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
PlacementGroup AbstractRayRuntime::GetPlacementGroupById(const std::string &id) {
|
||||
PlacementGroupID pg_id = PlacementGroupID::FromBinary(id);
|
||||
auto str_ptr = global_state_accessor_->GetPlacementGroupInfo(pg_id);
|
||||
if (str_ptr == nullptr) {
|
||||
return {};
|
||||
}
|
||||
PlacementGroup group = GeneratePlacementGroup(*str_ptr);
|
||||
return group;
|
||||
}
|
||||
|
||||
PlacementGroup AbstractRayRuntime::GetPlacementGroup(const std::string &name) {
|
||||
// TODO(WangTaoTheTonic): Add namespace support for placement group.
|
||||
auto str_ptr = global_state_accessor_->GetPlacementGroupByName(
|
||||
name, CoreWorkerProcess::GetCoreWorker().GetJobConfig().ray_namespace());
|
||||
if (str_ptr == nullptr) {
|
||||
return {};
|
||||
}
|
||||
PlacementGroup group = GeneratePlacementGroup(*str_ptr);
|
||||
return group;
|
||||
}
|
||||
|
||||
std::string AbstractRayRuntime::GetNamespace() {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
return core_worker.GetJobConfig().ray_namespace();
|
||||
}
|
||||
|
||||
std::string AbstractRayRuntime::SerializeActorHandle(const std::string &actor_id) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
std::string output;
|
||||
ObjectID actor_handle_id;
|
||||
auto status = core_worker.SerializeActorHandle(
|
||||
ActorID::FromBinary(actor_id), &output, &actor_handle_id);
|
||||
return output;
|
||||
}
|
||||
|
||||
std::string AbstractRayRuntime::DeserializeAndRegisterActorHandle(
|
||||
const std::string &serialized_actor_handle) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
return core_worker
|
||||
.DeserializeAndRegisterActorHandle(serialized_actor_handle,
|
||||
ObjectID::Nil(),
|
||||
/*add_local_ref=*/true)
|
||||
.Binary();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,133 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/ray_runtime.h>
|
||||
|
||||
#include <msgpack.hpp>
|
||||
#include <mutex>
|
||||
|
||||
#include "../config_internal.h"
|
||||
#include "../util/process_helper.h"
|
||||
#include "./object/object_store.h"
|
||||
#include "./task/task_executor.h"
|
||||
#include "./task/task_submitter.h"
|
||||
#include "ray/common/id.h"
|
||||
#include "ray/core_worker/context.h"
|
||||
#include "ray/core_worker/core_worker.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
using ray::core::WorkerContext;
|
||||
|
||||
class RayIntentionalSystemExitException : public RayException {
|
||||
public:
|
||||
RayIntentionalSystemExitException(const std::string &msg) : RayException(msg){};
|
||||
};
|
||||
|
||||
class AbstractRayRuntime : public RayRuntime {
|
||||
public:
|
||||
virtual ~AbstractRayRuntime(){};
|
||||
|
||||
void Put(std::shared_ptr<msgpack::sbuffer> data, ObjectID *object_id);
|
||||
|
||||
void Put(std::shared_ptr<msgpack::sbuffer> data, const ObjectID &object_id);
|
||||
|
||||
void Put(ray::rpc::ErrorType type, const ObjectID &object_id);
|
||||
|
||||
std::string Put(std::shared_ptr<msgpack::sbuffer> data);
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> Get(const std::string &id);
|
||||
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> Get(const std::vector<std::string> &ids);
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> Get(const std::string &object_id,
|
||||
const int &timeout_ms);
|
||||
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> Get(const std::vector<std::string> &ids,
|
||||
const int &timeout_ms);
|
||||
|
||||
std::vector<bool> Wait(const std::vector<std::string> &ids,
|
||||
int num_objects,
|
||||
int timeout_ms);
|
||||
|
||||
std::string Call(const RemoteFunctionHolder &remote_function_holder,
|
||||
std::vector<ray::internal::TaskArg> &args,
|
||||
const CallOptions &task_options);
|
||||
|
||||
std::string CreateActor(const RemoteFunctionHolder &remote_function_holder,
|
||||
std::vector<ray::internal::TaskArg> &args,
|
||||
const ActorCreationOptions &create_options);
|
||||
|
||||
std::string CallActor(const RemoteFunctionHolder &remote_function_holder,
|
||||
const std::string &actor,
|
||||
std::vector<ray::internal::TaskArg> &args,
|
||||
const CallOptions &call_options);
|
||||
|
||||
void AddLocalReference(const std::string &id);
|
||||
|
||||
void RemoveLocalReference(const std::string &id);
|
||||
|
||||
std::string GetActorId(const std::string &actor_name, const std::string &ray_namespace);
|
||||
|
||||
void KillActor(const std::string &str_actor_id, bool no_restart);
|
||||
|
||||
void ExitActor();
|
||||
|
||||
ray::PlacementGroup CreatePlacementGroup(
|
||||
const ray::PlacementGroupCreationOptions &create_options);
|
||||
void RemovePlacementGroup(const std::string &group_id);
|
||||
bool WaitPlacementGroupReady(const std::string &group_id, int64_t timeout_seconds);
|
||||
|
||||
const TaskID &GetCurrentTaskId();
|
||||
|
||||
JobID GetCurrentJobID();
|
||||
|
||||
const ActorID &GetCurrentActorID();
|
||||
|
||||
virtual const WorkerContext &GetWorkerContext() = 0;
|
||||
|
||||
static std::shared_ptr<AbstractRayRuntime> GetInstance();
|
||||
static std::shared_ptr<AbstractRayRuntime> DoInit();
|
||||
|
||||
static void DoShutdown();
|
||||
|
||||
const std::unique_ptr<ray::gcs::GlobalStateAccessor> &GetGlobalStateAccessor();
|
||||
|
||||
bool WasCurrentActorRestarted();
|
||||
|
||||
virtual std::vector<PlacementGroup> GetAllPlacementGroups();
|
||||
virtual PlacementGroup GetPlacementGroupById(const std::string &id);
|
||||
virtual PlacementGroup GetPlacementGroup(const std::string &name);
|
||||
|
||||
std::string GetNamespace();
|
||||
std::string SerializeActorHandle(const std::string &actor_id);
|
||||
std::string DeserializeAndRegisterActorHandle(
|
||||
const std::string &serialized_actor_handle);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<TaskSubmitter> task_submitter_;
|
||||
std::unique_ptr<TaskExecutor> task_executor_;
|
||||
std::unique_ptr<ObjectStore> object_store_;
|
||||
std::unique_ptr<ray::gcs::GlobalStateAccessor> global_state_accessor_;
|
||||
|
||||
private:
|
||||
static std::shared_ptr<AbstractRayRuntime> abstract_ray_runtime_;
|
||||
void Execute(const TaskSpecification &task_spec);
|
||||
PlacementGroup GeneratePlacementGroup(const std::string &str);
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,54 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "local_mode_ray_runtime.h"
|
||||
|
||||
#include <ray/api.h>
|
||||
|
||||
#include "./object/local_mode_object_store.h"
|
||||
#include "./object/object_store.h"
|
||||
#include "./task/local_mode_task_submitter.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
const JobID kUnusedJobId = JobID::FromInt(1);
|
||||
}
|
||||
|
||||
LocalModeRayRuntime::LocalModeRayRuntime()
|
||||
: job_id_(kUnusedJobId),
|
||||
worker_(ray::core::WorkerType::DRIVER, ComputeDriverIdFromJob(job_id_), job_id_) {
|
||||
object_store_ = std::make_unique<LocalModeObjectStore>(*this);
|
||||
task_submitter_ = std::make_unique<LocalModeTaskSubmitter>(*this);
|
||||
}
|
||||
|
||||
ActorID LocalModeRayRuntime::GetNextActorID() {
|
||||
const auto next_task_index = worker_.GetNextTaskIndex();
|
||||
const ActorID actor_id =
|
||||
ActorID::Of(worker_.GetCurrentJobID(), worker_.GetCurrentTaskID(), next_task_index);
|
||||
return actor_id;
|
||||
}
|
||||
|
||||
const WorkerContext &LocalModeRayRuntime::GetWorkerContext() { return worker_; }
|
||||
|
||||
std::string LocalModeRayRuntime::Put(std::shared_ptr<msgpack::sbuffer> data) {
|
||||
ObjectID object_id =
|
||||
ObjectID::FromIndex(worker_.GetCurrentTaskID(), worker_.GetNextPutIndex());
|
||||
AbstractRayRuntime::Put(data, &object_id);
|
||||
return object_id.Binary();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "abstract_ray_runtime.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class LocalModeRayRuntime : public AbstractRayRuntime {
|
||||
public:
|
||||
LocalModeRayRuntime();
|
||||
|
||||
ActorID GetNextActorID();
|
||||
std::string Put(std::shared_ptr<msgpack::sbuffer> data);
|
||||
const WorkerContext &GetWorkerContext();
|
||||
bool IsLocalMode() { return true; }
|
||||
|
||||
private:
|
||||
JobID job_id_;
|
||||
WorkerContext worker_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <ray/api/logging.h>
|
||||
#include <ray/util/logging.h>
|
||||
|
||||
namespace ray {
|
||||
|
||||
class RayLoggerImpl : public RayLogger, public ray::RayLog {
|
||||
public:
|
||||
RayLoggerImpl(const char *file_name, int line_number, RayLoggerLevel severity)
|
||||
: ray::RayLog(file_name, line_number, (ray::RayLogLevel)severity) {}
|
||||
bool IsEnabled() const override { return ray::RayLog::IsEnabled(); }
|
||||
|
||||
std::ostream &Stream() override { return ray::RayLog::Stream(); }
|
||||
};
|
||||
|
||||
std::unique_ptr<RayLogger> CreateRayLogger(const char *file_name,
|
||||
int line_number,
|
||||
RayLoggerLevel severity) {
|
||||
return std::make_unique<RayLoggerImpl>(file_name, line_number, severity);
|
||||
}
|
||||
|
||||
bool IsLevelEnabled(RayLoggerLevel log_level) {
|
||||
return ray::RayLog::IsLevelEnabled((ray::RayLogLevel)log_level);
|
||||
}
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,91 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "ray/api/metric.h"
|
||||
|
||||
#include "ray/stats/metric.h"
|
||||
#include "ray/util/logging.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
Metric::~Metric() {
|
||||
if (metric_ != nullptr) {
|
||||
stats::Metric *metric = reinterpret_cast<stats::Metric *>(metric_);
|
||||
delete metric;
|
||||
metric_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Metric::GetName() const {
|
||||
RAY_CHECK(metric_ != nullptr) << "The metric_ must not be nullptr.";
|
||||
stats::Metric *metric = reinterpret_cast<stats::Metric *>(metric_);
|
||||
return metric->GetName();
|
||||
}
|
||||
|
||||
void Metric::Record(double value,
|
||||
const std::unordered_map<std::string, std::string> &tags) {
|
||||
RAY_CHECK(metric_ != nullptr) << "The metric_ must not be nullptr.";
|
||||
stats::Metric *metric = reinterpret_cast<stats::Metric *>(metric_);
|
||||
std::vector<std::pair<std::string_view, std::string>> tags_pair_vec;
|
||||
tags_pair_vec.reserve(tags.size());
|
||||
for (const auto &tag : tags) {
|
||||
tags_pair_vec.emplace_back(std::string_view(tag.first), tag.second);
|
||||
}
|
||||
metric->Record(value, std::move(tags_pair_vec));
|
||||
}
|
||||
|
||||
Gauge::Gauge(const std::string &name,
|
||||
const std::string &description,
|
||||
const std::string &unit,
|
||||
const std::vector<std::string> &tag_str_keys) {
|
||||
metric_ = new stats::Gauge(name, description, unit, tag_str_keys);
|
||||
}
|
||||
|
||||
void Gauge::Set(double value, const std::unordered_map<std::string, std::string> &tags) {
|
||||
Record(value, tags);
|
||||
}
|
||||
|
||||
Histogram::Histogram(const std::string &name,
|
||||
const std::string &description,
|
||||
const std::string &unit,
|
||||
const std::vector<double> boundaries,
|
||||
const std::vector<std::string> &tag_str_keys) {
|
||||
metric_ = new stats::Histogram(name, description, unit, boundaries, tag_str_keys);
|
||||
}
|
||||
|
||||
void Histogram::Observe(double value,
|
||||
const std::unordered_map<std::string, std::string> &tags) {
|
||||
Record(value, tags);
|
||||
}
|
||||
|
||||
Counter::Counter(const std::string &name,
|
||||
const std::string &description,
|
||||
const std::string &unit,
|
||||
const std::vector<std::string> &tag_str_keys) {
|
||||
metric_ = new stats::Count(name, description, unit, tag_str_keys);
|
||||
}
|
||||
|
||||
void Counter::Inc(double value,
|
||||
const std::unordered_map<std::string, std::string> &tags) {
|
||||
Record(value, tags);
|
||||
}
|
||||
|
||||
Sum::Sum(const std::string &name,
|
||||
const std::string &description,
|
||||
const std::string &unit,
|
||||
const std::vector<std::string> &tag_str_keys) {
|
||||
metric_ = new stats::Sum(name, description, unit, tag_str_keys);
|
||||
}
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "native_ray_runtime.h"
|
||||
|
||||
#include <ray/api.h>
|
||||
|
||||
#include "./object/native_object_store.h"
|
||||
#include "./object/object_store.h"
|
||||
#include "./task/native_task_submitter.h"
|
||||
#include "ray/common/ray_config.h"
|
||||
#include "ray/util/network_util.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
NativeRayRuntime::NativeRayRuntime() {
|
||||
object_store_ = std::make_unique<NativeObjectStore>();
|
||||
task_submitter_ = std::make_unique<NativeTaskSubmitter>();
|
||||
task_executor_ = std::make_unique<TaskExecutor>();
|
||||
|
||||
auto bootstrap_address = ConfigInternal::Instance().bootstrap_ip;
|
||||
if (bootstrap_address.empty()) {
|
||||
bootstrap_address = ray::GetNodeIpAddressFromPerspective();
|
||||
}
|
||||
global_state_accessor_ = ProcessHelper::GetInstance().CreateGlobalStateAccessor(
|
||||
bootstrap_address, ConfigInternal::Instance().bootstrap_port);
|
||||
}
|
||||
|
||||
const WorkerContext &NativeRayRuntime::GetWorkerContext() {
|
||||
return core::CoreWorkerProcess::GetCoreWorker().GetWorkerContext();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "abstract_ray_runtime.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class NativeRayRuntime : public AbstractRayRuntime {
|
||||
public:
|
||||
NativeRayRuntime();
|
||||
|
||||
const WorkerContext &GetWorkerContext();
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,121 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "local_mode_object_store.h"
|
||||
|
||||
#include <ray/api/ray_exception.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
|
||||
#include "../abstract_ray_runtime.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
LocalModeObjectStore::LocalModeObjectStore(LocalModeRayRuntime &local_mode_ray_tuntime)
|
||||
: io_context_("LocalModeObjectStore"),
|
||||
local_mode_ray_tuntime_(local_mode_ray_tuntime) {
|
||||
memory_store_ =
|
||||
std::make_unique<CoreWorkerMemoryStore>(io_context_.GetIoService(),
|
||||
clock_,
|
||||
/*reference_counting_enabled=*/false);
|
||||
}
|
||||
|
||||
void LocalModeObjectStore::PutRaw(std::shared_ptr<msgpack::sbuffer> data,
|
||||
ObjectID *object_id) {
|
||||
*object_id = ObjectID::FromRandom();
|
||||
PutRaw(data, *object_id);
|
||||
}
|
||||
|
||||
void LocalModeObjectStore::PutRaw(std::shared_ptr<msgpack::sbuffer> data,
|
||||
const ObjectID &object_id) {
|
||||
auto buffer = std::make_shared<::ray::LocalMemoryBuffer>(
|
||||
reinterpret_cast<uint8_t *>(data->data()), data->size(), true);
|
||||
// NOTE: you can't have reference when reference counting is disabled in local mode
|
||||
memory_store_->Put(
|
||||
::ray::RayObject(buffer, nullptr, std::vector<rpc::ObjectReference>()),
|
||||
object_id,
|
||||
/*has_reference=*/false);
|
||||
}
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> LocalModeObjectStore::GetRaw(const ObjectID &object_id,
|
||||
int timeout_ms) {
|
||||
std::vector<ObjectID> object_ids;
|
||||
object_ids.push_back(object_id);
|
||||
auto buffers = GetRaw(object_ids, timeout_ms);
|
||||
RAY_CHECK(buffers.size() == 1);
|
||||
return buffers[0];
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> LocalModeObjectStore::GetRaw(
|
||||
const std::vector<ObjectID> &ids, int timeout_ms) {
|
||||
std::vector<std::shared_ptr<::ray::RayObject>> results;
|
||||
::ray::Status status = memory_store_->Get(ids,
|
||||
(int)ids.size(),
|
||||
timeout_ms,
|
||||
local_mode_ray_tuntime_.GetWorkerContext(),
|
||||
&results);
|
||||
if (!status.ok()) {
|
||||
throw RayException("Get object error: " + status.ToString());
|
||||
}
|
||||
RAY_CHECK(results.size() == ids.size());
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> result_sbuffers;
|
||||
result_sbuffers.reserve(results.size());
|
||||
for (size_t i = 0; i < results.size(); i++) {
|
||||
auto data_buffer = results[i]->GetData();
|
||||
auto sbuffer = std::make_shared<msgpack::sbuffer>(data_buffer->Size());
|
||||
sbuffer->write(reinterpret_cast<const char *>(data_buffer->Data()),
|
||||
data_buffer->Size());
|
||||
result_sbuffers.push_back(sbuffer);
|
||||
}
|
||||
return result_sbuffers;
|
||||
}
|
||||
|
||||
std::vector<bool> LocalModeObjectStore::Wait(const std::vector<ObjectID> &ids,
|
||||
int num_objects,
|
||||
int timeout_ms) {
|
||||
absl::flat_hash_set<ObjectID> memory_object_ids;
|
||||
for (const auto &object_id : ids) {
|
||||
memory_object_ids.insert(object_id);
|
||||
}
|
||||
absl::flat_hash_set<ObjectID> ready, plasma_object_ids;
|
||||
|
||||
::ray::Status status = memory_store_->Wait(memory_object_ids,
|
||||
num_objects,
|
||||
timeout_ms,
|
||||
local_mode_ray_tuntime_.GetWorkerContext(),
|
||||
&ready,
|
||||
&plasma_object_ids);
|
||||
if (!status.ok()) {
|
||||
throw RayException("Wait object error: " + status.ToString());
|
||||
}
|
||||
std::vector<bool> result;
|
||||
result.reserve(ids.size());
|
||||
for (size_t i = 0; i < ids.size(); i++) {
|
||||
if (ready.find(ids[i]) != ready.end()) {
|
||||
result.push_back(true);
|
||||
} else {
|
||||
result.push_back(false);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void LocalModeObjectStore::AddLocalReference(const std::string &id) { return; }
|
||||
|
||||
void LocalModeObjectStore::RemoveLocalReference(const std::string &id) { return; }
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../local_mode_ray_runtime.h"
|
||||
#include "object_store.h"
|
||||
#include "ray/asio/asio_util.h"
|
||||
#include "ray/core_worker/store_provider/memory_store/memory_store.h"
|
||||
#include "ray/util/clock.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
using ray::core::CoreWorkerMemoryStore;
|
||||
|
||||
class LocalModeObjectStore : public ObjectStore {
|
||||
public:
|
||||
explicit LocalModeObjectStore(LocalModeRayRuntime &local_mode_ray_tuntime);
|
||||
|
||||
std::vector<bool> Wait(const std::vector<ObjectID> &ids,
|
||||
int num_objects,
|
||||
int timeout_ms);
|
||||
|
||||
void AddLocalReference(const std::string &id);
|
||||
|
||||
void RemoveLocalReference(const std::string &id);
|
||||
|
||||
private:
|
||||
void PutRaw(std::shared_ptr<msgpack::sbuffer> data, ObjectID *object_id);
|
||||
|
||||
void PutRaw(std::shared_ptr<msgpack::sbuffer> data, const ObjectID &object_id);
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> GetRaw(const ObjectID &object_id, int timeout_ms);
|
||||
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> GetRaw(const std::vector<ObjectID> &ids,
|
||||
int timeout_ms);
|
||||
|
||||
InstrumentedIOContextWithThread io_context_;
|
||||
Clock clock_;
|
||||
std::unique_ptr<CoreWorkerMemoryStore> memory_store_;
|
||||
|
||||
LocalModeRayRuntime &local_mode_ray_tuntime_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,185 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "native_object_store.h"
|
||||
|
||||
#include <ray/api/ray_exception.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
|
||||
#include "../abstract_ray_runtime.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
using ray::core::CoreWorkerProcess;
|
||||
|
||||
void NativeObjectStore::PutRaw(std::shared_ptr<msgpack::sbuffer> data,
|
||||
ObjectID *object_id) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
auto buffer = std::make_shared<::ray::LocalMemoryBuffer>(
|
||||
reinterpret_cast<uint8_t *>(data->data()), data->size(), true);
|
||||
auto status = core_worker.Put(
|
||||
::ray::RayObject(buffer, nullptr, std::vector<rpc::ObjectReference>()),
|
||||
{},
|
||||
object_id);
|
||||
if (!status.ok()) {
|
||||
throw RayException("Put object error");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void NativeObjectStore::PutRaw(std::shared_ptr<msgpack::sbuffer> data,
|
||||
const ObjectID &object_id) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
auto buffer = std::make_shared<::ray::LocalMemoryBuffer>(
|
||||
reinterpret_cast<uint8_t *>(data->data()), data->size(), true);
|
||||
auto status = core_worker.Put(
|
||||
::ray::RayObject(buffer, nullptr, std::vector<rpc::ObjectReference>()),
|
||||
{},
|
||||
object_id);
|
||||
if (!status.ok()) {
|
||||
throw RayException("Put object error");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> NativeObjectStore::GetRaw(const ObjectID &object_id,
|
||||
int timeout_ms) {
|
||||
std::vector<ObjectID> object_ids;
|
||||
object_ids.push_back(object_id);
|
||||
auto buffers = GetRaw(object_ids, timeout_ms);
|
||||
RAY_CHECK(buffers.size() == 1);
|
||||
return buffers[0];
|
||||
}
|
||||
|
||||
void NativeObjectStore::CheckException(const std::string &meta_str,
|
||||
const std::shared_ptr<Buffer> &data_buffer) {
|
||||
std::string data_str =
|
||||
data_buffer ? std::string((char *)data_buffer->Data(), data_buffer->Size()) : "";
|
||||
|
||||
if (meta_str == std::to_string(ray::rpc::ErrorType::WORKER_DIED)) {
|
||||
throw RayWorkerException(std::move(data_str));
|
||||
} else if (meta_str == std::to_string(ray::rpc::ErrorType::ACTOR_DIED)) {
|
||||
throw RayActorException(std::move(data_str));
|
||||
} else if (meta_str == std::to_string(ray::rpc::ErrorType::TASK_EXECUTION_EXCEPTION)) {
|
||||
throw RayTaskException(std::move(data_str));
|
||||
} else if (meta_str == std::to_string(ray::rpc::ErrorType::OBJECT_LOST) ||
|
||||
meta_str == std::to_string(ray::rpc::ErrorType::OWNER_DIED) ||
|
||||
meta_str == std::to_string(ray::rpc::ErrorType::OBJECT_DELETED) ||
|
||||
meta_str ==
|
||||
std::to_string(ray::rpc::ErrorType::OBJECT_UNRECONSTRUCTABLE_PUT) ||
|
||||
meta_str ==
|
||||
std::to_string(
|
||||
ray::rpc::ErrorType::OBJECT_UNRECONSTRUCTABLE_RETRIES_DISABLED) ||
|
||||
meta_str ==
|
||||
std::to_string(
|
||||
ray::rpc::ErrorType::OBJECT_UNRECONSTRUCTABLE_LINEAGE_EVICTED) ||
|
||||
meta_str ==
|
||||
std::to_string(ray::rpc::ErrorType::
|
||||
OBJECT_UNRECONSTRUCTABLE_MAX_ATTEMPTS_EXCEEDED) ||
|
||||
meta_str ==
|
||||
std::to_string(ray::rpc::ErrorType::OBJECT_UNRECONSTRUCTABLE_BORROWED) ||
|
||||
meta_str ==
|
||||
std::to_string(
|
||||
ray::rpc::ErrorType::OBJECT_UNRECONSTRUCTABLE_REF_NOT_FOUND) ||
|
||||
meta_str ==
|
||||
std::to_string(
|
||||
ray::rpc::ErrorType::OBJECT_UNRECONSTRUCTABLE_TASK_CANCELLED) ||
|
||||
meta_str ==
|
||||
std::to_string(
|
||||
ray::rpc::ErrorType::OBJECT_UNRECONSTRUCTABLE_LINEAGE_DISABLED)) {
|
||||
// TODO: Differentiate object error
|
||||
throw UnreconstructableException(std::move(data_str));
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> NativeObjectStore::GetRaw(
|
||||
const std::vector<ObjectID> &ids, int timeout_ms) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
std::vector<std::shared_ptr<::ray::RayObject>> results;
|
||||
::ray::Status status = core_worker.Get(ids, timeout_ms, results);
|
||||
if (!status.ok()) {
|
||||
if (status.IsTimedOut()) {
|
||||
throw RayTimeoutException("Get object error:" + status.message());
|
||||
}
|
||||
throw RayException("Get object error: " + status.ToString());
|
||||
}
|
||||
RAY_CHECK(results.size() == ids.size());
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> result_sbuffers;
|
||||
result_sbuffers.reserve(results.size());
|
||||
for (size_t i = 0; i < results.size(); i++) {
|
||||
const auto &meta = results[i]->GetMetadata();
|
||||
const auto &data_buffer = results[i]->GetData();
|
||||
std::string meta_str = "";
|
||||
if (meta != nullptr) {
|
||||
meta_str = std::string((char *)meta->Data(), meta->Size());
|
||||
CheckException(meta_str, data_buffer);
|
||||
}
|
||||
|
||||
const char *data = nullptr;
|
||||
size_t data_size = 0;
|
||||
if (data_buffer) {
|
||||
data = reinterpret_cast<const char *>(data_buffer->Data());
|
||||
data_size = data_buffer->Size();
|
||||
}
|
||||
if (meta_str == METADATA_STR_RAW) {
|
||||
// TODO(LarryLian) In order to minimize the modification,
|
||||
// there is an extra serialization here, but the performance will be a little worse.
|
||||
// This code can be optimized later to improve performance
|
||||
auto raw_buffer = Serializer::Serialize(data, data_size);
|
||||
auto sbuffer = std::make_shared<msgpack::sbuffer>(raw_buffer.size());
|
||||
sbuffer->write(raw_buffer.data(), raw_buffer.size());
|
||||
result_sbuffers.push_back(sbuffer);
|
||||
} else {
|
||||
auto sbuffer = std::make_shared<msgpack::sbuffer>(data_size);
|
||||
sbuffer->write(data, data_size);
|
||||
result_sbuffers.push_back(sbuffer);
|
||||
}
|
||||
}
|
||||
return result_sbuffers;
|
||||
}
|
||||
|
||||
std::vector<bool> NativeObjectStore::Wait(const std::vector<ObjectID> &ids,
|
||||
int num_objects,
|
||||
int timeout_ms) {
|
||||
std::vector<bool> results;
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
// TODO(SongGuyang): Support `fetch_local` option in API.
|
||||
// Simply set `fetch_local` to be true.
|
||||
::ray::Status status = core_worker.Wait(ids, num_objects, timeout_ms, &results, true);
|
||||
if (!status.ok()) {
|
||||
throw RayException("Wait object error: " + status.ToString());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
void NativeObjectStore::AddLocalReference(const std::string &id) {
|
||||
if (CoreWorkerProcess::IsInitialized()) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
core_worker.AddLocalReference(ObjectID::FromBinary(id));
|
||||
}
|
||||
}
|
||||
|
||||
void NativeObjectStore::RemoveLocalReference(const std::string &id) {
|
||||
if (CoreWorkerProcess::IsInitialized()) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
core_worker.RemoveLocalReference(ObjectID::FromBinary(id));
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,49 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../native_ray_runtime.h"
|
||||
#include "object_store.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class NativeObjectStore : public ObjectStore {
|
||||
public:
|
||||
std::vector<bool> Wait(const std::vector<ObjectID> &ids,
|
||||
int num_objects,
|
||||
int timeout_ms);
|
||||
|
||||
void AddLocalReference(const std::string &id);
|
||||
|
||||
void RemoveLocalReference(const std::string &id);
|
||||
|
||||
private:
|
||||
void PutRaw(std::shared_ptr<msgpack::sbuffer> data, ObjectID *object_id);
|
||||
|
||||
void PutRaw(std::shared_ptr<msgpack::sbuffer> data, const ObjectID &object_id);
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> GetRaw(const ObjectID &object_id, int timeout_ms);
|
||||
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> GetRaw(const std::vector<ObjectID> &ids,
|
||||
int timeout_ms);
|
||||
void CheckException(const std::string &meta_str,
|
||||
const std::shared_ptr<Buffer> &data_buffer);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2020 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "object_store.h"
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include "ray/core_worker/context.h"
|
||||
#include "ray/core_worker/core_worker.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
using ray::core::CoreWorkerProcess;
|
||||
|
||||
void ObjectStore::Put(std::shared_ptr<msgpack::sbuffer> data, ObjectID *object_id) {
|
||||
PutRaw(data, object_id);
|
||||
}
|
||||
|
||||
void ObjectStore::Put(std::shared_ptr<msgpack::sbuffer> data, const ObjectID &object_id) {
|
||||
PutRaw(data, object_id);
|
||||
}
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> ObjectStore::Get(const ObjectID &object_id,
|
||||
int timeout_ms) {
|
||||
return GetRaw(object_id, timeout_ms);
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> ObjectStore::Get(
|
||||
const std::vector<ObjectID> &ids, int timeout_ms) {
|
||||
return GetRaw(ids, timeout_ms);
|
||||
}
|
||||
|
||||
std::unordered_map<ObjectID, std::pair<size_t, size_t>>
|
||||
ObjectStore::GetAllReferenceCounts() const {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
return core_worker.GetAllReferenceCounts();
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,105 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/wait_result.h>
|
||||
|
||||
#include <memory>
|
||||
#include <msgpack.hpp>
|
||||
|
||||
#include "ray/common/id.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class ObjectStore {
|
||||
public:
|
||||
/// The default timeout to get object.
|
||||
static const int default_get_timeout_ms = 1000;
|
||||
|
||||
virtual ~ObjectStore(){};
|
||||
|
||||
/// Store an object in the object store.
|
||||
///
|
||||
/// \param[in] data The serialized object data buffer to store.
|
||||
/// \param[out] The id which is allocated to the object.
|
||||
void Put(std::shared_ptr<msgpack::sbuffer> data, ObjectID *object_id);
|
||||
|
||||
/// Store an object in the object store.
|
||||
///
|
||||
/// \param[in] data The serialized object data buffer to store.
|
||||
/// \param[in] object_id The object which should be stored.
|
||||
void Put(std::shared_ptr<msgpack::sbuffer> data, const ObjectID &object_id);
|
||||
|
||||
/// Get a single object from the object store.
|
||||
/// This method will be blocked until the object are ready or wait for timeout.
|
||||
///
|
||||
/// \param[in] object_id The object id which should be got.
|
||||
/// \param[in] timeout_ms The maximum wait time in milliseconds.
|
||||
/// \return shared pointer of the result buffer.
|
||||
std::shared_ptr<msgpack::sbuffer> Get(const ObjectID &object_id,
|
||||
int timeout_ms = default_get_timeout_ms);
|
||||
|
||||
/// Get a list of objects from the object store.
|
||||
/// This method will be blocked until all the objects are ready or wait for timeout.
|
||||
///
|
||||
/// \param[in] ids The object id array which should be got.
|
||||
/// \param[in] timeout_ms The maximum wait time in milliseconds.
|
||||
/// \return shared pointer array of the result buffer.
|
||||
std::vector<std::shared_ptr<msgpack::sbuffer>> Get(
|
||||
const std::vector<ObjectID> &ids, int timeout_ms = default_get_timeout_ms);
|
||||
|
||||
/// Wait for a list of ObjectRefs to be locally available,
|
||||
/// until specified number of objects are ready, or specified timeout has passed.
|
||||
///
|
||||
/// \param[in] ids The object id array which should be waited.
|
||||
/// \param[in] num_objects The minimum number of objects to wait.
|
||||
/// \param[in] timeout_ms The maximum wait time in milliseconds.
|
||||
/// \return A vector that indicates each object has appeared or not.
|
||||
virtual std::vector<bool> Wait(const std::vector<ObjectID> &ids,
|
||||
int num_objects,
|
||||
int timeout_ms) = 0;
|
||||
|
||||
/// Increase the reference count for this object ID.
|
||||
/// Increase the local reference count for this object ID. Should be called
|
||||
/// by the language frontend when a new reference is created.
|
||||
///
|
||||
/// \param[in] id The binary string ID to increase the reference count for.
|
||||
virtual void AddLocalReference(const std::string &id) = 0;
|
||||
|
||||
/// Decrease the reference count for this object ID. Should be called
|
||||
/// by the language frontend when a reference is destroyed.
|
||||
///
|
||||
/// \param[in] id The binary string ID to decrease the reference count for.
|
||||
virtual void RemoveLocalReference(const std::string &id) = 0;
|
||||
|
||||
/// Returns a map of all ObjectIDs currently in scope with a pair of their
|
||||
/// (local, submitted_task) reference counts. For debugging purposes.
|
||||
std::unordered_map<ObjectID, std::pair<size_t, size_t>> GetAllReferenceCounts() const;
|
||||
|
||||
private:
|
||||
virtual void PutRaw(std::shared_ptr<msgpack::sbuffer> data, ObjectID *object_id) = 0;
|
||||
|
||||
virtual void PutRaw(std::shared_ptr<msgpack::sbuffer> data,
|
||||
const ObjectID &object_id) = 0;
|
||||
|
||||
virtual std::shared_ptr<msgpack::sbuffer> GetRaw(const ObjectID &object_id,
|
||||
int timeout_ms) = 0;
|
||||
|
||||
virtual std::vector<std::shared_ptr<msgpack::sbuffer>> GetRaw(
|
||||
const std::vector<ObjectID> &ids, int timeout_ms) = 0;
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2022 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <google/protobuf/util/json_util.h>
|
||||
#include <ray/api/runtime_env.h>
|
||||
#include <ray/util/logging.h>
|
||||
|
||||
#include "src/ray/protobuf/public/runtime_environment.pb.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
void RuntimeEnv::SetJsonStr(const std::string &name, const std::string &json_str) {
|
||||
try {
|
||||
nlohmann::json value_j = nlohmann::json::parse(json_str);
|
||||
fields_[name] = value_j;
|
||||
} catch (std::exception &e) {
|
||||
throw ray::internal::RayRuntimeEnvException("Failed to set the field " + name +
|
||||
" by json string: " + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::string RuntimeEnv::GetJsonStr(const std::string &name) const {
|
||||
if (!Contains(name)) {
|
||||
throw ray::internal::RayRuntimeEnvException("The field " + name + " not found.");
|
||||
}
|
||||
auto j = fields_[name].get<nlohmann::json>();
|
||||
return j.dump();
|
||||
}
|
||||
|
||||
bool RuntimeEnv::Contains(const std::string &name) const {
|
||||
return fields_.contains(name);
|
||||
}
|
||||
|
||||
bool RuntimeEnv::Remove(const std::string &name) {
|
||||
if (Contains(name)) {
|
||||
fields_.erase(name);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RuntimeEnv::Empty() const { return fields_.empty(); }
|
||||
|
||||
std::string RuntimeEnv::Serialize() const { return fields_.dump(); }
|
||||
|
||||
std::string RuntimeEnv::SerializeToRuntimeEnvInfo() const {
|
||||
rpc::RuntimeEnvInfo runtime_env_info;
|
||||
runtime_env_info.set_serialized_runtime_env(Serialize());
|
||||
std::string serialized_runtime_env_info;
|
||||
RAY_CHECK(google::protobuf::util::MessageToJsonString(runtime_env_info,
|
||||
&serialized_runtime_env_info)
|
||||
.ok());
|
||||
return serialized_runtime_env_info;
|
||||
}
|
||||
|
||||
RuntimeEnv RuntimeEnv::Deserialize(const std::string &serialized_runtime_env) {
|
||||
RuntimeEnv runtime_env;
|
||||
try {
|
||||
runtime_env.fields_ = nlohmann::json::parse(serialized_runtime_env);
|
||||
} catch (std::exception &e) {
|
||||
throw ray::internal::RayRuntimeEnvException("Failed to deserialize runtime env " +
|
||||
serialized_runtime_env + ": " + e.what());
|
||||
}
|
||||
return runtime_env;
|
||||
}
|
||||
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/ray_runtime.h>
|
||||
|
||||
#include <msgpack.hpp>
|
||||
|
||||
#include "ray/common/id.h"
|
||||
#include "ray/common/task/task_util.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class InvocationSpec {
|
||||
public:
|
||||
TaskType task_type;
|
||||
std::string name;
|
||||
ActorID actor_id;
|
||||
int sequence_number;
|
||||
RemoteFunctionHolder remote_function_holder;
|
||||
std::vector<std::unique_ptr<::ray::TaskArg>> args;
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,201 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "local_mode_task_submitter.h"
|
||||
|
||||
#include <ray/api/ray_exception.h>
|
||||
|
||||
#include <boost/asio/post.hpp>
|
||||
#include <memory>
|
||||
|
||||
#include "../abstract_ray_runtime.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
LocalModeTaskSubmitter::LocalModeTaskSubmitter(
|
||||
LocalModeRayRuntime &local_mode_ray_tuntime)
|
||||
: local_mode_ray_tuntime_(local_mode_ray_tuntime) {
|
||||
thread_pool_.reset(new boost::asio::thread_pool(10));
|
||||
}
|
||||
|
||||
ObjectID LocalModeTaskSubmitter::Submit(InvocationSpec &invocation,
|
||||
const ActorCreationOptions &options) {
|
||||
/// TODO(SongGuyang): Make the information of TaskSpecification more reasonable
|
||||
/// We just reuse the TaskSpecification class and make the single process mode work.
|
||||
/// Maybe some information of TaskSpecification are not reasonable or invalid.
|
||||
/// We will enhance this after implement the cluster mode.
|
||||
auto functionDescriptor = FunctionDescriptorBuilder::BuildCpp(
|
||||
invocation.remote_function_holder.function_name_);
|
||||
rpc::Address address;
|
||||
std::unordered_map<std::string, double> required_resources;
|
||||
std::unordered_map<std::string, double> required_placement_resources;
|
||||
std::string task_id_data(TaskID::Size(), 0);
|
||||
FillRandom(&task_id_data);
|
||||
auto task_id = TaskID::FromBinary(task_id_data);
|
||||
TaskSpecBuilder builder;
|
||||
std::string task_name =
|
||||
invocation.name.empty() ? functionDescriptor->DefaultTaskName() : invocation.name;
|
||||
|
||||
// TODO (Alex): Properly set the depth here?
|
||||
builder.SetCommonTaskSpec(task_id,
|
||||
task_name,
|
||||
rpc::Language::CPP,
|
||||
functionDescriptor,
|
||||
local_mode_ray_tuntime_.GetCurrentJobID(),
|
||||
rpc::JobConfig(),
|
||||
local_mode_ray_tuntime_.GetCurrentTaskId(),
|
||||
0,
|
||||
local_mode_ray_tuntime_.GetCurrentTaskId(),
|
||||
address,
|
||||
1,
|
||||
/*returns_dynamic=*/false,
|
||||
/*is_streaming_generator*/ false,
|
||||
/*generator_backpressure_num_objects*/ -1,
|
||||
required_resources,
|
||||
required_placement_resources,
|
||||
"",
|
||||
/*depth=*/0,
|
||||
local_mode_ray_tuntime_.GetCurrentTaskId(),
|
||||
// Stacktrace is not available in local mode.
|
||||
/*call_site=*/"");
|
||||
if (invocation.task_type == TaskType::NORMAL_TASK) {
|
||||
} else if (invocation.task_type == TaskType::ACTOR_CREATION_TASK) {
|
||||
invocation.actor_id = local_mode_ray_tuntime_.GetNextActorID();
|
||||
rpc::SchedulingStrategy scheduling_strategy;
|
||||
scheduling_strategy.mutable_default_scheduling_strategy();
|
||||
builder.SetActorCreationTaskSpec(invocation.actor_id,
|
||||
/*serialized_actor_handle=*/"",
|
||||
scheduling_strategy,
|
||||
options.max_restarts,
|
||||
/*max_task_retries=*/0,
|
||||
{},
|
||||
options.max_concurrency);
|
||||
} else if (invocation.task_type == TaskType::ACTOR_TASK) {
|
||||
const TaskID actor_creation_task_id =
|
||||
TaskID::ForActorCreationTask(invocation.actor_id);
|
||||
const ObjectID actor_creation_dummy_object_id =
|
||||
ObjectID::FromIndex(actor_creation_task_id, 1);
|
||||
// NOTE: Ray CPP doesn't support retries and retry_exceptions.
|
||||
builder.SetActorTaskSpec(invocation.actor_id,
|
||||
actor_creation_dummy_object_id,
|
||||
/*max_retries=*/0,
|
||||
/*retry_exceptions=*/false,
|
||||
/*serialized_retry_exception_allowlist=*/"",
|
||||
invocation.sequence_number,
|
||||
/*tensor_transport=*/std::nullopt,
|
||||
/*is_detached_actor=*/false);
|
||||
} else {
|
||||
throw RayException("unknown task type");
|
||||
}
|
||||
for (size_t i = 0; i < invocation.args.size(); i++) {
|
||||
builder.AddArg(*invocation.args[i]);
|
||||
}
|
||||
auto task_specification = std::move(builder).ConsumeAndBuild();
|
||||
|
||||
ObjectID return_object_id = task_specification.ReturnId(0);
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> actor;
|
||||
std::shared_ptr<absl::Mutex> mutex;
|
||||
if (invocation.task_type == TaskType::ACTOR_TASK) {
|
||||
absl::MutexLock lock(&actor_contexts_mutex_);
|
||||
actor = actor_contexts_.at(invocation.actor_id).get()->current_actor;
|
||||
mutex = actor_contexts_.at(invocation.actor_id).get()->actor_mutex;
|
||||
}
|
||||
AbstractRayRuntime *runtime = &local_mode_ray_tuntime_;
|
||||
if (invocation.task_type == TaskType::ACTOR_CREATION_TASK ||
|
||||
invocation.task_type == TaskType::ACTOR_TASK) {
|
||||
/// TODO(SongGuyang): Handle task dependencies.
|
||||
/// Execute actor task directly in the main thread because we must guarantee the actor
|
||||
/// task executed by calling order.
|
||||
TaskExecutor::Invoke(
|
||||
task_specification, actor, runtime, actor_contexts_, actor_contexts_mutex_);
|
||||
} else {
|
||||
boost::asio::post(
|
||||
*thread_pool_.get(),
|
||||
std::bind(
|
||||
[actor, mutex, runtime, this](TaskSpecification &ts) {
|
||||
if (mutex) {
|
||||
absl::MutexLock lock(mutex.get());
|
||||
}
|
||||
TaskExecutor::Invoke(
|
||||
ts, actor, runtime, this->actor_contexts_, this->actor_contexts_mutex_);
|
||||
},
|
||||
std::move(task_specification)));
|
||||
}
|
||||
return return_object_id;
|
||||
}
|
||||
|
||||
ObjectID LocalModeTaskSubmitter::SubmitTask(InvocationSpec &invocation,
|
||||
const CallOptions &call_options) {
|
||||
return Submit(invocation, {});
|
||||
}
|
||||
|
||||
ActorID LocalModeTaskSubmitter::CreateActor(InvocationSpec &invocation,
|
||||
const ActorCreationOptions &create_options) {
|
||||
Submit(invocation, create_options);
|
||||
if (!create_options.name.empty()) {
|
||||
absl::MutexLock lock(&named_actors_mutex_);
|
||||
named_actors_.emplace(create_options.name, invocation.actor_id);
|
||||
}
|
||||
|
||||
return invocation.actor_id;
|
||||
}
|
||||
|
||||
ObjectID LocalModeTaskSubmitter::SubmitActorTask(InvocationSpec &invocation,
|
||||
const CallOptions &call_options) {
|
||||
return Submit(invocation, {});
|
||||
}
|
||||
|
||||
ActorID LocalModeTaskSubmitter::GetActor(const std::string &actor_name,
|
||||
const std::string &ray_namespace) const {
|
||||
absl::MutexLock lock(&named_actors_mutex_);
|
||||
auto it = named_actors_.find(actor_name);
|
||||
if (it == named_actors_.end()) {
|
||||
return ActorID::Nil();
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
ray::PlacementGroup LocalModeTaskSubmitter::CreatePlacementGroup(
|
||||
const ray::PlacementGroupCreationOptions &create_options) {
|
||||
ray::PlacementGroup placement_group{
|
||||
PlacementGroupID::Of(local_mode_ray_tuntime_.GetCurrentJobID()).Binary(),
|
||||
create_options};
|
||||
placement_group.SetWaitCallbak([this](const std::string &id, int64_t timeout_seconds) {
|
||||
return WaitPlacementGroupReady(id, timeout_seconds);
|
||||
});
|
||||
placement_groups_.emplace(placement_group.GetID(), placement_group);
|
||||
return placement_group;
|
||||
}
|
||||
|
||||
void LocalModeTaskSubmitter::RemovePlacementGroup(const std::string &group_id) {
|
||||
placement_groups_.erase(group_id);
|
||||
}
|
||||
|
||||
std::vector<PlacementGroup> LocalModeTaskSubmitter::GetAllPlacementGroups() {
|
||||
throw RayException("Ray doesn't support placement group operations in local mode.");
|
||||
}
|
||||
|
||||
PlacementGroup LocalModeTaskSubmitter::GetPlacementGroupById(const std::string &id) {
|
||||
throw RayException("Ray doesn't support placement group operations in local mode.");
|
||||
}
|
||||
|
||||
PlacementGroup LocalModeTaskSubmitter::GetPlacementGroup(const std::string &name) {
|
||||
throw RayException("Ray doesn't support placement group operations in local mode.");
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/asio/thread_pool.hpp>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
#include "../local_mode_ray_runtime.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "invocation_spec.h"
|
||||
#include "task_executor.h"
|
||||
#include "task_submitter.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class LocalModeTaskSubmitter : public TaskSubmitter {
|
||||
public:
|
||||
LocalModeTaskSubmitter(LocalModeRayRuntime &local_mode_ray_tuntime);
|
||||
|
||||
ObjectID SubmitTask(InvocationSpec &invocation, const CallOptions &call_options);
|
||||
|
||||
ActorID CreateActor(InvocationSpec &invocation,
|
||||
const ActorCreationOptions &create_options);
|
||||
|
||||
ObjectID SubmitActorTask(InvocationSpec &invocation, const CallOptions &call_options);
|
||||
|
||||
ActorID GetActor(const std::string &actor_name, const std::string &ray_namespace) const;
|
||||
|
||||
ray::PlacementGroup CreatePlacementGroup(
|
||||
const ray::PlacementGroupCreationOptions &create_options);
|
||||
void RemovePlacementGroup(const std::string &group_id);
|
||||
std::vector<PlacementGroup> GetAllPlacementGroups();
|
||||
PlacementGroup GetPlacementGroupById(const std::string &id);
|
||||
PlacementGroup GetPlacementGroup(const std::string &name);
|
||||
|
||||
private:
|
||||
ObjectID Submit(InvocationSpec &invocation, const ActorCreationOptions &options);
|
||||
|
||||
std::unordered_map<ActorID, std::unique_ptr<ActorContext>> actor_contexts_;
|
||||
|
||||
absl::Mutex actor_contexts_mutex_;
|
||||
|
||||
std::unordered_map<std::string, ActorID> named_actors_
|
||||
ABSL_GUARDED_BY(named_actors_mutex_);
|
||||
mutable absl::Mutex named_actors_mutex_;
|
||||
|
||||
std::unique_ptr<boost::asio::thread_pool> thread_pool_;
|
||||
|
||||
LocalModeRayRuntime &local_mode_ray_tuntime_;
|
||||
|
||||
std::unordered_map<std::string, ray::PlacementGroup> placement_groups_;
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,241 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "native_task_submitter.h"
|
||||
|
||||
#include <ray/api/ray_exception.h>
|
||||
|
||||
#include "../abstract_ray_runtime.h"
|
||||
#include "ray/common/ray_config.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
using ray::core::CoreWorkerProcess;
|
||||
using ray::core::TaskOptions;
|
||||
|
||||
RayFunction BuildRayFunction(InvocationSpec &invocation) {
|
||||
if (invocation.remote_function_holder.lang_type_ == LangType::CPP) {
|
||||
auto function_descriptor = FunctionDescriptorBuilder::BuildCpp(
|
||||
invocation.remote_function_holder.function_name_,
|
||||
"",
|
||||
invocation.remote_function_holder.class_name_);
|
||||
return RayFunction(ray::Language::CPP, function_descriptor);
|
||||
} else if (invocation.remote_function_holder.lang_type_ == LangType::PYTHON) {
|
||||
auto function_descriptor = FunctionDescriptorBuilder::BuildPython(
|
||||
invocation.remote_function_holder.module_name_,
|
||||
invocation.remote_function_holder.class_name_,
|
||||
invocation.remote_function_holder.function_name_,
|
||||
"");
|
||||
return RayFunction(ray::Language::PYTHON, function_descriptor);
|
||||
} else if (invocation.remote_function_holder.lang_type_ == LangType::JAVA) {
|
||||
auto function_descriptor = FunctionDescriptorBuilder::BuildJava(
|
||||
invocation.remote_function_holder.class_name_,
|
||||
invocation.remote_function_holder.function_name_,
|
||||
"");
|
||||
return RayFunction(ray::Language::JAVA, function_descriptor);
|
||||
} else {
|
||||
throw RayException("not supported yet");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static BundleID GetBundleID(const T &options) {
|
||||
BundleID bundle_id = std::make_pair(PlacementGroupID::Nil(), -1);
|
||||
if (!options.group.Empty()) {
|
||||
PlacementGroupID id = PlacementGroupID::FromBinary(options.group.GetID());
|
||||
bundle_id = std::make_pair(id, options.bundle_index);
|
||||
}
|
||||
return bundle_id;
|
||||
};
|
||||
|
||||
ObjectID NativeTaskSubmitter::Submit(InvocationSpec &invocation,
|
||||
const CallOptions &call_options) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
TaskOptions options{};
|
||||
options.name = call_options.name;
|
||||
options.resources = call_options.resources;
|
||||
options.serialized_runtime_env_info = call_options.serialized_runtime_env_info;
|
||||
options.generator_backpressure_num_objects = -1;
|
||||
std::vector<rpc::ObjectReference> return_refs;
|
||||
|
||||
std::string call_site;
|
||||
if (::RayConfig::instance().record_task_actor_creation_sites()) {
|
||||
std::stringstream ss;
|
||||
ss << ray::StackTrace();
|
||||
call_site = ss.str();
|
||||
}
|
||||
if (invocation.task_type == TaskType::ACTOR_TASK) {
|
||||
// NOTE: Ray CPP doesn't support per-method max_retries and retry_exceptions
|
||||
const auto native_actor_handle = core_worker.GetActorHandle(invocation.actor_id);
|
||||
int max_retries = native_actor_handle->MaxTaskRetries();
|
||||
|
||||
auto status = core_worker.SubmitActorTask(invocation.actor_id,
|
||||
BuildRayFunction(invocation),
|
||||
invocation.args,
|
||||
options,
|
||||
max_retries,
|
||||
/*retry_exceptions=*/false,
|
||||
/*serialized_retry_exception_allowlist=*/"",
|
||||
call_site,
|
||||
return_refs);
|
||||
if (!status.ok()) {
|
||||
return ObjectID::Nil();
|
||||
}
|
||||
} else {
|
||||
BundleID bundle_id = GetBundleID(call_options);
|
||||
rpc::SchedulingStrategy scheduling_strategy;
|
||||
scheduling_strategy.mutable_default_scheduling_strategy();
|
||||
if (!bundle_id.first.IsNil()) {
|
||||
auto placement_group_scheduling_strategy =
|
||||
scheduling_strategy.mutable_placement_group_scheduling_strategy();
|
||||
placement_group_scheduling_strategy->set_placement_group_id(
|
||||
bundle_id.first.Binary());
|
||||
placement_group_scheduling_strategy->set_placement_group_bundle_index(
|
||||
bundle_id.second);
|
||||
placement_group_scheduling_strategy->set_placement_group_capture_child_tasks(false);
|
||||
}
|
||||
return_refs = core_worker.SubmitTask(BuildRayFunction(invocation),
|
||||
invocation.args,
|
||||
options,
|
||||
1,
|
||||
false,
|
||||
scheduling_strategy,
|
||||
"",
|
||||
/*serialized_retry_exception_allowlist=*/"",
|
||||
call_site);
|
||||
}
|
||||
return ObjectID::FromBinary(return_refs[0].object_id());
|
||||
}
|
||||
|
||||
ObjectID NativeTaskSubmitter::SubmitTask(InvocationSpec &invocation,
|
||||
const CallOptions &call_options) {
|
||||
return Submit(invocation, call_options);
|
||||
}
|
||||
|
||||
ActorID NativeTaskSubmitter::CreateActor(InvocationSpec &invocation,
|
||||
const ActorCreationOptions &create_options) {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
std::unordered_map<std::string, double> resources;
|
||||
std::string name = create_options.name;
|
||||
std::string ray_namespace = create_options.ray_namespace;
|
||||
BundleID bundle_id = GetBundleID(create_options);
|
||||
rpc::SchedulingStrategy scheduling_strategy;
|
||||
scheduling_strategy.mutable_default_scheduling_strategy();
|
||||
if (!bundle_id.first.IsNil()) {
|
||||
auto placement_group_scheduling_strategy =
|
||||
scheduling_strategy.mutable_placement_group_scheduling_strategy();
|
||||
placement_group_scheduling_strategy->set_placement_group_id(bundle_id.first.Binary());
|
||||
placement_group_scheduling_strategy->set_placement_group_bundle_index(
|
||||
bundle_id.second);
|
||||
placement_group_scheduling_strategy->set_placement_group_capture_child_tasks(false);
|
||||
}
|
||||
std::string call_site;
|
||||
if (::RayConfig::instance().record_task_actor_creation_sites()) {
|
||||
std::stringstream ss;
|
||||
ss << ray::StackTrace();
|
||||
call_site = ss.str();
|
||||
}
|
||||
ray::core::ActorCreationOptions actor_options{
|
||||
create_options.max_restarts,
|
||||
/*max_task_retries=*/0,
|
||||
create_options.max_concurrency,
|
||||
create_options.resources,
|
||||
resources,
|
||||
/*dynamic_worker_options=*/{},
|
||||
/*is_detached=*/std::nullopt,
|
||||
name,
|
||||
ray_namespace,
|
||||
/*is_asyncio=*/false,
|
||||
scheduling_strategy,
|
||||
create_options.serialized_runtime_env_info};
|
||||
ActorID actor_id;
|
||||
auto status = core_worker.CreateActor(BuildRayFunction(invocation),
|
||||
invocation.args,
|
||||
actor_options,
|
||||
/*extension_data=*/"",
|
||||
call_site,
|
||||
&actor_id);
|
||||
if (!status.ok()) {
|
||||
throw RayException("Create actor error");
|
||||
}
|
||||
return actor_id;
|
||||
}
|
||||
|
||||
ObjectID NativeTaskSubmitter::SubmitActorTask(InvocationSpec &invocation,
|
||||
const CallOptions &task_options) {
|
||||
return Submit(invocation, task_options);
|
||||
}
|
||||
|
||||
ActorID NativeTaskSubmitter::GetActor(const std::string &actor_name,
|
||||
const std::string &ray_namespace) const {
|
||||
auto &core_worker = CoreWorkerProcess::GetCoreWorker();
|
||||
const std::string ns =
|
||||
ray_namespace.empty() ? core_worker.GetJobConfig().ray_namespace() : ray_namespace;
|
||||
auto pair = core_worker.GetNamedActorHandle(actor_name, ns);
|
||||
if (!pair.second.ok()) {
|
||||
RAY_LOG(WARNING) << pair.second.message();
|
||||
return ActorID::Nil();
|
||||
}
|
||||
|
||||
auto actor_handle = pair.first;
|
||||
RAY_CHECK(actor_handle);
|
||||
return actor_handle->GetActorID();
|
||||
}
|
||||
|
||||
ray::PlacementGroup NativeTaskSubmitter::CreatePlacementGroup(
|
||||
const ray::PlacementGroupCreationOptions &create_options) {
|
||||
auto options = ray::core::PlacementGroupCreationOptions(
|
||||
create_options.name,
|
||||
(ray::core::PlacementStrategy)create_options.strategy,
|
||||
create_options.bundles,
|
||||
false);
|
||||
ray::PlacementGroupID placement_group_id;
|
||||
auto status = CoreWorkerProcess::GetCoreWorker().CreatePlacementGroup(
|
||||
options, &placement_group_id);
|
||||
if (!status.ok()) {
|
||||
throw RayException(status.message());
|
||||
}
|
||||
|
||||
ray::PlacementGroup placement_group{placement_group_id.Binary(), create_options};
|
||||
placement_group.SetWaitCallbak([this](const std::string &id, int64_t timeout_seconds) {
|
||||
return WaitPlacementGroupReady(id, timeout_seconds);
|
||||
});
|
||||
|
||||
return placement_group;
|
||||
}
|
||||
|
||||
void NativeTaskSubmitter::RemovePlacementGroup(const std::string &group_id) {
|
||||
auto placement_group_id = ray::PlacementGroupID::FromBinary(group_id);
|
||||
auto status =
|
||||
CoreWorkerProcess::GetCoreWorker().RemovePlacementGroup(placement_group_id);
|
||||
if (!status.ok()) {
|
||||
throw RayException(status.message());
|
||||
}
|
||||
}
|
||||
|
||||
bool NativeTaskSubmitter::WaitPlacementGroupReady(const std::string &group_id,
|
||||
int64_t timeout_seconds) {
|
||||
auto placement_group_id = ray::PlacementGroupID::FromBinary(group_id);
|
||||
auto status = CoreWorkerProcess::GetCoreWorker().WaitPlacementGroupReady(
|
||||
placement_group_id, timeout_seconds);
|
||||
|
||||
if (status.IsNotFound()) {
|
||||
throw RayException(status.message());
|
||||
}
|
||||
return status.ok();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,44 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../native_ray_runtime.h"
|
||||
#include "invocation_spec.h"
|
||||
#include "task_submitter.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class NativeTaskSubmitter : public TaskSubmitter {
|
||||
public:
|
||||
ObjectID SubmitTask(InvocationSpec &invocation, const CallOptions &call_options);
|
||||
|
||||
ActorID CreateActor(InvocationSpec &invocation,
|
||||
const ActorCreationOptions &create_options);
|
||||
|
||||
ObjectID SubmitActorTask(InvocationSpec &invocation, const CallOptions &call_options);
|
||||
|
||||
ActorID GetActor(const std::string &actor_name, const std::string &ray_namespace) const;
|
||||
|
||||
ray::PlacementGroup CreatePlacementGroup(
|
||||
const ray::PlacementGroupCreationOptions &create_options);
|
||||
void RemovePlacementGroup(const std::string &group_id);
|
||||
bool WaitPlacementGroupReady(const std::string &group_id, int64_t timeout_seconds);
|
||||
|
||||
private:
|
||||
ObjectID Submit(InvocationSpec &invocation, const CallOptions &call_options);
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,346 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "task_executor.h"
|
||||
|
||||
#include <ray/api/common_types.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "../../util/function_helper.h"
|
||||
#include "../abstract_ray_runtime.h"
|
||||
#include "ray/util/event.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
namespace internal {
|
||||
/// Execute remote functions by networking stream.
|
||||
msgpack::sbuffer TaskExecutionHandler(const std::string &func_name,
|
||||
const ArgsBufferList &args_buffer,
|
||||
msgpack::sbuffer *actor_ptr) {
|
||||
if (func_name.empty()) {
|
||||
throw std::invalid_argument("Task function name is empty");
|
||||
}
|
||||
|
||||
msgpack::sbuffer result;
|
||||
do {
|
||||
if (actor_ptr) {
|
||||
auto func_ptr = FunctionManager::Instance().GetMemberFunction(func_name);
|
||||
if (func_ptr == nullptr) {
|
||||
result = PackError("unknown actor task: " + func_name);
|
||||
break;
|
||||
}
|
||||
result = (*func_ptr)(actor_ptr, args_buffer);
|
||||
} else {
|
||||
auto func_ptr = FunctionManager::Instance().GetFunction(func_name);
|
||||
if (func_ptr == nullptr) {
|
||||
result = PackError("unknown function: " + func_name);
|
||||
break;
|
||||
}
|
||||
result = (*func_ptr)(args_buffer);
|
||||
}
|
||||
} while (0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
auto &init_func_manager = FunctionManager::Instance();
|
||||
|
||||
FunctionManager &GetFunctionManager() { return init_func_manager; }
|
||||
|
||||
std::pair<const RemoteFunctionMap_t &, const RemoteMemberFunctionMap_t &>
|
||||
GetRemoteFunctions() {
|
||||
return init_func_manager.GetRemoteFunctions();
|
||||
}
|
||||
|
||||
void InitRayRuntime(std::shared_ptr<RayRuntime> runtime) {
|
||||
RayRuntimeHolder::Instance().Init(runtime);
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
namespace internal {
|
||||
|
||||
using ray::core::CoreWorkerProcess;
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> TaskExecutor::current_actor_ = nullptr;
|
||||
|
||||
/// TODO(qicosmos): Need to add more details of the error messages, such as object id,
|
||||
/// task id etc.
|
||||
std::pair<Status, std::shared_ptr<msgpack::sbuffer>> GetExecuteResult(
|
||||
const std::string &func_name,
|
||||
const ArgsBufferList &args_buffer,
|
||||
msgpack::sbuffer *actor_ptr) {
|
||||
try {
|
||||
EntryFuntion entry_function;
|
||||
if (actor_ptr == nullptr) {
|
||||
entry_function = FunctionHelper::GetInstance().GetExecutableFunctions(func_name);
|
||||
} else {
|
||||
entry_function =
|
||||
FunctionHelper::GetInstance().GetExecutableMemberFunctions(func_name);
|
||||
}
|
||||
RAY_LOG(DEBUG) << "Get executable function " << func_name << " ok.";
|
||||
auto result = entry_function(func_name, args_buffer, actor_ptr);
|
||||
RAY_LOG(DEBUG) << "Execute function " << func_name << " ok.";
|
||||
return std::make_pair(ray::Status::OK(),
|
||||
std::make_shared<msgpack::sbuffer>(std::move(result)));
|
||||
} catch (RayIntentionalSystemExitException &e) {
|
||||
RAY_LOG(ERROR) << "Ray intentional system exit while executing function(" << func_name
|
||||
<< ").";
|
||||
return std::make_pair(ray::Status::IntentionalSystemExit(""), nullptr);
|
||||
} catch (const std::exception &e) {
|
||||
#ifdef _WIN32
|
||||
auto exception_name = std::string(typeid(e).name());
|
||||
#else
|
||||
auto exception_name =
|
||||
std::string(abi::__cxa_demangle(typeid(e).name(), nullptr, nullptr, nullptr));
|
||||
#endif
|
||||
std::string err_msg = "An exception was thrown while executing function(" +
|
||||
func_name + "): " + exception_name + ": " + e.what();
|
||||
RAY_LOG(ERROR) << err_msg;
|
||||
return std::make_pair(ray::Status::Invalid(err_msg), nullptr);
|
||||
} catch (...) {
|
||||
RAY_LOG(ERROR) << "An unknown exception was thrown while executing function("
|
||||
<< func_name << ").";
|
||||
return std::make_pair(ray::Status::UnknownError(std::string("unknown exception")),
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
Status TaskExecutor::ExecuteTask(
|
||||
const rpc::Address &caller_address,
|
||||
ray::TaskType task_type,
|
||||
const std::string task_name,
|
||||
const RayFunction &ray_function,
|
||||
const std::unordered_map<std::string, double> &required_resources,
|
||||
const std::vector<std::shared_ptr<ray::RayObject>> &args_buffer,
|
||||
const std::vector<rpc::ObjectReference> &arg_refs,
|
||||
const std::string &debugger_breakpoint,
|
||||
const std::string &serialized_retry_exception_allowlist,
|
||||
std::vector<std::pair<ObjectID, std::shared_ptr<RayObject>>> *returns,
|
||||
std::vector<std::pair<ObjectID, std::shared_ptr<RayObject>>> *dynamic_returns,
|
||||
std::vector<std::pair<ObjectID, bool>> *streaming_generator_returns,
|
||||
std::shared_ptr<ray::LocalMemoryBuffer> &creation_task_exception_pb_bytes,
|
||||
bool *is_retryable_error,
|
||||
std::string *actor_repr_name,
|
||||
std::string *application_error,
|
||||
const std::vector<ConcurrencyGroup> &defined_concurrency_groups,
|
||||
const std::string name_of_concurrency_group_to_execute,
|
||||
bool is_reattempt,
|
||||
bool is_streaming_generator,
|
||||
bool retry_exception,
|
||||
int64_t generator_backpressure_num_objects,
|
||||
int64_t num_objects_per_yield,
|
||||
const std::optional<std::string> &tensor_transport) {
|
||||
RAY_LOG(DEBUG) << "Execute task type: " << TaskType_Name(task_type)
|
||||
<< " name:" << task_name;
|
||||
RAY_CHECK(ray_function.GetLanguage() == ray::Language::CPP);
|
||||
auto function_descriptor = ray_function.GetFunctionDescriptor();
|
||||
RAY_CHECK(function_descriptor->Type() ==
|
||||
ray::FunctionDescriptorType::kCppFunctionDescriptor);
|
||||
auto typed_descriptor = function_descriptor->As<ray::CppFunctionDescriptor>();
|
||||
std::string func_name = typed_descriptor->FunctionName();
|
||||
bool cross_lang = !typed_descriptor->Caller().empty();
|
||||
// TODO(Clark): Support retrying application-level errors for C++.
|
||||
// TODO(Clark): Support exception allowlist for retrying application-level
|
||||
// errors for C++.
|
||||
*is_retryable_error = false;
|
||||
|
||||
Status status{};
|
||||
std::shared_ptr<msgpack::sbuffer> data = nullptr;
|
||||
ArgsBufferList ray_args_buffer;
|
||||
for (size_t i = 0; i < args_buffer.size(); i++) {
|
||||
auto &arg = args_buffer.at(i);
|
||||
std::string meta_str = "";
|
||||
if (arg->GetMetadata() != nullptr) {
|
||||
meta_str = std::string((const char *)arg->GetMetadata()->Data(),
|
||||
arg->GetMetadata()->Size());
|
||||
}
|
||||
msgpack::sbuffer sbuf;
|
||||
const char *arg_data = nullptr;
|
||||
size_t arg_data_size = 0;
|
||||
if (arg->GetData()) {
|
||||
arg_data = reinterpret_cast<const char *>(arg->GetData()->Data());
|
||||
arg_data_size = arg->GetData()->Size();
|
||||
}
|
||||
if (meta_str == METADATA_STR_RAW) {
|
||||
// TODO(LarryLian) In order to minimize the modification,
|
||||
// there is an extra serialization here, but the performance will be a little worse.
|
||||
// This code can be optimized later to improve performance
|
||||
const auto &raw_buffer = Serializer::Serialize(arg_data, arg_data_size);
|
||||
sbuf.write(raw_buffer.data(), raw_buffer.size());
|
||||
} else if (cross_lang) {
|
||||
RAY_CHECK(arg_data != nullptr)
|
||||
<< "Task " << task_name << " no." << i << " arg data is null.";
|
||||
sbuf.write(arg_data + XLANG_HEADER_LEN, arg_data_size - XLANG_HEADER_LEN);
|
||||
} else {
|
||||
sbuf.write(arg_data, arg_data_size);
|
||||
}
|
||||
|
||||
ray_args_buffer.push_back(std::move(sbuf));
|
||||
}
|
||||
if (task_type == ray::TaskType::ACTOR_CREATION_TASK) {
|
||||
std::tie(status, data) = GetExecuteResult(func_name, ray_args_buffer, nullptr);
|
||||
current_actor_ = data;
|
||||
} else if (task_type == ray::TaskType::ACTOR_TASK) {
|
||||
if (cross_lang) {
|
||||
RAY_CHECK(!typed_descriptor->ClassName().empty());
|
||||
func_name = std::string("&")
|
||||
.append(typed_descriptor->ClassName())
|
||||
.append("::")
|
||||
.append(typed_descriptor->FunctionName());
|
||||
}
|
||||
RAY_CHECK(current_actor_ != nullptr);
|
||||
std::tie(status, data) =
|
||||
GetExecuteResult(func_name, ray_args_buffer, current_actor_.get());
|
||||
} else { // NORMAL_TASK
|
||||
std::tie(status, data) = GetExecuteResult(func_name, ray_args_buffer, nullptr);
|
||||
}
|
||||
|
||||
std::shared_ptr<ray::LocalMemoryBuffer> meta_buffer = nullptr;
|
||||
if (!status.ok()) {
|
||||
if (status.IsIntentionalSystemExit()) {
|
||||
return status;
|
||||
} else {
|
||||
RAY_EVENT(ERROR, "RAY_CPP_TASK_FAILED")
|
||||
.WithField("task_type", TaskType_Name(task_type))
|
||||
.WithField("function_name", func_name)
|
||||
<< "C++ task failed: " << status.ToString();
|
||||
}
|
||||
|
||||
std::string meta_str = std::to_string(ray::rpc::ErrorType::TASK_EXECUTION_EXCEPTION);
|
||||
meta_buffer = std::make_shared<ray::LocalMemoryBuffer>(
|
||||
reinterpret_cast<uint8_t *>(&meta_str[0]), meta_str.size(), true);
|
||||
// Pass formatted exception string to CoreWorker
|
||||
*application_error = status.ToString();
|
||||
|
||||
msgpack::sbuffer buf;
|
||||
if (cross_lang) {
|
||||
ray::rpc::RayException ray_exception{};
|
||||
ray_exception.set_language(ray::rpc::Language::CPP);
|
||||
ray_exception.set_formatted_exception_string(status.ToString());
|
||||
auto msg = ray_exception.SerializeAsString();
|
||||
buf = Serializer::Serialize(msg.data(), msg.size());
|
||||
} else {
|
||||
std::string msg = status.ToString();
|
||||
buf.write(msg.data(), msg.size());
|
||||
}
|
||||
data = std::make_shared<msgpack::sbuffer>(std::move(buf));
|
||||
}
|
||||
|
||||
if (task_type != ray::TaskType::ACTOR_CREATION_TASK) {
|
||||
size_t data_size = data->size();
|
||||
auto &result_id = (*returns)[0].first;
|
||||
auto result_ptr = &(*returns)[0].second;
|
||||
int64_t task_output_inlined_bytes = 0;
|
||||
|
||||
if (cross_lang && meta_buffer == nullptr) {
|
||||
meta_buffer = std::make_shared<ray::LocalMemoryBuffer>(
|
||||
(uint8_t *)(&METADATA_STR_XLANG[0]), METADATA_STR_XLANG.size(), true);
|
||||
}
|
||||
|
||||
size_t total = cross_lang ? (XLANG_HEADER_LEN + data_size) : data_size;
|
||||
RAY_CHECK_OK(CoreWorkerProcess::GetCoreWorker().AllocateReturnObject(
|
||||
result_id,
|
||||
total,
|
||||
meta_buffer,
|
||||
std::vector<ray::ObjectID>(),
|
||||
caller_address,
|
||||
&task_output_inlined_bytes,
|
||||
result_ptr));
|
||||
|
||||
auto result = *result_ptr;
|
||||
if (result != nullptr) {
|
||||
if (result->HasData()) {
|
||||
if (cross_lang) {
|
||||
auto len_buf = Serializer::Serialize(data_size);
|
||||
|
||||
msgpack::sbuffer buffer(XLANG_HEADER_LEN + data_size);
|
||||
buffer.write(len_buf.data(), len_buf.size());
|
||||
for (size_t i = 0; i < XLANG_HEADER_LEN - len_buf.size(); ++i) {
|
||||
buffer.write("", 1);
|
||||
}
|
||||
buffer.write(data->data(), data_size);
|
||||
|
||||
memcpy(result->GetData()->Data(), buffer.data(), buffer.size());
|
||||
} else {
|
||||
memcpy(result->GetData()->Data(), data->data(), data_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RAY_CHECK_OK(CoreWorkerProcess::GetCoreWorker().SealReturnObject(
|
||||
result_id,
|
||||
result,
|
||||
/*generator_id=*/ObjectID::Nil(),
|
||||
caller_address));
|
||||
} else {
|
||||
if (!status.ok()) {
|
||||
return ray::Status::CreationTaskError("");
|
||||
}
|
||||
}
|
||||
return ray::Status::OK();
|
||||
}
|
||||
|
||||
void TaskExecutor::Invoke(
|
||||
const TaskSpecification &task_spec,
|
||||
std::shared_ptr<msgpack::sbuffer> actor,
|
||||
AbstractRayRuntime *runtime,
|
||||
std::unordered_map<ActorID, std::unique_ptr<ActorContext>> &actor_contexts,
|
||||
absl::Mutex &actor_contexts_mutex) {
|
||||
ArgsBufferList args_buffer;
|
||||
for (size_t i = 0; i < task_spec.NumArgs(); i++) {
|
||||
if (task_spec.ArgByRef(i)) {
|
||||
const auto &id = task_spec.ArgObjectIdBinary(i);
|
||||
msgpack::sbuffer sbuf;
|
||||
sbuf.write(id.data(), id.size());
|
||||
args_buffer.push_back(std::move(sbuf));
|
||||
} else {
|
||||
msgpack::sbuffer sbuf;
|
||||
sbuf.write((const char *)task_spec.ArgData(i), task_spec.ArgDataSize(i));
|
||||
args_buffer.push_back(std::move(sbuf));
|
||||
}
|
||||
}
|
||||
|
||||
auto function_descriptor = task_spec.FunctionDescriptor();
|
||||
auto typed_descriptor = function_descriptor->As<ray::CppFunctionDescriptor>();
|
||||
|
||||
std::shared_ptr<msgpack::sbuffer> data;
|
||||
try {
|
||||
if (actor) {
|
||||
auto result = TaskExecutionHandler(
|
||||
typed_descriptor->FunctionName(), args_buffer, actor.get());
|
||||
data = std::make_shared<msgpack::sbuffer>(std::move(result));
|
||||
runtime->Put(std::move(data), task_spec.ReturnId(0));
|
||||
} else {
|
||||
auto result =
|
||||
TaskExecutionHandler(typed_descriptor->FunctionName(), args_buffer, nullptr);
|
||||
data = std::make_shared<msgpack::sbuffer>(std::move(result));
|
||||
if (task_spec.IsActorCreationTask()) {
|
||||
auto actorContext = std::make_unique<ActorContext>();
|
||||
actorContext->current_actor = data;
|
||||
absl::MutexLock lock(&actor_contexts_mutex);
|
||||
actor_contexts.emplace(task_spec.ActorCreationId(), std::move(actorContext));
|
||||
} else {
|
||||
runtime->Put(std::move(data), task_spec.ReturnId(0));
|
||||
}
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
auto result = PackError(e.what());
|
||||
auto result_data = std::make_shared<msgpack::sbuffer>(std::move(result));
|
||||
runtime->Put(std::move(result_data), task_spec.ReturnId(0));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/function_manager.h>
|
||||
#include <ray/api/serializer.h>
|
||||
|
||||
#include <boost/dll.hpp>
|
||||
#include <memory>
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "invocation_spec.h"
|
||||
#include "ray/common/id.h"
|
||||
#include "ray/common/task/task_spec.h"
|
||||
#include "ray/core_worker/common.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
namespace internal {
|
||||
|
||||
/// Execute remote functions by networking stream.
|
||||
msgpack::sbuffer TaskExecutionHandler(const std::string &func_name,
|
||||
const ArgsBufferList &args_buffer,
|
||||
msgpack::sbuffer *actor_ptr);
|
||||
|
||||
BOOST_DLL_ALIAS(internal::TaskExecutionHandler, TaskExecutionHandler);
|
||||
|
||||
FunctionManager &GetFunctionManager();
|
||||
BOOST_DLL_ALIAS(internal::GetFunctionManager, GetFunctionManager);
|
||||
|
||||
std::pair<const RemoteFunctionMap_t &, const RemoteMemberFunctionMap_t &>
|
||||
GetRemoteFunctions();
|
||||
BOOST_DLL_ALIAS(internal::GetRemoteFunctions, GetRemoteFunctions);
|
||||
|
||||
void InitRayRuntime(std::shared_ptr<RayRuntime> runtime);
|
||||
BOOST_DLL_ALIAS(internal::InitRayRuntime, InitRayRuntime);
|
||||
} // namespace internal
|
||||
|
||||
namespace internal {
|
||||
|
||||
using ray::core::RayFunction;
|
||||
|
||||
class AbstractRayRuntime;
|
||||
|
||||
class ActorContext {
|
||||
public:
|
||||
std::shared_ptr<msgpack::sbuffer> current_actor = nullptr;
|
||||
|
||||
std::shared_ptr<absl::Mutex> actor_mutex;
|
||||
|
||||
ActorContext() { actor_mutex = std::shared_ptr<absl::Mutex>(new absl::Mutex); }
|
||||
};
|
||||
|
||||
class TaskExecutor {
|
||||
public:
|
||||
TaskExecutor() = default;
|
||||
|
||||
static void Invoke(
|
||||
const TaskSpecification &task_spec,
|
||||
std::shared_ptr<msgpack::sbuffer> actor,
|
||||
AbstractRayRuntime *runtime,
|
||||
std::unordered_map<ActorID, std::unique_ptr<ActorContext>> &actor_contexts,
|
||||
absl::Mutex &actor_contexts_mutex);
|
||||
|
||||
static Status ExecuteTask(
|
||||
const rpc::Address &caller_address,
|
||||
ray::TaskType task_type,
|
||||
const std::string task_name,
|
||||
const RayFunction &ray_function,
|
||||
const std::unordered_map<std::string, double> &required_resources,
|
||||
const std::vector<std::shared_ptr<ray::RayObject>> &args,
|
||||
const std::vector<rpc::ObjectReference> &arg_refs,
|
||||
const std::string &debugger_breakpoint,
|
||||
const std::string &serialized_retry_exception_allowlist,
|
||||
std::vector<std::pair<ObjectID, std::shared_ptr<RayObject>>> *returns,
|
||||
std::vector<std::pair<ObjectID, std::shared_ptr<RayObject>>> *dynamic_returns,
|
||||
std::vector<std::pair<ObjectID, bool>> *streaming_generator_returns,
|
||||
std::shared_ptr<ray::LocalMemoryBuffer> &creation_task_exception_pb_bytes,
|
||||
bool *is_retryable_error,
|
||||
std::string *actor_repr_name,
|
||||
std::string *application_error,
|
||||
const std::vector<ConcurrencyGroup> &defined_concurrency_groups,
|
||||
const std::string name_of_concurrency_group_to_execute,
|
||||
bool is_reattempt,
|
||||
bool is_streaming_generator,
|
||||
bool retry_exception,
|
||||
int64_t generator_backpressure_num_objects,
|
||||
int64_t num_objects_per_yield,
|
||||
/* This is used by the in-actor RDT object store. However, it is only supported in
|
||||
* the Python frontend. */
|
||||
const std::optional<std::string> &tensor_transport);
|
||||
|
||||
virtual ~TaskExecutor(){};
|
||||
|
||||
private:
|
||||
static std::shared_ptr<msgpack::sbuffer> current_actor_;
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2020 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/ray_runtime.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "invocation_spec.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
class TaskSubmitter {
|
||||
public:
|
||||
TaskSubmitter(){};
|
||||
|
||||
virtual ~TaskSubmitter(){};
|
||||
|
||||
virtual ObjectID SubmitTask(InvocationSpec &invocation,
|
||||
const CallOptions &call_options) = 0;
|
||||
|
||||
virtual ActorID CreateActor(InvocationSpec &invocation,
|
||||
const ActorCreationOptions &create_options) = 0;
|
||||
|
||||
virtual ObjectID SubmitActorTask(InvocationSpec &invocation,
|
||||
const CallOptions &call_options) = 0;
|
||||
|
||||
virtual ActorID GetActor(const std::string &actor_name,
|
||||
const std::string &ray_namespace) const = 0;
|
||||
|
||||
virtual ray::PlacementGroup CreatePlacementGroup(
|
||||
const ray::PlacementGroupCreationOptions &create_options) = 0;
|
||||
|
||||
virtual void RemovePlacementGroup(const std::string &group_id) = 0;
|
||||
|
||||
virtual bool WaitPlacementGroupReady(const std::string &group_id,
|
||||
int64_t timeout_seconds) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,368 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ray/api.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
||||
#include "../config_internal.h"
|
||||
#include "ray/util/logging.h"
|
||||
#include "ray/util/path_utils.h"
|
||||
|
||||
// using namespace ray;
|
||||
|
||||
int Return1() { return 1; }
|
||||
int Plus1(int x) { return x + 1; }
|
||||
|
||||
int Plus(int x, int y) { return x + y; }
|
||||
|
||||
int Triple(int x, int y, int z) { return x + y + z; }
|
||||
|
||||
std::string GetVal(ray::ObjectRef<std::string> obj) { return *obj.Get(); }
|
||||
|
||||
int GetIntVal(ray::ObjectRef<ray::ObjectRef<int>> obj) {
|
||||
auto val = *obj.Get();
|
||||
return *val.Get();
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<int>> GetList(int x, std::vector<ray::ObjectRef<int>> list) {
|
||||
return ray::Get(list);
|
||||
}
|
||||
|
||||
RAY_REMOTE(Return1, Plus1, Plus, Triple, GetVal, GetIntVal, GetList);
|
||||
|
||||
std::promise<bool> g_promise;
|
||||
|
||||
bool BlockGet() { return g_promise.get_future().get(); }
|
||||
|
||||
bool GetValue(ray::ObjectRef<bool> arg) {
|
||||
auto result = ray::Wait(std::vector<ray::ObjectRef<bool>>{arg}, 1, 1000);
|
||||
EXPECT_EQ(result.ready.size(), 0);
|
||||
|
||||
g_promise.set_value(true);
|
||||
bool r = *ray::Get(arg);
|
||||
EXPECT_EQ(r, true);
|
||||
return r;
|
||||
}
|
||||
|
||||
RAY_REMOTE(BlockGet, GetValue);
|
||||
|
||||
class Counter {
|
||||
public:
|
||||
int count;
|
||||
|
||||
MSGPACK_DEFINE(count);
|
||||
|
||||
Counter() { count = 0; }
|
||||
|
||||
static Counter *FactoryCreate() {
|
||||
Counter *counter = new Counter();
|
||||
return counter;
|
||||
}
|
||||
|
||||
int Plus1(int x) { return x + 1; }
|
||||
|
||||
int Plus(int x, int y) { return x + y; }
|
||||
|
||||
int Triple(int x, int y, int z) { return x + y + z; }
|
||||
|
||||
int Add(int x) {
|
||||
count += x;
|
||||
return count;
|
||||
}
|
||||
|
||||
std::string GetVal(ray::ObjectRef<std::string> obj) { return *obj.Get(); }
|
||||
|
||||
int GetIntVal(ray::ObjectRef<ray::ObjectRef<int>> obj) {
|
||||
auto val = *obj.Get();
|
||||
return *val.Get();
|
||||
}
|
||||
|
||||
// The dummy x is used to test a heterogeneous case: one is value arg, another is an
|
||||
// ObjectRef arg.
|
||||
std::vector<std::shared_ptr<int>> GetList(int x,
|
||||
std::vector<ray::ObjectRef<int>> list) {
|
||||
return ray::Get(list);
|
||||
}
|
||||
};
|
||||
|
||||
RAY_REMOTE(Counter::FactoryCreate,
|
||||
&Counter::Plus1,
|
||||
&Counter::Plus,
|
||||
&Counter::Triple,
|
||||
&Counter::Add,
|
||||
&Counter::GetVal,
|
||||
&Counter::GetIntVal,
|
||||
&Counter::GetList);
|
||||
|
||||
TEST(RayApiTest, LogTest) {
|
||||
const std::string app_name = "cpp_worker";
|
||||
const std::string log_dir = std::filesystem::current_path().string() + "/tmp/";
|
||||
ray::RayLog::StartRayLog(app_name,
|
||||
ray::RayLogLevel::DEBUG,
|
||||
ray::GetLogFilepathFromDirectory(log_dir, app_name));
|
||||
std::array<std::string, 3> str_arr{"debug test", "info test", "warning test"};
|
||||
RAYLOG(DEBUG) << str_arr[0];
|
||||
RAYLOG(INFO) << str_arr[1];
|
||||
RAYLOG(WARNING) << str_arr[2];
|
||||
RAY_CHECK(true);
|
||||
|
||||
for (auto &it : std::filesystem::directory_iterator(log_dir)) {
|
||||
if (!std::filesystem::is_directory(it)) {
|
||||
std::ifstream in(it.path().string(), std::ios::binary);
|
||||
std::string line;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::getline(in, line);
|
||||
EXPECT_TRUE(line.find(str_arr[i]) != std::string::npos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::remove_all(log_dir);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, TaskOptionsCheckTest) {
|
||||
std::unordered_map<std::string, double> map;
|
||||
map.emplace("", 1);
|
||||
EXPECT_THROW(ray::internal::CheckTaskOptions(map), ray::internal::RayException);
|
||||
map.clear();
|
||||
map.emplace("dummy", 0);
|
||||
EXPECT_THROW(ray::internal::CheckTaskOptions(map), ray::internal::RayException);
|
||||
map.clear();
|
||||
map.emplace("dummy", 2.0);
|
||||
ray::internal::CheckTaskOptions(map);
|
||||
map.emplace("dummy1", 2.5);
|
||||
EXPECT_THROW(ray::internal::CheckTaskOptions(map), ray::internal::RayException);
|
||||
map.clear();
|
||||
map.emplace("dummy", 0.5);
|
||||
ray::internal::CheckTaskOptions(map);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, PutTest) {
|
||||
ray::RayConfig config;
|
||||
config.local_mode = true;
|
||||
ray::Init(config);
|
||||
|
||||
auto obj1 = ray::Put(1);
|
||||
auto i1 = obj1.Get();
|
||||
EXPECT_EQ(1, *i1);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, StaticGetTest) {
|
||||
ray::RayConfig config;
|
||||
config.local_mode = true;
|
||||
ray::Init(config);
|
||||
/// `Get` member function
|
||||
auto obj_ref1 = ray::Put(100);
|
||||
auto res1 = obj_ref1.Get();
|
||||
EXPECT_EQ(100, *res1);
|
||||
|
||||
/// `Get` static function
|
||||
auto obj_ref2 = ray::Put(200);
|
||||
auto res2 = ray::Get(obj_ref2);
|
||||
EXPECT_EQ(200, *res2);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, WaitTest) {
|
||||
ray::RayConfig config;
|
||||
config.local_mode = true;
|
||||
ray::Init(config);
|
||||
auto r0 = ray::Task(Return1).Remote();
|
||||
auto r1 = ray::Task(Plus1).Remote(3);
|
||||
auto r2 = ray::Task(Plus).Remote(2, 3);
|
||||
std::vector<ray::ObjectRef<int>> objects = {r0, r1, r2};
|
||||
auto result = ray::Wait(objects, 3, 1000);
|
||||
EXPECT_EQ(result.ready.size(), 3);
|
||||
EXPECT_EQ(result.unready.size(), 0);
|
||||
std::vector<std::shared_ptr<int>> getResult = ray::Get<int>(objects);
|
||||
EXPECT_EQ(getResult.size(), 3);
|
||||
EXPECT_EQ(*getResult[0], 1);
|
||||
EXPECT_EQ(*getResult[1], 4);
|
||||
EXPECT_EQ(*getResult[2], 5);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, ObjectRefArgsTest) {
|
||||
auto obj = ray::Put(std::string("aaa"));
|
||||
auto r = ray::Task(GetVal).Remote(obj);
|
||||
EXPECT_EQ(*r.Get(), "aaa");
|
||||
|
||||
auto obj0 = ray::Put(42);
|
||||
auto obj1 = ray::Put(obj0);
|
||||
auto r1 = ray::Task(GetIntVal).Remote(obj1);
|
||||
EXPECT_EQ(*r1.Get(), 42);
|
||||
|
||||
std::vector<ray::ObjectRef<int>> list{obj0, obj0};
|
||||
auto r2 = ray::Task(GetList).Remote(1, list);
|
||||
auto result2 = *r2.Get();
|
||||
EXPECT_EQ(result2.size(), 2);
|
||||
EXPECT_EQ(*result2[0], 42);
|
||||
EXPECT_EQ(*result2[1], 42);
|
||||
|
||||
auto r4 = ray::Task(BlockGet).Remote();
|
||||
auto r5 = ray::Task(GetValue).Remote(r4);
|
||||
EXPECT_EQ(*r5.Get(), true);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, CallWithValueTest) {
|
||||
auto r0 = ray::Task(Return1).Remote();
|
||||
auto r1 = ray::Task(Plus1).Remote(3);
|
||||
auto r2 = ray::Task(Plus).Remote(2, 3);
|
||||
auto r3 = ray::Task(Triple).Remote(1, 2, 3);
|
||||
|
||||
int result0 = *(r0.Get());
|
||||
int result1 = *(r1.Get());
|
||||
int result2 = *(r2.Get());
|
||||
int result3 = *(r3.Get());
|
||||
|
||||
EXPECT_EQ(result0, 1);
|
||||
EXPECT_EQ(result1, 4);
|
||||
EXPECT_EQ(result2, 5);
|
||||
EXPECT_EQ(result3, 6);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, CallWithObjectTest) {
|
||||
auto rt0 = ray::Task(Return1).Remote();
|
||||
auto rt1 = ray::Task(Plus1).Remote(rt0);
|
||||
auto rt2 = ray::Task(Plus).Remote(rt1, 3);
|
||||
auto rt3 = ray::Task(Plus1).Remote(3);
|
||||
auto rt4 = ray::Task(Plus).Remote(rt2, rt3);
|
||||
|
||||
int return0 = *(rt0.Get());
|
||||
int return1 = *(rt1.Get());
|
||||
int return2 = *(rt2.Get());
|
||||
int return3 = *(rt3.Get());
|
||||
int return4 = *(rt4.Get());
|
||||
|
||||
EXPECT_EQ(return0, 1);
|
||||
EXPECT_EQ(return1, 2);
|
||||
EXPECT_EQ(return2, 5);
|
||||
EXPECT_EQ(return3, 4);
|
||||
EXPECT_EQ(return4, 9);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, ActorTest) {
|
||||
ray::RayConfig config;
|
||||
config.local_mode = true;
|
||||
ray::Init(config);
|
||||
auto actor = ray::Actor(Counter::FactoryCreate).Remote();
|
||||
auto obj = ray::Put(std::string("aaa"));
|
||||
auto r = actor.Task(&Counter::GetVal).Remote(obj);
|
||||
EXPECT_EQ(*r.Get(), "aaa");
|
||||
|
||||
auto obj0 = ray::Put(42);
|
||||
auto obj1 = ray::Put(obj0);
|
||||
auto r1 = actor.Task(&Counter::GetIntVal).Remote(obj1);
|
||||
EXPECT_EQ(*r1.Get(), 42);
|
||||
|
||||
std::vector<ray::ObjectRef<int>> list{obj0, obj0};
|
||||
auto r2 = actor.Task(&Counter::GetList).Remote(1, list);
|
||||
auto result2 = *r2.Get();
|
||||
EXPECT_EQ(result2.size(), 2);
|
||||
|
||||
auto r3 = actor.Task(&Counter::GetList).Remote(obj0, list);
|
||||
auto result3 = *r3.Get();
|
||||
EXPECT_EQ(result3.size(), 2);
|
||||
|
||||
auto rt1 = actor.Task(&Counter::Add).Remote(1);
|
||||
auto rt2 = actor.Task(&Counter::Add).Remote(2);
|
||||
auto rt3 = actor.Task(&Counter::Add).Remote(3);
|
||||
auto rt4 = actor.Task(&Counter::Add).Remote(rt3);
|
||||
auto rt5 = actor.Task(&Counter::Triple).Remote(1, 2, 3);
|
||||
|
||||
int return1 = *(rt1.Get());
|
||||
int return2 = *(rt2.Get());
|
||||
int return3 = *(rt3.Get());
|
||||
int return4 = *(rt4.Get());
|
||||
int return5 = *(rt5.Get());
|
||||
|
||||
EXPECT_EQ(return1, 1);
|
||||
EXPECT_EQ(return2, 3);
|
||||
EXPECT_EQ(return3, 6);
|
||||
EXPECT_EQ(return4, 12);
|
||||
EXPECT_EQ(return5, 6);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, GetActorTest) {
|
||||
ray::ActorHandle<Counter> actor =
|
||||
ray::Actor(Counter::FactoryCreate).SetName("named_actor").Remote();
|
||||
auto named_actor_obj = actor.Task(&Counter::Add).Remote(1);
|
||||
EXPECT_EQ(1, *named_actor_obj.Get());
|
||||
|
||||
auto named_actor_handle_optional = ray::GetActor<Counter>("named_actor");
|
||||
EXPECT_TRUE(named_actor_handle_optional);
|
||||
auto &named_actor_handle = *named_actor_handle_optional;
|
||||
auto named_actor_obj1 = named_actor_handle.Task(&Counter::Plus1).Remote(1);
|
||||
EXPECT_EQ(2, *named_actor_obj1.Get());
|
||||
EXPECT_FALSE(ray::GetActor<Counter>("not_exist_actor"));
|
||||
}
|
||||
|
||||
TEST(RayApiTest, CompareWithFuture) {
|
||||
// future from a packaged_task
|
||||
std::packaged_task<int(int)> task(Plus1);
|
||||
std::future<int> f1 = task.get_future();
|
||||
std::thread t(std::move(task), 1);
|
||||
int rt1 = f1.get();
|
||||
|
||||
// future from an async()
|
||||
std::future<int> f2 = std::async(std::launch::async, Plus1, 1);
|
||||
int rt2 = f2.get();
|
||||
|
||||
// Ray API
|
||||
ray::RayConfig config;
|
||||
config.local_mode = true;
|
||||
ray::Init(config);
|
||||
auto f3 = ray::Task(Plus1).Remote(1);
|
||||
int rt3 = *f3.Get();
|
||||
|
||||
EXPECT_EQ(rt1, 2);
|
||||
EXPECT_EQ(rt2, 2);
|
||||
EXPECT_EQ(rt3, 2);
|
||||
t.join();
|
||||
}
|
||||
|
||||
TEST(RayApiTest, CreateAndRemovePlacementGroup) {
|
||||
std::vector<std::unordered_map<std::string, double>> bundles{{{"CPU", 1}}};
|
||||
ray::PlacementGroupCreationOptions options1{
|
||||
"first_placement_group", bundles, ray::PlacementStrategy::PACK};
|
||||
auto first_placement_group = ray::CreatePlacementGroup(options1);
|
||||
EXPECT_TRUE(first_placement_group.Wait(10));
|
||||
|
||||
ray::RemovePlacementGroup(first_placement_group.GetID());
|
||||
}
|
||||
|
||||
TEST(RayApiTest, DefaultActorLifetimeTest) {
|
||||
ray::RayConfig config;
|
||||
ray::internal::ConfigInternal::Instance().Init(config, 0, nullptr);
|
||||
EXPECT_EQ(ray::rpc::JobConfig_ActorLifetime_NON_DETACHED,
|
||||
ray::internal::ConfigInternal::Instance().default_actor_lifetime);
|
||||
config.default_actor_lifetime = ray::ActorLifetime::DETACHED;
|
||||
ray::internal::ConfigInternal::Instance().Init(config, 0, nullptr);
|
||||
EXPECT_EQ(ray::rpc::JobConfig_ActorLifetime_DETACHED,
|
||||
ray::internal::ConfigInternal::Instance().default_actor_lifetime);
|
||||
std::string str = "--ray_default_actor_lifetime=NON_DETACHED";
|
||||
char exec_name[] = {' '};
|
||||
char *args[] = {exec_name, const_cast<char *>(str.c_str())};
|
||||
ray::internal::ConfigInternal::Instance().Init(config, 2, args);
|
||||
EXPECT_EQ(ray::rpc::JobConfig_ActorLifetime_NON_DETACHED,
|
||||
ray::internal::ConfigInternal::Instance().default_actor_lifetime);
|
||||
std::string str2 = "--ray_default_actor_lifetime=detached";
|
||||
char *args2[] = {exec_name, const_cast<char *>(str2.c_str())};
|
||||
ray::internal::ConfigInternal::Instance().Init(config, 2, args2);
|
||||
EXPECT_EQ(ray::rpc::JobConfig_ActorLifetime_DETACHED,
|
||||
ray::internal::ConfigInternal::Instance().default_actor_lifetime);
|
||||
}
|
||||
@@ -0,0 +1,727 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ray/api.h>
|
||||
|
||||
#include "../../runtime/abstract_ray_runtime.h"
|
||||
#include "../../runtime/object/native_object_store.h"
|
||||
#include "../../util/process_helper.h"
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/flags/parse.h"
|
||||
#include "counter.h"
|
||||
#include "plus.h"
|
||||
#include "ray/util/network_util.h"
|
||||
|
||||
int cmd_argc = 0;
|
||||
char **cmd_argv = nullptr;
|
||||
|
||||
ABSL_FLAG(bool, external_cluster, false, "");
|
||||
ABSL_FLAG(std::string, redis_username, "default", "");
|
||||
ABSL_FLAG(std::string, redis_password, "12345678", "");
|
||||
ABSL_FLAG(int32_t, redis_port, 6379, "");
|
||||
|
||||
TEST(RayClusterModeTest, Initialized) {
|
||||
ray::Init();
|
||||
EXPECT_TRUE(ray::IsInitialized());
|
||||
ray::Shutdown();
|
||||
EXPECT_TRUE(!ray::IsInitialized());
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, DefaultActorLifetimeTest) {
|
||||
ray::RayConfig config;
|
||||
config.default_actor_lifetime = ray::ActorLifetime::DETACHED;
|
||||
ray::Init(config, cmd_argc, cmd_argv);
|
||||
ray::ActorHandle<Counter> parent_actor =
|
||||
ray::Actor(RAY_FUNC(Counter::FactoryCreate)).Remote();
|
||||
std::string child_actor_name = "child_actor_name";
|
||||
parent_actor.Task(&Counter::CreateChildActor).Remote(child_actor_name).Get();
|
||||
auto child_actor_optional = ray::GetActor<Counter>(child_actor_name);
|
||||
EXPECT_TRUE(child_actor_optional);
|
||||
auto child_actor = *child_actor_optional;
|
||||
EXPECT_EQ(1, *child_actor.Task(&Counter::Plus1).Remote().Get());
|
||||
parent_actor.Kill();
|
||||
sleep(4);
|
||||
EXPECT_EQ(2, *child_actor.Task(&Counter::Plus1).Remote().Get());
|
||||
ray::Shutdown();
|
||||
}
|
||||
|
||||
struct Person {
|
||||
std::string name;
|
||||
int age;
|
||||
MSGPACK_DEFINE(name, age);
|
||||
};
|
||||
|
||||
TEST(RayClusterModeTest, FullTest) {
|
||||
ray::RayConfig config;
|
||||
config.head_args = {
|
||||
"--num-cpus", "2", "--resources", "{\"resource1\":1,\"resource2\":2}"};
|
||||
if (absl::GetFlag<bool>(FLAGS_external_cluster)) {
|
||||
auto port = absl::GetFlag<int32_t>(FLAGS_redis_port);
|
||||
std::string username = absl::GetFlag<std::string>(FLAGS_redis_username);
|
||||
std::string password = absl::GetFlag<std::string>(FLAGS_redis_password);
|
||||
std::string local_ip = ray::GetNodeIpAddressFromPerspective();
|
||||
ray::internal::ProcessHelper::GetInstance().StartRayNode(
|
||||
local_ip, port, username, password);
|
||||
config.address = ray::BuildAddress(local_ip, port);
|
||||
config.redis_username_ = username;
|
||||
config.redis_password_ = password;
|
||||
}
|
||||
ray::Init(config, cmd_argc, cmd_argv);
|
||||
|
||||
/// put and get object
|
||||
auto obj = ray::Put(12345);
|
||||
auto get_result = *(ray::Get(obj));
|
||||
EXPECT_EQ(12345, get_result);
|
||||
|
||||
EXPECT_EQ(12345, *(ray::Get(obj, 5)));
|
||||
|
||||
auto named_obj =
|
||||
ray::Task(Return1).SetName("named_task").SetResources({{"CPU", 1.0}}).Remote();
|
||||
EXPECT_EQ(1, *named_obj.Get());
|
||||
|
||||
/// common task without args
|
||||
auto task_obj = ray::Task(Return1).Remote();
|
||||
int task_result = *(ray::Get(task_obj));
|
||||
EXPECT_EQ(1, task_result);
|
||||
|
||||
/// common task with args
|
||||
auto task_obj1 = ray::Task(Plus1).Remote(5);
|
||||
auto task_result1 = *(ray::Get(task_obj1));
|
||||
EXPECT_EQ(6, task_result1);
|
||||
|
||||
ray::ActorHandle<Counter> actor = ray::Actor(RAY_FUNC(Counter::FactoryCreate))
|
||||
.SetMaxRestarts(1)
|
||||
.SetName("named_actor")
|
||||
.Remote();
|
||||
auto initialized_obj = actor.Task(&Counter::Initialized).Remote();
|
||||
EXPECT_TRUE(*initialized_obj.Get());
|
||||
auto named_actor_obj = actor.Task(&Counter::Plus1)
|
||||
.SetName("named_actor_task")
|
||||
.SetResources({{"CPU", 1.0}})
|
||||
.Remote();
|
||||
EXPECT_EQ(1, *named_actor_obj.Get());
|
||||
|
||||
auto named_actor_handle_optional = ray::GetActor<Counter>("named_actor");
|
||||
EXPECT_TRUE(named_actor_handle_optional);
|
||||
auto &named_actor_handle = *named_actor_handle_optional;
|
||||
auto named_actor_obj1 = named_actor_handle.Task(&Counter::Plus1).Remote();
|
||||
EXPECT_EQ(2, *named_actor_obj1.Get());
|
||||
EXPECT_FALSE(ray::GetActor<Counter>("not_exist_actor"));
|
||||
|
||||
EXPECT_FALSE(
|
||||
*named_actor_handle.Task(&Counter::CheckRestartInActorCreationTask).Remote().Get());
|
||||
EXPECT_FALSE(
|
||||
*named_actor_handle.Task(&Counter::CheckRestartInActorTask).Remote().Get());
|
||||
named_actor_handle.Kill(false);
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
auto named_actor_obj2 = named_actor_handle.Task(&Counter::Plus1).Remote();
|
||||
EXPECT_EQ(1, *named_actor_obj2.Get());
|
||||
EXPECT_TRUE(
|
||||
*named_actor_handle.Task(&Counter::CheckRestartInActorCreationTask).Remote().Get());
|
||||
EXPECT_TRUE(*named_actor_handle.Task(&Counter::CheckRestartInActorTask).Remote().Get());
|
||||
|
||||
named_actor_handle.Kill();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
EXPECT_THROW(named_actor_handle.Task(&Counter::Plus1).Remote().Get(),
|
||||
ray::internal::RayActorException);
|
||||
|
||||
EXPECT_FALSE(ray::GetActor<Counter>("named_actor"));
|
||||
|
||||
/// actor task without args
|
||||
auto actor1 = ray::Actor(RAY_FUNC(Counter::FactoryCreate)).Remote();
|
||||
auto actor_object1 = actor1.Task(&Counter::Plus1).Remote();
|
||||
int actor_task_result1 = *(ray::Get(actor_object1));
|
||||
EXPECT_EQ(1, actor_task_result1);
|
||||
|
||||
/// actor task with args
|
||||
auto actor2 = ray::Actor(RAY_FUNC(Counter::FactoryCreate, int)).Remote(1);
|
||||
auto actor_object2 = actor2.Task(&Counter::Add).Remote(5);
|
||||
int actor_task_result2 = *(ray::Get(actor_object2));
|
||||
EXPECT_EQ(6, actor_task_result2);
|
||||
|
||||
/// actor task with args which pass by reference
|
||||
auto actor3 = ray::Actor(RAY_FUNC(Counter::FactoryCreate, int, int)).Remote(6, 0);
|
||||
auto actor_object3 = actor3.Task(&Counter::Add).Remote(actor_object2);
|
||||
int actor_task_result3 = *(ray::Get(actor_object3));
|
||||
EXPECT_EQ(12, actor_task_result3);
|
||||
|
||||
/// general function remote call(args passed by value)
|
||||
auto r0 = ray::Task(Return1).Remote();
|
||||
auto r1 = ray::Task(Plus1).Remote(30);
|
||||
auto r2 = ray::Task(Plus).Remote(3, 22);
|
||||
|
||||
std::vector<ray::ObjectRef<int>> objects = {r0, r1, r2};
|
||||
auto result = ray::Wait(objects, 3, 5000);
|
||||
EXPECT_EQ(result.ready.size(), 3);
|
||||
EXPECT_EQ(result.unready.size(), 0);
|
||||
|
||||
auto result_vector = ray::Get(objects);
|
||||
int result0 = *(result_vector[0]);
|
||||
int result1 = *(result_vector[1]);
|
||||
int result2 = *(result_vector[2]);
|
||||
EXPECT_EQ(result0, 1);
|
||||
EXPECT_EQ(result1, 31);
|
||||
EXPECT_EQ(result2, 25);
|
||||
|
||||
result_vector = ray::Get(objects, 5);
|
||||
EXPECT_EQ(*(result_vector[0]), 1);
|
||||
EXPECT_EQ(*(result_vector[1]), 31);
|
||||
EXPECT_EQ(*(result_vector[2]), 25);
|
||||
|
||||
/// general function remote call(args passed by reference)
|
||||
auto r3 = ray::Task(Return1).Remote();
|
||||
auto r4 = ray::Task(Plus1).Remote(r3);
|
||||
auto r5 = ray::Task(Plus).Remote(r4, r3);
|
||||
auto r6 = ray::Task(Plus).Remote(r4, 10);
|
||||
|
||||
int result5 = *(ray::Get(r5));
|
||||
int result4 = *(ray::Get(r4));
|
||||
int result6 = *(ray::Get(r6));
|
||||
int result3 = *(ray::Get(r3));
|
||||
EXPECT_EQ(result0, 1);
|
||||
EXPECT_EQ(result3, 1);
|
||||
EXPECT_EQ(result4, 2);
|
||||
EXPECT_EQ(result5, 3);
|
||||
EXPECT_EQ(result6, 12);
|
||||
|
||||
/// create actor and actor function remote call with args passed by value
|
||||
auto actor4 = ray::Actor(RAY_FUNC(Counter::FactoryCreate, int)).Remote(10);
|
||||
auto r7 = actor4.Task(&Counter::Add).Remote(5);
|
||||
auto r8 = actor4.Task(&Counter::Add).Remote(1);
|
||||
auto r9 = actor4.Task(&Counter::Add).Remote(3);
|
||||
auto r10 = actor4.Task(&Counter::Add).Remote(8);
|
||||
|
||||
int result7 = *(ray::Get(r7));
|
||||
int result8 = *(ray::Get(r8));
|
||||
int result9 = *(ray::Get(r9));
|
||||
int result10 = *(ray::Get(r10));
|
||||
EXPECT_EQ(result7, 15);
|
||||
EXPECT_EQ(result8, 16);
|
||||
EXPECT_EQ(result9, 19);
|
||||
EXPECT_EQ(result10, 27);
|
||||
|
||||
/// create actor and task function remote call with args passed by reference
|
||||
auto actor5 = ray::Actor(RAY_FUNC(Counter::FactoryCreate, int, int)).Remote(r10, 0);
|
||||
|
||||
auto r11 = actor5.Task(&Counter::Add).Remote(r0);
|
||||
auto r12 = actor5.Task(&Counter::Add).Remote(r11);
|
||||
auto r13 = actor5.Task(&Counter::Add).Remote(r10);
|
||||
auto r14 = actor5.Task(&Counter::Add).Remote(r13);
|
||||
auto r15 = ray::Task(Plus).Remote(r0, r11);
|
||||
auto r16 = ray::Task(Plus1).Remote(r15);
|
||||
|
||||
int result12 = *(ray::Get(r12));
|
||||
int result14 = *(ray::Get(r14));
|
||||
int result11 = *(ray::Get(r11));
|
||||
int result13 = *(ray::Get(r13));
|
||||
int result16 = *(ray::Get(r16));
|
||||
int result15 = *(ray::Get(r15));
|
||||
|
||||
EXPECT_EQ(result11, 28);
|
||||
EXPECT_EQ(result12, 56);
|
||||
EXPECT_EQ(result13, 83);
|
||||
EXPECT_EQ(result14, 166);
|
||||
EXPECT_EQ(result15, 29);
|
||||
EXPECT_EQ(result16, 30);
|
||||
|
||||
/// Test Put, Get & Remote for large objects
|
||||
std::array<int, 100000> arr;
|
||||
auto r17 = ray::Put(arr);
|
||||
auto r18 = ray::Task(ReturnLargeArray).Remote(r17);
|
||||
EXPECT_EQ(arr, *(ray::Get(r17)));
|
||||
EXPECT_EQ(arr, *(ray::Get(r18)));
|
||||
|
||||
uint64_t pid = *actor1.Task(&Counter::GetPid).Remote().Get(5);
|
||||
EXPECT_TRUE(Counter::IsProcessAlive(pid));
|
||||
|
||||
auto actor_object4 = actor1.Task(&Counter::Exit).Remote();
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
EXPECT_THROW(actor_object4.Get(), ray::internal::RayActorException);
|
||||
EXPECT_FALSE(Counter::IsProcessAlive(pid));
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, ActorHandleTest) {
|
||||
auto actor1 = ray::Actor(RAY_FUNC(Counter::FactoryCreate)).Remote();
|
||||
auto obj1 = actor1.Task(&Counter::Plus1).Remote();
|
||||
EXPECT_EQ(1, *obj1.Get());
|
||||
// Test `ActorHandle` type object as parameter.
|
||||
auto actor2 = ray::Actor(RAY_FUNC(Counter::FactoryCreate)).Remote();
|
||||
auto obj2 = actor2.Task(&Counter::Plus1ForActor).Remote(actor1);
|
||||
EXPECT_EQ(2, *obj2.Get());
|
||||
// Test `ActorHandle` type object as return value.
|
||||
std::string child_actor_name = "child_actor_name";
|
||||
auto child_actor =
|
||||
actor1.Task(&Counter::CreateChildActor).Remote(child_actor_name).Get();
|
||||
EXPECT_EQ(1, *child_actor->Task(&Counter::Plus1).Remote().Get());
|
||||
|
||||
auto named_actor_handle_optional = ray::GetActor<Counter>(child_actor_name);
|
||||
EXPECT_TRUE(named_actor_handle_optional);
|
||||
auto &named_actor_handle = *named_actor_handle_optional;
|
||||
auto named_actor_obj1 = named_actor_handle.Task(&Counter::Plus1).Remote();
|
||||
EXPECT_EQ(2, *named_actor_obj1.Get());
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, PythonInvocationTest) {
|
||||
ray::ActorHandleXlang py_actor_handle =
|
||||
ray::Actor(ray::PyActorClass{"test_cross_language_invocation", "Counter"})
|
||||
.Remote(1);
|
||||
EXPECT_TRUE(!py_actor_handle.ID().empty());
|
||||
|
||||
auto py_actor_ret =
|
||||
py_actor_handle.Task(ray::PyActorMethod<std::string>{"increase"}).Remote(1);
|
||||
EXPECT_EQ("2", *py_actor_ret.Get());
|
||||
|
||||
auto py_obj =
|
||||
ray::Task(ray::PyFunction<int>{"test_cross_language_invocation", "py_return_val"})
|
||||
.Remote();
|
||||
EXPECT_EQ(42, *py_obj.Get());
|
||||
|
||||
auto py_obj1 =
|
||||
ray::Task(ray::PyFunction<int>{"test_cross_language_invocation", "py_return_input"})
|
||||
.Remote(42);
|
||||
EXPECT_EQ(42, *py_obj1.Get());
|
||||
|
||||
auto py_obj2 = ray::Task(ray::PyFunction<std::string>{"test_cross_language_invocation",
|
||||
"py_return_input"})
|
||||
.Remote("hello");
|
||||
EXPECT_EQ("hello", *py_obj2.Get());
|
||||
|
||||
Person p{"tom", 20};
|
||||
auto py_obj3 = ray::Task(ray::PyFunction<Person>{"test_cross_language_invocation",
|
||||
"py_return_input"})
|
||||
.Remote(p);
|
||||
auto py_result = *py_obj3.Get();
|
||||
EXPECT_EQ(p.age, py_result.age);
|
||||
EXPECT_EQ(p.name, py_result.name);
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, MaxConcurrentTest) {
|
||||
auto actor1 =
|
||||
ray::Actor(ActorConcurrentCall::FactoryCreate).SetMaxConcurrency(3).Remote();
|
||||
auto object1 = actor1.Task(&ActorConcurrentCall::CountDown).Remote();
|
||||
auto object2 = actor1.Task(&ActorConcurrentCall::CountDown).Remote();
|
||||
auto object3 = actor1.Task(&ActorConcurrentCall::CountDown).Remote();
|
||||
|
||||
EXPECT_EQ(*object1.Get(), "ok");
|
||||
EXPECT_EQ(*object2.Get(), "ok");
|
||||
EXPECT_EQ(*object3.Get(), "ok");
|
||||
|
||||
auto actor2 =
|
||||
ray::Actor(ActorConcurrentCall::FactoryCreate).SetMaxConcurrency(2).Remote();
|
||||
auto object2_1 = actor2.Task(&ActorConcurrentCall::CountDown).Remote();
|
||||
auto object2_2 = actor2.Task(&ActorConcurrentCall::CountDown).Remote();
|
||||
auto object2_3 = actor2.Task(&ActorConcurrentCall::CountDown).Remote();
|
||||
|
||||
EXPECT_THROW(object2_1.Get(2), ray::internal::RayTimeoutException);
|
||||
EXPECT_THROW(object2_2.Get(2), ray::internal::RayTimeoutException);
|
||||
EXPECT_THROW(object2_3.Get(2), ray::internal::RayTimeoutException);
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, ResourcesManagementTest) {
|
||||
auto actor1 =
|
||||
ray::Actor(RAY_FUNC(Counter::FactoryCreate)).SetResources({{"CPU", 1.0}}).Remote();
|
||||
auto r1 = actor1.Task(&Counter::Plus1).Remote();
|
||||
EXPECT_EQ(*r1.Get(), 1);
|
||||
|
||||
auto actor2 = ray::Actor(RAY_FUNC(Counter::FactoryCreate))
|
||||
.SetResources({{"CPU", 10000.0}})
|
||||
.Remote();
|
||||
auto r2 = actor2.Task(&Counter::Plus1).Remote();
|
||||
std::vector<ray::ObjectRef<int>> objects{r2};
|
||||
auto result = ray::Wait(objects, 1, 5000);
|
||||
EXPECT_EQ(result.ready.size(), 0);
|
||||
EXPECT_EQ(result.unready.size(), 1);
|
||||
|
||||
auto r3 = ray::Task(Return1).SetResource("CPU", 1.0).Remote();
|
||||
EXPECT_EQ(*r3.Get(), 1);
|
||||
|
||||
auto r4 = ray::Task(Return1).SetResource("CPU", 100.0).Remote();
|
||||
std::vector<ray::ObjectRef<int>> objects1{r4};
|
||||
auto result2 = ray::Wait(objects1, 1, 5000);
|
||||
EXPECT_EQ(result2.ready.size(), 0);
|
||||
EXPECT_EQ(result2.unready.size(), 1);
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, ExceptionTest) {
|
||||
EXPECT_THROW(ray::Task(ThrowTask).Remote().Get(), ray::internal::RayTaskException);
|
||||
try {
|
||||
ray::Task(ThrowTask).Remote().Get();
|
||||
} catch (ray::internal::RayTaskException &e) {
|
||||
EXPECT_TRUE(std::string(e.what()).find("std::logic_error") != std::string::npos);
|
||||
}
|
||||
|
||||
auto actor1 = ray::Actor(RAY_FUNC(Counter::FactoryCreate, int)).Remote(1);
|
||||
auto object1 = actor1.Task(&Counter::ExceptionFunc).Remote();
|
||||
EXPECT_THROW(object1.Get(), ray::internal::RayTaskException);
|
||||
|
||||
auto actor2 = ray::Actor(Counter::FactoryCreateException).Remote();
|
||||
auto object2 = actor2.Task(&Counter::Plus1).Remote();
|
||||
EXPECT_THROW(object2.Get(), ray::internal::RayActorException);
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, GetAllNodeInfoTest) {
|
||||
const auto &gcs_client =
|
||||
ray::internal::AbstractRayRuntime::GetInstance()->GetGlobalStateAccessor();
|
||||
auto all_node_info = gcs_client->GetAllNodeInfo();
|
||||
EXPECT_EQ(all_node_info.size(), 1);
|
||||
|
||||
ray::rpc::GcsNodeInfo node_info;
|
||||
node_info.ParseFromString(all_node_info[0]);
|
||||
EXPECT_EQ(node_info.state(),
|
||||
ray::rpc::GcsNodeInfo_GcsNodeState::GcsNodeInfo_GcsNodeState_ALIVE);
|
||||
}
|
||||
|
||||
bool CheckRefCount(
|
||||
std::unordered_map<ray::ObjectID, std::pair<size_t, size_t>> expected) {
|
||||
auto object_store = std::make_unique<ray::internal::NativeObjectStore>();
|
||||
auto map = object_store->GetAllReferenceCounts();
|
||||
return expected == map;
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, LocalRefrenceTest) {
|
||||
auto r1 = std::make_unique<ray::ObjectRef<int>>(ray::Task(Return1).Remote());
|
||||
auto object_id = ray::ObjectID::FromBinary(r1->ID());
|
||||
EXPECT_TRUE(CheckRefCount({{object_id, std::make_pair(1, 0)}}));
|
||||
auto r2 = std::make_unique<ray::ObjectRef<int>>(*r1);
|
||||
EXPECT_TRUE(CheckRefCount({{object_id, std::make_pair(2, 0)}}));
|
||||
r1.reset();
|
||||
EXPECT_TRUE(CheckRefCount({{object_id, std::make_pair(1, 0)}}));
|
||||
r2.reset();
|
||||
EXPECT_TRUE(CheckRefCount({}));
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, DependencyRefrenceTest) {
|
||||
{
|
||||
auto r1 = ray::Task(Return1).Remote();
|
||||
auto object_id = ray::ObjectID::FromBinary(r1.ID());
|
||||
EXPECT_TRUE(CheckRefCount({{object_id, std::make_pair(1, 0)}}));
|
||||
|
||||
auto r2 = ray::Task(Plus1).Remote(r1);
|
||||
EXPECT_TRUE(
|
||||
CheckRefCount({{object_id, std::make_pair(1, 1)},
|
||||
{ray::ObjectID::FromBinary(r2.ID()), std::make_pair(1, 0)}}));
|
||||
r2.Get();
|
||||
EXPECT_TRUE(
|
||||
CheckRefCount({{object_id, std::make_pair(1, 0)},
|
||||
{ray::ObjectID::FromBinary(r2.ID()), std::make_pair(1, 0)}}));
|
||||
}
|
||||
EXPECT_TRUE(CheckRefCount({}));
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, GetActorTest) {
|
||||
ray::ActorHandle<Counter> actor = ray::Actor(RAY_FUNC(Counter::FactoryCreate))
|
||||
.SetMaxRestarts(1)
|
||||
.SetName("named_actor")
|
||||
.Remote();
|
||||
auto named_actor_obj = actor.Task(&Counter::Plus1).Remote();
|
||||
EXPECT_EQ(1, *named_actor_obj.Get());
|
||||
|
||||
auto named_actor_handle_optional = ray::GetActor<Counter>("named_actor");
|
||||
EXPECT_TRUE(named_actor_handle_optional);
|
||||
auto &named_actor_handle = *named_actor_handle_optional;
|
||||
auto named_actor_obj1 = named_actor_handle.Task(&Counter::Plus1).Remote();
|
||||
EXPECT_EQ(2, *named_actor_obj1.Get());
|
||||
EXPECT_FALSE(ray::GetActor<Counter>("not_exist_actor"));
|
||||
}
|
||||
|
||||
ray::PlacementGroup CreateSimplePlacementGroup(const std::string &name) {
|
||||
std::vector<std::unordered_map<std::string, double>> bundles{{{"CPU", 1}}};
|
||||
|
||||
ray::PlacementGroupCreationOptions options{name, bundles, ray::PlacementStrategy::PACK};
|
||||
return ray::CreatePlacementGroup(options);
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, CreateAndRemovePlacementGroup) {
|
||||
auto first_placement_group = CreateSimplePlacementGroup("first_placement_group");
|
||||
EXPECT_TRUE(first_placement_group.Wait(10));
|
||||
EXPECT_THROW(CreateSimplePlacementGroup("first_placement_group"),
|
||||
ray::internal::RayException);
|
||||
|
||||
auto groups = ray::GetAllPlacementGroups();
|
||||
EXPECT_EQ(groups.size(), 1);
|
||||
|
||||
auto placement_group = ray::GetPlacementGroupById(first_placement_group.GetID());
|
||||
EXPECT_EQ(placement_group.GetID(), first_placement_group.GetID());
|
||||
|
||||
auto placement_group1 = ray::GetPlacementGroup("first_placement_group");
|
||||
EXPECT_EQ(placement_group1.GetID(), first_placement_group.GetID());
|
||||
|
||||
ray::RemovePlacementGroup(first_placement_group.GetID());
|
||||
auto deleted_group = ray::GetPlacementGroupById(first_placement_group.GetID());
|
||||
EXPECT_EQ(deleted_group.GetState(), ray::PlacementGroupState::REMOVED);
|
||||
|
||||
auto not_exist_group = ray::GetPlacementGroup("not_exist_placement_group");
|
||||
EXPECT_TRUE(not_exist_group.GetID().empty());
|
||||
|
||||
ray::RemovePlacementGroup(first_placement_group.GetID());
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, CreatePlacementGroupExceedsClusterResource) {
|
||||
std::vector<std::unordered_map<std::string, double>> bundles{{{"CPU", 10000}}};
|
||||
|
||||
ray::PlacementGroupCreationOptions options{
|
||||
"first_placement_group", bundles, ray::PlacementStrategy::PACK};
|
||||
auto first_placement_group = ray::CreatePlacementGroup(options);
|
||||
EXPECT_FALSE(first_placement_group.Wait(3));
|
||||
ray::RemovePlacementGroup(first_placement_group.GetID());
|
||||
auto deleted_group = ray::GetPlacementGroupById(first_placement_group.GetID());
|
||||
EXPECT_EQ(deleted_group.GetState(), ray::PlacementGroupState::REMOVED);
|
||||
|
||||
auto not_exist_group = ray::GetPlacementGroup("not_exist_placement_group");
|
||||
EXPECT_TRUE(not_exist_group.GetID().empty());
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, CreateActorWithPlacementGroup) {
|
||||
auto placement_group = CreateSimplePlacementGroup("first_placement_group");
|
||||
EXPECT_TRUE(placement_group.Wait(10));
|
||||
|
||||
auto actor1 = ray::Actor(RAY_FUNC(Counter::FactoryCreate))
|
||||
.SetResources({{"CPU", 1.0}})
|
||||
.SetPlacementGroup(placement_group, 0)
|
||||
.Remote();
|
||||
auto r1 = actor1.Task(&Counter::Plus1).Remote();
|
||||
std::vector<ray::ObjectRef<int>> objects{r1};
|
||||
auto result = ray::Wait(objects, 1, 5000);
|
||||
EXPECT_EQ(result.ready.size(), 1);
|
||||
EXPECT_EQ(result.unready.size(), 0);
|
||||
auto result_vector = ray::Get(objects);
|
||||
EXPECT_EQ(*(result_vector[0]), 1);
|
||||
|
||||
// Exceeds the resources of PlacementGroup.
|
||||
auto actor2 = ray::Actor(RAY_FUNC(Counter::FactoryCreate))
|
||||
.SetResources({{"CPU", 2.0}})
|
||||
.SetPlacementGroup(placement_group, 0)
|
||||
.Remote();
|
||||
auto r2 = actor2.Task(&Counter::Plus1).Remote();
|
||||
std::vector<ray::ObjectRef<int>> objects2{r2};
|
||||
auto result2 = ray::Wait(objects2, 1, 5000);
|
||||
EXPECT_EQ(result2.ready.size(), 0);
|
||||
EXPECT_EQ(result2.unready.size(), 1);
|
||||
ray::RemovePlacementGroup(placement_group.GetID());
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, TaskWithPlacementGroup) {
|
||||
auto placement_group = CreateSimplePlacementGroup("first_placement_group");
|
||||
EXPECT_TRUE(placement_group.Wait(10));
|
||||
|
||||
auto r = ray::Task(Return1)
|
||||
.SetResources({{"CPU", 1.0}})
|
||||
.SetPlacementGroup(placement_group, 0)
|
||||
.Remote();
|
||||
EXPECT_EQ(*r.Get(), 1);
|
||||
ray::RemovePlacementGroup(placement_group.GetID());
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, NamespaceTest) {
|
||||
if (ray::IsInitialized()) {
|
||||
ray::Shutdown();
|
||||
}
|
||||
ray::Init();
|
||||
// Create a named actor in namespace `isolated_ns`.
|
||||
std::string actor_name_in_isolated_ns = "named_actor_in_isolated_ns";
|
||||
std::string isolated_ns_name = "isolated_ns";
|
||||
ray::ActorHandle<Counter> actor =
|
||||
ray::Actor(RAY_FUNC(Counter::FactoryCreate))
|
||||
.SetName(actor_name_in_isolated_ns, isolated_ns_name)
|
||||
.Remote();
|
||||
auto initialized_obj = actor.Task(&Counter::Initialized).Remote();
|
||||
EXPECT_TRUE(*initialized_obj.Get());
|
||||
// It is invisible to job default namespace.
|
||||
auto actor_optional = ray::GetActor<Counter>(actor_name_in_isolated_ns);
|
||||
EXPECT_TRUE(!actor_optional);
|
||||
// It is visible to the namespace it belongs.
|
||||
actor_optional = ray::GetActor<Counter>(actor_name_in_isolated_ns, isolated_ns_name);
|
||||
EXPECT_TRUE(actor_optional);
|
||||
// It is invisible to any other namespaces.
|
||||
actor_optional = ray::GetActor<Counter>(actor_name_in_isolated_ns, "other_ns");
|
||||
EXPECT_TRUE(!actor_optional);
|
||||
|
||||
// Create a named actor in job default namespace.
|
||||
std::string actor_name_in_default_ns = "actor_name_in_default_ns";
|
||||
auto actor1 = ray::Actor(RAY_FUNC(Counter::FactoryCreate))
|
||||
.SetName(actor_name_in_default_ns)
|
||||
.Remote();
|
||||
auto initialized_obj1 = actor1.Task(&Counter::Initialized).Remote();
|
||||
EXPECT_TRUE(*initialized_obj1.Get());
|
||||
// It is visible to job default namespace.
|
||||
actor_optional = ray::GetActor<Counter>(actor_name_in_default_ns);
|
||||
EXPECT_TRUE(actor_optional);
|
||||
// It is invisible to any other namespaces.
|
||||
actor_optional = ray::GetActor<Counter>(actor_name_in_default_ns, isolated_ns_name);
|
||||
EXPECT_TRUE(!actor_optional);
|
||||
ray::Shutdown();
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, GetNamespaceApiTest) {
|
||||
std::string ns = "test_get_current_namespace";
|
||||
ray::RayConfig config;
|
||||
config.ray_namespace = ns;
|
||||
if (ray::IsInitialized()) {
|
||||
ray::Shutdown();
|
||||
}
|
||||
ray::Init(config, cmd_argc, cmd_argv);
|
||||
// Get namespace in driver.
|
||||
EXPECT_EQ(ray::GetNamespace(), ns);
|
||||
// Get namespace in task.
|
||||
auto task_ns = ray::Task(GetNamespaceInTask).Remote();
|
||||
EXPECT_EQ(*task_ns.Get(), ns);
|
||||
// Get namespace in actor.
|
||||
auto actor_handle = ray::Actor(RAY_FUNC(Counter::FactoryCreate)).Remote();
|
||||
auto actor_ns = actor_handle.Task(&Counter::GetNamespaceInActor).Remote();
|
||||
EXPECT_EQ(*actor_ns.Get(), ns);
|
||||
ray::Shutdown();
|
||||
}
|
||||
|
||||
class Pip {
|
||||
public:
|
||||
std::vector<std::string> packages_;
|
||||
bool pip_check_ = false;
|
||||
Pip() = default;
|
||||
Pip(const std::vector<std::string> &packages, bool pip_check)
|
||||
: packages_(packages), pip_check_(pip_check) {}
|
||||
};
|
||||
|
||||
void to_json(nlohmann::json &j, const Pip &pip) {
|
||||
j = nlohmann::json{{"packages", pip.packages_}, {"pip_check", pip.pip_check_}};
|
||||
};
|
||||
|
||||
void from_json(const nlohmann::json &j, Pip &pip) {
|
||||
j.at("packages").get_to(pip.packages_);
|
||||
j.at("pip_check").get_to(pip.pip_check_);
|
||||
};
|
||||
|
||||
TEST(RayClusterModeTest, RuntimeEnvApiTest) {
|
||||
ray::RuntimeEnv runtime_env;
|
||||
// Set pip
|
||||
std::vector<std::string> packages = {"requests"};
|
||||
Pip pip(packages, true);
|
||||
runtime_env.Set("pip", pip);
|
||||
// Set working_dir
|
||||
std::string working_dir = "https://path/to/working_dir.zip";
|
||||
runtime_env.Set("working_dir", working_dir);
|
||||
|
||||
// Serialize
|
||||
auto serialized_runtime_env = runtime_env.Serialize();
|
||||
|
||||
// Deserialize
|
||||
auto runtime_env_2 = ray::RuntimeEnv::Deserialize(serialized_runtime_env);
|
||||
auto pip2 = runtime_env_2.Get<Pip>("pip");
|
||||
EXPECT_EQ(pip2.packages_, pip.packages_);
|
||||
EXPECT_EQ(pip2.pip_check_, pip.pip_check_);
|
||||
auto working_dir2 = runtime_env_2.Get<std::string>("working_dir");
|
||||
EXPECT_EQ(working_dir2, working_dir);
|
||||
|
||||
// Construct runtime env with raw json string
|
||||
ray::RuntimeEnv runtime_env_3;
|
||||
std::string pip_raw_json_string =
|
||||
R"({"packages":["requests","tensorflow"],"pip_check":false})";
|
||||
runtime_env_3.SetJsonStr("pip", pip_raw_json_string);
|
||||
auto get_json_result = runtime_env_3.GetJsonStr("pip");
|
||||
EXPECT_EQ(get_json_result, pip_raw_json_string);
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, RuntimeEnvApiExceptionTest) {
|
||||
ray::RuntimeEnv runtime_env;
|
||||
EXPECT_THROW(runtime_env.Get<std::string>("working_dir"),
|
||||
ray::internal::RayRuntimeEnvException);
|
||||
runtime_env.Set("working_dir", "https://path/to/working_dir.zip");
|
||||
EXPECT_THROW(runtime_env.Get<Pip>("working_dir"),
|
||||
ray::internal::RayRuntimeEnvException);
|
||||
EXPECT_THROW(runtime_env.SetJsonStr("pip", "{123"),
|
||||
ray::internal::RayRuntimeEnvException);
|
||||
EXPECT_THROW(runtime_env.GetJsonStr("pip"), ray::internal::RayRuntimeEnvException);
|
||||
EXPECT_EQ(runtime_env.Empty(), false);
|
||||
EXPECT_EQ(runtime_env.Remove("working_dir"), true);
|
||||
// Do nothing when removing a non-existent key.
|
||||
EXPECT_EQ(runtime_env.Remove("pip"), false);
|
||||
EXPECT_EQ(runtime_env.Empty(), true);
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, RuntimeEnvTaskLevelEnvVarsTest) {
|
||||
ray::RayConfig config;
|
||||
ray::Init(config, cmd_argc, cmd_argv);
|
||||
auto r0 = ray::Task(GetEnvVar).Remote("KEY1");
|
||||
auto get_result0 = *(ray::Get(r0));
|
||||
EXPECT_EQ("", get_result0);
|
||||
|
||||
auto actor_handle = ray::Actor(RAY_FUNC(Counter::FactoryCreate)).Remote();
|
||||
auto r1 = actor_handle.Task(&Counter::GetEnvVar).Remote("KEY1");
|
||||
auto get_result1 = *(ray::Get(r1));
|
||||
EXPECT_EQ("", get_result1);
|
||||
|
||||
ray::RuntimeEnv runtime_env;
|
||||
std::map<std::string, std::string> env_vars{{"KEY1", "value1"}};
|
||||
runtime_env.Set("env_vars", env_vars);
|
||||
auto r2 = ray::Task(GetEnvVar).SetRuntimeEnv(runtime_env).Remote("KEY1");
|
||||
auto get_result2 = *(ray::Get(r2));
|
||||
EXPECT_EQ("value1", get_result2);
|
||||
|
||||
ray::RuntimeEnv runtime_env2;
|
||||
std::map<std::string, std::string> env_vars2{{"KEY1", "value2"}};
|
||||
runtime_env2.Set("env_vars", env_vars2);
|
||||
auto actor_handle2 =
|
||||
ray::Actor(RAY_FUNC(Counter::FactoryCreate)).SetRuntimeEnv(runtime_env2).Remote();
|
||||
auto r3 = actor_handle2.Task(&Counter::GetEnvVar).Remote("KEY1");
|
||||
auto get_result3 = *(ray::Get(r3));
|
||||
EXPECT_EQ("value2", get_result3);
|
||||
|
||||
ray::Shutdown();
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, RuntimeEnvJobLevelEnvVarsTest) {
|
||||
ray::RayConfig config;
|
||||
ray::RuntimeEnv runtime_env;
|
||||
std::map<std::string, std::string> env_vars{{"KEY1", "value1"}};
|
||||
runtime_env.Set("env_vars", env_vars);
|
||||
config.runtime_env = runtime_env;
|
||||
ray::Init(config, cmd_argc, cmd_argv);
|
||||
auto r0 = ray::Task(GetEnvVar).Remote("KEY1");
|
||||
auto get_result0 = *(ray::Get(r0));
|
||||
EXPECT_EQ("value1", get_result0);
|
||||
|
||||
auto actor_handle = ray::Actor(RAY_FUNC(Counter::FactoryCreate)).Remote();
|
||||
auto r1 = actor_handle.Task(&Counter::GetEnvVar).Remote("KEY1");
|
||||
auto get_result1 = *(ray::Get(r1));
|
||||
EXPECT_EQ("value1", get_result1);
|
||||
|
||||
ray::Shutdown();
|
||||
}
|
||||
|
||||
TEST(RayClusterModeTest, UnsupportObjectRefTest) {
|
||||
ray::RayConfig config;
|
||||
ray::Init(config, cmd_argc, cmd_argv);
|
||||
ray::ActorHandle<Counter> actor = ray::Actor(RAY_FUNC(Counter::FactoryCreate)).Remote();
|
||||
auto int_ref = ray::Put(1);
|
||||
EXPECT_THROW(actor.Task(&Counter::GetIntByObjectRef).Remote(int_ref),
|
||||
std::invalid_argument);
|
||||
|
||||
ray::Shutdown();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
absl::ParseCommandLine(argc, argv);
|
||||
cmd_argc = argc;
|
||||
cmd_argv = argv;
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
int ret = RUN_ALL_TESTS();
|
||||
|
||||
ray::Shutdown();
|
||||
|
||||
if (absl::GetFlag<bool>(FLAGS_external_cluster)) {
|
||||
ray::internal::ProcessHelper::GetInstance().StopRayNode();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
// Copyright 2022 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ray/api.h>
|
||||
|
||||
#include "cpp/include/ray/api/actor_handle.h"
|
||||
|
||||
TEST(RayClusterModeXLangTest, JavaInvocationTest) {
|
||||
// Test java nested static class
|
||||
ray::ActorHandleXlang java_nested_class_actor_handle =
|
||||
ray::Actor(ray::JavaActorClass{"io.ray.test.Counter$NestedActor"}).Remote("hello");
|
||||
EXPECT_TRUE(!java_nested_class_actor_handle.ID().empty());
|
||||
auto java_actor_ret =
|
||||
java_nested_class_actor_handle.Task(ray::JavaActorMethod<std::string>{"concat"})
|
||||
.Remote("world");
|
||||
EXPECT_EQ("helloworld", *java_actor_ret.Get());
|
||||
|
||||
// Test java static function
|
||||
auto java_task_ret =
|
||||
ray::Task(ray::JavaFunction<std::string>{"io.ray.test.CrossLanguageInvocationTest",
|
||||
"returnInputString"})
|
||||
.Remote("helloworld");
|
||||
EXPECT_EQ("helloworld", *java_task_ret.Get());
|
||||
|
||||
// Test java normal class
|
||||
std::string actor_name = "java_actor";
|
||||
auto java_class_actor_handle = ray::Actor(ray::JavaActorClass{"io.ray.test.Counter"})
|
||||
.SetName(actor_name)
|
||||
.Remote(0);
|
||||
auto ref2 =
|
||||
java_class_actor_handle.Task(ray::JavaActorMethod<int>{"getValue"}).Remote();
|
||||
EXPECT_EQ(0, *ref2.Get());
|
||||
|
||||
// Test get java actor by actor name.
|
||||
boost::optional<ray::ActorHandleXlang> named_actor_handle_optional =
|
||||
ray::GetActor(actor_name);
|
||||
EXPECT_TRUE(named_actor_handle_optional);
|
||||
ray::ActorHandleXlang named_actor_handle = *named_actor_handle_optional;
|
||||
auto named_actor_obj1 =
|
||||
named_actor_handle.Task(ray::JavaActorMethod<int>{"getValue"}).Remote();
|
||||
EXPECT_EQ(0, *named_actor_obj1.Get());
|
||||
|
||||
std::vector<std::byte> bytes = {std::byte{1}, std::byte{2}, std::byte{3}};
|
||||
auto ref_bytes = java_class_actor_handle
|
||||
.Task(ray::JavaActorMethod<std::vector<std::byte>>{"echoBytes"})
|
||||
.Remote(bytes);
|
||||
EXPECT_EQ(*ref_bytes.Get(), bytes);
|
||||
|
||||
auto ref_bytes2 = java_class_actor_handle
|
||||
.Task(ray::JavaActorMethod<std::vector<std::byte>>{"echoBytes"})
|
||||
.Remote(std::vector<std::byte>());
|
||||
EXPECT_EQ(*ref_bytes2.Get(), std::vector<std::byte>());
|
||||
|
||||
// Test get other java actor by actor name.
|
||||
auto ref_1 =
|
||||
java_class_actor_handle.Task(ray::JavaActorMethod<std::string>{"createChildActor"})
|
||||
.Remote("child_actor");
|
||||
EXPECT_EQ(*ref_1.Get(), "OK");
|
||||
boost::optional<ray::ActorHandleXlang> child_actor_optional =
|
||||
ray::GetActor("child_actor");
|
||||
EXPECT_TRUE(child_actor_optional);
|
||||
ray::ActorHandleXlang &child_actor = *child_actor_optional;
|
||||
auto ref_2 = child_actor.Task(ray::JavaActorMethod<int>{"getValue"}).Remote();
|
||||
EXPECT_EQ(0, *ref_2.Get());
|
||||
|
||||
auto ref_3 =
|
||||
child_actor.Task(ray::JavaActorMethod<std::string>{"echo"}).Remote("C++ worker");
|
||||
EXPECT_EQ("C++ worker", *ref_3.Get());
|
||||
|
||||
auto ref_4 = child_actor.Task(ray::JavaActorMethod<std::vector<std::byte>>{"echoBytes"})
|
||||
.Remote(bytes);
|
||||
EXPECT_EQ(*ref_4.Get(), bytes);
|
||||
}
|
||||
|
||||
TEST(RayClusterModeXLangTest, GetXLangActorByNameTest) {
|
||||
// Create a named java actor in namespace `isolated_ns`.
|
||||
std::string actor_name_in_isolated_ns = "named_actor_in_isolated_ns";
|
||||
std::string isolated_ns_name = "isolated_ns";
|
||||
|
||||
auto java_actor_handle = ray::Actor(ray::JavaActorClass{"io.ray.test.Counter"})
|
||||
.SetName(actor_name_in_isolated_ns, isolated_ns_name)
|
||||
.Remote(0);
|
||||
auto ref = java_actor_handle.Task(ray::JavaActorMethod<int>{"getValue"}).Remote();
|
||||
EXPECT_EQ(0, *ref.Get());
|
||||
|
||||
// It is invisible to job default namespace.
|
||||
boost::optional<ray::ActorHandleXlang> actor_optional =
|
||||
ray::GetActor(actor_name_in_isolated_ns);
|
||||
EXPECT_TRUE(!actor_optional);
|
||||
// It is invisible to any other namespaces.
|
||||
actor_optional = ray::GetActor(actor_name_in_isolated_ns, "other_ns");
|
||||
EXPECT_TRUE(!actor_optional);
|
||||
// It is visible to the namespace it belongs.
|
||||
actor_optional = ray::GetActor(actor_name_in_isolated_ns, isolated_ns_name);
|
||||
EXPECT_TRUE(actor_optional);
|
||||
ref = (*actor_optional).Task(ray::JavaActorMethod<int>{"getValue"}).Remote();
|
||||
EXPECT_EQ(0, *ref.Get());
|
||||
|
||||
// Create a named java actor in job default namespace.
|
||||
std::string actor_name_in_default_ns = "actor_name_in_default_ns";
|
||||
java_actor_handle = ray::Actor(ray::JavaActorClass{"io.ray.test.Counter"})
|
||||
.SetName(actor_name_in_default_ns)
|
||||
.Remote(0);
|
||||
ref = java_actor_handle.Task(ray::JavaActorMethod<int>{"getValue"}).Remote();
|
||||
EXPECT_EQ(0, *ref.Get());
|
||||
// It is invisible to any other namespaces.
|
||||
actor_optional = ray::GetActor(actor_name_in_default_ns, isolated_ns_name);
|
||||
EXPECT_TRUE(!actor_optional);
|
||||
// It is visible to job default namespace.
|
||||
actor_optional = ray::GetActor(actor_name_in_default_ns);
|
||||
EXPECT_TRUE(actor_optional);
|
||||
ref = (*actor_optional).Task(ray::JavaActorMethod<int>{"getValue"}).Remote();
|
||||
EXPECT_EQ(0, *ref.Get());
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
ray::RayConfig config;
|
||||
ray::Init(config, argc, argv);
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
int ret = RUN_ALL_TESTS();
|
||||
ray::Shutdown();
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
// Copyright 2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "counter.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
#include "signal.h"
|
||||
#include "unistd.h"
|
||||
#endif
|
||||
|
||||
Counter::Counter(int init, bool with_exception) {
|
||||
if (with_exception) {
|
||||
throw std::invalid_argument("creation error");
|
||||
}
|
||||
count = init;
|
||||
is_restared = ray::WasCurrentActorRestarted();
|
||||
}
|
||||
|
||||
Counter *Counter::FactoryCreate() { return new Counter(0); }
|
||||
|
||||
Counter *Counter::FactoryCreateException() { return new Counter(0, true); }
|
||||
|
||||
Counter *Counter::FactoryCreate(int init) { return new Counter(init); }
|
||||
|
||||
Counter *Counter::FactoryCreate(int init1, int init2) {
|
||||
return new Counter(init1 + init2);
|
||||
}
|
||||
|
||||
int Counter::Plus1() {
|
||||
count += 1;
|
||||
return count;
|
||||
}
|
||||
|
||||
int Counter::Add(int x) {
|
||||
count += x;
|
||||
return count;
|
||||
}
|
||||
|
||||
int Counter::Exit() {
|
||||
ray::ExitActor();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool Counter::IsProcessAlive(uint64_t pid) {
|
||||
#ifdef _WIN32
|
||||
auto process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
|
||||
if (process == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CloseHandle(process);
|
||||
return true;
|
||||
#else
|
||||
if (kill(pid, 0) == -1 && errno == ESRCH) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint64_t Counter::GetPid() {
|
||||
#ifdef _WIN32
|
||||
return GetCurrentProcessId();
|
||||
#else
|
||||
return getpid();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Counter::CheckRestartInActorCreationTask() { return is_restared; }
|
||||
|
||||
bool Counter::CheckRestartInActorTask() { return ray::WasCurrentActorRestarted(); }
|
||||
|
||||
ray::ActorHandle<Counter> Counter::CreateChildActor(std::string actor_name) {
|
||||
auto new_child_actor =
|
||||
ray::Actor(RAY_FUNC(Counter::FactoryCreate)).SetName(actor_name).Remote();
|
||||
new_child_actor.Task(&Counter::GetCount).Remote().Get();
|
||||
return new_child_actor;
|
||||
}
|
||||
|
||||
std::string Counter::GetNamespaceInActor() { return ray::GetNamespace(); }
|
||||
|
||||
std::string Counter::CreateNestedChildActor(std::string actor_name) {
|
||||
child_actor = ray::Actor(RAY_FUNC(Counter::FactoryCreate)).SetName(actor_name).Remote();
|
||||
child_actor.Task(&Counter::GetCount).Remote().Get();
|
||||
return "OK";
|
||||
}
|
||||
|
||||
int Counter::Plus1ForActor(ray::ActorHandle<Counter> actor) {
|
||||
return *actor.Task(&Counter::Plus1).Remote().Get();
|
||||
}
|
||||
|
||||
int Counter::GetIntByObjectRef(ray::ObjectRef<int> object_ref) {
|
||||
return *object_ref.Get();
|
||||
}
|
||||
|
||||
RAY_REMOTE(RAY_FUNC(Counter::FactoryCreate),
|
||||
Counter::FactoryCreateException,
|
||||
RAY_FUNC(Counter::FactoryCreate, int),
|
||||
RAY_FUNC(Counter::FactoryCreate, int, int),
|
||||
&Counter::Plus1,
|
||||
&Counter::Add,
|
||||
&Counter::Exit,
|
||||
&Counter::GetPid,
|
||||
&Counter::ExceptionFunc,
|
||||
&Counter::CheckRestartInActorCreationTask,
|
||||
&Counter::CheckRestartInActorTask,
|
||||
&Counter::GetNamespaceInActor,
|
||||
&Counter::GetVal,
|
||||
&Counter::GetIntVal,
|
||||
&Counter::Initialized,
|
||||
&Counter::CreateChildActor,
|
||||
&Counter::GetEnvVar,
|
||||
&Counter::Plus1ForActor,
|
||||
&Counter::GetCount,
|
||||
&Counter::CreateNestedChildActor,
|
||||
&Counter::GetBytes,
|
||||
&Counter::EchoBytes,
|
||||
&Counter::EchoString,
|
||||
&Counter::GetIntByObjectRef,
|
||||
&Counter::EchoStrings,
|
||||
&Counter::EchoAnyArray);
|
||||
|
||||
RAY_REMOTE(ActorConcurrentCall::FactoryCreate, &ActorConcurrentCall::CountDown);
|
||||
|
||||
std::string GetEnvVar(std::string key) {
|
||||
auto value = std::getenv(key.c_str());
|
||||
return value == NULL ? "" : std::string(value);
|
||||
}
|
||||
|
||||
RAY_REMOTE(GetEnvVar);
|
||||
@@ -0,0 +1,167 @@
|
||||
// Copyright 2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
|
||||
/// a class of user code
|
||||
class Counter {
|
||||
public:
|
||||
Counter(int init, bool with_exception = false);
|
||||
static Counter *FactoryCreate();
|
||||
static Counter *FactoryCreateException();
|
||||
static Counter *FactoryCreate(int init);
|
||||
static Counter *FactoryCreate(int init1, int init2);
|
||||
|
||||
int Plus1();
|
||||
int Add(int x);
|
||||
int Exit();
|
||||
int GetCount() { return count; }
|
||||
uint64_t GetPid();
|
||||
void ExceptionFunc() { throw std::invalid_argument("error"); }
|
||||
static bool IsProcessAlive(uint64_t pid);
|
||||
|
||||
bool CheckRestartInActorCreationTask();
|
||||
bool CheckRestartInActorTask();
|
||||
ray::ActorHandle<Counter> CreateChildActor(std::string actor_name);
|
||||
std::string CreateNestedChildActor(std::string actor_name);
|
||||
int Plus1ForActor(ray::ActorHandle<Counter> actor);
|
||||
|
||||
std::string GetNamespaceInActor();
|
||||
|
||||
std::string GetVal(ray::ObjectRef<std::string> obj) { return *obj.Get(); }
|
||||
|
||||
std::vector<std::byte> GetBytes(std::string s) {
|
||||
std::vector<std::byte> bytes;
|
||||
bytes.reserve(s.size());
|
||||
|
||||
std::transform(std::begin(s), std::end(s), std::back_inserter(bytes), [](char c) {
|
||||
return std::byte(c);
|
||||
});
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
std::vector<std::byte> EchoBytes(const std::vector<std::byte> &bytes) { return bytes; }
|
||||
|
||||
std::string EchoString(const std::string &str) { return str; }
|
||||
|
||||
std::vector<std::string> EchoStrings(const std::vector<std::string> &strings) {
|
||||
return strings;
|
||||
}
|
||||
|
||||
std::vector<std::any> EchoAnyArray(const std::vector<std::any> &anys) {
|
||||
assert(anys.size() == 11);
|
||||
// check bool
|
||||
assert(anys[0].type() == typeid(bool));
|
||||
assert(std::any_cast<bool>(anys[0]) == true);
|
||||
// equal to java Byte.MAX_VALUE
|
||||
assert(anys[1].type() == typeid(uint64_t));
|
||||
assert(std::any_cast<uint64_t>(anys[1]) == 127);
|
||||
// equal to java Short.MAX_VALUE
|
||||
assert(anys[2].type() == typeid(uint64_t));
|
||||
assert(std::any_cast<uint64_t>(anys[2]) == 32767);
|
||||
// equal to java Integer.MAX_VALUE
|
||||
assert(anys[3].type() == typeid(uint64_t));
|
||||
assert(std::any_cast<uint64_t>(anys[3]) == 2147483647);
|
||||
// equal to java Short.MAX_VALUE
|
||||
assert(anys[4].type() == typeid(uint64_t));
|
||||
assert(std::any_cast<uint64_t>(anys[4]) == 9223372036854775807);
|
||||
// equal to java Long.MIN_VALUE
|
||||
assert(anys[5].type() == typeid(int64_t));
|
||||
assert(std::any_cast<int64_t>(anys[5]) == -9223372036854775808);
|
||||
// equal to java BigInteger.valueOf(Long.MAX_VALUE)
|
||||
assert(anys[6].type() == typeid(uint64_t));
|
||||
assert(std::any_cast<uint64_t>(anys[6]) == 9223372036854775807);
|
||||
// equal to java string "Hello World!"
|
||||
assert(anys[7].type() == typeid(std::string));
|
||||
assert(std::any_cast<std::string>(anys[7]) == "Hello World!");
|
||||
// equal to java float 1.234f
|
||||
assert(anys[8].type() == typeid(double));
|
||||
assert(std::any_cast<double>(anys[8]) == 1.234);
|
||||
// equal to java double 1.234
|
||||
assert(anys[9].type() == typeid(double));
|
||||
assert(std::any_cast<double>(anys[9]) == 1.234);
|
||||
// equal to java byte[]
|
||||
std::vector<char> bytes = {'b', 'i', 'n', 'a', 'r', 'y'};
|
||||
assert(anys[10].type() == typeid(std::vector<std::byte>));
|
||||
assert(std::any_cast<std::vector<char>>(anys[10]) == bytes);
|
||||
return anys;
|
||||
}
|
||||
|
||||
int GetIntVal(ray::ObjectRef<ray::ObjectRef<int>> obj) {
|
||||
auto val = *obj.Get();
|
||||
return *val.Get();
|
||||
}
|
||||
|
||||
bool Initialized() { return ray::IsInitialized(); }
|
||||
|
||||
std::string GetEnvVar(std::string key) {
|
||||
auto value = std::getenv(key.c_str());
|
||||
return value == NULL ? "" : std::string(value);
|
||||
}
|
||||
|
||||
int GetIntByObjectRef(ray::ObjectRef<int> object_ref);
|
||||
|
||||
private:
|
||||
int count;
|
||||
bool is_restared = false;
|
||||
ray::ActorHandle<Counter> child_actor;
|
||||
};
|
||||
|
||||
std::string GetEnvVar(std::string key);
|
||||
|
||||
class CountDownLatch {
|
||||
public:
|
||||
explicit CountDownLatch(size_t count) : m_count(count) {}
|
||||
|
||||
void Wait() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (m_count > 0) {
|
||||
m_cv.wait(lock, [this]() { return m_count == 0; });
|
||||
}
|
||||
}
|
||||
|
||||
void CountDown() {
|
||||
std::unique_lock<std::mutex> lock(m_mutex);
|
||||
if (m_count > 0) {
|
||||
m_count--;
|
||||
m_cv.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex m_mutex;
|
||||
std::condition_variable m_cv;
|
||||
size_t m_count = 0;
|
||||
};
|
||||
|
||||
class ActorConcurrentCall {
|
||||
public:
|
||||
static ActorConcurrentCall *FactoryCreate() { return new ActorConcurrentCall(); }
|
||||
|
||||
std::string CountDown() {
|
||||
contdown_.CountDown();
|
||||
contdown_.Wait();
|
||||
return "ok";
|
||||
}
|
||||
|
||||
private:
|
||||
CountDownLatch contdown_{3};
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "plus.h"
|
||||
|
||||
int Return1() { return 1; };
|
||||
int Plus1(int x) { return x + 1; };
|
||||
int Plus(int x, int y) { return x + y; };
|
||||
|
||||
std::array<int, 100000> ReturnLargeArray(std::array<int, 100000> x) { return x; };
|
||||
void ThrowTask() { throw std::logic_error("error"); }
|
||||
|
||||
std::string Echo(std::string str) { return str; }
|
||||
|
||||
std::map<int, std::string> GetMap(std::map<int, std::string> map) {
|
||||
map.emplace(1, "world");
|
||||
return map;
|
||||
}
|
||||
|
||||
std::array<std::string, 2> GetArray(std::array<std::string, 2> array) { return array; }
|
||||
|
||||
std::vector<std::string> GetList(std::vector<std::string> list) { return list; }
|
||||
|
||||
std::tuple<int, std::string> GetTuple(std::tuple<int, std::string> tp) { return tp; }
|
||||
|
||||
std::string GetNamespaceInTask() { return ray::GetNamespace(); }
|
||||
|
||||
Student GetStudent(Student student) { return student; }
|
||||
|
||||
std::map<int, Student> GetStudents(std::map<int, Student> students) { return students; }
|
||||
|
||||
RAY_REMOTE(Return1,
|
||||
Plus1,
|
||||
Plus,
|
||||
ThrowTask,
|
||||
ReturnLargeArray,
|
||||
Echo,
|
||||
GetMap,
|
||||
GetArray,
|
||||
GetList,
|
||||
GetTuple,
|
||||
GetNamespaceInTask,
|
||||
GetStudent,
|
||||
GetStudents);
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api.h>
|
||||
|
||||
/// general function of user code
|
||||
int Return1();
|
||||
int Plus1(int x);
|
||||
int Plus(int x, int y);
|
||||
void ThrowTask();
|
||||
|
||||
std::array<int, 100000> ReturnLargeArray(std::array<int, 100000> x);
|
||||
std::string Echo(std::string str);
|
||||
std::map<int, std::string> GetMap(std::map<int, std::string> map);
|
||||
std::array<std::string, 2> GetArray(std::array<std::string, 2> array);
|
||||
std::vector<std::string> GetList(std::vector<std::string> list);
|
||||
std::tuple<int, std::string> GetTuple(std::tuple<int, std::string> tp);
|
||||
|
||||
std::string GetNamespaceInTask();
|
||||
|
||||
struct Student {
|
||||
std::string name;
|
||||
int age;
|
||||
MSGPACK_DEFINE(name, age);
|
||||
};
|
||||
|
||||
Student GetStudent(Student student);
|
||||
std::map<int, Student> GetStudents(std::map<int, Student> students);
|
||||
@@ -0,0 +1,21 @@
|
||||
import ray
|
||||
|
||||
|
||||
@ray.remote
|
||||
def py_return_input(v):
|
||||
return v
|
||||
|
||||
|
||||
@ray.remote
|
||||
def py_return_val():
|
||||
return 42
|
||||
|
||||
|
||||
@ray.remote
|
||||
class Counter(object):
|
||||
def __init__(self, value):
|
||||
self.value = int(value)
|
||||
|
||||
def increase(self, delta):
|
||||
self.value += int(delta)
|
||||
return str(self.value)
|
||||
@@ -0,0 +1,72 @@
|
||||
// Copyright 2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/// This is an example of Ray C++ application. Please visit
|
||||
/// `https://docs.ray.io/en/master/index.html` for more details.
|
||||
#include <ray/api.h>
|
||||
#include <ray/api/metric.h>
|
||||
|
||||
#include "absl/flags/flag.h"
|
||||
#include "absl/flags/parse.h"
|
||||
|
||||
ABSL_FLAG(int32_t, metric_time, 10, "The total time in seconds for recording metrics");
|
||||
|
||||
void test_metric(const std::string &exec_type, int total_time) {
|
||||
ray::Gauge gauge("ray_test_gauge", "test gauge", "unit", {"tag1", "tag2"});
|
||||
ray::Counter counter("ray_test_counter", "test counter", "unit", {"tag1", "tag2"});
|
||||
ray::Histogram histogram(
|
||||
"ray_test_histogram", "test histogram", "unit", {1, 10}, {"tag1", "tag2"});
|
||||
ray::Sum sum("ray_test_sum", "test sum", "unit", {"tag1", "tag2"});
|
||||
|
||||
std::unordered_map<std::string, std::string> tag_1 = {{"tag1", "increasing"},
|
||||
{"tag2", exec_type}};
|
||||
std::unordered_map<std::string, std::string> tag_2 = {{"tag1", "steady"},
|
||||
{"tag2", exec_type}};
|
||||
int num = total_time;
|
||||
for (int i = 0; i < num; i++) {
|
||||
gauge.Set(i, tag_1);
|
||||
counter.Inc(i, tag_1);
|
||||
histogram.Observe(i, tag_1);
|
||||
sum.Record(i, tag_1);
|
||||
|
||||
gauge.Set(1, tag_2);
|
||||
counter.Inc(1, tag_2);
|
||||
histogram.Observe(1, tag_2);
|
||||
sum.Record(1, tag_2);
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
|
||||
class MetricActor {
|
||||
public:
|
||||
static MetricActor *FactoryCreate() { return new MetricActor(); }
|
||||
void record_metric(int total_time) { test_metric("actor", total_time); }
|
||||
};
|
||||
|
||||
RAY_REMOTE(RAY_FUNC(MetricActor::FactoryCreate), &MetricActor::record_metric);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
absl::ParseCommandLine(argc, argv);
|
||||
int total_time = absl::GetFlag(FLAGS_metric_time);
|
||||
// Start ray cluster and ray runtime.
|
||||
ray::RayConfig config;
|
||||
ray::Init(config, argc, argv);
|
||||
auto actor = ray::Actor(MetricActor::FactoryCreate).Remote();
|
||||
auto object_ref = actor.Task(&MetricActor::record_metric).Remote(total_time);
|
||||
test_metric("driver", total_time);
|
||||
object_ref.Get();
|
||||
// Stop ray cluster and ray runtime.
|
||||
ray::Shutdown();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2022 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/// This is a simple job for test submit cpp job.
|
||||
|
||||
#include <ray/api.h>
|
||||
|
||||
/// common function
|
||||
int Plus(int x, int y) { return x + y; }
|
||||
/// Declare remote function
|
||||
RAY_REMOTE(Plus);
|
||||
|
||||
/// class
|
||||
class Counter {
|
||||
public:
|
||||
int count;
|
||||
|
||||
Counter(int init) { count = init; }
|
||||
/// static factory method
|
||||
static Counter *FactoryCreate(int init) { return new Counter(init); }
|
||||
|
||||
/// non static function
|
||||
int Add(int x) {
|
||||
count += x;
|
||||
return count;
|
||||
}
|
||||
};
|
||||
/// Declare remote function
|
||||
RAY_REMOTE(Counter::FactoryCreate, &Counter::Add);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
/// initialization
|
||||
ray::Init();
|
||||
|
||||
/// put and get object
|
||||
auto object = ray::Put(100);
|
||||
auto put_get_result = *(ray::Get(object));
|
||||
std::cout << "put_get_result = " << put_get_result << std::endl;
|
||||
|
||||
/// common task
|
||||
auto task_object = ray::Task(Plus).Remote(1, 2);
|
||||
int task_result = *(ray::Get(task_object));
|
||||
std::cout << "task_result = " << task_result << std::endl;
|
||||
|
||||
/// actor
|
||||
ray::ActorHandle<Counter> actor = ray::Actor(Counter::FactoryCreate).Remote(0);
|
||||
/// actor task
|
||||
auto actor_object = actor.Task(&Counter::Add).Remote(3);
|
||||
int actor_task_result = *(ray::Get(actor_object));
|
||||
std::cout << "actor_task_result = " << actor_task_result << std::endl;
|
||||
/// actor task with reference argument
|
||||
auto actor_object2 = actor.Task(&Counter::Add).Remote(task_object);
|
||||
int actor_task_result2 = *(ray::Get(actor_object2));
|
||||
std::cout << "actor_task_result2 = " << actor_task_result2 << std::endl;
|
||||
|
||||
std::cout << "try to get TEST_KEY: " << std::getenv("TEST_KEY") << std::endl;
|
||||
/// shutdown
|
||||
ray::Shutdown();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
// Copyright 2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/// This is an example of Ray C++ application. Please visit
|
||||
/// `https://docs.ray.io/en/master/index.html` for more details.
|
||||
#include <ray/api.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
// Name of the main server actor.
|
||||
const std::string MAIN_SERVER_NAME = "main_actor";
|
||||
// Name of the backup server actor.
|
||||
const std::string BACKUP_SERVER_NAME = "backup_actor";
|
||||
// Resources that each actor needs: 1 CPU core and 1 GB memory.
|
||||
const std::unordered_map<std::string, double> RESOUECES{
|
||||
{"CPU", 1.0}, {"memory", 1024.0 * 1024.0 * 1024.0}};
|
||||
|
||||
namespace common {
|
||||
inline std::pair<bool, std::string> Get(
|
||||
const std::string &key, const std::unordered_map<std::string, std::string> &data) {
|
||||
auto it = data.find(key);
|
||||
if (it == data.end()) {
|
||||
return std::pair<bool, std::string>{};
|
||||
}
|
||||
|
||||
return {true, it->second};
|
||||
}
|
||||
} // namespace common
|
||||
|
||||
class MainServer;
|
||||
class BackupServer {
|
||||
public:
|
||||
BackupServer();
|
||||
|
||||
// The main server will get all BackupServer's data when it restarts.
|
||||
std::unordered_map<std::string, std::string> GetAllData();
|
||||
|
||||
// This is used for the main server to backup data before putting data.
|
||||
void BackupData(const std::string &key, const std::string &val);
|
||||
|
||||
private:
|
||||
// When the backup server restarts from a failure. It will get all data from the main
|
||||
// server.
|
||||
void HandleFailover();
|
||||
// A map that stores the key-value data.
|
||||
std::unordered_map<std::string, std::string> data_;
|
||||
};
|
||||
|
||||
BackupServer::BackupServer() {
|
||||
// Handle failover when the actor restarts.
|
||||
if (ray::WasCurrentActorRestarted()) {
|
||||
HandleFailover();
|
||||
}
|
||||
RAYLOG(INFO) << "BackupServer created";
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> BackupServer::GetAllData() { return data_; }
|
||||
|
||||
void BackupServer::BackupData(const std::string &key, const std::string &val) {
|
||||
data_[key] = val;
|
||||
}
|
||||
|
||||
class MainServer {
|
||||
public:
|
||||
MainServer();
|
||||
|
||||
// Set value by the given key.
|
||||
void Put(const std::string &key, const std::string &val);
|
||||
|
||||
// Get value from a key.
|
||||
std::pair<bool, std::string> Get(const std::string &key);
|
||||
|
||||
// This is used for the backup server to recover data when it restarts.
|
||||
std::unordered_map<std::string, std::string> GetAllData();
|
||||
|
||||
private:
|
||||
// When the main server restarts from a failure. It will get all data from the backup
|
||||
// server.
|
||||
void HandleFailover();
|
||||
// A map that stores the key-value data.
|
||||
std::unordered_map<std::string, std::string> data_;
|
||||
// Actor handle to the backup server actor.
|
||||
ray::ActorHandle<BackupServer> backup_actor_;
|
||||
};
|
||||
|
||||
MainServer::MainServer() {
|
||||
if (ray::WasCurrentActorRestarted()) {
|
||||
HandleFailover();
|
||||
}
|
||||
|
||||
backup_actor_ = *ray::GetActor<BackupServer>(BACKUP_SERVER_NAME);
|
||||
RAYLOG(INFO) << "MainServer created";
|
||||
}
|
||||
|
||||
void MainServer::Put(const std::string &key, const std::string &val) {
|
||||
// Backup data before putting data.
|
||||
auto r = backup_actor_.Task(&BackupServer::BackupData).Remote(key, val);
|
||||
std::vector<ray::ObjectRef<void>> objects{r};
|
||||
auto result = ray::Wait(objects, objects.size(), 2000);
|
||||
if (result.ready.empty()) {
|
||||
RAYLOG(WARNING) << "MainServer BackupData failed.";
|
||||
}
|
||||
|
||||
data_[key] = val;
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> MainServer::Get(const std::string &key) {
|
||||
return common::Get(key, data_);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string> MainServer::GetAllData() { return data_; }
|
||||
|
||||
void BackupServer::HandleFailover() {
|
||||
// Get all data from MainServer.
|
||||
auto dest_actor = *ray::GetActor<MainServer>(MAIN_SERVER_NAME);
|
||||
data_ = *dest_actor.Task(&MainServer::GetAllData).Remote().Get();
|
||||
RAYLOG(INFO) << "BackupServer recovered all data from MainServer";
|
||||
}
|
||||
|
||||
void MainServer::HandleFailover() {
|
||||
// Get all data from BackupServer.
|
||||
backup_actor_ = *ray::GetActor<BackupServer>(BACKUP_SERVER_NAME);
|
||||
data_ = *backup_actor_.Task(&BackupServer::GetAllData).Remote().Get();
|
||||
RAYLOG(INFO) << "MainServer recovered all data from BackupServer";
|
||||
}
|
||||
|
||||
static MainServer *CreateMainServer() { return new MainServer(); }
|
||||
|
||||
static BackupServer *CreateBackupServer() { return new BackupServer(); }
|
||||
|
||||
RAY_REMOTE(CreateMainServer, &MainServer::GetAllData, &MainServer::Get, &MainServer::Put);
|
||||
|
||||
RAY_REMOTE(CreateBackupServer, &BackupServer::GetAllData, &BackupServer::BackupData);
|
||||
|
||||
void StartServer() {
|
||||
// Start the main server and the backup server.
|
||||
// Each of them needs 1 cpu core and 1 GB memory.
|
||||
// We use Ray's placement group to make sure that the 2 actors will be scheduled to 2
|
||||
// different nodes if possible.
|
||||
std::vector<std::unordered_map<std::string, double>> bundles{RESOUECES, RESOUECES};
|
||||
|
||||
ray::PlacementGroupCreationOptions options{
|
||||
"kv_server_pg", bundles, ray::PlacementStrategy::SPREAD};
|
||||
auto placement_group = ray::CreatePlacementGroup(options);
|
||||
// Wait until the placement group is created.
|
||||
assert(placement_group.Wait(10));
|
||||
|
||||
// Create the main server actor and backup server actor.
|
||||
ray::Actor(CreateMainServer)
|
||||
.SetName(MAIN_SERVER_NAME) // Set name of this actor.
|
||||
.SetResources(RESOUECES) // Set the resources that this actor needs.
|
||||
.SetPlacementGroup(placement_group, 0) // Set the corresponding placement group.
|
||||
.SetMaxRestarts(-1) // Tell Ray to restart this actor automatically upon failures.
|
||||
.Remote();
|
||||
|
||||
ray::Actor(CreateBackupServer)
|
||||
.SetName(BACKUP_SERVER_NAME)
|
||||
.SetResources(RESOUECES)
|
||||
.SetPlacementGroup(placement_group, 1)
|
||||
.SetMaxRestarts(-1)
|
||||
.Remote();
|
||||
}
|
||||
|
||||
void KillMainServer() {
|
||||
auto main_server = *ray::GetActor<MainServer>(MAIN_SERVER_NAME);
|
||||
main_server.Kill(false);
|
||||
}
|
||||
|
||||
class Client {
|
||||
public:
|
||||
Client() {
|
||||
main_actor_ = ray::GetActor<MainServer>(MAIN_SERVER_NAME);
|
||||
// In case the main server hasn't started yet, retry getting
|
||||
// the actor handle.
|
||||
if (!main_actor_) {
|
||||
RetryGetActor();
|
||||
}
|
||||
}
|
||||
|
||||
bool Put(const std::string &key, const std::string &val) {
|
||||
// During the restart of the main server actor, the task may fail.
|
||||
// So we use retry here.
|
||||
AlwaysRetry([this, &key, &val] {
|
||||
(*main_actor_).Task(&MainServer::Put).Remote(key, val).Get();
|
||||
return true;
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<bool, std::string> Get(const std::string &key) {
|
||||
// During the restart of the main server actor, the task may fail.
|
||||
// So we use retry here.
|
||||
return AlwaysRetry([this, &key] {
|
||||
return *(*main_actor_).Task(&MainServer::Get).Remote(key).Get();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
void RetryGetActor() {
|
||||
AlwaysRetry([this] {
|
||||
main_actor_ = ray::GetActor<MainServer>(MAIN_SERVER_NAME);
|
||||
return std::make_pair(bool(main_actor_), "");
|
||||
});
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
std::invoke_result_t<F> AlwaysRetry(const F &f) {
|
||||
using R = std::invoke_result_t<F>;
|
||||
R r{};
|
||||
while (true) {
|
||||
try {
|
||||
r = f();
|
||||
if (IsValid(r)) {
|
||||
break;
|
||||
}
|
||||
} catch (const std::exception &) {
|
||||
}
|
||||
|
||||
std::cout << "Retry in 2 seconds\n";
|
||||
std::this_thread::sleep_for(std::chrono::seconds(2));
|
||||
continue;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
bool IsValid(bool r) { return r; }
|
||||
|
||||
bool IsValid(const std::pair<bool, std::string> r) { return r.first; }
|
||||
|
||||
boost::optional<ray::ActorHandle<MainServer>> main_actor_;
|
||||
};
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
// Start ray cluster and ray runtime.
|
||||
ray::RayConfig config;
|
||||
ray::Init(config, argc, argv);
|
||||
|
||||
StartServer();
|
||||
|
||||
Client client;
|
||||
bool r = client.Put("hello", "ray");
|
||||
assert(r);
|
||||
// Silence warning.
|
||||
(void)r;
|
||||
|
||||
auto get_result = [&client](const std::string &key) {
|
||||
bool ok;
|
||||
std::string result;
|
||||
std::tie(ok, result) = client.Get("hello");
|
||||
assert(ok);
|
||||
assert(result == "ray");
|
||||
};
|
||||
|
||||
get_result("hello");
|
||||
|
||||
// Kill main server. It should restart automatically and recover data from the backup
|
||||
// server.
|
||||
KillMainServer();
|
||||
get_result("hello");
|
||||
|
||||
// Stop ray cluster and ray runtime.
|
||||
ray::Shutdown();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,232 @@
|
||||
// Copyright 2017 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ray/api.h>
|
||||
#include <ray/api/serializer.h>
|
||||
|
||||
#include "cpp/src/ray/runtime/task/task_executor.h"
|
||||
#include "cpp/src/ray/util/function_helper.h"
|
||||
|
||||
int Return() { return 1; }
|
||||
int PlusOne(int x) { return x + 1; }
|
||||
int PlusTwo(int x, int y) { return x + y; }
|
||||
|
||||
int out_for_void_func = 0;
|
||||
int out_for_void_func_no_args = 0;
|
||||
|
||||
void VoidFuncNoArgs() { out_for_void_func = 1; }
|
||||
void VoidFuncWithArgs(int x, int y) { out_for_void_func_no_args = (x + y); }
|
||||
|
||||
int NotRegisteredFunc(int x) { return x; }
|
||||
|
||||
void ExceptionFunc(int x) { throw std::invalid_argument(std::to_string(x)); }
|
||||
|
||||
std::string Concat1(std::string &&a, std::string &&b) { return a + b; }
|
||||
|
||||
std::string Concat2(const std::string &a, std::string &&b) { return a + b; }
|
||||
|
||||
std::string Concat3(std::string &a, std::string &b) { return a + b; }
|
||||
|
||||
int OverloadFunc() {
|
||||
std::cout << "OverloadFunc with no argument\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
int OverloadFunc(int i) {
|
||||
std::cout << "OverloadFunc with one argument\n";
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
int OverloadFunc(int i, int j) {
|
||||
std::cout << "OverloadFunc with two arguments\n";
|
||||
return i + j;
|
||||
}
|
||||
|
||||
RAY_REMOTE(RAY_FUNC(OverloadFunc));
|
||||
RAY_REMOTE(RAY_FUNC(OverloadFunc, int));
|
||||
RAY_REMOTE(RAY_FUNC(OverloadFunc, int, int));
|
||||
|
||||
class DummyObject {
|
||||
public:
|
||||
int count;
|
||||
|
||||
MSGPACK_DEFINE(count);
|
||||
DummyObject() = default;
|
||||
DummyObject(int init) { count = init; }
|
||||
|
||||
int Add(int x, int y) { return x + y; }
|
||||
|
||||
std::string Concat1(std::string &&a, std::string &&b) { return a + b; }
|
||||
|
||||
std::string Concat2(const std::string &a, std::string &&b) { return a + b; }
|
||||
|
||||
~DummyObject() { std::cout << "destruct DummyObject\n"; }
|
||||
|
||||
static DummyObject *FactoryCreate(int init) { return new DummyObject(init); }
|
||||
};
|
||||
RAY_REMOTE(DummyObject::FactoryCreate);
|
||||
RAY_REMOTE(&DummyObject::Add, &DummyObject::Concat1, &DummyObject::Concat2);
|
||||
|
||||
RAY_REMOTE(PlusOne, Concat1, Concat2, Concat3);
|
||||
RAY_REMOTE(PlusTwo, VoidFuncNoArgs, VoidFuncWithArgs, ExceptionFunc);
|
||||
|
||||
struct Base {
|
||||
static Base *FactoryCreate() { return new Base(); }
|
||||
virtual int Foo() { return 1; }
|
||||
virtual int Bar() { return 2; }
|
||||
virtual ~Base() {}
|
||||
};
|
||||
|
||||
struct Base1 {
|
||||
static Base1 *FactoryCreate() { return new Base1(); }
|
||||
virtual int Foo() { return 3; }
|
||||
virtual int Bar() { return 4; }
|
||||
virtual ~Base1() {}
|
||||
};
|
||||
RAY_REMOTE(Base::FactoryCreate, &Base::Foo, &Base::Bar);
|
||||
RAY_REMOTE(Base1::FactoryCreate, &Base1::Foo, &Base1::Bar);
|
||||
|
||||
struct Derived : public Base {
|
||||
static Derived *FactoryCreate() { return new Derived(); }
|
||||
int Foo() override { return 10; }
|
||||
int Bar() override { return 20; }
|
||||
};
|
||||
RAY_REMOTE(Derived::FactoryCreate);
|
||||
|
||||
TEST(RayApiTest, DuplicateRegister) {
|
||||
bool r = FunctionManager::Instance().RegisterRemoteFunction("Return", Return);
|
||||
EXPECT_TRUE(r);
|
||||
|
||||
/// Duplicate register
|
||||
EXPECT_THROW(FunctionManager::Instance().RegisterRemoteFunction("Return", Return),
|
||||
ray::internal::RayException);
|
||||
EXPECT_THROW(FunctionManager::Instance().RegisterRemoteFunction("PlusOne", PlusOne),
|
||||
ray::internal::RayException);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, NormalTask) {
|
||||
auto r = ray::Task(Return).Remote();
|
||||
EXPECT_EQ(1, *(r.Get()));
|
||||
|
||||
auto r1 = ray::Task(PlusOne).Remote(1);
|
||||
EXPECT_EQ(2, *(r1.Get()));
|
||||
}
|
||||
|
||||
TEST(RayApiTest, VoidFunction) {
|
||||
auto r2 = ray::Task(VoidFuncNoArgs).Remote();
|
||||
r2.Get();
|
||||
EXPECT_EQ(1, out_for_void_func);
|
||||
|
||||
auto r3 = ray::Task(VoidFuncWithArgs).Remote(1, 2);
|
||||
r3.Get();
|
||||
EXPECT_EQ(3, out_for_void_func_no_args);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, ReferenceArgs) {
|
||||
auto r = ray::Task(Concat1).Remote("a", "b");
|
||||
EXPECT_EQ(*(r.Get()), "ab");
|
||||
std::string a = "a";
|
||||
std::string b = "b";
|
||||
auto r1 = ray::Task(Concat1).Remote(std::move(a), std::move(b));
|
||||
EXPECT_EQ(*(r.Get()), *(r1.Get()));
|
||||
|
||||
std::string str = "a";
|
||||
std::string str1 = "b";
|
||||
auto r2 = ray::Task(Concat2).Remote(str, std::move(str1));
|
||||
|
||||
std::string str2 = "b";
|
||||
auto r3 = ray::Task(Concat3).Remote(str, str2);
|
||||
EXPECT_EQ(*(r2.Get()), *(r3.Get()));
|
||||
|
||||
ray::ActorHandle<DummyObject> actor = ray::Actor(DummyObject::FactoryCreate).Remote(1);
|
||||
auto r4 = actor.Task(&DummyObject::Concat1).Remote("a", "b");
|
||||
auto r5 = actor.Task(&DummyObject::Concat2).Remote(str, "b");
|
||||
EXPECT_EQ(*(r4.Get()), *(r5.Get()));
|
||||
}
|
||||
|
||||
TEST(RayApiTest, VirtualFunctions) {
|
||||
auto actor = ray::Actor(Base::FactoryCreate).Remote();
|
||||
auto r = actor.Task(&Base::Foo).Remote();
|
||||
auto r1 = actor.Task(&Base::Bar).Remote();
|
||||
auto actor1 = ray::Actor(Base1::FactoryCreate).Remote();
|
||||
auto r2 = actor1.Task(&Base1::Foo).Remote();
|
||||
auto r3 = actor1.Task(&Base1::Bar).Remote();
|
||||
EXPECT_EQ(*(r.Get()), 1);
|
||||
EXPECT_EQ(*(r1.Get()), 2);
|
||||
EXPECT_EQ(*(r2.Get()), 3);
|
||||
EXPECT_EQ(*(r3.Get()), 4);
|
||||
|
||||
auto derived = ray::Actor(Derived::FactoryCreate).Remote();
|
||||
auto r4 = derived.Task(&Base::Foo).Remote();
|
||||
auto r5 = derived.Task(&Base::Bar).Remote();
|
||||
EXPECT_EQ(*(r4.Get()), 10);
|
||||
EXPECT_EQ(*(r5.Get()), 20);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, CallWithObjectRef) {
|
||||
auto rt0 = ray::Task(Return).Remote();
|
||||
auto rt1 = ray::Task(PlusOne).Remote(rt0);
|
||||
auto rt2 = ray::Task(PlusTwo).Remote(rt1, 3);
|
||||
auto rt3 = ray::Task(PlusOne).Remote(3);
|
||||
auto rt4 = ray::Task(PlusTwo).Remote(rt2, rt3);
|
||||
|
||||
int return0 = *(rt0.Get());
|
||||
int return1 = *(rt1.Get());
|
||||
int return2 = *(rt2.Get());
|
||||
int return3 = *(rt3.Get());
|
||||
int return4 = *(rt4.Get());
|
||||
|
||||
EXPECT_EQ(return0, 1);
|
||||
EXPECT_EQ(return1, 2);
|
||||
EXPECT_EQ(return2, 5);
|
||||
EXPECT_EQ(return3, 4);
|
||||
EXPECT_EQ(return4, 9);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, OverloadTest) {
|
||||
auto rt0 = ray::Task(RAY_FUNC(OverloadFunc)).Remote();
|
||||
auto rt1 = ray::Task(RAY_FUNC(OverloadFunc, int)).Remote(rt0);
|
||||
auto rt2 = ray::Task(RAY_FUNC(OverloadFunc, int, int)).Remote(rt1, 3);
|
||||
|
||||
int return0 = *(rt0.Get());
|
||||
int return1 = *(rt1.Get());
|
||||
int return2 = *(rt2.Get());
|
||||
|
||||
EXPECT_EQ(return0, 1);
|
||||
EXPECT_EQ(return1, 2);
|
||||
EXPECT_EQ(return2, 5);
|
||||
}
|
||||
|
||||
/// We should consider the driver so is not same with the worker so, and find the error
|
||||
/// reason.
|
||||
TEST(RayApiTest, NotExistFunction) {
|
||||
EXPECT_THROW(ray::Task(NotRegisteredFunc), ray::internal::RayException);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, ExceptionTask) {
|
||||
/// Normal task Exception.
|
||||
auto r4 = ray::Task(ExceptionFunc).Remote(2);
|
||||
EXPECT_THROW(r4.Get(), ray::internal::RayTaskException);
|
||||
}
|
||||
|
||||
TEST(RayApiTest, GetClassNameByFuncNameTest) {
|
||||
using ray::internal::FunctionManager;
|
||||
EXPECT_EQ(FunctionManager::GetClassNameByFuncName("RAY_FUNC(Counter::FactoryCreate)"),
|
||||
"Counter");
|
||||
EXPECT_EQ(FunctionManager::GetClassNameByFuncName("Counter::FactoryCreate"), "Counter");
|
||||
EXPECT_EQ(FunctionManager::GetClassNameByFuncName("FactoryCreate"), "");
|
||||
EXPECT_EQ(FunctionManager::GetClassNameByFuncName(""), "");
|
||||
EXPECT_EQ(FunctionManager::GetClassNameByFuncName("::FactoryCreate"), "");
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ray/api.h>
|
||||
|
||||
bool IsAnyEqual(const std::any &lhs, const std::any &rhs) {
|
||||
if (lhs.type() != rhs.type()) {
|
||||
return false;
|
||||
}
|
||||
if (lhs.type() == typeid(uint64_t)) {
|
||||
return std::any_cast<uint64_t>(lhs) == std::any_cast<uint64_t>(rhs);
|
||||
} else if (lhs.type() == typeid(int64_t)) {
|
||||
return std::any_cast<int64_t>(lhs) == std::any_cast<int64_t>(rhs);
|
||||
} else if (lhs.type() == typeid(bool)) {
|
||||
return std::any_cast<bool>(lhs) == std::any_cast<bool>(rhs);
|
||||
} else if (lhs.type() == typeid(float)) {
|
||||
return std::any_cast<float>(lhs) == std::any_cast<float>(rhs);
|
||||
} else if (lhs.type() == typeid(double)) {
|
||||
return std::any_cast<double>(lhs) == std::any_cast<double>(rhs);
|
||||
} else if (lhs.type() == typeid(std::string)) {
|
||||
return std::any_cast<std::string>(lhs) == std::any_cast<std::string>(rhs);
|
||||
} else if (lhs.type() == typeid(std::vector<char>)) {
|
||||
return std::any_cast<std::vector<char>>(lhs) == std::any_cast<std::vector<char>>(rhs);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SerializationTest, TypeHybridTest) {
|
||||
uint32_t in_arg1 = 123456789, out_arg1;
|
||||
std::string in_arg2 = "123567ABC", out_arg2;
|
||||
double in_arg3 = 1.1;
|
||||
float in_arg4 = 1.2;
|
||||
uint64_t in_arg5 = 100;
|
||||
int64_t in_arg6 = -100;
|
||||
bool in_arg7 = false;
|
||||
std::vector<char> in_arg8 = {'a', 'b'};
|
||||
|
||||
// 1 arg
|
||||
// marshall
|
||||
msgpack::sbuffer buffer1 = ray::internal::Serializer::Serialize(in_arg1);
|
||||
// unmarshall
|
||||
out_arg1 =
|
||||
ray::internal::Serializer::Deserialize<uint32_t>(buffer1.data(), buffer1.size());
|
||||
|
||||
EXPECT_EQ(in_arg1, out_arg1);
|
||||
|
||||
// 2 args
|
||||
// marshall
|
||||
msgpack::sbuffer buffer2 =
|
||||
ray::internal::Serializer::Serialize(std::make_tuple(in_arg1, in_arg2));
|
||||
|
||||
// unmarshall
|
||||
std::tie(out_arg1, out_arg2) =
|
||||
ray::internal::Serializer::Deserialize<std::tuple<uint32_t, std::string>>(
|
||||
buffer2.data(), buffer2.size());
|
||||
|
||||
EXPECT_EQ(in_arg1, out_arg1);
|
||||
EXPECT_EQ(in_arg2, out_arg2);
|
||||
|
||||
// TODO(Larry Lian) Adapt on windows
|
||||
#ifndef _WIN32
|
||||
// Test std::any
|
||||
msgpack::sbuffer buffer3 = ray::internal::Serializer::Serialize(std::make_tuple(
|
||||
in_arg1, in_arg2, in_arg3, in_arg4, in_arg5, in_arg6, in_arg7, in_arg8));
|
||||
|
||||
std::vector<std::any> result =
|
||||
ray::internal::Serializer::Deserialize<std::vector<std::any>>(buffer3.data(),
|
||||
buffer3.size());
|
||||
EXPECT_TRUE(result[0].type() == typeid(uint64_t));
|
||||
EXPECT_EQ(std::any_cast<uint64_t>(result[0]), in_arg1);
|
||||
EXPECT_TRUE(result[1].type() == typeid(std::string));
|
||||
EXPECT_EQ(std::any_cast<std::string>(result[1]), in_arg2);
|
||||
EXPECT_TRUE(result[2].type() == typeid(double));
|
||||
EXPECT_EQ(std::any_cast<double>(result[2]), in_arg3);
|
||||
EXPECT_TRUE(result[3].type() == typeid(double));
|
||||
EXPECT_EQ(std::any_cast<double>(result[3]), in_arg4);
|
||||
EXPECT_TRUE(result[4].type() == typeid(uint64_t));
|
||||
EXPECT_EQ(std::any_cast<uint64_t>(result[4]), in_arg5);
|
||||
EXPECT_TRUE(result[5].type() == typeid(int64_t));
|
||||
EXPECT_EQ(std::any_cast<int64_t>(result[5]), in_arg6);
|
||||
EXPECT_TRUE(result[6].type() == typeid(bool));
|
||||
EXPECT_EQ(std::any_cast<bool>(result[6]), in_arg7);
|
||||
EXPECT_TRUE(result[7].type() == typeid(std::vector<char>));
|
||||
EXPECT_EQ(std::any_cast<std::vector<char>>(result[7]), in_arg8);
|
||||
|
||||
msgpack::sbuffer buffer4 = ray::internal::Serializer::Serialize(result);
|
||||
|
||||
std::vector<std::any> result_2 =
|
||||
ray::internal::Serializer::Deserialize<std::vector<std::any>>(buffer4.data(),
|
||||
buffer4.size());
|
||||
EXPECT_TRUE(std::equal(result.begin(), result.end(), result_2.begin(), IsAnyEqual));
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(SerializationTest, BoundaryValueTest) {
|
||||
std::string in_arg1 = "", out_arg1;
|
||||
msgpack::sbuffer buffer1 = ray::internal::Serializer::Serialize(in_arg1);
|
||||
out_arg1 =
|
||||
ray::internal::Serializer::Deserialize<std::string>(buffer1.data(), buffer1.size());
|
||||
EXPECT_EQ(in_arg1, out_arg1);
|
||||
|
||||
std::vector<std::byte> in_arg2, out_arg2;
|
||||
msgpack::sbuffer buffer2 = ray::internal::Serializer::Serialize(in_arg2);
|
||||
out_arg2 = ray::internal::Serializer::Deserialize<std::vector<std::byte>>(
|
||||
buffer1.data(), buffer1.size());
|
||||
EXPECT_EQ(in_arg2, out_arg2);
|
||||
|
||||
char *in_arg3 = nullptr;
|
||||
msgpack::sbuffer buffer3 = ray::internal::Serializer::Serialize(in_arg3, 0);
|
||||
auto out_arg3 = ray::internal::Serializer::Deserialize<std::vector<std::byte>>(
|
||||
buffer1.data(), buffer1.size());
|
||||
EXPECT_EQ(std::vector<std::byte>(), out_arg3);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <ray/api.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
int slow_function(int i) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(i));
|
||||
return i;
|
||||
}
|
||||
|
||||
RAY_REMOTE(slow_function);
|
||||
|
||||
TEST(RaySlowFunctionTest, BaseTest) {
|
||||
ray::RayConfig config;
|
||||
config.local_mode = true;
|
||||
ray::Init(config);
|
||||
auto time1 = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch());
|
||||
auto r0 = ray::Task(slow_function).Remote(1);
|
||||
auto r1 = ray::Task(slow_function).Remote(2);
|
||||
auto r2 = ray::Task(slow_function).Remote(3);
|
||||
auto r3 = ray::Task(slow_function).Remote(4);
|
||||
|
||||
int result0 = *(r0.Get());
|
||||
int result1 = *(r1.Get());
|
||||
int result2 = *(r2.Get());
|
||||
int result3 = *(r3.Get());
|
||||
auto time2 = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch());
|
||||
|
||||
EXPECT_EQ(result0, 1);
|
||||
EXPECT_EQ(result1, 2);
|
||||
EXPECT_EQ(result2, 3);
|
||||
EXPECT_EQ(result3, 4);
|
||||
|
||||
EXPECT_LT(time2.count() - time1.count(), 4200);
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "function_helper.h"
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <memory>
|
||||
|
||||
#include "ray/common/constants.h"
|
||||
#include "ray/util/logging.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
void FunctionHelper::LoadDll(const std::filesystem::path &lib_path) {
|
||||
RAY_LOG(INFO) << "Start loading the library " << lib_path << ".";
|
||||
|
||||
auto it = libraries_.find(lib_path.string());
|
||||
if (it != libraries_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
RAY_CHECK(std::filesystem::exists(lib_path))
|
||||
<< lib_path << " dynamic library not found.";
|
||||
|
||||
std::shared_ptr<boost::dll::shared_library> lib = nullptr;
|
||||
try {
|
||||
lib = std::make_shared<boost::dll::shared_library>(
|
||||
lib_path.string(), boost::dll::load_mode::type::rtld_lazy);
|
||||
} catch (std::exception &e) {
|
||||
RAY_LOG(FATAL) << "Failed to load library, lib_path: " << lib_path
|
||||
<< ", failed reason: " << e.what();
|
||||
return;
|
||||
} catch (...) {
|
||||
RAY_LOG(FATAL) << "Failed to load library, lib_path: " << lib_path
|
||||
<< ", unknown failed reason.";
|
||||
return;
|
||||
}
|
||||
|
||||
RAY_CHECK(libraries_.emplace(lib_path.string(), lib).second);
|
||||
|
||||
try {
|
||||
auto entry_func = boost::dll::import_alias<msgpack::sbuffer(
|
||||
const std::string &, const ArgsBufferList &, msgpack::sbuffer *)>(
|
||||
*lib, "TaskExecutionHandler");
|
||||
auto function_names = LoadAllRemoteFunctions(lib_path.string(), *lib, entry_func);
|
||||
if (function_names.empty()) {
|
||||
RAY_LOG(WARNING)
|
||||
<< "No remote functions in library " << lib_path
|
||||
<< ". If you've already used Ray::Task or Ray::Actor in the library, please "
|
||||
"ensure the remote functions have been registered by `RAY_REMOTE` macro.";
|
||||
lib->unload();
|
||||
return;
|
||||
}
|
||||
RAY_LOG(INFO) << "The library " << lib_path
|
||||
<< " is loaded successfully. The remote functions: " << function_names
|
||||
<< ".";
|
||||
return;
|
||||
} catch (boost::system::system_error &e) {
|
||||
RAY_LOG(INFO) << "The library " << lib_path << " isn't integrated with Ray, skip it.";
|
||||
lib->unload();
|
||||
} catch (std::exception &e) {
|
||||
RAY_LOG(WARNING) << "Failed to get entry function from library: " << lib_path
|
||||
<< ", failed reason: " << e.what();
|
||||
lib->unload();
|
||||
} catch (...) {
|
||||
RAY_LOG(WARNING) << "Failed to get entry function from library: " << lib_path
|
||||
<< ", unknown failed reason.";
|
||||
lib->unload();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::string FunctionHelper::LoadAllRemoteFunctions(const std::string lib_path,
|
||||
const boost::dll::shared_library &lib,
|
||||
const EntryFuntion &entry_function) {
|
||||
static const std::string internal_function_name = "GetRemoteFunctions";
|
||||
if (!lib.has(internal_function_name)) {
|
||||
RAY_LOG(WARNING) << "Internal function '" << internal_function_name
|
||||
<< "' not found in " << lib_path;
|
||||
return "";
|
||||
}
|
||||
// Both default worker and user dynamic library static link libray_api.so which has a
|
||||
// singleton class RayRuntimeHolder, the user dynamic library will get a new un-init
|
||||
// instance of RayRuntimeHolder, so we need to init the RayRuntimeHolder singleton when
|
||||
// loading the user dynamic library to make sure the new instance valid.
|
||||
auto init_func =
|
||||
boost::dll::import_alias<void(std::shared_ptr<RayRuntime>)>(lib, "InitRayRuntime");
|
||||
init_func(RayRuntimeHolder::Instance().Runtime());
|
||||
|
||||
auto get_remote_func = boost::dll::import_alias<
|
||||
std::pair<const RemoteFunctionMap_t &, const RemoteMemberFunctionMap_t &>()>(
|
||||
lib, internal_function_name);
|
||||
std::string names_str;
|
||||
auto function_maps = get_remote_func();
|
||||
for (const auto &pair : function_maps.first) {
|
||||
names_str.append(pair.first).append(", ");
|
||||
remote_funcs_.emplace(pair.first, entry_function);
|
||||
}
|
||||
for (const auto &pair : function_maps.second) {
|
||||
names_str.append(pair.first).append(", ");
|
||||
remote_member_funcs_.emplace(pair.first, entry_function);
|
||||
}
|
||||
if (!names_str.empty()) {
|
||||
names_str.pop_back();
|
||||
names_str.pop_back();
|
||||
}
|
||||
return names_str;
|
||||
}
|
||||
|
||||
void FindDynamicLibrary(std::filesystem::path path,
|
||||
std::list<std::filesystem::path> &dynamic_libraries) {
|
||||
#if defined(_WIN32)
|
||||
static const std::unordered_set<std::string> dynamic_library_extension = {".dll"};
|
||||
#elif __APPLE__
|
||||
static const std::unordered_set<std::string> dynamic_library_extension = {".dylib",
|
||||
".so"};
|
||||
#else
|
||||
static const std::unordered_set<std::string> dynamic_library_extension = {".so"};
|
||||
#endif
|
||||
auto extension = path.extension();
|
||||
if (dynamic_library_extension.find(extension.string()) !=
|
||||
dynamic_library_extension.end()) {
|
||||
dynamic_libraries.emplace_back(path);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionHelper::LoadFunctionsFromPaths(const std::vector<std::string> &paths) {
|
||||
std::list<std::filesystem::path> dynamic_libraries;
|
||||
// Lookup dynamic libraries from paths.
|
||||
for (auto path : paths) {
|
||||
if (std::filesystem::is_directory(path)) {
|
||||
for (auto &entry :
|
||||
boost::make_iterator_range(std::filesystem::directory_iterator(path), {})) {
|
||||
FindDynamicLibrary(entry, dynamic_libraries);
|
||||
}
|
||||
} else if (std::filesystem::exists(path)) {
|
||||
FindDynamicLibrary(path, dynamic_libraries);
|
||||
} else {
|
||||
RAY_LOG(FATAL) << path << " dynamic library not found.";
|
||||
}
|
||||
}
|
||||
|
||||
RAY_LOG(INFO) << std::string(kLibraryPathEnvName) << ": " << getLibraryPathEnv();
|
||||
// Try to load all found libraries.
|
||||
for (auto lib : dynamic_libraries) {
|
||||
LoadDll(lib);
|
||||
}
|
||||
}
|
||||
|
||||
const EntryFuntion &FunctionHelper::GetExecutableFunctions(
|
||||
const std::string &function_name) {
|
||||
auto it = remote_funcs_.find(function_name);
|
||||
if (it == remote_funcs_.end()) {
|
||||
throw RayFunctionNotFound("Executable function not found, the function name " +
|
||||
function_name);
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
const EntryFuntion &FunctionHelper::GetExecutableMemberFunctions(
|
||||
const std::string &function_name) {
|
||||
auto it = remote_member_funcs_.find(function_name);
|
||||
if (it == remote_member_funcs_.end()) {
|
||||
throw RayFunctionNotFound("Executable member function not found, the function name " +
|
||||
function_name);
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,65 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ray/api/common_types.h>
|
||||
#include <ray/api/ray_runtime_holder.h>
|
||||
|
||||
#include <boost/dll.hpp>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <msgpack.hpp>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace ::ray::internal;
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
using EntryFuntion = std::function<msgpack::sbuffer(
|
||||
const std::string &, const ArgsBufferList &, msgpack::sbuffer *)>;
|
||||
|
||||
class FunctionHelper {
|
||||
public:
|
||||
static FunctionHelper &GetInstance() {
|
||||
// We use `new` here because we don't want to destruct this instance forever.
|
||||
// If we do destruct, the shared libraries will be unloaded. And Maybe the unloading
|
||||
// will bring some errors which hard to debug.
|
||||
static auto *instance = new FunctionHelper();
|
||||
return *instance;
|
||||
}
|
||||
|
||||
void LoadDll(const std::filesystem::path &lib_path);
|
||||
void LoadFunctionsFromPaths(const std::vector<std::string> &paths);
|
||||
const EntryFuntion &GetExecutableFunctions(const std::string &function_name);
|
||||
const EntryFuntion &GetExecutableMemberFunctions(const std::string &function_name);
|
||||
|
||||
private:
|
||||
FunctionHelper() = default;
|
||||
~FunctionHelper() = default;
|
||||
FunctionHelper(FunctionHelper const &) = delete;
|
||||
FunctionHelper(FunctionHelper &&) = delete;
|
||||
std::string LoadAllRemoteFunctions(const std::string lib_path,
|
||||
const boost::dll::shared_library &lib,
|
||||
const EntryFuntion &entry_function);
|
||||
std::unordered_map<std::string, std::shared_ptr<boost::dll::shared_library>> libraries_;
|
||||
// Map from remote function name to executable entry function.
|
||||
std::unordered_map<std::string, EntryFuntion> remote_funcs_;
|
||||
// Map from remote member function name to executable entry function.
|
||||
std::unordered_map<std::string, EntryFuntion> remote_member_funcs_;
|
||||
};
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,192 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "process_helper.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "ray/common/ray_config.h"
|
||||
#include "ray/util/cmd_line_utils.h"
|
||||
#include "ray/util/network_util.h"
|
||||
#include "ray/util/process.h"
|
||||
#include "src/ray/protobuf/gcs.pb.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
using ray::core::CoreWorkerProcess;
|
||||
using ray::core::WorkerType;
|
||||
|
||||
void ProcessHelper::StartRayNode(const std::string node_id_address,
|
||||
const int port,
|
||||
const std::string redis_username,
|
||||
const std::string redis_password,
|
||||
const std::vector<std::string> &head_args) {
|
||||
std::vector<std::string> cmdargs({"ray",
|
||||
"start",
|
||||
"--head",
|
||||
"--port",
|
||||
std::to_string(port),
|
||||
"--redis-username",
|
||||
redis_username,
|
||||
"--redis-password",
|
||||
redis_password,
|
||||
"--node-ip-address",
|
||||
node_id_address});
|
||||
if (!head_args.empty()) {
|
||||
cmdargs.insert(cmdargs.end(), head_args.begin(), head_args.end());
|
||||
}
|
||||
RAY_LOG(INFO) << CreateCommandLine(cmdargs);
|
||||
auto [proc, ec] = Process::Spawn(cmdargs, true);
|
||||
RAY_CHECK(!ec) << "Failed to spawn process to start ray node: " << ec.message();
|
||||
proc->Wait();
|
||||
return;
|
||||
}
|
||||
|
||||
void ProcessHelper::StopRayNode() {
|
||||
std::vector<std::string> cmdargs({"ray", "stop"});
|
||||
RAY_LOG(INFO) << CreateCommandLine(cmdargs);
|
||||
auto [proc, ec] = Process::Spawn(cmdargs, true);
|
||||
RAY_CHECK(!ec) << "Failed to spawn process to stop ray node: " << ec.message();
|
||||
proc->Wait();
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<ray::gcs::GlobalStateAccessor> ProcessHelper::CreateGlobalStateAccessor(
|
||||
const std::string &gcs_ip, int gcs_port) {
|
||||
ray::gcs::GcsClientOptions client_options(gcs_ip,
|
||||
gcs_port,
|
||||
ray::ClusterID::Nil(),
|
||||
/*allow_cluster_id_nil=*/true,
|
||||
/*fetch_cluster_id_if_nil=*/false);
|
||||
auto global_state_accessor =
|
||||
std::make_unique<ray::gcs::GlobalStateAccessor>(client_options);
|
||||
RAY_CHECK(global_state_accessor->Connect()) << "Failed to connect to GCS.";
|
||||
return global_state_accessor;
|
||||
}
|
||||
|
||||
void ProcessHelper::RayStart(CoreWorkerOptions::TaskExecutionCallback callback) {
|
||||
std::string bootstrap_ip = ConfigInternal::Instance().bootstrap_ip;
|
||||
int bootstrap_port = ConfigInternal::Instance().bootstrap_port;
|
||||
|
||||
if (ConfigInternal::Instance().worker_type == WorkerType::DRIVER &&
|
||||
bootstrap_ip.empty()) {
|
||||
bootstrap_ip = ray::GetNodeIpAddressFromPerspective();
|
||||
StartRayNode(bootstrap_ip,
|
||||
bootstrap_port,
|
||||
ConfigInternal::Instance().redis_username,
|
||||
ConfigInternal::Instance().redis_password,
|
||||
ConfigInternal::Instance().head_args);
|
||||
}
|
||||
|
||||
std::string bootstrap_address = BuildAddress(bootstrap_ip, bootstrap_port);
|
||||
std::string node_ip = ConfigInternal::Instance().node_ip_address;
|
||||
if (node_ip.empty()) {
|
||||
if (!bootstrap_ip.empty()) {
|
||||
node_ip = ray::GetNodeIpAddressFromPerspective(bootstrap_address);
|
||||
} else {
|
||||
node_ip = ray::GetNodeIpAddressFromPerspective();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<ray::gcs::GlobalStateAccessor> global_state_accessor =
|
||||
CreateGlobalStateAccessor(bootstrap_ip, bootstrap_port);
|
||||
if (ConfigInternal::Instance().worker_type == WorkerType::DRIVER) {
|
||||
std::string node_to_connect;
|
||||
auto status =
|
||||
global_state_accessor->GetNodeToConnectForDriver(node_ip, &node_to_connect);
|
||||
RAY_CHECK_OK(status)
|
||||
<< "Failed to get node to connect for driver when starting the cluster";
|
||||
ray::rpc::GcsNodeInfo node_info;
|
||||
node_info.ParseFromString(node_to_connect);
|
||||
ConfigInternal::Instance().raylet_socket_name = node_info.raylet_socket_name();
|
||||
ConfigInternal::Instance().plasma_store_socket_name =
|
||||
node_info.object_store_socket_name();
|
||||
ConfigInternal::Instance().node_manager_port = node_info.node_manager_port();
|
||||
ConfigInternal::Instance().UpdateSessionDir(node_info.session_dir());
|
||||
}
|
||||
RAY_CHECK(!ConfigInternal::Instance().raylet_socket_name.empty())
|
||||
<< "Failed to start ray cluster, raylet socket name could not be resolved";
|
||||
RAY_CHECK(!ConfigInternal::Instance().plasma_store_socket_name.empty())
|
||||
<< "Failed to start ray cluster, plasma store socket name could not be resolved";
|
||||
RAY_CHECK(ConfigInternal::Instance().node_manager_port > 0)
|
||||
<< "Failed to start ray cluster, node manager port could not be resolved";
|
||||
|
||||
gcs::GcsClientOptions gcs_options =
|
||||
gcs::GcsClientOptions(bootstrap_ip,
|
||||
bootstrap_port,
|
||||
ClusterID::Nil(),
|
||||
/*allow_cluster_id_nil=*/true,
|
||||
/*fetch_cluster_id_if_nil=*/false);
|
||||
|
||||
CoreWorkerOptions options;
|
||||
options.worker_type = ConfigInternal::Instance().worker_type;
|
||||
options.language = Language::CPP;
|
||||
options.store_socket = ConfigInternal::Instance().plasma_store_socket_name;
|
||||
options.raylet_socket = ConfigInternal::Instance().raylet_socket_name;
|
||||
if (options.worker_type == WorkerType::DRIVER) {
|
||||
if (!ConfigInternal::Instance().job_id.empty()) {
|
||||
options.job_id = JobID::FromHex(ConfigInternal::Instance().job_id);
|
||||
} else {
|
||||
options.job_id = global_state_accessor->GetNextJobID();
|
||||
}
|
||||
}
|
||||
options.gcs_options = gcs_options;
|
||||
options.enable_logging = true;
|
||||
options.log_dir = ConfigInternal::Instance().logs_dir;
|
||||
options.install_failure_signal_handler = true;
|
||||
options.node_ip_address = node_ip;
|
||||
options.node_manager_port = ConfigInternal::Instance().node_manager_port;
|
||||
options.driver_name = "cpp_worker";
|
||||
options.metrics_agent_port = -1;
|
||||
options.task_execution_callback = callback;
|
||||
if (ConfigInternal::Instance().worker_type != WorkerType::DRIVER) {
|
||||
options.worker_id = WorkerID::FromHex(ConfigInternal::Instance().worker_id);
|
||||
}
|
||||
options.runtime_env_hash = ConfigInternal::Instance().runtime_env_hash;
|
||||
rpc::JobConfig job_config;
|
||||
job_config.set_default_actor_lifetime(
|
||||
ConfigInternal::Instance().default_actor_lifetime);
|
||||
|
||||
for (const auto &path : ConfigInternal::Instance().code_search_path) {
|
||||
job_config.add_code_search_path(path);
|
||||
}
|
||||
job_config.set_ray_namespace(ConfigInternal::Instance().ray_namespace);
|
||||
if (ConfigInternal::Instance().runtime_env) {
|
||||
job_config.mutable_runtime_env_info()->set_serialized_runtime_env(
|
||||
ConfigInternal::Instance().runtime_env->Serialize());
|
||||
}
|
||||
if (ConfigInternal::Instance().job_config_metadata.size()) {
|
||||
auto metadata_ptr = job_config.mutable_metadata();
|
||||
for (const auto &it : ConfigInternal::Instance().job_config_metadata) {
|
||||
(*metadata_ptr)[it.first] = it.second;
|
||||
}
|
||||
}
|
||||
std::string serialized_job_config;
|
||||
RAY_CHECK(job_config.SerializeToString(&serialized_job_config))
|
||||
<< "Could not start ray cluster: failed to serialize job config";
|
||||
options.serialized_job_config = serialized_job_config;
|
||||
CoreWorkerProcess::Initialize(options);
|
||||
}
|
||||
|
||||
void ProcessHelper::RayStop() {
|
||||
CoreWorkerProcess::Shutdown();
|
||||
if (ConfigInternal::Instance().bootstrap_ip.empty()) {
|
||||
StopRayNode();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include "../config_internal.h"
|
||||
#include "ray/core_worker/core_worker.h"
|
||||
#include "ray/gcs_rpc_client/global_state_accessor.h"
|
||||
#include "util.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
using ray::core::CoreWorkerOptions;
|
||||
|
||||
class ProcessHelper {
|
||||
public:
|
||||
void RayStart(CoreWorkerOptions::TaskExecutionCallback callback);
|
||||
void RayStop();
|
||||
void StartRayNode(const std::string node_id_address,
|
||||
const int port,
|
||||
const std::string redis_username,
|
||||
const std::string redis_password,
|
||||
const std::vector<std::string> &head_args = {});
|
||||
void StopRayNode();
|
||||
|
||||
static ProcessHelper &GetInstance() {
|
||||
static ProcessHelper processHelper;
|
||||
return processHelper;
|
||||
}
|
||||
|
||||
std::unique_ptr<ray::gcs::GlobalStateAccessor> CreateGlobalStateAccessor(
|
||||
const std::string &gcs_ip, int gcs_port);
|
||||
|
||||
ProcessHelper(ProcessHelper const &) = delete;
|
||||
void operator=(ProcessHelper const &) = delete;
|
||||
|
||||
private:
|
||||
ProcessHelper(){};
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
|
||||
#include "ray/common/constants.h"
|
||||
#include "ray/util/logging.h"
|
||||
#include "ray/util/network_util.h"
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
std::string getLibraryPathEnv() {
|
||||
auto path_env_p = std::getenv(kLibraryPathEnvName);
|
||||
if (path_env_p != nullptr && strlen(path_env_p) != 0) {
|
||||
return std::string(path_env_p);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace ray {
|
||||
namespace internal {
|
||||
|
||||
std::string getLibraryPathEnv();
|
||||
|
||||
} // namespace internal
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2020-2021 The Ray Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <ray/api.h>
|
||||
#include <ray/api/internal_api.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
ray::RayConfig config;
|
||||
config.is_worker_ = true;
|
||||
ray::Init(config, argc, argv);
|
||||
ray::RunTaskExecutionLoop();
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# This file defines the C++ symbols that need to be exported (aka ABI, application binary interface).
|
||||
# These symbols will be used by other libraries.
|
||||
# Note: This file is used for linux only, and should be kept in sync with `ray_api_exported_symbols.lds`.
|
||||
# Ray ABI is not finalized, the exact set of exported (C/C++) APIs is subject to change.
|
||||
VERSION_1.0 {
|
||||
global:
|
||||
# common
|
||||
*[0-9]ray[0-9]*;
|
||||
TaskExecutionHandler;
|
||||
GetFunctionManager;
|
||||
GetRemoteFunctions;
|
||||
InitRayRuntime;
|
||||
# If the symbols of absl::flags are hidden, and the users also use the absl::flags library,
|
||||
# then the flags feature will bring issues, e.g. `ERROR: Unknown command line flag`.
|
||||
*absl*;
|
||||
FLAGS_*;
|
||||
local:
|
||||
*;
|
||||
};
|
||||
@@ -0,0 +1,117 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import ray
|
||||
import ray.cluster_utils
|
||||
from ray.exceptions import CrossLanguageError, RayActorError
|
||||
|
||||
# plus.so / counter.so are staged next to this file via the bazel
|
||||
# target's `data` attr; resolve them absolutely so the worker finds them
|
||||
# regardless of its cwd.
|
||||
_CODE_SEARCH_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
_CODE_SEARCH_PATH = [
|
||||
os.path.join(_CODE_SEARCH_DIR, "plus.so"),
|
||||
os.path.join(_CODE_SEARCH_DIR, "counter.so"),
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module", autouse=True)
|
||||
def ray_start():
|
||||
ray.init(job_config=ray.job_config.JobConfig(code_search_path=_CODE_SEARCH_PATH))
|
||||
yield
|
||||
ray.shutdown()
|
||||
|
||||
|
||||
def test_cross_language_cpp():
|
||||
obj = ray.cross_language.cpp_function("Plus1").remote(1)
|
||||
assert 2 == ray.get(obj)
|
||||
|
||||
obj1 = ray.cross_language.cpp_function("ThrowTask").remote()
|
||||
with pytest.raises(CrossLanguageError):
|
||||
ray.get(obj1)
|
||||
|
||||
obj = ray.cross_language.cpp_function("Plus1").remote("invalid arg")
|
||||
with pytest.raises(CrossLanguageError):
|
||||
ray.get(obj)
|
||||
|
||||
obj = ray.cross_language.cpp_function("Plus1").remote(1, 2)
|
||||
with pytest.raises(CrossLanguageError):
|
||||
ray.get(obj)
|
||||
|
||||
obj = ray.cross_language.cpp_function("Plus1").remote()
|
||||
with pytest.raises(CrossLanguageError):
|
||||
ray.get(obj)
|
||||
|
||||
obj2 = ray.cross_language.cpp_function("NotExsitTask").remote()
|
||||
with pytest.raises(CrossLanguageError):
|
||||
ray.get(obj2)
|
||||
|
||||
obj3 = ray.cross_language.cpp_function("Echo").remote("hello")
|
||||
assert "hello" == ray.get(obj3)
|
||||
|
||||
list = [0] * 100000
|
||||
obj4 = ray.cross_language.cpp_function("ReturnLargeArray").remote(list)
|
||||
assert list == ray.get(obj4)
|
||||
|
||||
map = {0: "hello"}
|
||||
obj5 = ray.cross_language.cpp_function("GetMap").remote(map)
|
||||
assert {0: "hello", 1: "world"} == ray.get(obj5)
|
||||
|
||||
v = ["hello", "world"]
|
||||
obj6 = ray.cross_language.cpp_function("GetList").remote(v)
|
||||
assert v == ray.get(obj6)
|
||||
|
||||
obj6 = ray.cross_language.cpp_function("GetArray").remote(v)
|
||||
assert v == ray.get(obj6)
|
||||
|
||||
tuple = [1, "hello"]
|
||||
obj7 = ray.cross_language.cpp_function("GetTuple").remote(tuple)
|
||||
assert tuple == ray.get(obj7)
|
||||
|
||||
student = ["tom", 20]
|
||||
obj8 = ray.cross_language.cpp_function("GetStudent").remote(student)
|
||||
assert student == ray.get(obj8)
|
||||
|
||||
students = {0: ["tom", 20], 1: ["jerry", 10]}
|
||||
obj9 = ray.cross_language.cpp_function("GetStudents").remote(students)
|
||||
assert students == ray.get(obj9)
|
||||
|
||||
|
||||
def test_cross_language_cpp_actor():
|
||||
actor = ray.cross_language.cpp_actor_class(
|
||||
"RAY_FUNC(Counter::FactoryCreate)", "Counter"
|
||||
).remote()
|
||||
obj = actor.Plus1.remote()
|
||||
assert 1 == ray.get(obj)
|
||||
|
||||
actor1 = ray.cross_language.cpp_actor_class(
|
||||
"RAY_FUNC(Counter::FactoryCreate)", "Counter"
|
||||
).remote("invalid arg")
|
||||
obj = actor1.Plus1.remote()
|
||||
with pytest.raises(RayActorError):
|
||||
ray.get(obj)
|
||||
|
||||
actor1 = ray.cross_language.cpp_actor_class(
|
||||
"RAY_FUNC(Counter::FactoryCreate)", "Counter"
|
||||
).remote()
|
||||
|
||||
obj = actor1.Plus1.remote()
|
||||
assert 1 == ray.get(obj)
|
||||
|
||||
obj = actor1.Add.remote(2)
|
||||
assert 3 == ray.get(obj)
|
||||
|
||||
obj2 = actor1.ExceptionFunc.remote()
|
||||
with pytest.raises(CrossLanguageError):
|
||||
ray.get(obj2)
|
||||
|
||||
obj3 = actor1.NotExistFunc.remote()
|
||||
with pytest.raises(CrossLanguageError):
|
||||
ray.get(obj3)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
|
||||
sys.exit(pytest.main(["-v", __file__]))
|
||||
@@ -0,0 +1,82 @@
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
|
||||
from ray._common.test_utils import wait_for_condition
|
||||
from ray._private.test_utils import (
|
||||
format_web_url,
|
||||
wait_until_server_available,
|
||||
)
|
||||
from ray.job_submission import JobStatus, JobSubmissionClient
|
||||
from ray.tests.conftest import _ray_start
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def headers():
|
||||
return {"Connection": "keep-alive", "Authorization": "TOK:<MY_TOKEN>"}
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def job_sdk_client(headers):
|
||||
with _ray_start(include_dashboard=True, num_cpus=1) as ctx:
|
||||
address = ctx.address_info["webui_url"]
|
||||
assert wait_until_server_available(address)
|
||||
yield JobSubmissionClient(format_web_url(address), headers=headers)
|
||||
|
||||
|
||||
def _check_job_succeeded(client: JobSubmissionClient, job_id: str) -> bool:
|
||||
status = client.get_job_status(job_id)
|
||||
if status == JobStatus.FAILED:
|
||||
logs = client.get_job_logs(job_id)
|
||||
raise RuntimeError(f"Job failed\nlogs:\n{logs}")
|
||||
return status == JobStatus.SUCCEEDED
|
||||
|
||||
|
||||
def test_submit_simple_cpp_job(job_sdk_client):
|
||||
client = job_sdk_client
|
||||
|
||||
simple_job_so_path = os.environ["SIMPLE_DRIVER_SO_PATH"]
|
||||
simple_job_so_filename = os.path.basename(simple_job_so_path)
|
||||
simple_job_main_path = os.environ["SIMPLE_DRIVER_MAIN_PATH"]
|
||||
simple_job_main_filename = os.path.basename(simple_job_main_path)
|
||||
with tempfile.TemporaryDirectory() as tmp_dir:
|
||||
working_dir = os.path.join(tmp_dir, "cpp_worker")
|
||||
os.makedirs(working_dir)
|
||||
shutil.copy2(
|
||||
simple_job_so_path, os.path.join(working_dir, simple_job_so_filename)
|
||||
)
|
||||
shutil.copy2(
|
||||
simple_job_main_path,
|
||||
os.path.join(working_dir, simple_job_main_filename),
|
||||
)
|
||||
shutil.copymode(
|
||||
simple_job_main_path,
|
||||
os.path.join(working_dir, simple_job_main_filename),
|
||||
)
|
||||
entrypoint = (
|
||||
f"chmod +x {simple_job_main_filename} && ./{simple_job_main_filename}"
|
||||
)
|
||||
runtime_env = dict(
|
||||
working_dir=working_dir,
|
||||
env_vars={"TEST_KEY": "TEST_VALUE"},
|
||||
)
|
||||
|
||||
job_id = client.submit_job(
|
||||
entrypoint=entrypoint,
|
||||
runtime_env=runtime_env,
|
||||
)
|
||||
|
||||
wait_for_condition(
|
||||
_check_job_succeeded, client=client, job_id=job_id, timeout=120
|
||||
)
|
||||
|
||||
logs = client.get_job_logs(job_id)
|
||||
print(f"================== logs ================== \n {logs}")
|
||||
assert "try to get TEST_KEY: TEST_VALUE" in logs
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(pytest.main(["-v", __file__]))
|
||||
Reference in New Issue
Block a user