Remove CoreWorkerObjectInterface (#6023)

This commit is contained in:
Edward Oakes
2019-10-28 10:48:41 -07:00
committed by Eric Liang
parent e08b5d0cae
commit c1418b04df
22 changed files with 568 additions and 921 deletions
+13 -12
View File
@@ -510,7 +510,8 @@ cdef execute_task(
if not execution_info:
function_descriptor = FunctionDescriptor.from_bytes_list(
ray_function.GetFunctionDescriptor())
execution_info = manager.get_execution_info(job_id, function_descriptor)
execution_info = manager.get_execution_info(
job_id, function_descriptor)
execution_infos[descriptor] = execution_info
function_name = execution_info.function_name
@@ -696,7 +697,7 @@ cdef class CoreWorker:
c_vector[CObjectID] c_object_ids = ObjectIDsToVector(object_ids)
with nogil:
check_status(self.core_worker.get().Objects().Get(
check_status(self.core_worker.get().Get(
c_object_ids, timeout_ms, &results))
return RayObjectsToDataMetadataPairs(results)
@@ -707,7 +708,7 @@ cdef class CoreWorker:
CObjectID c_object_id = object_id.native()
with nogil:
check_status(self.core_worker.get().Objects().Contains(
check_status(self.core_worker.get().Contains(
c_object_id, &has_object))
return has_object
@@ -721,12 +722,12 @@ cdef class CoreWorker:
try:
if object_id is None:
with nogil:
check_status(self.core_worker.get().Objects().Create(
check_status(self.core_worker.get().Create(
metadata, data_size, c_object_id, data))
else:
c_object_id[0] = object_id.native()
with nogil:
check_status(self.core_worker.get().Objects().Create(
check_status(self.core_worker.get().Create(
metadata, data_size, c_object_id[0], data))
break
except ObjectStoreFullError as e:
@@ -763,7 +764,7 @@ cdef class CoreWorker:
with nogil:
check_status(
self.core_worker.get().Objects().Seal(c_object_id))
self.core_worker.get().Seal(c_object_id))
return ObjectID(c_object_id.Binary())
@@ -788,7 +789,7 @@ cdef class CoreWorker:
with nogil:
check_status(
self.core_worker.get().Objects().Seal(c_object_id))
self.core_worker.get().Seal(c_object_id))
return ObjectID(c_object_id.Binary())
@@ -811,7 +812,7 @@ cdef class CoreWorker:
writer.write_to(inband, data, memcopy_threads)
with nogil:
check_status(
self.core_worker.get().Objects().Seal(c_object_id))
self.core_worker.get().Seal(c_object_id))
return ObjectID(c_object_id.Binary())
@@ -825,7 +826,7 @@ cdef class CoreWorker:
wait_ids = ObjectIDsToVector(object_ids)
with nogil:
check_status(self.core_worker.get().Objects().Wait(
check_status(self.core_worker.get().Wait(
wait_ids, num_returns, timeout_ms, &results))
assert len(results) == len(object_ids)
@@ -845,7 +846,7 @@ cdef class CoreWorker:
c_vector[CObjectID] free_ids = ObjectIDsToVector(object_ids)
with nogil:
check_status(self.core_worker.get().Objects().Delete(
check_status(self.core_worker.get().Delete(
free_ids, local_only, delete_creating_tasks))
def set_object_store_client_options(self, client_name,
@@ -853,7 +854,7 @@ cdef class CoreWorker:
try:
logger.debug("Setting plasma memory limit to {} for {}".format(
limit_bytes, client_name))
check_status(self.core_worker.get().Objects().SetClientOptions(
check_status(self.core_worker.get().SetClientOptions(
client_name.encode("ascii"), limit_bytes))
except RayError as e:
self.dump_object_store_memory_usage()
@@ -866,7 +867,7 @@ cdef class CoreWorker:
limit_bytes, client_name, e))
def dump_object_store_memory_usage(self):
message = self.core_worker.get().Objects().MemoryUsageString()
message = self.core_worker.get().MemoryUsageString()
logger.warning("Local object store memory usage:\n{}\n".format(
message.decode("utf-8")))
+19 -22
View File
@@ -48,27 +48,6 @@ cdef extern from "ray/core_worker/profiling.h" nogil:
cdef cppclass CProfileEvent "ray::worker::ProfileEvent":
void SetExtraData(const c_string &extra_data)
cdef extern from "ray/core_worker/object_interface.h" nogil:
cdef cppclass CObjectInterface "ray::CoreWorkerObjectInterface":
CRayStatus SetClientOptions(c_string client_name, int64_t limit)
CRayStatus Put(const CRayObject &object, CObjectID *object_id)
CRayStatus Put(const CRayObject &object, const CObjectID &object_id)
CRayStatus Create(const shared_ptr[CBuffer] &metadata,
const size_t data_size, CObjectID *object_id,
shared_ptr[CBuffer] *data)
CRayStatus Create(const shared_ptr[CBuffer] &metadata,
const size_t data_size, const CObjectID &object_id,
shared_ptr[CBuffer] *data)
CRayStatus Seal(const CObjectID &object_id)
CRayStatus Get(const c_vector[CObjectID] &ids, int64_t timeout_ms,
c_vector[shared_ptr[CRayObject]] *results)
CRayStatus Contains(const CObjectID &object_id, c_bool *has_object)
CRayStatus Wait(const c_vector[CObjectID] &object_ids, int num_objects,
int64_t timeout_ms, c_vector[c_bool] *results)
CRayStatus Delete(const c_vector[CObjectID] &object_ids,
c_bool local_only, c_bool delete_creating_tasks)
c_string MemoryUsageString()
cdef extern from "ray/core_worker/core_worker.h" nogil:
cdef cppclass CCoreWorker "ray::CoreWorker":
CCoreWorker(const CWorkerType worker_type, const CLanguage language,
@@ -88,7 +67,6 @@ cdef extern from "ray/core_worker/core_worker.h" nogil:
void Disconnect()
CWorkerType &GetWorkerType()
CLanguage &GetLanguage()
CObjectInterface &Objects()
void StartExecutingTasks()
@@ -119,3 +97,22 @@ cdef extern from "ray/core_worker/core_worker.h" nogil:
*bytes)
void AddActiveObjectID(const CObjectID &object_id)
void RemoveActiveObjectID(const CObjectID &object_id)
CRayStatus SetClientOptions(c_string client_name, int64_t limit)
CRayStatus Put(const CRayObject &object, CObjectID *object_id)
CRayStatus Put(const CRayObject &object, const CObjectID &object_id)
CRayStatus Create(const shared_ptr[CBuffer] &metadata,
const size_t data_size, CObjectID *object_id,
shared_ptr[CBuffer] *data)
CRayStatus Create(const shared_ptr[CBuffer] &metadata,
const size_t data_size, const CObjectID &object_id,
shared_ptr[CBuffer] *data)
CRayStatus Seal(const CObjectID &object_id)
CRayStatus Get(const c_vector[CObjectID] &ids, int64_t timeout_ms,
c_vector[shared_ptr[CRayObject]] *results)
CRayStatus Contains(const CObjectID &object_id, c_bool *has_object)
CRayStatus Wait(const c_vector[CObjectID] &object_ids, int num_objects,
int64_t timeout_ms, c_vector[c_bool] *results)
CRayStatus Delete(const c_vector[CObjectID] &object_ids,
c_bool local_only, c_bool delete_creating_tasks)
c_string MemoryUsageString()
-2
View File
@@ -81,8 +81,6 @@ class TaskArg {
const std::shared_ptr<RayObject> value_;
};
enum class StoreProviderType { PLASMA, MEMORY };
enum class TaskTransportType { RAYLET, DIRECT_ACTOR };
/// Options for all tasks (actor and non-actor) except for actor creation.
+217 -8
View File
@@ -37,6 +37,33 @@ void BuildCommonTaskSpec(
}
}
// Group object ids according the the corresponding store providers.
void GroupObjectIdsByStoreProvider(const std::vector<ObjectID> &object_ids,
std::unordered_set<ObjectID> *plasma_object_ids,
std::unordered_set<ObjectID> *memory_object_ids) {
// There are two cases:
// - for task return objects from direct actor call, use memory store provider;
// - all the others use plasma store provider.
for (const auto &object_id : object_ids) {
// For raylet transport we always use plasma store provider, for direct actor call
// there are a few cases:
// - objects manually added to store by `ray.put`: for these objects they always use
// plasma store provider;
// - task arguments: these objects are passed by value, and are not put into store;
// - task return objects: these are put into memory store of the task submitter
// and are only used locally.
// Thus we need to check whether this object is a task return object in additional
// to whether it's from direct actor call before we can choose memory store provider.
if (object_id.IsReturnObject() &&
object_id.GetTransportType() ==
static_cast<uint8_t>(ray::TaskTransportType::DIRECT_ACTOR)) {
memory_object_ids->insert(object_id);
} else {
plasma_object_ids->insert(object_id);
}
}
}
} // namespace
namespace ray {
@@ -50,12 +77,13 @@ CoreWorker::CoreWorker(const WorkerType worker_type, const Language language,
: worker_type_(worker_type),
language_(language),
log_dir_(log_dir),
check_signals_(check_signals),
worker_context_(worker_type, job_id),
io_work_(io_service_),
heartbeat_timer_(io_service_),
worker_server_(WorkerTypeString(worker_type), 0 /* let grpc choose a port */),
gcs_client_(gcs_options),
object_interface_(worker_context_, raylet_client_, store_socket, check_signals),
memory_store_(std::make_shared<CoreWorkerMemoryStore>()),
task_execution_service_work_(task_execution_service_),
task_execution_callback_(task_execution_callback) {
// Initialize logging if log_dir is passed. Otherwise, it must be initialized
@@ -84,12 +112,11 @@ CoreWorker::CoreWorker(const WorkerType worker_type, const Language language,
std::placeholders::_2, std::placeholders::_3);
raylet_task_receiver_ =
std::unique_ptr<CoreWorkerRayletTaskReceiver>(new CoreWorkerRayletTaskReceiver(
worker_context_, raylet_client_, object_interface_, task_execution_service_,
worker_server_, execute_task));
worker_context_, raylet_client_, task_execution_service_, worker_server_,
execute_task));
direct_actor_task_receiver_ = std::unique_ptr<CoreWorkerDirectActorTaskReceiver>(
new CoreWorkerDirectActorTaskReceiver(worker_context_, object_interface_,
task_execution_service_, worker_server_,
execute_task));
new CoreWorkerDirectActorTaskReceiver(worker_context_, task_execution_service_,
worker_server_, execute_task));
}
// Start RPC server after all the task receivers are properly initialized.
@@ -115,6 +142,10 @@ CoreWorker::CoreWorker(const WorkerType worker_type, const Language language,
io_thread_ = std::thread(&CoreWorker::RunIOService, this);
plasma_store_provider_.reset(
new CoreWorkerPlasmaStoreProvider(store_socket, raylet_client_, check_signals_));
memory_store_provider_.reset(new CoreWorkerMemoryStoreProvider(memory_store_));
// Create an entry for the driver task in the task table. This task is
// added immediately with status RUNNING. This allows us to push errors
// related to this driver task back to the driver. For example, if the
@@ -137,9 +168,11 @@ CoreWorker::CoreWorker(const WorkerType worker_type, const Language language,
SetCurrentTaskId(task_id);
}
// TODO(edoakes): why don't we just share the memory store provider?
direct_actor_submitter_ = std::unique_ptr<CoreWorkerDirectActorTaskSubmitter>(
new CoreWorkerDirectActorTaskSubmitter(
io_service_, object_interface_.CreateStoreProvider(StoreProviderType::MEMORY)));
io_service_, std::unique_ptr<CoreWorkerMemoryStoreProvider>(
new CoreWorkerMemoryStoreProvider(memory_store_))));
}
CoreWorker::~CoreWorker() {
@@ -224,6 +257,163 @@ void CoreWorker::ReportActiveObjectIDs() {
active_object_ids_updated_ = false;
}
Status CoreWorker::SetClientOptions(std::string name, int64_t limit_bytes) {
// Currently only the Plasma store supports client options.
return plasma_store_provider_->SetClientOptions(name, limit_bytes);
}
Status CoreWorker::Put(const RayObject &object, ObjectID *object_id) {
*object_id = ObjectID::ForPut(worker_context_.GetCurrentTaskID(),
worker_context_.GetNextPutIndex(),
static_cast<uint8_t>(TaskTransportType::RAYLET));
return Put(object, *object_id);
}
Status CoreWorker::Put(const RayObject &object, const ObjectID &object_id) {
RAY_CHECK(object_id.GetTransportType() ==
static_cast<uint8_t>(TaskTransportType::RAYLET))
<< "Invalid transport type flag in object ID: " << object_id.GetTransportType();
return plasma_store_provider_->Put(object, object_id);
}
Status CoreWorker::Create(const std::shared_ptr<Buffer> &metadata, const size_t data_size,
ObjectID *object_id, std::shared_ptr<Buffer> *data) {
*object_id = ObjectID::ForPut(worker_context_.GetCurrentTaskID(),
worker_context_.GetNextPutIndex(),
static_cast<uint8_t>(TaskTransportType::RAYLET));
return Create(metadata, data_size, *object_id, data);
}
Status CoreWorker::Create(const std::shared_ptr<Buffer> &metadata, const size_t data_size,
const ObjectID &object_id, std::shared_ptr<Buffer> *data) {
return plasma_store_provider_->Create(metadata, data_size, object_id, data);
}
Status CoreWorker::Seal(const ObjectID &object_id) {
return plasma_store_provider_->Seal(object_id);
}
Status CoreWorker::Get(const std::vector<ObjectID> &ids, int64_t timeout_ms,
std::vector<std::shared_ptr<RayObject>> *results) {
results->resize(ids.size(), nullptr);
std::unordered_set<ObjectID> plasma_object_ids;
std::unordered_set<ObjectID> memory_object_ids;
GroupObjectIdsByStoreProvider(ids, &plasma_object_ids, &memory_object_ids);
bool got_exception = false;
std::unordered_map<ObjectID, std::shared_ptr<RayObject>> result_map;
auto start_time = current_time_ms();
RAY_RETURN_NOT_OK(plasma_store_provider_->Get(plasma_object_ids, timeout_ms,
worker_context_.GetCurrentTaskID(),
&result_map, &got_exception));
if (!got_exception) {
if (timeout_ms >= 0) {
timeout_ms = std::max(static_cast<int64_t>(0),
timeout_ms - (current_time_ms() - start_time));
}
RAY_RETURN_NOT_OK(memory_store_provider_->Get(memory_object_ids, timeout_ms,
worker_context_.GetCurrentTaskID(),
&result_map, &got_exception));
}
// Loop through `ids` and fill each entry for the `results` vector,
// this ensures that entries `results` have exactly the same order as
// they are in `ids`. When there are duplicate object ids, all the entries
// for the same id are filled in.
for (size_t i = 0; i < ids.size(); i++) {
if (result_map.find(ids[i]) != result_map.end()) {
(*results)[i] = result_map[ids[i]];
}
}
return Status::OK();
}
Status CoreWorker::Contains(const ObjectID &object_id, bool *has_object) {
// Currently only the Plasma store supports Contains().
return plasma_store_provider_->Contains(object_id, has_object);
}
Status CoreWorker::Wait(const std::vector<ObjectID> &ids, int num_objects,
int64_t timeout_ms, std::vector<bool> *results) {
results->resize(ids.size(), false);
if (num_objects <= 0 || num_objects > static_cast<int>(ids.size())) {
return Status::Invalid(
"Number of objects to wait for must be between 1 and the number of ids.");
}
std::unordered_set<ObjectID> plasma_object_ids;
std::unordered_set<ObjectID> memory_object_ids;
GroupObjectIdsByStoreProvider(ids, &plasma_object_ids, &memory_object_ids);
if (plasma_object_ids.size() + memory_object_ids.size() != ids.size()) {
return Status::Invalid("Duplicate object IDs not supported in wait.");
}
// TODO(edoakes): this logic is not ideal, and will have to be addressed
// before we enable direct actor calls in the Python code. If we are waiting
// on a list of objects mixed between multiple store providers, we could
// easily end up in the situation where we're blocked waiting on one store
// provider while another actually has enough objects ready to fulfill
// 'num_objects'. This is partially addressed by trying them all once with
// a timeout of 0, but that does not address the situation where objects
// become available on the second store provider while waiting on the first.
std::unordered_set<ObjectID> ready;
// Wait from both store providers with timeout set to 0. This is to avoid the case
// where we might use up the entire timeout on trying to get objects from one store
// provider before even trying another (which might have all of the objects available).
RAY_RETURN_NOT_OK(
plasma_store_provider_->Wait(plasma_object_ids, num_objects, /*timeout_ms=*/0,
worker_context_.GetCurrentTaskID(), &ready));
RAY_RETURN_NOT_OK(memory_store_provider_->Wait(
memory_object_ids, std::max(0, static_cast<int>(ready.size()) - num_objects),
/*timeout_ms=*/0, worker_context_.GetCurrentTaskID(), &ready));
if (static_cast<int>(ready.size()) < num_objects && timeout_ms != 0) {
int64_t start_time = current_time_ms();
RAY_RETURN_NOT_OK(
plasma_store_provider_->Wait(plasma_object_ids, num_objects, timeout_ms,
worker_context_.GetCurrentTaskID(), &ready));
if (timeout_ms > 0) {
timeout_ms =
std::max(0, static_cast<int>(timeout_ms - (current_time_ms() - start_time)));
}
RAY_RETURN_NOT_OK(
memory_store_provider_->Wait(memory_object_ids, num_objects, timeout_ms,
worker_context_.GetCurrentTaskID(), &ready));
}
for (size_t i = 0; i < ids.size(); i++) {
if (ready.find(ids[i]) != ready.end()) {
results->at(i) = true;
}
}
return Status::OK();
}
Status CoreWorker::Delete(const std::vector<ObjectID> &object_ids, bool local_only,
bool delete_creating_tasks) {
std::unordered_set<ObjectID> plasma_object_ids;
std::unordered_set<ObjectID> memory_object_ids;
GroupObjectIdsByStoreProvider(object_ids, &plasma_object_ids, &memory_object_ids);
RAY_RETURN_NOT_OK(plasma_store_provider_->Delete(plasma_object_ids, local_only,
delete_creating_tasks));
RAY_RETURN_NOT_OK(memory_store_provider_->Delete(memory_object_ids));
return Status::OK();
}
std::string CoreWorker::MemoryUsageString() {
// Currently only the Plasma store returns a debug string.
return plasma_store_provider_->MemoryUsageString();
}
TaskID CoreWorker::GetCallerId() const {
TaskID caller_id;
ActorID actor_id = GetActorId();
@@ -438,6 +628,25 @@ Status CoreWorker::ExecuteTask(const TaskSpecification &task_spec,
SetCurrentTaskId(TaskID::Nil());
worker_context_.ResetCurrentTask(task_spec);
// TODO(edoakes): also check if not direct actor call.
// TODO(edoakes): this is only used by java.
if (results->size() != 0) {
for (size_t i = 0; i < results->size(); i++) {
ObjectID id = ObjectID::ForTaskReturn(
task_spec.TaskId(), /*index=*/i + 1,
/*transport_type=*/static_cast<int>(TaskTransportType::RAYLET));
if (!Put(*results->at(i), id).ok()) {
// NOTE(hchen): `PlasmaObjectExists` error is already ignored inside
// Put`, we treat other error types as fatal here.
RAY_LOG(FATAL) << "Task " << task_spec.TaskId() << " failed to put object " << id
<< " in store: " << status.message();
} else {
RAY_LOG(DEBUG) << "Task " << task_spec.TaskId() << " put object " << id
<< " in store.";
}
}
}
// TODO(zhijunfu):
// 1. Check and handle failure.
// 2. Save or load checkpoint.
@@ -481,7 +690,7 @@ Status CoreWorker::BuildArgsForExecutor(const TaskSpecification &task,
}
std::vector<std::shared_ptr<RayObject>> results;
auto status = object_interface_.Get(object_ids_to_fetch, -1, &results);
auto status = Get(object_ids_to_fetch, -1, &results);
if (status.ok()) {
for (size_t i = 0; i < results.size(); i++) {
args->at(indices[i]) = results[i];
+124 -9
View File
@@ -5,8 +5,9 @@
#include "ray/core_worker/actor_handle.h"
#include "ray/core_worker/common.h"
#include "ray/core_worker/context.h"
#include "ray/core_worker/object_interface.h"
#include "ray/core_worker/profiling.h"
#include "ray/core_worker/store_provider/memory_store_provider.h"
#include "ray/core_worker/store_provider/plasma_store_provider.h"
#include "ray/core_worker/transport/direct_actor_transport.h"
#include "ray/core_worker/transport/raylet_transport.h"
#include "ray/gcs/redis_gcs_client.h"
@@ -67,8 +68,6 @@ class CoreWorker {
RayletClient &GetRayletClient() { return *raylet_client_; }
CoreWorkerObjectInterface &Objects() { return object_interface_; }
const TaskID &GetCurrentTaskId() const { return worker_context_.GetCurrentTaskID(); }
void SetCurrentTaskId(const TaskID &task_id);
@@ -88,6 +87,109 @@ class CoreWorker {
// in the heartbeat messsage.
void RemoveActiveObjectID(const ObjectID &object_id);
/* Public methods related to storing and retrieving objects. */
/// Set options for this client's interactions with the object store.
///
/// \param[in] name Unique name for this object store client.
/// \param[in] limit The maximum amount of memory in bytes that this client
/// can use in the object store.
Status SetClientOptions(std::string name, int64_t limit_bytes);
/// Put an object into object store.
///
/// \param[in] object The ray object.
/// \param[out] object_id Generated ID of the object.
/// \return Status.
Status Put(const RayObject &object, ObjectID *object_id);
/// Put an object with specified ID into object store.
///
/// \param[in] object The ray object.
/// \param[in] object_id Object ID specified by the user.
/// \return Status.
Status Put(const RayObject &object, const ObjectID &object_id);
/// Create and return a buffer in the object store that can be directly written
/// into. After writing to the buffer, the caller must call `Seal()` to finalize
/// the object. The `Create()` and `Seal()` combination is an alternative interface
/// to `Put()` that allows frontends to avoid an extra copy when possible.
///
/// \param[in] metadata Metadata of the object to be written.
/// \param[in] data_size Size of the object to be written.
/// \param[out] object_id Object ID generated for the put.
/// \param[out] data Buffer for the user to write the object into.
/// \return Status.
Status Create(const std::shared_ptr<Buffer> &metadata, const size_t data_size,
ObjectID *object_id, std::shared_ptr<Buffer> *data);
/// Create and return a buffer in the object store that can be directly written
/// into. After writing to the buffer, the caller must call `Seal()` to finalize
/// the object. The `Create()` and `Seal()` combination is an alternative interface
/// to `Put()` that allows frontends to avoid an extra copy when possible.
///
/// \param[in] metadata Metadata of the object to be written.
/// \param[in] data_size Size of the object to be written.
/// \param[in] object_id Object ID specified by the user.
/// \param[out] data Buffer for the user to write the object into.
/// \return Status.
Status Create(const std::shared_ptr<Buffer> &metadata, const size_t data_size,
const ObjectID &object_id, std::shared_ptr<Buffer> *data);
/// Finalize placing an object into the object store. This should be called after
/// a corresponding `Create()` call and then writing into the returned buffer.
///
/// \param[in] object_id Object ID corresponding to the object.
/// \return Status.
Status Seal(const ObjectID &object_id);
/// Get a list of objects from the object store. Objects that failed to be retrieved
/// will be returned as nullptrs.
///
/// \param[in] ids IDs of the objects to get.
/// \param[in] timeout_ms Timeout in milliseconds, wait infinitely if it's negative.
/// \param[out] results Result list of objects data.
/// \return Status.
Status Get(const std::vector<ObjectID> &ids, int64_t timeout_ms,
std::vector<std::shared_ptr<RayObject>> *results);
/// Return whether or not the object store contains the given object.
///
/// \param[in] object_id ID of the objects to check for.
/// \param[out] has_object Whether or not the object is present.
/// \return Status.
Status Contains(const ObjectID &object_id, bool *has_object);
/// Wait for a list of objects to appear in the object store.
/// Duplicate object ids are supported, and `num_objects` includes duplicate ids in this
/// case.
/// TODO(zhijunfu): it is probably more clear in semantics to just fail when there
/// are duplicates, and require it to be handled at application level.
///
/// \param[in] IDs of the objects to wait for.
/// \param[in] num_objects Number of objects that should appear.
/// \param[in] timeout_ms Timeout in milliseconds, wait infinitely if it's negative.
/// \param[out] results A bitset that indicates each object has appeared or not.
/// \return Status.
Status Wait(const std::vector<ObjectID> &object_ids, int num_objects,
int64_t timeout_ms, std::vector<bool> *results);
/// Delete a list of objects from the object store.
///
/// \param[in] object_ids IDs of the objects to delete.
/// \param[in] local_only Whether only delete the objects in local node, or all nodes in
/// the cluster.
/// \param[in] delete_creating_tasks Whether also delete the tasks that
/// created these objects.
/// \return Status.
Status Delete(const std::vector<ObjectID> &object_ids, bool local_only,
bool delete_creating_tasks);
/// Get a string describing object store memory usage for debugging purposes.
///
/// \return std::string The string describing memory usage.
std::string MemoryUsageString();
/* Public methods related to task submission. */
/// Get the caller ID used to submit tasks from this worker to an actor.
@@ -240,6 +342,11 @@ class CoreWorker {
/// Directory where log files are written.
const std::string log_dir_;
/// Application-language callback to check for signals that have been received
/// since calling into C++. This will be called periodically (at least every
/// 1s) during long-running operations.
std::function<Status()> check_signals_;
/// Shared state of the worker. Includes process-level and thread-level state.
/// TODO(edoakes): we should move process-level state into this class and make
/// this a ThreadContext.
@@ -279,8 +386,16 @@ class CoreWorker {
/// last time it was sent to the raylet.
bool active_object_ids_updated_ = false;
// Interface for storing and retrieving shared objects.
CoreWorkerObjectInterface object_interface_;
/* Fields related to storing and retrieving objects. */
/// In-memory store for return objects. This is used for `MEMORY` store provider.
std::shared_ptr<CoreWorkerMemoryStore> memory_store_;
/// Plasma store interface.
std::unique_ptr<CoreWorkerPlasmaStoreProvider> plasma_store_provider_;
/// In-memory store interface.
std::unique_ptr<CoreWorkerMemoryStoreProvider> memory_store_provider_;
/* Fields related to task submission. */
@@ -301,14 +416,14 @@ class CoreWorker {
/// The asio work to keep task_execution_service_ alive.
boost::asio::io_service::work task_execution_service_work_;
// Profiler including a background thread that pushes profiling events to the GCS.
/// Profiler including a background thread that pushes profiling events to the GCS.
std::shared_ptr<worker::Profiler> profiler_;
// Profile event for when the worker is idle. Should be reset when the worker
// enters and exits an idle period.
/// Profile event for when the worker is idle. Should be reset when the worker
/// enters and exits an idle period.
std::unique_ptr<worker::ProfileEvent> idle_profile_event_;
// Task execution callback.
/// Task execution callback.
TaskExecutionCallback task_execution_callback_;
/// A map from resource name to the resource IDs that are currently reserved
-1
View File
@@ -6,7 +6,6 @@
#include "ray/common/id.h"
#include "ray/common/ray_object.h"
#include "ray/common/status.h"
#include "ray/core_worker/store_provider/store_provider.h"
/// Boolean class
extern jclass java_boolean_class;
@@ -4,7 +4,6 @@
#include "ray/core_worker/common.h"
#include "ray/core_worker/core_worker.h"
#include "ray/core_worker/lib/java/jni_utils.h"
#include "ray/core_worker/object_interface.h"
inline ray::CoreWorkerObjectInterface &GetObjectInterfaceFromPointer(
jlong nativeCoreWorkerPointer) {
@@ -26,8 +25,8 @@ Java_org_ray_runtime_object_NativeObjectStore_nativePut__JLorg_ray_runtime_objec
auto ray_object = JavaNativeRayObjectToNativeRayObject(env, obj);
RAY_CHECK(ray_object != nullptr);
ray::ObjectID object_id;
auto status =
GetObjectInterfaceFromPointer(nativeCoreWorkerPointer).Put(*ray_object, &object_id);
auto status = reinterpret_cast<ray::CoreWorker *>(nativeCoreWorkerPointer)
.Put(*ray_object, &object_id);
THROW_EXCEPTION_AND_RETURN_IF_NOT_OK(env, status, nullptr);
return IdToJavaByteArray<ray::ObjectID>(env, object_id);
}
@@ -44,8 +43,8 @@ Java_org_ray_runtime_object_NativeObjectStore_nativePut__J_3BLorg_ray_runtime_ob
auto object_id = JavaByteArrayToId<ray::ObjectID>(env, objectId);
auto ray_object = JavaNativeRayObjectToNativeRayObject(env, obj);
RAY_CHECK(ray_object != nullptr);
auto status =
GetObjectInterfaceFromPointer(nativeCoreWorkerPointer).Put(*ray_object, object_id);
auto status = reinterpret_cast<ray::CoreWorker *>(nativeCoreWorkerPointer)
.Put(*ray_object, object_id);
THROW_EXCEPTION_AND_RETURN_IF_NOT_OK(env, status, (void)0);
}
@@ -62,7 +61,7 @@ JNIEXPORT jobject JNICALL Java_org_ray_runtime_object_NativeObjectStore_nativeGe
return JavaByteArrayToId<ray::ObjectID>(env, static_cast<jbyteArray>(id));
});
std::vector<std::shared_ptr<ray::RayObject>> results;
auto status = GetObjectInterfaceFromPointer(nativeCoreWorkerPointer)
auto status = reinterpret_cast<ray::CoreWorker *>(nativeCoreWorkerPointer)
.Get(object_ids, (int64_t)timeoutMs, &results);
THROW_EXCEPTION_AND_RETURN_IF_NOT_OK(env, status, nullptr);
return NativeVectorToJavaList<std::shared_ptr<ray::RayObject>>(
@@ -83,7 +82,7 @@ JNIEXPORT jobject JNICALL Java_org_ray_runtime_object_NativeObjectStore_nativeWa
return JavaByteArrayToId<ray::ObjectID>(env, static_cast<jbyteArray>(id));
});
std::vector<bool> results;
auto status = GetObjectInterfaceFromPointer(nativeCoreWorkerPointer)
auto status = reinterpret_cast<ray::CoreWorker *>(nativeCoreWorkerPointer)
.Wait(object_ids, (int)numObjects, (int64_t)timeoutMs, &results);
THROW_EXCEPTION_AND_RETURN_IF_NOT_OK(env, status, nullptr);
return NativeVectorToJavaList<bool>(env, results, [](JNIEnv *env, const bool &item) {
@@ -104,7 +103,7 @@ JNIEXPORT void JNICALL Java_org_ray_runtime_object_NativeObjectStore_nativeDelet
env, objectIds, &object_ids, [](JNIEnv *env, jobject id) {
return JavaByteArrayToId<ray::ObjectID>(env, static_cast<jbyteArray>(id));
});
auto status = GetObjectInterfaceFromPointer(nativeCoreWorkerPointer)
auto status = reinterpret_cast<ray::CoreWorker *>(nativeCoreWorkerPointer)
.Delete(object_ids, (bool)localOnly, (bool)deleteCreatingTasks);
THROW_EXCEPTION_AND_RETURN_IF_NOT_OK(env, status, (void)0);
}
-291
View File
@@ -1,291 +0,0 @@
#include <algorithm>
#include "ray/common/ray_config.h"
#include "ray/core_worker/object_interface.h"
#include "ray/core_worker/store_provider/memory_store_provider.h"
#include "ray/core_worker/store_provider/plasma_store_provider.h"
namespace ray {
// Group object ids according the the corresponding store providers.
void CoreWorkerObjectInterface::GroupObjectIdsByStoreProvider(
const std::vector<ObjectID> &object_ids,
EnumUnorderedMap<StoreProviderType, std::unordered_set<ObjectID>> *results) {
// There are two cases:
// - for task return objects from direct actor call, use memory store provider;
// - all the others use plasma store provider.
for (const auto &object_id : object_ids) {
auto type = StoreProviderType::PLASMA;
// For raylet transport we always use plasma store provider, for direct actor call
// there are a few cases:
// - objects manually added to store by `ray.put`: for these objects they always use
// plasma store provider;
// - task arguments: these objects are passed by value, and are not put into store;
// - task return objects: these are put into memory store of the task submitter
// and are only used locally.
// Thus we need to check whether this object is a task return object in additional
// to whether it's from direct actor call before we can choose memory store provider.
if (object_id.IsReturnObject() &&
object_id.GetTransportType() ==
static_cast<uint8_t>(TaskTransportType::DIRECT_ACTOR)) {
type = StoreProviderType::MEMORY;
}
(*results)[type].insert(object_id);
}
}
CoreWorkerObjectInterface::CoreWorkerObjectInterface(
WorkerContext &worker_context, std::unique_ptr<RayletClient> &raylet_client,
const std::string &store_socket, std::function<Status()> check_signals)
: worker_context_(worker_context),
raylet_client_(raylet_client),
store_socket_(store_socket),
memory_store_(std::make_shared<CoreWorkerMemoryStore>()) {
check_signals_ = check_signals;
AddStoreProvider(StoreProviderType::PLASMA);
AddStoreProvider(StoreProviderType::MEMORY);
}
Status CoreWorkerObjectInterface::SetClientOptions(std::string name,
int64_t limit_bytes) {
// Currently only the Plasma store supports client options.
return store_providers_[StoreProviderType::PLASMA]->SetClientOptions(name, limit_bytes);
}
Status CoreWorkerObjectInterface::Put(const RayObject &object, ObjectID *object_id) {
*object_id = ObjectID::ForPut(worker_context_.GetCurrentTaskID(),
worker_context_.GetNextPutIndex(),
static_cast<uint8_t>(TaskTransportType::RAYLET));
return Put(object, *object_id);
}
Status CoreWorkerObjectInterface::Put(const RayObject &object,
const ObjectID &object_id) {
RAY_CHECK(object_id.GetTransportType() ==
static_cast<uint8_t>(TaskTransportType::RAYLET))
<< "Invalid transport type flag in object ID: " << object_id.GetTransportType();
return store_providers_[StoreProviderType::PLASMA]->Put(object, object_id);
}
Status CoreWorkerObjectInterface::Create(const std::shared_ptr<Buffer> &metadata,
const size_t data_size, ObjectID *object_id,
std::shared_ptr<Buffer> *data) {
*object_id = ObjectID::ForPut(worker_context_.GetCurrentTaskID(),
worker_context_.GetNextPutIndex(),
static_cast<uint8_t>(TaskTransportType::RAYLET));
return Create(metadata, data_size, *object_id, data);
}
Status CoreWorkerObjectInterface::Create(const std::shared_ptr<Buffer> &metadata,
const size_t data_size,
const ObjectID &object_id,
std::shared_ptr<Buffer> *data) {
return store_providers_[StoreProviderType::PLASMA]->Create(metadata, data_size,
object_id, data);
}
Status CoreWorkerObjectInterface::Seal(const ObjectID &object_id) {
return store_providers_[StoreProviderType::PLASMA]->Seal(object_id);
}
Status CoreWorkerObjectInterface::Get(const std::vector<ObjectID> &ids,
int64_t timeout_ms,
std::vector<std::shared_ptr<RayObject>> *results) {
(*results).resize(ids.size(), nullptr);
// Divide the object ids by store provider type. For each store provider,
// maintain an unordered_set which does proper de-duplication, thus the
// store provider could simply assume its object ids don't have duplicates.
EnumUnorderedMap<StoreProviderType, std::unordered_set<ObjectID>>
object_ids_per_store_provider;
GroupObjectIdsByStoreProvider(ids, &object_ids_per_store_provider);
std::unordered_map<ObjectID, std::shared_ptr<RayObject>> result_map;
auto remaining_timeout_ms = timeout_ms;
bool got_exception = false;
// Re-order the list so that we always get from plasma store provider first,
// since it uses a loop of `FetchOrReconstruct` and plasma `Get`, it's not
// desirable if other store providers use up the timeout and leaves no time
// for plasma provider to reconstruct the objects as necessary.
std::list<std::pair<StoreProviderType,
std::reference_wrapper<const std::unordered_set<ObjectID>>>>
ids_per_provider;
for (const auto &entry : object_ids_per_store_provider) {
auto list_entry = std::make_pair(entry.first, std::ref(entry.second));
if (entry.first == StoreProviderType::PLASMA) {
ids_per_provider.emplace_front(list_entry);
} else {
ids_per_provider.emplace_back(list_entry);
}
}
// Note that if one store provider uses up the timeout, we will still try the others
// with a timeout of 0.
for (const auto &entry : ids_per_provider) {
auto start_time = current_time_ms();
RAY_RETURN_NOT_OK(store_providers_[entry.first]->Get(
entry.second, remaining_timeout_ms, worker_context_.GetCurrentTaskID(),
&result_map, &got_exception));
if (got_exception) {
break;
}
if (remaining_timeout_ms > 0) {
int64_t duration = current_time_ms() - start_time;
remaining_timeout_ms =
std::max(static_cast<int64_t>(0), remaining_timeout_ms - duration);
}
}
// Loop through `ids` and fill each entry for the `results` vector,
// this ensures that entries `results` have exactly the same order as
// they are in `ids`. When there are duplicate object ids, all the entries
// for the same id are filled in.
for (size_t i = 0; i < ids.size(); i++) {
if (result_map.find(ids[i]) != result_map.end()) {
(*results)[i] = result_map[ids[i]];
}
}
return Status::OK();
}
Status CoreWorkerObjectInterface::Contains(const ObjectID &object_id, bool *has_object) {
// Currently only the Plasma store supports Contains().
return store_providers_[StoreProviderType::PLASMA]->Contains(object_id, has_object);
}
Status CoreWorkerObjectInterface::Wait(const std::vector<ObjectID> &ids, int num_objects,
int64_t timeout_ms, std::vector<bool> *results) {
(*results).resize(ids.size(), false);
if (num_objects <= 0 || num_objects > static_cast<int>(ids.size())) {
return Status::Invalid(
"Number of objects to wait for must be between 1 and the number of ids.");
}
EnumUnorderedMap<StoreProviderType, std::unordered_set<ObjectID>>
object_ids_per_store_provider;
GroupObjectIdsByStoreProvider(ids, &object_ids_per_store_provider);
size_t total_count = 0;
for (const auto &entry : object_ids_per_store_provider) {
total_count += entry.second.size();
}
if (total_count != ids.size()) {
return Status::Invalid("Duplicate object IDs not supported in wait.");
}
// TODO(edoakes): this logic is not ideal, and will have to be addressed
// before we enable direct actor calls in the Python code. If we are waiting
// on a list of objects mixed between multiple store providers, we could
// easily end up in the situation where we're blocked waiting on one store
// provider while another actually has enough objects ready to fulfill
// 'num_objects'. This is partially addressed by trying them all once with
// a timeout of 0, but that does not address the situation where objects
// become available on the second store provider while waiting on the first.
std::unordered_set<ObjectID> ready;
// Wait from all the store providers with timeout set to 0. This is to avoid the case
// where we might use up the entire timeout on trying to get objects from one store
// provider before even trying another (which might have all of the objects available).
RAY_RETURN_NOT_OK(WaitFromMultipleStoreProviders(object_ids_per_store_provider,
/*timeout_ms=*/0, &num_objects,
&ready));
if (num_objects > 0) {
// Wait from all the store providers with the specified timeout
// if the required number of objects haven't been ready yet.
RAY_RETURN_NOT_OK(WaitFromMultipleStoreProviders(object_ids_per_store_provider,
/*timeout_ms=*/timeout_ms,
&num_objects, &ready));
}
for (size_t i = 0; i < ids.size(); i++) {
if (ready.find(ids[i]) != ready.end()) {
(*results)[i] = true;
}
}
return Status::OK();
}
Status CoreWorkerObjectInterface::WaitFromMultipleStoreProviders(
EnumUnorderedMap<StoreProviderType, std::unordered_set<ObjectID>> &ids_per_provider,
int64_t timeout_ms, int *num_objects, std::unordered_set<ObjectID> *ready) {
int64_t remaining_timeout_ms = timeout_ms;
for (auto &provider_entry : ids_per_provider) {
if (*num_objects <= 0) {
break;
}
int64_t start_time = current_time_ms();
int required_objects =
std::min(static_cast<int>(provider_entry.second.size()), *num_objects);
std::unordered_set<ObjectID> provider_ready;
RAY_RETURN_NOT_OK(store_providers_[provider_entry.first]->Wait(
provider_entry.second, required_objects, remaining_timeout_ms,
worker_context_.GetCurrentTaskID(), &provider_ready));
// Update num_objects and remove the ready objects from the list so they don't get
// double-counted.
*num_objects -= provider_ready.size();
for (const ObjectID &ready_id : provider_ready) {
ready->insert(ready_id);
provider_entry.second.erase(ready_id);
}
if (remaining_timeout_ms > 0) {
int64_t duration = current_time_ms() - start_time;
remaining_timeout_ms =
std::max(static_cast<int64_t>(0), remaining_timeout_ms - duration);
}
}
return Status::OK();
}
Status CoreWorkerObjectInterface::Delete(const std::vector<ObjectID> &object_ids,
bool local_only, bool delete_creating_tasks) {
EnumUnorderedMap<StoreProviderType, std::unordered_set<ObjectID>>
object_ids_per_store_provider;
GroupObjectIdsByStoreProvider(object_ids, &object_ids_per_store_provider);
for (const auto &entry : object_ids_per_store_provider) {
auto type = entry.first;
bool is_plasma = (type == StoreProviderType::PLASMA);
std::vector<ObjectID> ids(entry.second.begin(), entry.second.end());
RAY_RETURN_NOT_OK(store_providers_[type]->Delete(
ids, is_plasma ? local_only : false, is_plasma ? delete_creating_tasks : false));
}
return Status::OK();
}
std::string CoreWorkerObjectInterface::MemoryUsageString() {
// Currently only the Plasma store returns a debug string.
return store_providers_[StoreProviderType::PLASMA]->MemoryUsageString();
}
void CoreWorkerObjectInterface::AddStoreProvider(StoreProviderType type) {
store_providers_.emplace(type, CreateStoreProvider(type));
}
std::unique_ptr<CoreWorkerStoreProvider> CoreWorkerObjectInterface::CreateStoreProvider(
StoreProviderType type) const {
switch (type) {
case StoreProviderType::PLASMA:
return std::unique_ptr<CoreWorkerStoreProvider>(
new CoreWorkerPlasmaStoreProvider(store_socket_, raylet_client_, check_signals_));
case StoreProviderType::MEMORY:
return std::unique_ptr<CoreWorkerStoreProvider>(
new CoreWorkerMemoryStoreProvider(memory_store_));
break;
default:
RAY_LOG(FATAL) << "unknown store provider type " << static_cast<int>(type);
return nullptr;
}
}
} // namespace ray
-186
View File
@@ -1,186 +0,0 @@
#ifndef RAY_CORE_WORKER_OBJECT_INTERFACE_H
#define RAY_CORE_WORKER_OBJECT_INTERFACE_H
#include "plasma/client.h"
#include "ray/common/buffer.h"
#include "ray/common/id.h"
#include "ray/common/status.h"
#include "ray/core_worker/common.h"
#include "ray/core_worker/context.h"
#include "ray/core_worker/store_provider/store_provider.h"
namespace ray {
class CoreWorker;
class CoreWorkerStoreProvider;
class CoreWorkerMemoryStore;
/// The interface that contains all `CoreWorker` methods related to the object store.
class CoreWorkerObjectInterface {
public:
/// \param[in] worker_context WorkerContext of the parent CoreWorker.
/// \param[in] store_socket Path to the plasma store socket.
CoreWorkerObjectInterface(WorkerContext &worker_context,
std::unique_ptr<RayletClient> &raylet_client,
const std::string &store_socket,
std::function<Status()> check_signals = nullptr);
/// Set options for this client's interactions with the object store.
///
/// \param[in] name Unique name for this object store client.
/// \param[in] limit The maximum amount of memory in bytes that this client
/// can use in the object store.
Status SetClientOptions(std::string name, int64_t limit_bytes);
/// Put an object into object store.
///
/// \param[in] object The ray object.
/// \param[out] object_id Generated ID of the object.
/// \return Status.
Status Put(const RayObject &object, ObjectID *object_id);
/// Put an object with specified ID into object store.
///
/// \param[in] object The ray object.
/// \param[in] object_id Object ID specified by the user.
/// \return Status.
Status Put(const RayObject &object, const ObjectID &object_id);
/// Create and return a buffer in the object store that can be directly written
/// into. After writing to the buffer, the caller must call `Seal()` to finalize
/// the object. The `Create()` and `Seal()` combination is an alternative interface
/// to `Put()` that allows frontends to avoid an extra copy when possible.
///
/// \param[in] metadata Metadata of the object to be written.
/// \param[in] data_size Size of the object to be written.
/// \param[out] object_id Object ID generated for the put.
/// \param[out] data Buffer for the user to write the object into.
/// \return Status.
Status Create(const std::shared_ptr<Buffer> &metadata, const size_t data_size,
ObjectID *object_id, std::shared_ptr<Buffer> *data);
/// Create and return a buffer in the object store that can be directly written
/// into. After writing to the buffer, the caller must call `Seal()` to finalize
/// the object. The `Create()` and `Seal()` combination is an alternative interface
/// to `Put()` that allows frontends to avoid an extra copy when possible.
///
/// \param[in] metadata Metadata of the object to be written.
/// \param[in] data_size Size of the object to be written.
/// \param[in] object_id Object ID specified by the user.
/// \param[out] data Buffer for the user to write the object into.
/// \return Status.
Status Create(const std::shared_ptr<Buffer> &metadata, const size_t data_size,
const ObjectID &object_id, std::shared_ptr<Buffer> *data);
/// Finalize placing an object into the object store. This should be called after
/// a corresponding `Create()` call and then writing into the returned buffer.
///
/// \param[in] object_id Object ID corresponding to the object.
/// \return Status.
Status Seal(const ObjectID &object_id);
/// Get a list of objects from the object store. Objects that failed to be retrieved
/// will be returned as nullptrs.
///
/// \param[in] ids IDs of the objects to get.
/// \param[in] timeout_ms Timeout in milliseconds, wait infinitely if it's negative.
/// \param[out] results Result list of objects data.
/// \return Status.
Status Get(const std::vector<ObjectID> &ids, int64_t timeout_ms,
std::vector<std::shared_ptr<RayObject>> *results);
/// Return whether or not the object store contains the given object.
///
/// \param[in] object_id ID of the objects to check for.
/// \param[out] has_object Whether or not the object is present.
/// \return Status.
Status Contains(const ObjectID &object_id, bool *has_object);
/// Wait for a list of objects to appear in the object store.
/// Duplicate object ids are supported, and `num_objects` includes duplicate ids in this
/// case.
/// TODO(zhijunfu): it is probably more clear in semantics to just fail when there
/// are duplicates, and require it to be handled at application level.
///
/// \param[in] IDs of the objects to wait for.
/// \param[in] num_objects Number of objects that should appear.
/// \param[in] timeout_ms Timeout in milliseconds, wait infinitely if it's negative.
/// \param[out] results A bitset that indicates each object has appeared or not.
/// \return Status.
Status Wait(const std::vector<ObjectID> &object_ids, int num_objects,
int64_t timeout_ms, std::vector<bool> *results);
/// Delete a list of objects from the object store.
///
/// \param[in] object_ids IDs of the objects to delete.
/// \param[in] local_only Whether only delete the objects in local node, or all nodes in
/// the cluster.
/// \param[in] delete_creating_tasks Whether also delete the tasks that
/// created these objects.
/// \return Status.
Status Delete(const std::vector<ObjectID> &object_ids, bool local_only,
bool delete_creating_tasks);
/// Get a string describing object store memory usage for debugging purposes.
///
/// \return std::string The string describing memory usage.
std::string MemoryUsageString();
/// Create a new store provider for the specified type on demand.
std::unique_ptr<CoreWorkerStoreProvider> CreateStoreProvider(
StoreProviderType type) const;
private:
/// Helper function to group object IDs by the store provider that should be used
/// for them.
///
/// \param[in] object_ids Object IDs to group.
/// \param[out] results Map of provider type to object IDs.
void GroupObjectIdsByStoreProvider(
const std::vector<ObjectID> &object_ids,
EnumUnorderedMap<StoreProviderType, std::unordered_set<ObjectID>> *results);
/// Helper function to get a set of objects from different store providers.
///
/// \param[in] ids_per_provider A map from store provider type to the set of
// object ids for that store provider.
/// \param[in] timeout_ms Timeout in milliseconds, wait infinitely if it's -1.
/// \param[in/out] num_objects Number of objects that should appear before returning.
/// Should be updated as objects are added to the ready set.
/// \param[in/out] results A set that holds objects that are ready.
/// \return Status.
Status WaitFromMultipleStoreProviders(
EnumUnorderedMap<StoreProviderType, std::unordered_set<ObjectID>> &ids_per_provider,
int64_t timeout_ms, int *num_objects, std::unordered_set<ObjectID> *results);
/// Add a store provider for the specified type.
void AddStoreProvider(StoreProviderType type);
/// Reference to the parent CoreWorker's context.
WorkerContext &worker_context_;
/// Reference to the parent CoreWorker's raylet client.
std::unique_ptr<RayletClient> &raylet_client_;
std::string store_socket_;
/// In-memory store for return objects. This is used for `MEMORY` store provider.
std::shared_ptr<CoreWorkerMemoryStore> memory_store_;
/// All the store providers supported.
EnumUnorderedMap<StoreProviderType, std::unique_ptr<CoreWorkerStoreProvider>>
store_providers_;
std::function<Status()> check_signals_;
friend class CoreWorkerTaskInterface;
/// TODO(zhijunfu): This is necessary as direct call task submitter needs to create
/// a local plasma store provider, later we can refactor ObjectInterface to add a
/// `ObjectProviderLayer`, which will encapsulate the functionalities to get or create
/// a specific `StoreProvider`, and this can be removed then.
friend class CoreWorkerDirectActorTaskSubmitter;
};
} // namespace ray
#endif // RAY_CORE_WORKER_OBJECT_INTERFACE_H
@@ -2,7 +2,6 @@
#include "ray/common/ray_config.h"
#include "ray/core_worker/context.h"
#include "ray/core_worker/core_worker.h"
#include "ray/core_worker/object_interface.h"
#include "ray/core_worker/store_provider/memory_store_provider.h"
namespace ray {
@@ -4,7 +4,6 @@
#include "ray/common/id.h"
#include "ray/common/status.h"
#include "ray/core_worker/common.h"
#include "ray/core_worker/store_provider/store_provider.h"
namespace ray {
@@ -3,7 +3,6 @@
#include "ray/common/ray_config.h"
#include "ray/core_worker/context.h"
#include "ray/core_worker/core_worker.h"
#include "ray/core_worker/object_interface.h"
namespace ray {
@@ -13,12 +12,6 @@ CoreWorkerMemoryStoreProvider::CoreWorkerMemoryStoreProvider(
RAY_CHECK(store != nullptr);
}
Status CoreWorkerMemoryStoreProvider::SetClientOptions(std::string name,
int64_t limit_bytes) {
return Status::NotImplemented(
"SetClientOptions() not implemented for in-memory store.");
}
Status CoreWorkerMemoryStoreProvider::Put(const RayObject &object,
const ObjectID &object_id) {
Status status = store_->Put(object_id, object);
@@ -29,19 +22,6 @@ Status CoreWorkerMemoryStoreProvider::Put(const RayObject &object,
return status;
}
Status CoreWorkerMemoryStoreProvider::Create(const std::shared_ptr<Buffer> &metadata,
const size_t data_size,
const ObjectID &object_id,
std::shared_ptr<Buffer> *data) {
return Status::NotImplemented(
"Create/Seal interface not implemented for in-memory store.");
}
Status CoreWorkerMemoryStoreProvider::Seal(const ObjectID &object_id) {
return Status::NotImplemented(
"Create/Seal interface not implemented for in-memory store.");
}
Status CoreWorkerMemoryStoreProvider::Get(
const std::unordered_set<ObjectID> &object_ids, int64_t timeout_ms,
const TaskID &task_id,
@@ -63,11 +43,6 @@ Status CoreWorkerMemoryStoreProvider::Get(
return Status::OK();
}
Status CoreWorkerMemoryStoreProvider::Contains(const ObjectID &object_id,
bool *has_object) {
return Status::NotImplemented("Contains() not implemented for in-memory store.");
}
Status CoreWorkerMemoryStoreProvider::Wait(const std::unordered_set<ObjectID> &object_ids,
int num_objects, int64_t timeout_ms,
const TaskID &task_id,
@@ -87,13 +62,11 @@ Status CoreWorkerMemoryStoreProvider::Wait(const std::unordered_set<ObjectID> &o
return Status::OK();
}
Status CoreWorkerMemoryStoreProvider::Delete(const std::vector<ObjectID> &object_ids,
bool local_only,
bool delete_creating_tasks) {
store_->Delete(object_ids);
Status CoreWorkerMemoryStoreProvider::Delete(
const std::unordered_set<ObjectID> &object_ids) {
std::vector<ObjectID> object_id_vector(object_ids.begin(), object_ids.end());
store_->Delete(object_id_vector);
return Status::OK();
}
std::string CoreWorkerMemoryStoreProvider::MemoryUsageString() { return ""; }
} // namespace ray
@@ -6,7 +6,6 @@
#include "ray/common/status.h"
#include "ray/core_worker/common.h"
#include "ray/core_worker/store_provider/memory_store/memory_store.h"
#include "ray/core_worker/store_provider/store_provider.h"
namespace ray {
@@ -16,36 +15,24 @@ class CoreWorker;
/// An example usage for this is to retrieve the returned objects from direct
/// actor call (see direct_actor_transport.cc).
/// See `CoreWorkerStoreProvider` for the semantics of public methods.
class CoreWorkerMemoryStoreProvider : public CoreWorkerStoreProvider {
class CoreWorkerMemoryStoreProvider {
public:
CoreWorkerMemoryStoreProvider(std::shared_ptr<CoreWorkerMemoryStore> store);
Status SetClientOptions(std::string name, int64_t limit_bytes) override;
Status Put(const RayObject &object, const ObjectID &object_id) override;
Status Create(const std::shared_ptr<Buffer> &metadata, const size_t data_size,
const ObjectID &object_id, std::shared_ptr<Buffer> *data) override;
Status Seal(const ObjectID &object_id) override;
Status Put(const RayObject &object, const ObjectID &object_id);
Status Get(const std::unordered_set<ObjectID> &object_ids, int64_t timeout_ms,
const TaskID &task_id,
std::unordered_map<ObjectID, std::shared_ptr<RayObject>> *results,
bool *got_exception) override;
Status Contains(const ObjectID &object_id, bool *has_object) override;
bool *got_exception);
/// Note that `num_objects` must equal to number of items in `object_ids`.
Status Wait(const std::unordered_set<ObjectID> &object_ids, int num_objects,
int64_t timeout_ms, const TaskID &task_id,
std::unordered_set<ObjectID> *ready) override;
std::unordered_set<ObjectID> *ready);
/// Note that `local_only` must be true, and `delete_creating_tasks` must be false here.
Status Delete(const std::vector<ObjectID> &object_ids, bool local_only = true,
bool delete_creating_tasks = false) override;
std::string MemoryUsageString() override;
Status Delete(const std::unordered_set<ObjectID> &object_ids);
private:
/// Implementation.
@@ -2,13 +2,12 @@
#include "ray/common/ray_config.h"
#include "ray/core_worker/context.h"
#include "ray/core_worker/core_worker.h"
#include "ray/core_worker/object_interface.h"
#include "ray/protobuf/gcs.pb.h"
namespace ray {
CoreWorkerPlasmaStoreProvider::CoreWorkerPlasmaStoreProvider(
const std::string &store_socket, std::unique_ptr<RayletClient> &raylet_client,
const std::string &store_socket, const std::unique_ptr<RayletClient> &raylet_client,
std::function<Status()> check_signals)
: raylet_client_(raylet_client) {
check_signals_ = check_signals;
@@ -240,10 +239,11 @@ Status CoreWorkerPlasmaStoreProvider::Wait(const std::unordered_set<ObjectID> &o
return Status::OK();
}
Status CoreWorkerPlasmaStoreProvider::Delete(const std::vector<ObjectID> &object_ids,
bool local_only,
bool delete_creating_tasks) {
return raylet_client_->FreeObjects(object_ids, local_only, delete_creating_tasks);
Status CoreWorkerPlasmaStoreProvider::Delete(
const std::unordered_set<ObjectID> &object_ids, bool local_only,
bool delete_creating_tasks) {
std::vector<ObjectID> object_id_vector(object_ids.begin(), object_ids.end());
return raylet_client_->FreeObjects(object_id_vector, local_only, delete_creating_tasks);
}
std::string CoreWorkerPlasmaStoreProvider::MemoryUsageString() {
@@ -6,7 +6,6 @@
#include "ray/common/id.h"
#include "ray/common/status.h"
#include "ray/core_worker/common.h"
#include "ray/core_worker/store_provider/store_provider.h"
#include "ray/raylet/raylet_client.h"
namespace ray {
@@ -17,38 +16,38 @@ class CoreWorker;
/// local and remote stores. Local access goes is done via a
/// CoreWorkerLocalPlasmaStoreProvider and remote access goes through the raylet.
/// See `CoreWorkerStoreProvider` for the semantics of public methods.
class CoreWorkerPlasmaStoreProvider : public CoreWorkerStoreProvider {
class CoreWorkerPlasmaStoreProvider {
public:
CoreWorkerPlasmaStoreProvider(const std::string &store_socket,
std::unique_ptr<RayletClient> &raylet_client,
const std::unique_ptr<RayletClient> &raylet_client,
std::function<Status()> check_signals);
~CoreWorkerPlasmaStoreProvider();
Status SetClientOptions(std::string name, int64_t limit_bytes);
Status Put(const RayObject &object, const ObjectID &object_id) override;
Status Put(const RayObject &object, const ObjectID &object_id);
Status Create(const std::shared_ptr<Buffer> &metadata, const size_t data_size,
const ObjectID &object_id, std::shared_ptr<Buffer> *data) override;
const ObjectID &object_id, std::shared_ptr<Buffer> *data);
Status Seal(const ObjectID &object_id) override;
Status Seal(const ObjectID &object_id);
Status Get(const std::unordered_set<ObjectID> &object_ids, int64_t timeout_ms,
const TaskID &task_id,
std::unordered_map<ObjectID, std::shared_ptr<RayObject>> *results,
bool *got_exception) override;
bool *got_exception);
Status Contains(const ObjectID &object_id, bool *has_object) override;
Status Contains(const ObjectID &object_id, bool *has_object);
Status Wait(const std::unordered_set<ObjectID> &object_ids, int num_objects,
int64_t timeout_ms, const TaskID &task_id,
std::unordered_set<ObjectID> *ready) override;
std::unordered_set<ObjectID> *ready);
Status Delete(const std::vector<ObjectID> &object_ids, bool local_only = true,
bool delete_creating_tasks = false) override;
Status Delete(const std::unordered_set<ObjectID> &object_ids, bool local_only,
bool delete_creating_tasks);
std::string MemoryUsageString() override;
std::string MemoryUsageString();
private:
/// Ask the raylet to fetch a set of objects and then attempt to get them
@@ -81,7 +80,7 @@ class CoreWorkerPlasmaStoreProvider : public CoreWorkerStoreProvider {
static void WarnIfAttemptedTooManyTimes(int num_attempts,
const std::unordered_set<ObjectID> &remaining);
std::unique_ptr<RayletClient> &raylet_client_;
const std::unique_ptr<RayletClient> &raylet_client_;
plasma::PlasmaClient store_client_;
std::mutex store_client_mutex_;
std::function<Status()> check_signals_;
@@ -1,110 +0,0 @@
#ifndef RAY_CORE_WORKER_STORE_PROVIDER_H
#define RAY_CORE_WORKER_STORE_PROVIDER_H
#include "ray/common/buffer.h"
#include "ray/common/id.h"
#include "ray/common/status.h"
#include "ray/core_worker/common.h"
namespace ray {
/// Provider interface for store access. Store provider should inherit from this class and
/// provide implementions for the methods. The actual store provider may use a plasma
/// store or local memory store in worker process, or possibly other types of storage.
class CoreWorkerStoreProvider {
public:
CoreWorkerStoreProvider() {}
virtual ~CoreWorkerStoreProvider() {}
/// Set options for this client's interactions with the object store.
///
/// \param[in] name Unique name for this object store client.
/// \param[in] limit The maximum amount of memory in bytes that this client
/// can use in the object store.
virtual Status SetClientOptions(std::string name, int64_t limit_bytes) = 0;
/// Put an object with specified ID into object store.
///
/// \param[in] object The ray object.
/// \param[in] object_id Object ID specified by user.
/// \return Status.
virtual Status Put(const RayObject &object, const ObjectID &object_id) = 0;
/// Create and return a buffer in the object store that can be directly written
/// into. After writing to the buffer, the caller must call `Seal()` to finalize
/// the object. The `Create()` and `Seal()` combination is an alternative interface
/// to `Put()` that allows frontends to avoid an extra copy when possible.
///
/// \param[in] metadata Metadata of the object to be written.
/// \param[in] data_size Size of the object to be written.
/// \param[in] object_id Object ID specified by the user.
/// \param[out] data Buffer for the user to write the object into.
/// \return Status.
virtual Status Create(const std::shared_ptr<Buffer> &metadata, const size_t data_size,
const ObjectID &object_id, std::shared_ptr<Buffer> *data) = 0;
/// Finalize placing an object into the object store. This should be called after
/// a corresponding `Create()` call and then writing into the returned buffer.
///
/// \param[in] object_id Object ID corresponding to the object.
/// \return Status.
virtual Status Seal(const ObjectID &object_id) = 0;
/// Get a set of objects from the object store.
///
/// \param[in] object_ids IDs of the objects to get.
/// \param[in] timeout_ms Timeout in milliseconds, wait infinitely if it's negative.
/// \param[in] task_id ID for the current task.
/// \param[out] results Map of objects to write results into. Get will only add to this
/// map, not clear or remove from it, so the caller can pass in a non-empty map.
/// \param[out] got_exception Set to true if any of the fetched results were an
/// exception.
/// \return Status.
virtual Status Get(const std::unordered_set<ObjectID> &object_ids, int64_t timeout_ms,
const TaskID &task_id,
std::unordered_map<ObjectID, std::shared_ptr<RayObject>> *results,
bool *got_exception) = 0;
/// Return whether or not the object store contains the given object.
///
/// \param[in] object_id ID of the objects to check for.
/// \param[out] has_object Whether or not the object is present.
/// \return Status.
virtual Status Contains(const ObjectID &object_id, bool *has_object) = 0;
/// Wait for a list of objects to appear in the object store. Objects that appear will
/// be added to the ready set.
///
/// \param[in] object_ids IDs of the objects to wait for.
/// \param[in] num_objects Number of objects that should appear before returning.
/// \param[in] timeout_ms Timeout in milliseconds, wait infinitely if it's negative.
/// \param[in] task_id ID for the current task.
/// \param[out] ready IDs of objects that have appeared. Wait will only add to this
/// set, not clear or remove from it, so the caller can pass in a non-empty set.
/// \return Status.
virtual Status Wait(const std::unordered_set<ObjectID> &object_ids, int num_objects,
int64_t timeout_ms, const TaskID &task_id,
std::unordered_set<ObjectID> *ready) = 0;
/// Delete a list of objects from the object store.
///
/// \param[in] object_ids IDs of the objects to delete.
/// \param[in] local_only Whether only delete the objects in local node, or all nodes in
/// the cluster.
/// \param[in] delete_creating_tasks Whether also delete the tasks that
/// created these objects.
/// \return Status.
virtual Status Delete(const std::vector<ObjectID> &object_ids, bool local_only = true,
bool delete_creating_tasks = false) = 0;
/// Get a string describing object store memory usage for debugging purposes.
///
/// \return std::string The string describing memory usage.
virtual std::string MemoryUsageString() = 0;
};
} // namespace ray
#endif // RAY_CORE_WORKER_STORE_PROVIDER_H
+149 -165
View File
@@ -168,9 +168,6 @@ class CoreWorkerTest : public ::testing::Test {
void TearDown() {}
// Test tore provider.
void TestStoreProvider(StoreProviderType type);
// Test normal tasks.
void TestNormalTask(std::unordered_map<std::string, double> &resources);
@@ -223,7 +220,7 @@ void CoreWorkerTest::TestNormalTask(std::unordered_map<std::string, double> &res
auto buffer2 = GenerateRandomBuffer();
ObjectID object_id;
RAY_CHECK_OK(driver.Objects().Put(RayObject(buffer2, nullptr), &object_id));
RAY_CHECK_OK(driver.Put(RayObject(buffer2, nullptr), &object_id));
std::vector<TaskArg> args;
args.emplace_back(
@@ -239,7 +236,7 @@ void CoreWorkerTest::TestNormalTask(std::unordered_map<std::string, double> &res
ASSERT_EQ(return_ids.size(), 1);
std::vector<std::shared_ptr<ray::RayObject>> results;
RAY_CHECK_OK(driver.Objects().Get(return_ids, -1, &results));
RAY_CHECK_OK(driver.Get(return_ids, -1, &results));
ASSERT_EQ(results.size(), 1);
ASSERT_EQ(results[0]->GetData()->Size(), buffer1->Size() + buffer2->Size());
@@ -286,7 +283,7 @@ void CoreWorkerTest::TestActorTask(std::unordered_map<std::string, double> &reso
is_direct_call ? TaskTransportType::DIRECT_ACTOR : TaskTransportType::RAYLET);
std::vector<std::shared_ptr<ray::RayObject>> results;
RAY_CHECK_OK(driver.Objects().Get(return_ids, -1, &results));
RAY_CHECK_OK(driver.Get(return_ids, -1, &results));
ASSERT_EQ(results.size(), 1);
ASSERT_EQ(results[0]->GetData()->Size(), buffer1->Size() + buffer2->Size());
@@ -307,7 +304,7 @@ void CoreWorkerTest::TestActorTask(std::unordered_map<std::string, double> &reso
auto buffer2 = std::make_shared<LocalMemoryBuffer>(array2, sizeof(array2));
ObjectID object_id;
RAY_CHECK_OK(driver.Objects().Put(RayObject(buffer1, nullptr), &object_id));
RAY_CHECK_OK(driver.Put(RayObject(buffer1, nullptr), &object_id));
// Create arguments with PassByRef and PassByValue.
std::vector<TaskArg> args;
@@ -330,7 +327,7 @@ void CoreWorkerTest::TestActorTask(std::unordered_map<std::string, double> &reso
ASSERT_EQ(return_ids.size(), 1);
std::vector<std::shared_ptr<ray::RayObject>> results;
RAY_CHECK_OK(driver.Objects().Get(return_ids, -1, &results));
RAY_CHECK_OK(driver.Get(return_ids, -1, &results));
ASSERT_EQ(results.size(), 1);
ASSERT_EQ(results[0]->GetData()->Size(), buffer1->Size() + buffer2->Size());
@@ -390,7 +387,7 @@ void CoreWorkerTest::TestActorReconstruction(
// Verify if it's expected data.
std::vector<std::shared_ptr<RayObject>> results;
RAY_CHECK_OK(driver.Objects().Get(return_ids, -1, &results));
RAY_CHECK_OK(driver.Get(return_ids, -1, &results));
ASSERT_EQ(results[0]->GetData()->Size(), buffer1->Size());
ASSERT_EQ(*results[0]->GetData(), *buffer1);
}
@@ -441,7 +438,7 @@ void CoreWorkerTest::TestActorFailure(std::unordered_map<std::string, double> &r
std::vector<ObjectID> return_ids;
return_ids.push_back(entry.first);
std::vector<std::shared_ptr<RayObject>> results;
RAY_CHECK_OK(driver.Objects().Get(return_ids, -1, &results));
RAY_CHECK_OK(driver.Get(return_ids, -1, &results));
ASSERT_EQ(results.size(), 1);
if (results[0]->HasMetadata()) {
@@ -457,143 +454,6 @@ void CoreWorkerTest::TestActorFailure(std::unordered_map<std::string, double> &r
}
}
void CoreWorkerTest::TestStoreProvider(StoreProviderType type) {
std::unique_ptr<CoreWorkerStoreProvider> provider_ptr;
std::shared_ptr<CoreWorkerMemoryStore> memory_store;
switch (type) {
case StoreProviderType::MEMORY:
memory_store = std::make_shared<CoreWorkerMemoryStore>();
provider_ptr = std::unique_ptr<CoreWorkerStoreProvider>(
new CoreWorkerMemoryStoreProvider(memory_store));
break;
default:
RAY_LOG(FATAL) << "unspported store provider type " << static_cast<int>(type);
break;
}
auto &provider = *provider_ptr;
uint8_t array1[] = {1, 2, 3, 4, 5, 6, 7, 8};
uint8_t array2[] = {10, 11, 12, 13, 14, 15};
std::vector<RayObject> buffers;
buffers.emplace_back(std::make_shared<LocalMemoryBuffer>(array1, sizeof(array1)),
std::make_shared<LocalMemoryBuffer>(array1, sizeof(array1) / 2));
buffers.emplace_back(std::make_shared<LocalMemoryBuffer>(array2, sizeof(array2)),
std::make_shared<LocalMemoryBuffer>(array2, sizeof(array2) / 2));
std::vector<ObjectID> ids(buffers.size());
for (size_t i = 0; i < ids.size(); i++) {
ids[i] = ObjectID::FromRandom();
RAY_CHECK_OK(provider.Put(buffers[i], ids[i]));
}
std::unordered_set<ObjectID> wait_ids(ids.begin(), ids.end());
std::unordered_set<ObjectID> wait_results;
ObjectID nonexistent_id = ObjectID::FromRandom();
wait_ids.insert(nonexistent_id);
RAY_CHECK_OK(
provider.Wait(wait_ids, ids.size() + 1, 100, RandomTaskId(), &wait_results));
ASSERT_EQ(wait_results.size(), ids.size());
ASSERT_TRUE(wait_results.count(nonexistent_id) == 0);
// Test Wait() where the required `num_objects` is less than size of `wait_ids`.
wait_results.clear();
RAY_CHECK_OK(provider.Wait(wait_ids, ids.size(), -1, RandomTaskId(), &wait_results));
ASSERT_EQ(wait_results.size(), ids.size());
ASSERT_TRUE(wait_results.count(nonexistent_id) == 0);
// Test Get().
bool got_exception = false;
std::unordered_map<ObjectID, std::shared_ptr<RayObject>> results;
std::unordered_set<ObjectID> ids_set(ids.begin(), ids.end());
RAY_CHECK_OK(provider.Get(ids_set, -1, RandomTaskId(), &results, &got_exception));
ASSERT_TRUE(!got_exception);
ASSERT_EQ(results.size(), ids.size());
for (size_t i = 0; i < ids.size(); i++) {
const auto &expected = buffers[i];
ASSERT_EQ(results[ids[i]]->GetData()->Size(), expected.GetData()->Size());
ASSERT_EQ(memcmp(results[ids[i]]->GetData()->Data(), expected.GetData()->Data(),
expected.GetData()->Size()),
0);
ASSERT_EQ(results[ids[i]]->GetMetadata()->Size(), expected.GetMetadata()->Size());
ASSERT_EQ(memcmp(results[ids[i]]->GetMetadata()->Data(),
expected.GetMetadata()->Data(), expected.GetMetadata()->Size()),
0);
}
// Test Delete().
// clear the reference held.
results.clear();
RAY_CHECK_OK(provider.Delete(ids, true, false));
usleep(200 * 1000);
RAY_CHECK_OK(provider.Get(ids_set, 0, RandomTaskId(), &results, &got_exception));
ASSERT_TRUE(!got_exception);
ASSERT_EQ(results.size(), 0);
// Test Wait() with objects which will become ready later.
std::vector<ObjectID> ready_ids(buffers.size());
std::vector<ObjectID> unready_ids(buffers.size());
for (size_t i = 0; i < unready_ids.size(); i++) {
ready_ids[i] = ObjectID::FromRandom();
RAY_CHECK_OK(provider.Put(buffers[i], ready_ids[i]));
unready_ids[i] = ObjectID::FromRandom();
}
auto thread_func = [&unready_ids, &provider, &buffers]() {
sleep(1);
for (size_t i = 0; i < unready_ids.size(); i++) {
RAY_CHECK_OK(provider.Put(buffers[i], unready_ids[i]));
}
};
std::thread async_thread(thread_func);
wait_ids.clear();
wait_ids.insert(ready_ids.begin(), ready_ids.end());
wait_ids.insert(unready_ids.begin(), unready_ids.end());
wait_results.clear();
// Check that only the ready ids are returned when timeout ends before thread runs.
RAY_CHECK_OK(
provider.Wait(wait_ids, ready_ids.size() + 1, 100, RandomTaskId(), &wait_results));
ASSERT_EQ(ready_ids.size(), wait_results.size());
for (const auto &ready_id : ready_ids) {
ASSERT_TRUE(wait_results.find(ready_id) != wait_results.end());
}
for (const auto &unready_id : unready_ids) {
ASSERT_TRUE(wait_results.find(unready_id) == wait_results.end());
}
wait_results.clear();
// Check that enough objects are returned after the thread inserts at least one object.
RAY_CHECK_OK(
provider.Wait(wait_ids, ready_ids.size() + 1, 5000, RandomTaskId(), &wait_results));
ASSERT_TRUE(wait_results.size() >= ready_ids.size() + 1);
for (const auto &ready_id : ready_ids) {
ASSERT_TRUE(wait_results.find(ready_id) != wait_results.end());
}
wait_results.clear();
// Check that all objects are returned after the thread completes.
async_thread.join();
RAY_CHECK_OK(
provider.Wait(wait_ids, wait_ids.size(), -1, RandomTaskId(), &wait_results));
ASSERT_EQ(wait_results.size(), ready_ids.size() + unready_ids.size());
for (const auto &ready_id : ready_ids) {
ASSERT_TRUE(wait_results.find(ready_id) != wait_results.end());
}
for (const auto &unready_id : unready_ids) {
ASSERT_TRUE(wait_results.find(unready_id) != wait_results.end());
}
}
class ZeroNodeTest : public CoreWorkerTest {
public:
ZeroNodeTest() : CoreWorkerTest(0) {}
@@ -716,7 +576,7 @@ TEST_F(SingleNodeTest, TestDirectActorTaskSubmissionPerf) {
for (const auto &object_id : object_ids) {
std::vector<std::shared_ptr<RayObject>> results;
RAY_CHECK_OK(driver.Objects().Get({object_id}, -1, &results));
RAY_CHECK_OK(driver.Get({object_id}, -1, &results));
ASSERT_EQ(results.size(), 1);
}
RAY_LOG(INFO) << "finish executing " << num_tasks << " tasks"
@@ -766,7 +626,132 @@ TEST_F(ZeroNodeTest, TestActorHandle) {
}
TEST_F(SingleNodeTest, TestMemoryStoreProvider) {
TestStoreProvider(StoreProviderType::MEMORY);
std::shared_ptr<CoreWorkerMemoryStore> memory_store =
std::make_shared<CoreWorkerMemoryStore>();
std::unique_ptr<CoreWorkerMemoryStoreProvider> provider_ptr =
std::unique_ptr<CoreWorkerMemoryStoreProvider>(
new CoreWorkerMemoryStoreProvider(memory_store));
auto &provider = *provider_ptr;
uint8_t array1[] = {1, 2, 3, 4, 5, 6, 7, 8};
uint8_t array2[] = {10, 11, 12, 13, 14, 15};
std::vector<RayObject> buffers;
buffers.emplace_back(std::make_shared<LocalMemoryBuffer>(array1, sizeof(array1)),
std::make_shared<LocalMemoryBuffer>(array1, sizeof(array1) / 2));
buffers.emplace_back(std::make_shared<LocalMemoryBuffer>(array2, sizeof(array2)),
std::make_shared<LocalMemoryBuffer>(array2, sizeof(array2) / 2));
std::vector<ObjectID> ids(buffers.size());
for (size_t i = 0; i < ids.size(); i++) {
ids[i] = ObjectID::FromRandom();
RAY_CHECK_OK(provider.Put(buffers[i], ids[i]));
}
std::unordered_set<ObjectID> wait_ids(ids.begin(), ids.end());
std::unordered_set<ObjectID> wait_results;
ObjectID nonexistent_id = ObjectID::FromRandom();
wait_ids.insert(nonexistent_id);
RAY_CHECK_OK(
provider.Wait(wait_ids, ids.size() + 1, 100, RandomTaskId(), &wait_results));
ASSERT_EQ(wait_results.size(), ids.size());
ASSERT_TRUE(wait_results.count(nonexistent_id) == 0);
// Test Wait() where the required `num_objects` is less than size of `wait_ids`.
wait_results.clear();
RAY_CHECK_OK(provider.Wait(wait_ids, ids.size(), -1, RandomTaskId(), &wait_results));
ASSERT_EQ(wait_results.size(), ids.size());
ASSERT_TRUE(wait_results.count(nonexistent_id) == 0);
// Test Get().
bool got_exception = false;
std::unordered_map<ObjectID, std::shared_ptr<RayObject>> results;
std::unordered_set<ObjectID> ids_set(ids.begin(), ids.end());
RAY_CHECK_OK(provider.Get(ids_set, -1, RandomTaskId(), &results, &got_exception));
ASSERT_TRUE(!got_exception);
ASSERT_EQ(results.size(), ids.size());
for (size_t i = 0; i < ids.size(); i++) {
const auto &expected = buffers[i];
ASSERT_EQ(results[ids[i]]->GetData()->Size(), expected.GetData()->Size());
ASSERT_EQ(memcmp(results[ids[i]]->GetData()->Data(), expected.GetData()->Data(),
expected.GetData()->Size()),
0);
ASSERT_EQ(results[ids[i]]->GetMetadata()->Size(), expected.GetMetadata()->Size());
ASSERT_EQ(memcmp(results[ids[i]]->GetMetadata()->Data(),
expected.GetMetadata()->Data(), expected.GetMetadata()->Size()),
0);
}
// Test Delete().
// clear the reference held.
results.clear();
RAY_CHECK_OK(provider.Delete(ids_set));
usleep(200 * 1000);
RAY_CHECK_OK(provider.Get(ids_set, 0, RandomTaskId(), &results, &got_exception));
ASSERT_TRUE(!got_exception);
ASSERT_EQ(results.size(), 0);
// Test Wait() with objects which will become ready later.
std::vector<ObjectID> ready_ids(buffers.size());
std::vector<ObjectID> unready_ids(buffers.size());
for (size_t i = 0; i < unready_ids.size(); i++) {
ready_ids[i] = ObjectID::FromRandom();
RAY_CHECK_OK(provider.Put(buffers[i], ready_ids[i]));
unready_ids[i] = ObjectID::FromRandom();
}
auto thread_func = [&unready_ids, &provider, &buffers]() {
sleep(1);
for (size_t i = 0; i < unready_ids.size(); i++) {
RAY_CHECK_OK(provider.Put(buffers[i], unready_ids[i]));
}
};
std::thread async_thread(thread_func);
wait_ids.clear();
wait_ids.insert(ready_ids.begin(), ready_ids.end());
wait_ids.insert(unready_ids.begin(), unready_ids.end());
wait_results.clear();
// Check that only the ready ids are returned when timeout ends before thread runs.
RAY_CHECK_OK(
provider.Wait(wait_ids, ready_ids.size() + 1, 100, RandomTaskId(), &wait_results));
ASSERT_EQ(ready_ids.size(), wait_results.size());
for (const auto &ready_id : ready_ids) {
ASSERT_TRUE(wait_results.find(ready_id) != wait_results.end());
}
for (const auto &unready_id : unready_ids) {
ASSERT_TRUE(wait_results.find(unready_id) == wait_results.end());
}
wait_results.clear();
// Check that enough objects are returned after the thread inserts at least one object.
RAY_CHECK_OK(
provider.Wait(wait_ids, ready_ids.size() + 1, 5000, RandomTaskId(), &wait_results));
ASSERT_TRUE(wait_results.size() >= ready_ids.size() + 1);
for (const auto &ready_id : ready_ids) {
ASSERT_TRUE(wait_results.find(ready_id) != wait_results.end());
}
wait_results.clear();
// Check that all objects are returned after the thread completes.
async_thread.join();
RAY_CHECK_OK(
provider.Wait(wait_ids, wait_ids.size(), -1, RandomTaskId(), &wait_results));
ASSERT_EQ(wait_results.size(), ready_ids.size() + unready_ids.size());
for (const auto &ready_id : ready_ids) {
ASSERT_TRUE(wait_results.find(ready_id) != wait_results.end());
}
for (const auto &unready_id : unready_ids) {
ASSERT_TRUE(wait_results.find(unready_id) != wait_results.end());
}
}
TEST_F(SingleNodeTest, TestObjectInterface) {
@@ -785,12 +770,12 @@ TEST_F(SingleNodeTest, TestObjectInterface) {
std::vector<ObjectID> ids(buffers.size());
for (size_t i = 0; i < ids.size(); i++) {
RAY_CHECK_OK(core_worker.Objects().Put(buffers[i], &ids[i]));
RAY_CHECK_OK(core_worker.Put(buffers[i], &ids[i]));
}
// Test Get().
std::vector<std::shared_ptr<RayObject>> results;
RAY_CHECK_OK(core_worker.Objects().Get(ids, -1, &results));
RAY_CHECK_OK(core_worker.Get(ids, -1, &results));
ASSERT_EQ(results.size(), ids.size());
for (size_t i = 0; i < ids.size(); i++) {
ASSERT_EQ(*results[i]->GetData(), *buffers[i].GetData());
@@ -808,9 +793,8 @@ TEST_F(SingleNodeTest, TestObjectInterface) {
nullptr, std::make_shared<LocalMemoryBuffer>(
reinterpret_cast<uint8_t *>(error_buffer), len));
RAY_CHECK_OK(core_worker.Objects().Put(buffers_with_exception.back(),
ids_with_exception.back()));
RAY_CHECK_OK(core_worker.Objects().Get(ids_with_exception, -1, &results));
RAY_CHECK_OK(core_worker.Put(buffers_with_exception.back(), ids_with_exception.back()));
RAY_CHECK_OK(core_worker.Get(ids_with_exception, -1, &results));
// Test Wait().
ObjectID non_existent_id = ObjectID::FromRandom();
@@ -818,24 +802,24 @@ TEST_F(SingleNodeTest, TestObjectInterface) {
all_ids.push_back(non_existent_id);
std::vector<bool> wait_results;
RAY_CHECK_OK(core_worker.Objects().Wait(all_ids, 2, -1, &wait_results));
RAY_CHECK_OK(core_worker.Wait(all_ids, 2, -1, &wait_results));
ASSERT_EQ(wait_results.size(), 3);
ASSERT_EQ(wait_results, std::vector<bool>({true, true, false}));
RAY_CHECK_OK(core_worker.Objects().Wait(all_ids, 3, 100, &wait_results));
RAY_CHECK_OK(core_worker.Wait(all_ids, 3, 100, &wait_results));
ASSERT_EQ(wait_results.size(), 3);
ASSERT_EQ(wait_results, std::vector<bool>({true, true, false}));
// Test Delete().
// clear the reference held by PlasmaBuffer.
results.clear();
RAY_CHECK_OK(core_worker.Objects().Delete(ids, true, false));
RAY_CHECK_OK(core_worker.Delete(ids, true, false));
// Note that Delete() calls RayletClient::FreeObjects and would not
// wait for objects being deleted, so wait a while for plasma store
// to process the command.
usleep(200 * 1000);
RAY_CHECK_OK(core_worker.Objects().Get(ids, 0, &results));
RAY_CHECK_OK(core_worker.Get(ids, 0, &results));
ASSERT_EQ(results.size(), 2);
ASSERT_TRUE(!results[0]);
ASSERT_TRUE(!results[1]);
@@ -859,12 +843,12 @@ TEST_F(TwoNodeTest, TestObjectInterfaceCrossNodes) {
std::vector<ObjectID> ids(buffers.size());
for (size_t i = 0; i < ids.size(); i++) {
RAY_CHECK_OK(worker1.Objects().Put(RayObject(buffers[i], nullptr), &ids[i]));
RAY_CHECK_OK(worker1.Put(RayObject(buffers[i], nullptr), &ids[i]));
}
// Test Get() from remote node.
std::vector<std::shared_ptr<RayObject>> results;
RAY_CHECK_OK(worker2.Objects().Get(ids, -1, &results));
RAY_CHECK_OK(worker2.Get(ids, -1, &results));
ASSERT_EQ(results.size(), 2);
for (size_t i = 0; i < ids.size(); i++) {
@@ -878,30 +862,30 @@ TEST_F(TwoNodeTest, TestObjectInterfaceCrossNodes) {
all_ids.push_back(non_existent_id);
std::vector<bool> wait_results;
RAY_CHECK_OK(worker2.Objects().Wait(all_ids, 2, -1, &wait_results));
RAY_CHECK_OK(worker2.Wait(all_ids, 2, -1, &wait_results));
ASSERT_EQ(wait_results.size(), 3);
ASSERT_EQ(wait_results, std::vector<bool>({true, true, false}));
RAY_CHECK_OK(worker2.Objects().Wait(all_ids, 3, 100, &wait_results));
RAY_CHECK_OK(worker2.Wait(all_ids, 3, 100, &wait_results));
ASSERT_EQ(wait_results.size(), 3);
ASSERT_EQ(wait_results, std::vector<bool>({true, true, false}));
// Test Delete() from all machines.
// clear the reference held by PlasmaBuffer.
results.clear();
RAY_CHECK_OK(worker2.Objects().Delete(ids, false, false));
RAY_CHECK_OK(worker2.Delete(ids, false, false));
// Note that Delete() calls RayletClient::FreeObjects and would not
// wait for objects being deleted, so wait a while for plasma store
// to process the command.
usleep(1000 * 1000);
// Verify objects are deleted from both machines.
RAY_CHECK_OK(worker2.Objects().Get(ids, 0, &results));
RAY_CHECK_OK(worker2.Get(ids, 0, &results));
ASSERT_EQ(results.size(), 2);
ASSERT_TRUE(!results[0]);
ASSERT_TRUE(!results[1]);
RAY_CHECK_OK(worker1.Objects().Get(ids, 0, &results));
RAY_CHECK_OK(worker1.Get(ids, 0, &results));
ASSERT_EQ(results.size(), 2);
ASSERT_TRUE(!results[0]);
ASSERT_TRUE(!results[1]);
-1
View File
@@ -1,7 +1,6 @@
#define BOOST_BIND_NO_PLACEHOLDERS
#include "ray/core_worker/context.h"
#include "ray/core_worker/core_worker.h"
#include "ray/core_worker/store_provider/store_provider.h"
#include "src/ray/util/test_util.h"
using namespace std::placeholders;
@@ -16,7 +16,7 @@ bool HasByReferenceArgs(const TaskSpecification &spec) {
CoreWorkerDirectActorTaskSubmitter::CoreWorkerDirectActorTaskSubmitter(
boost::asio::io_service &io_service,
std::unique_ptr<CoreWorkerStoreProvider> store_provider)
std::unique_ptr<CoreWorkerMemoryStoreProvider> store_provider)
: io_service_(io_service),
client_call_manager_(io_service),
store_provider_(std::move(store_provider)) {}
@@ -199,12 +199,10 @@ bool CoreWorkerDirectActorTaskSubmitter::IsActorAlive(const ActorID &actor_id) c
}
CoreWorkerDirectActorTaskReceiver::CoreWorkerDirectActorTaskReceiver(
WorkerContext &worker_context, CoreWorkerObjectInterface &object_interface,
boost::asio::io_service &io_service, rpc::GrpcServer &server,
const TaskHandler &task_handler)
WorkerContext &worker_context, boost::asio::io_service &io_service,
rpc::GrpcServer &server, const TaskHandler &task_handler)
: worker_context_(worker_context),
io_service_(io_service),
object_interface_(object_interface),
task_service_(io_service, *this),
task_handler_(task_handler) {
server.RegisterService(task_service_);
@@ -6,7 +6,9 @@
#include <utility>
#include "ray/common/id.h"
#include "ray/core_worker/object_interface.h"
#include "ray/common/ray_object.h"
#include "ray/core_worker/context.h"
#include "ray/core_worker/store_provider/memory_store_provider.h"
#include "ray/gcs/redis_gcs_client.h"
#include "ray/rpc/worker/direct_actor_client.h"
#include "ray/rpc/worker/direct_actor_server.h"
@@ -36,7 +38,7 @@ class CoreWorkerDirectActorTaskSubmitter {
public:
CoreWorkerDirectActorTaskSubmitter(
boost::asio::io_service &io_service,
std::unique_ptr<CoreWorkerStoreProvider> store_provider);
std::unique_ptr<CoreWorkerMemoryStoreProvider> store_provider);
/// Submit a task to an actor for execution.
///
@@ -118,7 +120,7 @@ class CoreWorkerDirectActorTaskSubmitter {
std::unordered_map<ActorID, std::unordered_map<TaskID, int>> waiting_reply_tasks_;
/// The store provider.
std::unique_ptr<CoreWorkerStoreProvider> store_provider_;
std::unique_ptr<CoreWorkerMemoryStoreProvider> store_provider_;
friend class CoreWorkerTest;
};
@@ -202,7 +204,6 @@ class CoreWorkerDirectActorTaskReceiver : public rpc::DirectActorHandler {
std::vector<std::shared_ptr<RayObject>> *results)>;
CoreWorkerDirectActorTaskReceiver(WorkerContext &worker_context,
CoreWorkerObjectInterface &object_interface,
boost::asio::io_service &io_service,
rpc::GrpcServer &server,
const TaskHandler &task_handler);
@@ -222,8 +223,6 @@ class CoreWorkerDirectActorTaskReceiver : public rpc::DirectActorHandler {
WorkerContext &worker_context_;
/// The IO event loop.
boost::asio::io_service &io_service_;
// Object interface.
CoreWorkerObjectInterface &object_interface_;
/// The rpc service for `DirectActorService`.
rpc::DirectActorGrpcService task_service_;
/// The callback function to process a task.
@@ -7,11 +7,10 @@ namespace ray {
CoreWorkerRayletTaskReceiver::CoreWorkerRayletTaskReceiver(
WorkerContext &worker_context, std::unique_ptr<RayletClient> &raylet_client,
CoreWorkerObjectInterface &object_interface, boost::asio::io_service &io_service,
rpc::GrpcServer &server, const TaskHandler &task_handler)
boost::asio::io_service &io_service, rpc::GrpcServer &server,
const TaskHandler &task_handler)
: worker_context_(worker_context),
raylet_client_(raylet_client),
object_interface_(object_interface),
task_service_(io_service, *this),
task_handler_(task_handler) {
server.RegisterService(task_service_);
@@ -67,24 +66,6 @@ void CoreWorkerRayletTaskReceiver::HandleAssignTask(
RAY_LOG(DEBUG) << "Assigned task " << task_spec.TaskId()
<< " finished execution. num_returns: " << num_returns;
if (results.size() != 0) {
RAY_CHECK(results.size() == num_returns);
for (size_t i = 0; i < num_returns; i++) {
ObjectID id = ObjectID::ForTaskReturn(
task_spec.TaskId(), /*index=*/i + 1,
/*transport_type=*/static_cast<int>(TaskTransportType::RAYLET));
Status status = object_interface_.Put(*results[i], id);
if (!status.ok()) {
// NOTE(hchen): `PlasmaObjectExists` error is already ignored inside
// `ObjectInterface::Put`, we treat other error types as fatal here.
RAY_LOG(FATAL) << "Task " << task_spec.TaskId() << " failed to put object " << id
<< " in store: " << status.message();
} else {
RAY_LOG(DEBUG) << "Task " << task_spec.TaskId() << " put object " << id
<< " in store.";
}
}
}
// Notify raylet that current task is done via a `TaskDone` message. This is to
// ensure that the task is marked as finished by raylet only after previous
@@ -3,7 +3,8 @@
#include <list>
#include "ray/core_worker/object_interface.h"
#include "ray/common/ray_object.h"
#include "ray/core_worker/context.h"
#include "ray/raylet/raylet_client.h"
#include "ray/rpc/worker/worker_server.h"
@@ -17,7 +18,6 @@ class CoreWorkerRayletTaskReceiver : public rpc::WorkerTaskHandler {
CoreWorkerRayletTaskReceiver(WorkerContext &worker_context,
std::unique_ptr<RayletClient> &raylet_client,
CoreWorkerObjectInterface &object_interface,
boost::asio::io_service &io_service,
rpc::GrpcServer &server, const TaskHandler &task_handler);
@@ -37,8 +37,6 @@ class CoreWorkerRayletTaskReceiver : public rpc::WorkerTaskHandler {
WorkerContext &worker_context_;
/// Raylet client.
std::unique_ptr<RayletClient> &raylet_client_;
// Object interface.
CoreWorkerObjectInterface &object_interface_;
/// The rpc service for `WorkerTaskService`.
rpc::WorkerTaskGrpcService task_service_;
/// The callback function to process a task.