chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:17:40 +08:00
commit f1825c8ceb
10096 changed files with 2364182 additions and 0 deletions
+480
View File
@@ -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",
],
)
+2
View File
@@ -0,0 +1,2 @@
build --cxxopt="-std=c++17"
build --cxxopt="-D_GLIBCXX_USE_CXX11_ABI=0"
+43
View File
@@ -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"],
)
View File
+59
View File
@@ -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;
}
+13
View File
@@ -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
+11
View File
@@ -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",
],
)
+402
View File
@@ -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
+113
View File
@@ -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
+92
View File
@@ -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
+97
View File
@@ -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
+123
View File
@@ -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
+56
View File
@@ -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
+354
View File
@@ -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
+21
View File
@@ -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
+83
View File
@@ -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
+135
View File
@@ -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
+88
View File
@@ -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
+225
View File
@@ -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
+200
View File
@@ -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
+74
View File
@@ -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
+68
View File
@@ -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
+83
View File
@@ -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
+105
View File
@@ -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
+48
View File
@@ -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
+100
View File
@@ -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
+86
View File
@@ -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
+73
View File
@@ -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
+109
View File
@@ -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
+116
View File
@@ -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
+88
View File
@@ -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
+37
View File
@@ -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
+85
View File
@@ -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
+50
View File
@@ -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
+273
View File
@@ -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
+100
View File
@@ -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
+399
View File
@@ -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
+133
View File
@@ -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
+39
View File
@@ -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
+91
View File
@@ -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
+46
View File
@@ -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
+32
View File
@@ -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
+105
View File
@@ -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
+78
View File
@@ -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
+346
View File
@@ -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
+111
View File
@@ -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
+55
View File
@@ -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
+368
View File
@@ -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 callargs 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 callargs 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;
}
+143
View File
@@ -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);
+167
View File
@@ -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};
};
+55
View File
@@ -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);
+41
View File
@@ -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;
}
+71
View File
@@ -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;
}
+232
View File
@@ -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"), "");
}
+126
View File
@@ -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);
}
+52
View File
@@ -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);
}
+186
View File
@@ -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
+65
View File
@@ -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
+192
View File
@@ -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
+55
View File
@@ -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
+36
View File
@@ -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
+24
View File
@@ -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
+24
View File
@@ -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:
*;
};
+117
View File
@@ -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__]))
+82
View 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__]))