mirror of
https://github.com/wassname/ray.git
synced 2026-08-03 13:10:57 +08:00
Implement actor checkpointing (#3839)
* Implement Actor checkpointing * docs * fix * fix * fix * move restore-from-checkpoint to HandleActorStateTransition * Revert "move restore-from-checkpoint to HandleActorStateTransition" This reverts commit 9aa4447c1e3e321f42a1d895d72f17098b72de12. * resubmit waiting tasks when actor frontier restored * add doc about num_actor_checkpoints_to_keep=1 * add num_actor_checkpoints_to_keep to Cython * add checkpoint_expired api * check if actor class is abstract * change checkpoint_ids to long string * implement java * Refactor to delay actor creation publish until checkpoint is resumed * debug, lint * Erase from checkpoints to restore if task fails * fix lint * update comments * avoid duplicated actor notification log * fix unintended change * add actor_id to checkpoint_expired * small java updates * make checkpoint info per actor * lint * Remove logging * Remove old actor checkpointing Python code, move new checkpointing code to FunctionActionManager * Replace old actor checkpointing tests * Fix test and lint * address comments * consolidate kill_actor * Remove __ray_checkpoint__ * fix non-ascii char * Loosen test checks * fix java * fix sphinx-build
This commit is contained in:
@@ -118,6 +118,8 @@ AsyncGcsClient::AsyncGcsClient(const std::string &address, int port,
|
||||
task_lease_table_.reset(new TaskLeaseTable(shard_contexts_, this));
|
||||
heartbeat_table_.reset(new HeartbeatTable(shard_contexts_, this));
|
||||
profile_table_.reset(new ProfileTable(shard_contexts_, this));
|
||||
actor_checkpoint_table_.reset(new ActorCheckpointTable(shard_contexts_, this));
|
||||
actor_checkpoint_id_table_.reset(new ActorCheckpointIdTable(shard_contexts_, this));
|
||||
command_type_ = command_type;
|
||||
|
||||
// TODO(swang): Call the client table's Connect() method here. To do this,
|
||||
@@ -219,6 +221,14 @@ DriverTable &AsyncGcsClient::driver_table() { return *driver_table_; }
|
||||
|
||||
ProfileTable &AsyncGcsClient::profile_table() { return *profile_table_; }
|
||||
|
||||
ActorCheckpointTable &AsyncGcsClient::actor_checkpoint_table() {
|
||||
return *actor_checkpoint_table_;
|
||||
}
|
||||
|
||||
ActorCheckpointIdTable &AsyncGcsClient::actor_checkpoint_id_table() {
|
||||
return *actor_checkpoint_id_table_;
|
||||
}
|
||||
|
||||
} // namespace gcs
|
||||
|
||||
} // namespace ray
|
||||
|
||||
@@ -60,6 +60,8 @@ class RAY_EXPORT AsyncGcsClient {
|
||||
ErrorTable &error_table();
|
||||
DriverTable &driver_table();
|
||||
ProfileTable &profile_table();
|
||||
ActorCheckpointTable &actor_checkpoint_table();
|
||||
ActorCheckpointIdTable &actor_checkpoint_id_table();
|
||||
|
||||
// We also need something to export generic code to run on workers from the
|
||||
// driver (to set the PYTHONPATH)
|
||||
@@ -90,6 +92,8 @@ class RAY_EXPORT AsyncGcsClient {
|
||||
std::unique_ptr<ErrorTable> error_table_;
|
||||
std::unique_ptr<ProfileTable> profile_table_;
|
||||
std::unique_ptr<ClientTable> client_table_;
|
||||
std::unique_ptr<ActorCheckpointTable> actor_checkpoint_table_;
|
||||
std::unique_ptr<ActorCheckpointIdTable> actor_checkpoint_id_table_;
|
||||
// The following contexts write to the data shard
|
||||
std::vector<std::shared_ptr<RedisContext>> shard_contexts_;
|
||||
std::vector<std::unique_ptr<RedisAsioClient>> shard_asio_async_clients_;
|
||||
|
||||
@@ -20,6 +20,8 @@ enum TablePrefix:int {
|
||||
DRIVER,
|
||||
PROFILE,
|
||||
TASK_LEASE,
|
||||
ACTOR_CHECKPOINT,
|
||||
ACTOR_CHECKPOINT_ID,
|
||||
}
|
||||
|
||||
// The channel that Add operations to the Table should be published on, if any.
|
||||
@@ -72,8 +74,6 @@ table TaskInfo {
|
||||
actor_handle_id: string;
|
||||
// Number of tasks that have been submitted to this actor so far.
|
||||
actor_counter: int;
|
||||
// True if this task is an actor checkpoint task and false otherwise.
|
||||
is_actor_checkpoint_method: bool;
|
||||
// If this is an actor task, then this will be populated with all of the new
|
||||
// actor handles that were forked from this handle since the last task on
|
||||
// this handle was submitted.
|
||||
@@ -318,3 +318,34 @@ table DriverTableData {
|
||||
// Whether it's dead.
|
||||
is_dead: bool;
|
||||
}
|
||||
|
||||
// This table stores the actor checkpoint data. An actor checkpoint
|
||||
// is the snapshot of an actor's state in the actor registration.
|
||||
// See `actor_registration.h` for more detailed explanation of these fields.
|
||||
table ActorCheckpointData {
|
||||
// ID of this actor.
|
||||
actor_id: string;
|
||||
// The dummy object ID of actor's most recently executed task.
|
||||
execution_dependency: string;
|
||||
// A list of IDs of this actor's handles.
|
||||
handle_ids: [string];
|
||||
// The task counters of the above handles.
|
||||
task_counters: [long];
|
||||
// The frontier dependencies of the above handles.
|
||||
frontier_dependencies: [string];
|
||||
// A list of unreleased dummy objects from this actor.
|
||||
unreleased_dummy_objects: [string];
|
||||
// The numbers of dependencies for the above unreleased dummy objects.
|
||||
num_dummy_object_dependencies: [int];
|
||||
}
|
||||
|
||||
// This table stores the actor-to-available-checkpoint-ids mapping.
|
||||
table ActorCheckpointIdData {
|
||||
// ID of this actor.
|
||||
actor_id: string;
|
||||
// IDs of this actor's available checkpoints.
|
||||
// Note, this is a long string that concatenates all the IDs.
|
||||
checkpoint_ids: string;
|
||||
// A list of the timestamps for each of the above `checkpoint_ids`.
|
||||
timestamps: [long];
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "ray/common/common_protocol.h"
|
||||
#include "ray/gcs/client.h"
|
||||
#include "ray/ray_config.h"
|
||||
#include "ray/util/util.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -438,6 +440,41 @@ std::string ClientTable::DebugString() const {
|
||||
return result.str();
|
||||
}
|
||||
|
||||
Status ActorCheckpointIdTable::AddCheckpointId(const JobID &job_id,
|
||||
const ActorID &actor_id,
|
||||
const UniqueID &checkpoint_id) {
|
||||
auto lookup_callback = [this, checkpoint_id, job_id, actor_id](
|
||||
ray::gcs::AsyncGcsClient *client, const UniqueID &id,
|
||||
const ActorCheckpointIdDataT &data) {
|
||||
std::shared_ptr<ActorCheckpointIdDataT> copy =
|
||||
std::make_shared<ActorCheckpointIdDataT>(data);
|
||||
copy->timestamps.push_back(current_sys_time_ms());
|
||||
copy->checkpoint_ids += checkpoint_id.binary();
|
||||
auto num_to_keep = RayConfig::instance().num_actor_checkpoints_to_keep();
|
||||
while (copy->timestamps.size() > num_to_keep) {
|
||||
// Delete the checkpoint from actor checkpoint table.
|
||||
const auto &checkpoint_id =
|
||||
UniqueID::from_binary(copy->checkpoint_ids.substr(0, kUniqueIDSize));
|
||||
RAY_LOG(DEBUG) << "Deleting checkpoint " << checkpoint_id << " for actor "
|
||||
<< actor_id;
|
||||
copy->timestamps.erase(copy->timestamps.begin());
|
||||
copy->checkpoint_ids.erase(0, kUniqueIDSize);
|
||||
// TODO(hchen): also delete checkpoint data from GCS.
|
||||
}
|
||||
RAY_CHECK_OK(Add(job_id, actor_id, copy, nullptr));
|
||||
};
|
||||
auto failure_callback = [this, checkpoint_id, job_id, actor_id](
|
||||
ray::gcs::AsyncGcsClient *client, const UniqueID &id) {
|
||||
std::shared_ptr<ActorCheckpointIdDataT> data =
|
||||
std::make_shared<ActorCheckpointIdDataT>();
|
||||
data->actor_id = id.binary();
|
||||
data->timestamps.push_back(current_sys_time_ms());
|
||||
data->checkpoint_ids = checkpoint_id.binary();
|
||||
RAY_CHECK_OK(Add(job_id, actor_id, data, nullptr));
|
||||
};
|
||||
return Lookup(job_id, actor_id, lookup_callback, failure_callback);
|
||||
}
|
||||
|
||||
template class Log<ObjectID, ObjectTableData>;
|
||||
template class Log<TaskID, ray::protocol::Task>;
|
||||
template class Table<TaskID, ray::protocol::Task>;
|
||||
@@ -451,6 +488,8 @@ template class Log<JobID, ErrorTableData>;
|
||||
template class Log<UniqueID, ClientTableData>;
|
||||
template class Log<JobID, DriverTableData>;
|
||||
template class Log<UniqueID, ProfileTableData>;
|
||||
template class Table<ActorCheckpointID, ActorCheckpointData>;
|
||||
template class Table<ActorID, ActorCheckpointIdData>;
|
||||
|
||||
} // namespace gcs
|
||||
|
||||
|
||||
@@ -443,6 +443,34 @@ class TaskLeaseTable : public Table<TaskID, TaskLeaseData> {
|
||||
}
|
||||
};
|
||||
|
||||
class ActorCheckpointTable : public Table<ActorCheckpointID, ActorCheckpointData> {
|
||||
public:
|
||||
ActorCheckpointTable(const std::vector<std::shared_ptr<RedisContext>> &contexts,
|
||||
AsyncGcsClient *client)
|
||||
: Table(contexts, client) {
|
||||
prefix_ = TablePrefix::ACTOR_CHECKPOINT;
|
||||
};
|
||||
};
|
||||
|
||||
class ActorCheckpointIdTable : public Table<ActorID, ActorCheckpointIdData> {
|
||||
public:
|
||||
ActorCheckpointIdTable(const std::vector<std::shared_ptr<RedisContext>> &contexts,
|
||||
AsyncGcsClient *client)
|
||||
: Table(contexts, client) {
|
||||
prefix_ = TablePrefix::ACTOR_CHECKPOINT_ID;
|
||||
};
|
||||
|
||||
/// Add a checkpoint id to an actor, and remove a previous checkpoint if the
|
||||
/// total number of checkpoints in GCS exceeds the max allowed value.
|
||||
///
|
||||
/// \param job_id The ID of the job (= driver).
|
||||
/// \param actor_id ID of the actor.
|
||||
/// \param checkpoint_id ID of the checkpoint.
|
||||
/// \return Status.
|
||||
Status AddCheckpointId(const JobID &job_id, const ActorID &actor_id,
|
||||
const UniqueID &checkpoint_id);
|
||||
};
|
||||
|
||||
namespace raylet {
|
||||
|
||||
class TaskTable : public Table<TaskID, ray::protocol::Task> {
|
||||
|
||||
@@ -45,6 +45,7 @@ typedef UniqueID FunctionID;
|
||||
typedef UniqueID ActorClassID;
|
||||
typedef UniqueID ActorID;
|
||||
typedef UniqueID ActorHandleID;
|
||||
typedef UniqueID ActorCheckpointID;
|
||||
typedef UniqueID WorkerID;
|
||||
typedef UniqueID DriverID;
|
||||
typedef UniqueID ConfigID;
|
||||
|
||||
@@ -144,3 +144,9 @@ RAY_CONFIG(int, num_workers_per_process, 1);
|
||||
|
||||
/// Maximum timeout in milliseconds within which a task lease must be renewed.
|
||||
RAY_CONFIG(int64_t, max_task_lease_timeout_ms, 60000);
|
||||
|
||||
/// Maximum number of checkpoints to keep in GCS for an actor.
|
||||
/// Note: this number should be set to at least 2. Because saving a application
|
||||
/// checkpoint isn't atomic with saving the backend checkpoint, and it will break
|
||||
/// if this number is set to 1 and users save application checkpoints in place.
|
||||
RAY_CONFIG(uint32_t, num_actor_checkpoints_to_keep, 20);
|
||||
|
||||
@@ -11,6 +11,25 @@ namespace raylet {
|
||||
ActorRegistration::ActorRegistration(const ActorTableDataT &actor_table_data)
|
||||
: actor_table_data_(actor_table_data) {}
|
||||
|
||||
ActorRegistration::ActorRegistration(const ActorTableDataT &actor_table_data,
|
||||
const ActorCheckpointDataT &checkpoint_data)
|
||||
: actor_table_data_(actor_table_data),
|
||||
execution_dependency_(ObjectID::from_binary(checkpoint_data.execution_dependency)) {
|
||||
// Restore `frontier_`.
|
||||
for (size_t i = 0; i < checkpoint_data.handle_ids.size(); i++) {
|
||||
auto handle_id = ActorHandleID::from_binary(checkpoint_data.handle_ids[i]);
|
||||
auto &frontier_entry = frontier_[handle_id];
|
||||
frontier_entry.task_counter = checkpoint_data.task_counters[i];
|
||||
frontier_entry.execution_dependency =
|
||||
ObjectID::from_binary(checkpoint_data.frontier_dependencies[i]);
|
||||
}
|
||||
// Restore `dummy_objects_`.
|
||||
for (size_t i = 0; i < checkpoint_data.unreleased_dummy_objects.size(); i++) {
|
||||
auto dummy = ObjectID::from_binary(checkpoint_data.unreleased_dummy_objects[i]);
|
||||
dummy_objects_[dummy] = checkpoint_data.num_dummy_object_dependencies[i];
|
||||
}
|
||||
}
|
||||
|
||||
const ClientID ActorRegistration::GetNodeManagerId() const {
|
||||
return ClientID::from_binary(actor_table_data_.node_manager_id);
|
||||
}
|
||||
@@ -77,6 +96,35 @@ void ActorRegistration::AddHandle(const ActorHandleID &handle_id,
|
||||
|
||||
int ActorRegistration::NumHandles() const { return frontier_.size(); }
|
||||
|
||||
std::shared_ptr<ActorCheckpointDataT> ActorRegistration::GenerateCheckpointData(
|
||||
const ActorID &actor_id, const Task &task) {
|
||||
const auto actor_handle_id = task.GetTaskSpecification().ActorHandleId();
|
||||
const auto dummy_object = task.GetTaskSpecification().ActorDummyObject();
|
||||
// Make a copy of the actor registration, and extend its frontier to include
|
||||
// the most recent task.
|
||||
// Note(hchen): this is needed because this method is called before
|
||||
// `FinishAssignedTask`, which will be called when the worker tries to fetch
|
||||
// the next task.
|
||||
ActorRegistration copy = *this;
|
||||
copy.ExtendFrontier(actor_handle_id, dummy_object);
|
||||
|
||||
// Use actor's current state to generate checkpoint data.
|
||||
auto checkpoint_data = std::make_shared<ActorCheckpointDataT>();
|
||||
checkpoint_data->actor_id = actor_id.binary();
|
||||
checkpoint_data->execution_dependency = copy.GetExecutionDependency().binary();
|
||||
for (const auto &frontier : copy.GetFrontier()) {
|
||||
checkpoint_data->handle_ids.push_back(frontier.first.binary());
|
||||
checkpoint_data->task_counters.push_back(frontier.second.task_counter);
|
||||
checkpoint_data->frontier_dependencies.push_back(
|
||||
frontier.second.execution_dependency.binary());
|
||||
}
|
||||
for (const auto &entry : copy.GetDummyObjects()) {
|
||||
checkpoint_data->unreleased_dummy_objects.push_back(entry.first.binary());
|
||||
checkpoint_data->num_dummy_object_dependencies.push_back(entry.second);
|
||||
}
|
||||
return checkpoint_data;
|
||||
}
|
||||
|
||||
} // namespace raylet
|
||||
|
||||
} // namespace ray
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "ray/gcs/format/gcs_generated.h"
|
||||
#include "ray/id.h"
|
||||
#include "ray/raylet/task.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
@@ -24,6 +25,12 @@ class ActorRegistration {
|
||||
/// this actor. This includes the actor's node manager location.
|
||||
ActorRegistration(const ActorTableDataT &actor_table_data);
|
||||
|
||||
/// Recreate an actor's registration from a checkpoint.
|
||||
///
|
||||
/// \param checkpoint_data The checkpoint used to restore the actor.
|
||||
ActorRegistration(const ActorTableDataT &actor_table_data,
|
||||
const ActorCheckpointDataT &checkpoint_data);
|
||||
|
||||
/// Each actor may have multiple callers, or "handles". A frontier leaf
|
||||
/// represents the execution state of the actor with respect to a single
|
||||
/// handle.
|
||||
@@ -119,6 +126,14 @@ class ActorRegistration {
|
||||
/// \return int.
|
||||
int NumHandles() const;
|
||||
|
||||
/// Generate checkpoint data based on actor's current state.
|
||||
///
|
||||
/// \param actor_id ID of this actor.
|
||||
/// \param task The task that just finished on the actor.
|
||||
/// \return A shared pointer to the generated checkpoint data.
|
||||
std::shared_ptr<ActorCheckpointDataT> GenerateCheckpointData(const ActorID &actor_id,
|
||||
const Task &task);
|
||||
|
||||
private:
|
||||
/// Information from the global actor table about this actor, including the
|
||||
/// node manager location.
|
||||
|
||||
@@ -71,6 +71,12 @@ enum MessageType:int {
|
||||
PushProfileEventsRequest,
|
||||
// Free the objects in objects store.
|
||||
FreeObjectsInObjectStoreRequest,
|
||||
// Request raylet backend to prepare a checkpoint for an actor.
|
||||
PrepareActorCheckpointRequest,
|
||||
// Reply of `PrepareActorCheckpointRequest`.
|
||||
PrepareActorCheckpointReply,
|
||||
// Notify raylet backend that an actor was resumed from a checkpoint.
|
||||
NotifyActorResumedFromCheckpoint,
|
||||
// A node manager requests to connect to another node manager.
|
||||
ConnectClient,
|
||||
}
|
||||
@@ -207,6 +213,23 @@ table FreeObjectsRequest {
|
||||
object_ids: [string];
|
||||
}
|
||||
|
||||
table PrepareActorCheckpointRequest {
|
||||
// ID of the actor.
|
||||
actor_id: string;
|
||||
}
|
||||
|
||||
table PrepareActorCheckpointReply {
|
||||
// ID of the checkpoint.
|
||||
checkpoint_id: string;
|
||||
}
|
||||
|
||||
table NotifyActorResumedFromCheckpoint {
|
||||
// ID of the actor.
|
||||
actor_id: string;
|
||||
// ID of the checkpoint from which the actor was resumed.
|
||||
checkpoint_id: string;
|
||||
}
|
||||
|
||||
table ConnectClient {
|
||||
// ID of the connecting client.
|
||||
client_id: string;
|
||||
|
||||
@@ -268,6 +268,40 @@ Java_org_ray_runtime_raylet_RayletClientImpl_nativeFreePlasmaObjects(
|
||||
ThrowRayExceptionIfNotOK(env, status, "[RayletClient] Failed to free objects.");
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativePrepareCheckpoint
|
||||
* Signature: (J[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativePrepareCheckpoint(JNIEnv *env, jclass,
|
||||
jlong client,
|
||||
jbyteArray actorId) {
|
||||
auto raylet_client = reinterpret_cast<RayletClient *>(client);
|
||||
UniqueIdFromJByteArray actor_id(env, actorId);
|
||||
ActorCheckpointID checkpoint_id;
|
||||
RAY_CHECK_OK(raylet_client->PrepareActorCheckpoint(*actor_id.PID, checkpoint_id));
|
||||
jbyteArray result = env->NewByteArray(sizeof(ActorCheckpointID));
|
||||
env->SetByteArrayRegion(result, 0, sizeof(ActorCheckpointID),
|
||||
reinterpret_cast<jbyte *>(&checkpoint_id));
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativeNotifyActorResumedFromCheckpoint
|
||||
* Signature: (J[B[B)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativeNotifyActorResumedFromCheckpoint(
|
||||
JNIEnv *env, jclass, jlong client, jbyteArray actorId, jbyteArray checkpointId) {
|
||||
auto raylet_client = reinterpret_cast<RayletClient *>(client);
|
||||
UniqueIdFromJByteArray actor_id(env, actorId);
|
||||
UniqueIdFromJByteArray checkpoint_id(env, checkpointId);
|
||||
RAY_CHECK_OK(
|
||||
raylet_client->NotifyActorResumedFromCheckpoint(*actor_id.PID, *checkpoint_id.PID));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#undef org_ray_runtime_raylet_RayletClientImpl_TASK_SPEC_BUFFER_SIZE
|
||||
#define org_ray_runtime_raylet_RayletClientImpl_TASK_SPEC_BUFFER_SIZE 2097152L
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativeInit
|
||||
@@ -58,6 +60,14 @@ Java_org_ray_runtime_raylet_RayletClientImpl_nativeFetchOrReconstruct(JNIEnv *,
|
||||
JNIEXPORT void JNICALL Java_org_ray_runtime_raylet_RayletClientImpl_nativeNotifyUnblocked(
|
||||
JNIEnv *, jclass, jlong, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativePutObject
|
||||
* Signature: (J[B[B)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_org_ray_runtime_raylet_RayletClientImpl_nativePutObject(
|
||||
JNIEnv *, jclass, jlong, jbyteArray, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativeWaitObject
|
||||
@@ -88,6 +98,24 @@ Java_org_ray_runtime_raylet_RayletClientImpl_nativeFreePlasmaObjects(JNIEnv *, j
|
||||
jlong, jobjectArray,
|
||||
jboolean);
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativePrepareCheckpoint
|
||||
* Signature: (J[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativePrepareCheckpoint(JNIEnv *, jclass,
|
||||
jlong, jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativeNotifyActorResumedFromCheckpoint
|
||||
* Signature: (J[B[B)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativeNotifyActorResumedFromCheckpoint(
|
||||
JNIEnv *, jclass, jlong, jbyteArray, jbyteArray);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
+202
-78
@@ -140,7 +140,7 @@ ray::Status NodeManager::RegisterGcs() {
|
||||
if (!data.empty()) {
|
||||
// We only need the last entry, because it represents the latest state of
|
||||
// this actor.
|
||||
HandleActorStateTransition(actor_id, data.back());
|
||||
HandleActorStateTransition(actor_id, ActorRegistration(data.back()));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -507,13 +507,7 @@ void NodeManager::PublishActorStateTransition(
|
||||
}
|
||||
|
||||
void NodeManager::HandleActorStateTransition(const ActorID &actor_id,
|
||||
const ActorTableDataT &data) {
|
||||
ActorRegistration actor_registration(data);
|
||||
RAY_LOG(DEBUG) << "Actor notification received: actor_id = " << actor_id
|
||||
<< ", node_manager_id = " << actor_registration.GetNodeManagerId()
|
||||
<< ", state = " << EnumNameActorState(actor_registration.GetState())
|
||||
<< ", remaining_reconstructions = "
|
||||
<< actor_registration.GetRemainingReconstructions();
|
||||
ActorRegistration &&actor_registration) {
|
||||
// Update local registry.
|
||||
auto it = actor_registry_.find(actor_id);
|
||||
if (it == actor_registry_.end()) {
|
||||
@@ -536,6 +530,11 @@ void NodeManager::HandleActorStateTransition(const ActorID &actor_id,
|
||||
return;
|
||||
}
|
||||
}
|
||||
RAY_LOG(DEBUG) << "Actor notification received: actor_id = " << actor_id
|
||||
<< ", node_manager_id = " << actor_registration.GetNodeManagerId()
|
||||
<< ", state = " << EnumNameActorState(actor_registration.GetState())
|
||||
<< ", remaining_reconstructions = "
|
||||
<< actor_registration.GetRemainingReconstructions();
|
||||
|
||||
if (actor_registration.GetState() == ActorState::ALIVE) {
|
||||
// The actor's location is now known. Dequeue any methods that were
|
||||
@@ -700,6 +699,12 @@ void NodeManager::ProcessClientMessage(
|
||||
std::vector<ObjectID> object_ids = from_flatbuf(*message->object_ids());
|
||||
object_manager_.FreeObjects(object_ids, message->local_only());
|
||||
} break;
|
||||
case protocol::MessageType::PrepareActorCheckpointRequest: {
|
||||
ProcessPrepareActorCheckpointRequest(client, message_data);
|
||||
} break;
|
||||
case protocol::MessageType::NotifyActorResumedFromCheckpoint: {
|
||||
ProcessNotifyActorResumedFromCheckpoint(message_data);
|
||||
} break;
|
||||
|
||||
default:
|
||||
RAY_LOG(FATAL) << "Received unexpected message type " << message_type;
|
||||
@@ -762,7 +767,7 @@ void NodeManager::HandleDisconnectedActor(const ActorID &actor_id, bool was_loca
|
||||
// So if we receive any actor tasks before we receive GCS notification,
|
||||
// these tasks can be correctly routed to the `MethodsWaitingForActorCreation` queue,
|
||||
// instead of being assigned to the dead actor.
|
||||
HandleActorStateTransition(actor_id, new_actor_data);
|
||||
HandleActorStateTransition(actor_id, ActorRegistration(new_actor_data));
|
||||
}
|
||||
ray::gcs::ActorTable::WriteCallback failure_callback = nullptr;
|
||||
if (was_local) {
|
||||
@@ -1014,6 +1019,64 @@ void NodeManager::ProcessPushErrorRequestMessage(const uint8_t *message_data) {
|
||||
timestamp));
|
||||
}
|
||||
|
||||
void NodeManager::ProcessPrepareActorCheckpointRequest(
|
||||
const std::shared_ptr<LocalClientConnection> &client, const uint8_t *message_data) {
|
||||
auto message =
|
||||
flatbuffers::GetRoot<protocol::PrepareActorCheckpointRequest>(message_data);
|
||||
ActorID actor_id = from_flatbuf(*message->actor_id());
|
||||
RAY_LOG(DEBUG) << "Preparing checkpoint for actor " << actor_id;
|
||||
const auto &actor_entry = actor_registry_.find(actor_id);
|
||||
RAY_CHECK(actor_entry != actor_registry_.end());
|
||||
|
||||
std::shared_ptr<Worker> worker = worker_pool_.GetRegisteredWorker(client);
|
||||
RAY_CHECK(worker && worker->GetActorId() == actor_id);
|
||||
|
||||
// Find the task that is running on this actor.
|
||||
const auto task_id = worker->GetAssignedTaskId();
|
||||
const Task &task = local_queues_.GetTaskOfState(task_id, TaskState::RUNNING);
|
||||
// Generate checkpoint id and data.
|
||||
ActorCheckpointID checkpoint_id = UniqueID::from_random();
|
||||
auto checkpoint_data =
|
||||
actor_entry->second.GenerateCheckpointData(actor_entry->first, task);
|
||||
|
||||
// Write checkpoint data to GCS.
|
||||
RAY_CHECK_OK(gcs_client_->actor_checkpoint_table().Add(
|
||||
UniqueID::nil(), checkpoint_id, checkpoint_data,
|
||||
[worker, actor_id, this](ray::gcs::AsyncGcsClient *client,
|
||||
const UniqueID &checkpoint_id,
|
||||
const ActorCheckpointDataT &data) {
|
||||
RAY_LOG(DEBUG) << "Checkpoint " << checkpoint_id << " saved for actor "
|
||||
<< worker->GetActorId();
|
||||
// Save this actor-to-checkpoint mapping, and remove old checkpoints associated
|
||||
// with this actor.
|
||||
RAY_CHECK_OK(gcs_client_->actor_checkpoint_id_table().AddCheckpointId(
|
||||
JobID::nil(), actor_id, checkpoint_id));
|
||||
// Send reply to worker.
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto reply = ray::protocol::CreatePrepareActorCheckpointReply(
|
||||
fbb, to_flatbuf(fbb, checkpoint_id));
|
||||
fbb.Finish(reply);
|
||||
worker->Connection()->WriteMessageAsync(
|
||||
static_cast<int64_t>(protocol::MessageType::PrepareActorCheckpointReply),
|
||||
fbb.GetSize(), fbb.GetBufferPointer(), [](const ray::Status &status) {
|
||||
if (!status.ok()) {
|
||||
RAY_LOG(WARNING)
|
||||
<< "Failed to send PrepareActorCheckpointReply to client";
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
void NodeManager::ProcessNotifyActorResumedFromCheckpoint(const uint8_t *message_data) {
|
||||
auto message =
|
||||
flatbuffers::GetRoot<protocol::NotifyActorResumedFromCheckpoint>(message_data);
|
||||
ActorID actor_id = from_flatbuf(*message->actor_id());
|
||||
ActorCheckpointID checkpoint_id = from_flatbuf(*message->checkpoint_id());
|
||||
RAY_LOG(DEBUG) << "Actor " << actor_id << " was resumed from checkpoint "
|
||||
<< checkpoint_id;
|
||||
checkpoint_id_to_restore_.emplace(actor_id, checkpoint_id);
|
||||
}
|
||||
|
||||
void NodeManager::ProcessNewNodeManager(TcpClientConnection &node_manager_client) {
|
||||
node_manager_client.ProcessMessages();
|
||||
}
|
||||
@@ -1154,6 +1217,12 @@ bool NodeManager::CheckDependencyManagerInvariant() const {
|
||||
void NodeManager::TreatTaskAsFailed(const Task &task) {
|
||||
const TaskSpecification &spec = task.GetTaskSpecification();
|
||||
RAY_LOG(DEBUG) << "Treating task " << spec.TaskId() << " as failed.";
|
||||
// If this was an actor creation task that tried to resume from a checkpoint,
|
||||
// then erase it here since the task did not finish.
|
||||
if (spec.IsActorCreationTask()) {
|
||||
ActorID actor_id = spec.ActorCreationId();
|
||||
checkpoint_id_to_restore_.erase(actor_id);
|
||||
}
|
||||
// Loop over the return IDs (except the dummy ID) and store a fake object in
|
||||
// the object store.
|
||||
int64_t num_returns = spec.NumReturns();
|
||||
@@ -1320,7 +1389,7 @@ void NodeManager::SubmitTask(const Task &task, const Lineage &uncommitted_lineag
|
||||
if (!data.empty()) {
|
||||
// The actor has been created. We only need the last entry, because
|
||||
// it represents the latest state of this actor.
|
||||
HandleActorStateTransition(actor_id, data.back());
|
||||
HandleActorStateTransition(actor_id, ActorRegistration(data.back()));
|
||||
}
|
||||
};
|
||||
RAY_CHECK_OK(gcs_client_->actor_table().Lookup(JobID::nil(), spec.ActorId(),
|
||||
@@ -1672,86 +1741,141 @@ void NodeManager::FinishAssignedTask(Worker &worker) {
|
||||
}
|
||||
}
|
||||
|
||||
void NodeManager::FinishAssignedActorTask(Worker &worker, const Task &task) {
|
||||
// If this was an actor creation task, then convert the worker to an actor
|
||||
// and notify the other node managers.
|
||||
if (task.GetTaskSpecification().IsActorCreationTask()) {
|
||||
// Convert the worker to an actor.
|
||||
auto actor_id = task.GetTaskSpecification().ActorCreationId();
|
||||
worker.AssignActorId(actor_id);
|
||||
// Publish the actor creation event to all other nodes so that methods for
|
||||
// the actor will be forwarded directly to this node.
|
||||
auto actor_entry = actor_registry_.find(actor_id);
|
||||
ActorTableDataT new_actor_data;
|
||||
if (actor_entry == actor_registry_.end()) {
|
||||
// Set all of the static fields for the actor. These fields will not
|
||||
// change even if the actor fails or is reconstructed.
|
||||
new_actor_data.actor_id = actor_id.binary();
|
||||
new_actor_data.actor_creation_dummy_object_id =
|
||||
task.GetTaskSpecification().ActorDummyObject().binary();
|
||||
new_actor_data.driver_id = task.GetTaskSpecification().DriverId().binary();
|
||||
new_actor_data.max_reconstructions =
|
||||
task.GetTaskSpecification().MaxActorReconstructions();
|
||||
// This is the first time that the actor has been created, so the number
|
||||
// of remaining reconstructions is the max.
|
||||
new_actor_data.remaining_reconstructions =
|
||||
task.GetTaskSpecification().MaxActorReconstructions();
|
||||
} else {
|
||||
// If we've already seen this actor, it means that this actor was reconstructed.
|
||||
// Thus, its previous state must be RECONSTRUCTING.
|
||||
RAY_CHECK(actor_entry->second.GetState() == ActorState::RECONSTRUCTING);
|
||||
// Copy the static fields from the current actor entry.
|
||||
new_actor_data = actor_entry->second.GetTableData();
|
||||
// We are reconstructing the actor, so subtract its
|
||||
// remaining_reconstructions by 1.
|
||||
new_actor_data.remaining_reconstructions--;
|
||||
}
|
||||
|
||||
// Set the new fields for the actor's state to indicate that the actor is
|
||||
// now alive on this node manager.
|
||||
new_actor_data.node_manager_id =
|
||||
gcs_client_->client_table().GetLocalClientId().binary();
|
||||
new_actor_data.state = ActorState::ALIVE;
|
||||
HandleActorStateTransition(actor_id, new_actor_data);
|
||||
PublishActorStateTransition(
|
||||
actor_id, new_actor_data,
|
||||
/*failure_callback=*/
|
||||
[](gcs::AsyncGcsClient *client, const ActorID &id, const ActorTableDataT &data) {
|
||||
// Only one node at a time should succeed at creating the actor.
|
||||
RAY_LOG(FATAL) << "Failed to update state to ALIVE for actor " << id;
|
||||
});
|
||||
ActorTableDataT NodeManager::CreateActorTableDataFromCreationTask(const Task &task) {
|
||||
RAY_CHECK(task.GetTaskSpecification().IsActorCreationTask());
|
||||
auto actor_id = task.GetTaskSpecification().ActorCreationId();
|
||||
auto actor_entry = actor_registry_.find(actor_id);
|
||||
ActorTableDataT new_actor_data;
|
||||
// TODO(swang): If this is an actor that was reconstructed, and previous
|
||||
// actor notifications were delayed, then this node may not have an entry for
|
||||
// the actor in actor_regisry_. Then, the fields for the number of
|
||||
// reconstructions will be wrong.
|
||||
if (actor_entry == actor_registry_.end()) {
|
||||
// Set all of the static fields for the actor. These fields will not
|
||||
// change even if the actor fails or is reconstructed.
|
||||
new_actor_data.actor_id = actor_id.binary();
|
||||
new_actor_data.actor_creation_dummy_object_id =
|
||||
task.GetTaskSpecification().ActorDummyObject().binary();
|
||||
new_actor_data.driver_id = task.GetTaskSpecification().DriverId().binary();
|
||||
new_actor_data.max_reconstructions =
|
||||
task.GetTaskSpecification().MaxActorReconstructions();
|
||||
// This is the first time that the actor has been created, so the number
|
||||
// of remaining reconstructions is the max.
|
||||
new_actor_data.remaining_reconstructions =
|
||||
task.GetTaskSpecification().MaxActorReconstructions();
|
||||
} else {
|
||||
// If we've already seen this actor, it means that this actor was reconstructed.
|
||||
// Thus, its previous state must be RECONSTRUCTING.
|
||||
RAY_CHECK(actor_entry->second.GetState() == ActorState::RECONSTRUCTING);
|
||||
// Copy the static fields from the current actor entry.
|
||||
new_actor_data = actor_entry->second.GetTableData();
|
||||
// We are reconstructing the actor, so subtract its
|
||||
// remaining_reconstructions by 1.
|
||||
new_actor_data.remaining_reconstructions--;
|
||||
}
|
||||
|
||||
// Update the actor's frontier.
|
||||
// Set the new fields for the actor's state to indicate that the actor is
|
||||
// now alive on this node manager.
|
||||
new_actor_data.node_manager_id =
|
||||
gcs_client_->client_table().GetLocalClientId().binary();
|
||||
new_actor_data.state = ActorState::ALIVE;
|
||||
return new_actor_data;
|
||||
}
|
||||
|
||||
void NodeManager::FinishAssignedActorTask(Worker &worker, const Task &task) {
|
||||
ActorID actor_id;
|
||||
ActorHandleID actor_handle_id;
|
||||
bool resumed_from_checkpoint = false;
|
||||
if (task.GetTaskSpecification().IsActorCreationTask()) {
|
||||
actor_id = task.GetTaskSpecification().ActorCreationId();
|
||||
actor_handle_id = ActorHandleID::nil();
|
||||
if (checkpoint_id_to_restore_.count(actor_id) > 0) {
|
||||
resumed_from_checkpoint = true;
|
||||
}
|
||||
} else {
|
||||
actor_id = task.GetTaskSpecification().ActorId();
|
||||
actor_handle_id = task.GetTaskSpecification().ActorHandleId();
|
||||
}
|
||||
auto actor_entry = actor_registry_.find(actor_id);
|
||||
RAY_CHECK(actor_entry != actor_registry_.end());
|
||||
// Extend the actor's frontier to include the executed task.
|
||||
const auto dummy_object = task.GetTaskSpecification().ActorDummyObject();
|
||||
const ObjectID object_to_release =
|
||||
actor_entry->second.ExtendFrontier(actor_handle_id, dummy_object);
|
||||
if (!object_to_release.is_nil()) {
|
||||
// If there were no new actor handles created, then no other actor task
|
||||
// will depend on this execution dependency, so it safe to release.
|
||||
HandleObjectMissing(object_to_release);
|
||||
|
||||
if (task.GetTaskSpecification().IsActorCreationTask()) {
|
||||
// This was an actor creation task. Convert the worker to an actor.
|
||||
worker.AssignActorId(actor_id);
|
||||
// Notify the other node managers that the actor has been created.
|
||||
const auto new_actor_data = CreateActorTableDataFromCreationTask(task);
|
||||
if (resumed_from_checkpoint) {
|
||||
// This actor was resumed from a checkpoint. In this case, we first look
|
||||
// up the checkpoint in GCS and use it to restore the actor registration
|
||||
// and frontier.
|
||||
const auto checkpoint_id = checkpoint_id_to_restore_[actor_id];
|
||||
checkpoint_id_to_restore_.erase(actor_id);
|
||||
RAY_LOG(DEBUG) << "Looking up checkpoint " << checkpoint_id << " for actor "
|
||||
<< actor_id;
|
||||
RAY_CHECK_OK(gcs_client_->actor_checkpoint_table().Lookup(
|
||||
JobID::nil(), checkpoint_id,
|
||||
[this, actor_id, new_actor_data](ray::gcs::AsyncGcsClient *client,
|
||||
const UniqueID &checkpoint_id,
|
||||
const ActorCheckpointDataT &checkpoint_data) {
|
||||
RAY_LOG(INFO) << "Restoring registration for actor " << actor_id
|
||||
<< " from checkpoint " << checkpoint_id;
|
||||
ActorRegistration actor_registration =
|
||||
ActorRegistration(new_actor_data, checkpoint_data);
|
||||
// Mark the unreleased dummy objects in the checkpoint frontier as local.
|
||||
for (const auto &entry : actor_registration.GetDummyObjects()) {
|
||||
HandleObjectLocal(entry.first);
|
||||
}
|
||||
HandleActorStateTransition(actor_id, std::move(actor_registration));
|
||||
PublishActorStateTransition(
|
||||
actor_id, new_actor_data,
|
||||
/*failure_callback=*/
|
||||
[](gcs::AsyncGcsClient *client, const ActorID &id,
|
||||
const ActorTableDataT &data) {
|
||||
// Only one node at a time should succeed at creating the actor.
|
||||
RAY_LOG(FATAL) << "Failed to update state to ALIVE for actor " << id;
|
||||
});
|
||||
},
|
||||
[actor_id](ray::gcs::AsyncGcsClient *client, const UniqueID &checkpoint_id) {
|
||||
RAY_LOG(FATAL) << "Couldn't find checkpoint " << checkpoint_id
|
||||
<< " for actor " << actor_id << " in GCS.";
|
||||
}));
|
||||
} else {
|
||||
// The actor did not resume from a checkpoint. Immediately notify the
|
||||
// other node managers that the actor has been created.
|
||||
HandleActorStateTransition(actor_id, ActorRegistration(new_actor_data));
|
||||
PublishActorStateTransition(
|
||||
actor_id, new_actor_data,
|
||||
/*failure_callback=*/
|
||||
[](gcs::AsyncGcsClient *client, const ActorID &id,
|
||||
const ActorTableDataT &data) {
|
||||
// Only one node at a time should succeed at creating the actor.
|
||||
RAY_LOG(FATAL) << "Failed to update state to ALIVE for actor " << id;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (!resumed_from_checkpoint) {
|
||||
// The actor was not resumed from a checkpoint. We extend the actor's
|
||||
// frontier as usual since there is no frontier to restore.
|
||||
auto actor_entry = actor_registry_.find(actor_id);
|
||||
RAY_CHECK(actor_entry != actor_registry_.end());
|
||||
// Extend the actor's frontier to include the executed task.
|
||||
const auto dummy_object = task.GetTaskSpecification().ActorDummyObject();
|
||||
const ObjectID object_to_release =
|
||||
actor_entry->second.ExtendFrontier(actor_handle_id, dummy_object);
|
||||
if (!object_to_release.is_nil()) {
|
||||
// If there were no new actor handles created, then no other actor task
|
||||
// will depend on this execution dependency, so it safe to release.
|
||||
HandleObjectMissing(object_to_release);
|
||||
}
|
||||
// Mark the dummy object as locally available to indicate that the actor's
|
||||
// state has changed and the next method can run. This is not added to the
|
||||
// object table, so the update will be invisible to both the local object
|
||||
// manager and the other nodes.
|
||||
// NOTE(swang): The dummy objects must be marked as local whenever
|
||||
// ExtendFrontier is called, and vice versa, so that we can clean up the
|
||||
// dummy objects properly in case the actor fails and needs to be
|
||||
// reconstructed.
|
||||
HandleObjectLocal(dummy_object);
|
||||
}
|
||||
// Mark the dummy object as locally available to indicate that the actor's
|
||||
// state has changed and the next method can run. This is not added to the
|
||||
// object table, so the update will be invisible to both the local object
|
||||
// manager and the other nodes.
|
||||
// NOTE(swang): The dummy objects must be marked as local whenever
|
||||
// ExtendFrontier is called, and vice versa, so that we can clean up the
|
||||
// dummy objects properly in case the actor fails and needs to be
|
||||
// reconstructed.
|
||||
HandleObjectLocal(dummy_object);
|
||||
}
|
||||
|
||||
void NodeManager::HandleTaskReconstruction(const TaskID &task_id) {
|
||||
|
||||
@@ -186,6 +186,10 @@ class NodeManager {
|
||||
/// \param worker The worker that finished the task.
|
||||
/// \return Void.
|
||||
void FinishAssignedTask(Worker &worker);
|
||||
/// Helper function to produce actor table data for a newly created actor.
|
||||
///
|
||||
/// \param task The actor creation task that created the actor.
|
||||
ActorTableDataT CreateActorTableDataFromCreationTask(const Task &task);
|
||||
/// Handle a worker finishing an assigned actor task or actor creation task.
|
||||
/// \param worker The worker that finished the task.
|
||||
/// \param task The actor task or actor creationt ask.
|
||||
@@ -282,9 +286,11 @@ class NodeManager {
|
||||
/// old state transition.
|
||||
///
|
||||
/// \param actor_id The actor ID of the actor whose state was updated.
|
||||
/// \param data Data associated with this notification.
|
||||
/// \param actor_registration The ActorRegistration object that represents actor's
|
||||
/// new state.
|
||||
/// \return Void.
|
||||
void HandleActorStateTransition(const ActorID &actor_id, const ActorTableDataT &data);
|
||||
void HandleActorStateTransition(const ActorID &actor_id,
|
||||
ActorRegistration &&actor_registration);
|
||||
|
||||
/// Publish an actor's state transition to all other nodes.
|
||||
///
|
||||
@@ -385,6 +391,25 @@ class NodeManager {
|
||||
/// \return Void.
|
||||
void ProcessPushErrorRequestMessage(const uint8_t *message_data);
|
||||
|
||||
/// Process client message of PrepareActorCheckpointRequest.
|
||||
///
|
||||
/// \param client The client that sent the message.
|
||||
/// \param message_data A pointer to the message data.
|
||||
void ProcessPrepareActorCheckpointRequest(
|
||||
const std::shared_ptr<LocalClientConnection> &client, const uint8_t *message_data);
|
||||
|
||||
/// Process client message of NotifyActorResumedFromCheckpoint.
|
||||
///
|
||||
/// \param message_data A pointer to the message data.
|
||||
void ProcessNotifyActorResumedFromCheckpoint(const uint8_t *message_data);
|
||||
|
||||
/// Update actor frontier when a task finishes.
|
||||
/// If the task is an actor creation task and the actor was resumed from a checkpoint,
|
||||
/// restore the frontier from the checkpoint. Otherwise, just extend actor frontier.
|
||||
///
|
||||
/// \param task The task that just finished.
|
||||
void UpdateActorFrontier(const Task &task);
|
||||
|
||||
/// Handle the case where an actor is disconnected, determine whether this
|
||||
/// actor needs to be reconstructed and then update actor table.
|
||||
/// This function needs to be called either when actor process dies or when
|
||||
@@ -458,6 +483,10 @@ class NodeManager {
|
||||
/// A mapping from actor ID to registration information about that actor
|
||||
/// (including which node manager owns it).
|
||||
std::unordered_map<ActorID, ActorRegistration> actor_registry_;
|
||||
|
||||
/// This map stores actor ID to the ID of the checkpoint that will be used to
|
||||
/// restore the actor.
|
||||
std::unordered_map<ActorID, ActorCheckpointID> checkpoint_id_to_restore_;
|
||||
};
|
||||
|
||||
} // namespace raylet
|
||||
|
||||
@@ -358,3 +358,31 @@ ray::Status RayletClient::FreeObjects(const std::vector<ray::ObjectID> &object_i
|
||||
auto status = conn_->WriteMessage(MessageType::FreeObjectsInObjectStoreRequest, &fbb);
|
||||
return status;
|
||||
}
|
||||
|
||||
ray::Status RayletClient::PrepareActorCheckpoint(const ActorID &actor_id,
|
||||
ActorCheckpointID &checkpoint_id) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message =
|
||||
ray::protocol::CreatePrepareActorCheckpointRequest(fbb, to_flatbuf(fbb, actor_id));
|
||||
fbb.Finish(message);
|
||||
|
||||
std::unique_ptr<uint8_t[]> reply;
|
||||
auto status =
|
||||
conn_->AtomicRequestReply(MessageType::PrepareActorCheckpointRequest,
|
||||
MessageType::PrepareActorCheckpointReply, reply, &fbb);
|
||||
if (!status.ok()) return status;
|
||||
auto reply_message =
|
||||
flatbuffers::GetRoot<ray::protocol::PrepareActorCheckpointReply>(reply.get());
|
||||
checkpoint_id = ObjectID::from_binary(reply_message->checkpoint_id()->str());
|
||||
return ray::Status::OK();
|
||||
}
|
||||
|
||||
ray::Status RayletClient::NotifyActorResumedFromCheckpoint(
|
||||
const ActorID &actor_id, const ActorCheckpointID &checkpoint_id) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = ray::protocol::CreateNotifyActorResumedFromCheckpoint(
|
||||
fbb, to_flatbuf(fbb, actor_id), to_flatbuf(fbb, checkpoint_id));
|
||||
fbb.Finish(message);
|
||||
|
||||
return conn_->WriteMessage(MessageType::NotifyActorResumedFromCheckpoint, &fbb);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "ray/status.h"
|
||||
|
||||
using ray::ActorID;
|
||||
using ray::ActorCheckpointID;
|
||||
using ray::JobID;
|
||||
using ray::ObjectID;
|
||||
using ray::TaskID;
|
||||
@@ -146,6 +147,22 @@ class RayletClient {
|
||||
/// \return ray::Status.
|
||||
ray::Status FreeObjects(const std::vector<ray::ObjectID> &object_ids, bool local_only);
|
||||
|
||||
/// Request raylet backend to prepare a checkpoint for an actor.
|
||||
///
|
||||
/// \param actor_id ID of the actor.
|
||||
/// \param checkpoint_id ID of the new checkpoint (output parameter).
|
||||
/// \return ray::Status.
|
||||
ray::Status PrepareActorCheckpoint(const ActorID &actor_id,
|
||||
ActorCheckpointID &checkpoint_id);
|
||||
|
||||
/// Notify raylet backend that an actor was resumed from a checkpoint.
|
||||
///
|
||||
/// \param actor_id ID of the actor.
|
||||
/// \param checkpoint_id ID of the checkpoint from which the actor was resumed.
|
||||
/// \return ray::Status.
|
||||
ray::Status NotifyActorResumedFromCheckpoint(const ActorID &actor_id,
|
||||
const ActorCheckpointID &checkpoint_id);
|
||||
|
||||
Language GetLanguage() const { return language_; }
|
||||
|
||||
ClientID GetClientID() const { return client_id_; }
|
||||
|
||||
@@ -99,7 +99,7 @@ TaskSpecification::TaskSpecification(
|
||||
fbb, to_flatbuf(fbb, driver_id), to_flatbuf(fbb, task_id),
|
||||
to_flatbuf(fbb, parent_task_id), parent_counter, to_flatbuf(fbb, actor_creation_id),
|
||||
to_flatbuf(fbb, actor_creation_dummy_object_id), max_actor_reconstructions,
|
||||
to_flatbuf(fbb, actor_id), to_flatbuf(fbb, actor_handle_id), actor_counter, false,
|
||||
to_flatbuf(fbb, actor_id), to_flatbuf(fbb, actor_handle_id), actor_counter,
|
||||
object_ids_to_flatbuf(fbb, new_actor_handles), fbb.CreateVector(arguments),
|
||||
object_ids_to_flatbuf(fbb, returns), map_to_flatbuf(fbb, required_resources),
|
||||
map_to_flatbuf(fbb, required_placement_resources), language,
|
||||
|
||||
Reference in New Issue
Block a user