mirror of
https://github.com/wassname/ray.git
synced 2026-07-09 02:57:46 +08:00
[ID Refactor] Refactor ActorID, TaskID and ObjectID (#5286)
* Refactor ActorID, TaskID on the Java side. Left a TODO comment WIP for ObjectID ADD test Fix Add java part Fix Java test Fix Refine test. Enable test in CI * Extra a helper function. * Resolve TODOs * Fix Python CI * Fix Java lint * Update .travis.yml Co-Authored-By: Stephanie Wang <swang@cs.berkeley.edu> * Address some comments. Address some comments. Add id_specification.rst Reanme id_specification.rst to id_specification.md typo Address zhijun's comments. Fix test Address comments. Fix lint Address comments * Fix test * Address comments. * Fix build error * Update src/ray/design_docs/id_specification.md Co-Authored-By: Stephanie Wang <swang@cs.berkeley.edu> * Update src/ray/design_docs/id_specification.md Co-Authored-By: Stephanie Wang <swang@cs.berkeley.edu> * Update src/ray/design_docs/id_specification.md Co-Authored-By: Stephanie Wang <swang@cs.berkeley.edu> * Update src/ray/design_docs/id_specification.md Co-Authored-By: Stephanie Wang <swang@cs.berkeley.edu> * Update src/ray/design_docs/id_specification.md Co-Authored-By: Stephanie Wang <swang@cs.berkeley.edu> * Address comments * Update src/ray/common/id.h Co-Authored-By: Stephanie Wang <swang@cs.berkeley.edu> * Update src/ray/common/id.h Co-Authored-By: Stephanie Wang <swang@cs.berkeley.edu> * Update src/ray/common/id.h Co-Authored-By: Stephanie Wang <swang@cs.berkeley.edu> * Update src/ray/design_docs/id_specification.md Co-Authored-By: Hao Chen <chenh1024@gmail.com> * Update src/ray/design_docs/id_specification.md Co-Authored-By: Hao Chen <chenh1024@gmail.com> * Address comments. * Address comments. * Address comments. * Update C++ part to make sure task id is generated determantic * WIP * Fix core worker * Fix Java part * Fix comments. * Add Python side * Fix python * Address comments * Fix linting * Fix * Fix C++ linting * Add JobId() method to TaskID * Fix linting * Update src/ray/common/id.h Co-Authored-By: Hao Chen <chenh1024@gmail.com> * Update java/api/src/main/java/org/ray/api/id/TaskId.java Co-Authored-By: Hao Chen <chenh1024@gmail.com> * Update java/api/src/main/java/org/ray/api/id/TaskId.java Co-Authored-By: Hao Chen <chenh1024@gmail.com> * Update java/api/src/main/java/org/ray/api/id/ActorId.java Co-Authored-By: Hao Chen <chenh1024@gmail.com> * Address comments * Add DriverTaskId embeding job id * Fix tests * Add python dor_fake_driver_id * Address comments and fix linting * Fix CI
This commit is contained in:
@@ -90,7 +90,6 @@ flatbuffers::Offset<flatbuffers::String> to_flatbuf(flatbuffers::FlatBufferBuild
|
||||
|
||||
template <typename ID>
|
||||
ID from_flatbuf(const flatbuffers::String &string) {
|
||||
RAY_CHECK(string.size() == ID::Size());
|
||||
return ID::FromBinary(string.str());
|
||||
}
|
||||
|
||||
|
||||
@@ -7,30 +7,15 @@
|
||||
/// Length of Ray full-length IDs in bytes.
|
||||
constexpr size_t kUniqueIDSize = 20;
|
||||
|
||||
/// Length of plasma ID in bytes.
|
||||
constexpr size_t kPlasmaIdSize = 20;
|
||||
|
||||
/// An ObjectID's bytes are split into the task ID itself and the index of the
|
||||
/// object's creation. This is the maximum width of the object index in bits.
|
||||
constexpr int kObjectIdIndexSize = 32;
|
||||
static_assert(kObjectIdIndexSize % CHAR_BIT == 0,
|
||||
"ObjectID prefix not a multiple of bytes");
|
||||
|
||||
/// Length of Ray TaskID in bytes. 32-bit integer is used for object index.
|
||||
constexpr int64_t kTaskIDSize = kUniqueIDSize - kObjectIdIndexSize / 8;
|
||||
|
||||
/// The maximum number of objects that can be returned by a task when finishing
|
||||
/// execution. An ObjectID's bytes are split into the task ID itself and the
|
||||
/// index of the object's creation. A positive index indicates an object
|
||||
/// returned by the task, so the maximum number of objects that a task can
|
||||
/// return is the maximum positive value for an integer with bit-width
|
||||
/// `kObjectIdIndexSize`.
|
||||
constexpr int64_t kMaxTaskReturns = ((int64_t)1 << (kObjectIdIndexSize - 1)) - 1;
|
||||
/// The maximum number of objects that can be put by a task during execution.
|
||||
/// An ObjectID's bytes are split into the task ID itself and the index of the
|
||||
/// object's creation. A negative index indicates an object put by the task
|
||||
/// during execution, so the maximum number of objects that a task can put is
|
||||
/// the maximum negative value for an integer with bit-width
|
||||
/// `kObjectIdIndexSize`.
|
||||
constexpr int64_t kMaxTaskPuts = ((int64_t)1 << (kObjectIdIndexSize - 1));
|
||||
|
||||
/// Prefix for the object table keys in redis.
|
||||
constexpr char kObjectTablePrefix[] = "ObjectTable";
|
||||
/// Prefix for the task table keys in redis.
|
||||
|
||||
+242
-32
@@ -2,12 +2,14 @@
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
|
||||
#include "ray/common/constants.h"
|
||||
#include "ray/common/status.h"
|
||||
#include "ray/util/util.h"
|
||||
|
||||
extern "C" {
|
||||
#include "ray/thirdparty/sha256.h"
|
||||
@@ -18,13 +20,89 @@ extern "C" {
|
||||
|
||||
namespace ray {
|
||||
|
||||
std::mt19937 RandomlySeededMersenneTwister() {
|
||||
auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
std::mt19937 seeded_engine(seed);
|
||||
return seeded_engine;
|
||||
uint64_t MurmurHash64A(const void *key, int len, unsigned int seed);
|
||||
|
||||
/// A helper function to generate the unique bytes by hash.
|
||||
std::string GenerateUniqueBytes(const JobID &job_id, const TaskID &parent_task_id,
|
||||
size_t parent_task_counter, size_t length) {
|
||||
RAY_CHECK(length <= DIGEST_SIZE);
|
||||
SHA256_CTX ctx;
|
||||
sha256_init(&ctx);
|
||||
sha256_update(&ctx, reinterpret_cast<const BYTE *>(job_id.Data()), job_id.Size());
|
||||
sha256_update(&ctx, reinterpret_cast<const BYTE *>(parent_task_id.Data()),
|
||||
parent_task_id.Size());
|
||||
sha256_update(&ctx, (const BYTE *)&parent_task_counter, sizeof(parent_task_counter));
|
||||
|
||||
BYTE buff[DIGEST_SIZE];
|
||||
sha256_final(&ctx, buff);
|
||||
return std::string(buff, buff + length);
|
||||
}
|
||||
|
||||
uint64_t MurmurHash64A(const void *key, int len, unsigned int seed);
|
||||
namespace {
|
||||
|
||||
/// The bit offset of the flag `CreatedByTask` in a flags bytes.
|
||||
constexpr uint8_t kCreatedByTaskBitsOffset = 15;
|
||||
|
||||
/// The bit offset of the flag `ObjectType` in a flags bytes.
|
||||
constexpr uint8_t kObjectTypeBitsOffset = 14;
|
||||
|
||||
/// The bit offset of the flag `TransportType` in a flags bytes.
|
||||
constexpr uint8_t kTransportTypeBitsOffset = 11;
|
||||
|
||||
/// The mask that is used to mask the flag `CreatedByTask`.
|
||||
constexpr ObjectIDFlagsType kCreatedByTaskFlagBitMask = 0x1 << kCreatedByTaskBitsOffset;
|
||||
|
||||
/// The mask that is used to mask a bit to indicates the type of this object.
|
||||
/// So it can represent for 2 types.
|
||||
constexpr ObjectIDFlagsType kObjectTypeFlagBitMask = 0x1 << kObjectTypeBitsOffset;
|
||||
|
||||
/// The mask that is used to mask 3 bits to indicate the type of transport.
|
||||
constexpr ObjectIDFlagsType kTransportTypeFlagBitMask = 0x7 << kTransportTypeBitsOffset;
|
||||
|
||||
/// The implementations of helper functions.
|
||||
inline void SetCreatedByTaskFlag(bool created_by_task, ObjectIDFlagsType *flags) {
|
||||
const ObjectIDFlagsType object_type_bits =
|
||||
static_cast<ObjectIDFlagsType>(created_by_task) << kCreatedByTaskBitsOffset;
|
||||
*flags = (*flags bitor object_type_bits);
|
||||
}
|
||||
|
||||
inline void SetObjectTypeFlag(ObjectType object_type, ObjectIDFlagsType *flags) {
|
||||
const ObjectIDFlagsType object_type_bits = static_cast<ObjectIDFlagsType>(object_type)
|
||||
<< kObjectTypeBitsOffset;
|
||||
*flags = (*flags bitor object_type_bits);
|
||||
}
|
||||
|
||||
inline void SetTransportTypeFlag(uint8_t transport_type, ObjectIDFlagsType *flags) {
|
||||
const ObjectIDFlagsType transport_type_bits =
|
||||
static_cast<ObjectIDFlagsType>(transport_type) << kTransportTypeBitsOffset;
|
||||
*flags = (*flags bitor transport_type_bits);
|
||||
}
|
||||
|
||||
inline bool CreatedByTask(ObjectIDFlagsType flags) {
|
||||
return ((flags bitand kCreatedByTaskFlagBitMask) >> kCreatedByTaskBitsOffset) != 0x0;
|
||||
}
|
||||
|
||||
inline ObjectType GetObjectType(ObjectIDFlagsType flags) {
|
||||
const ObjectIDFlagsType object_type =
|
||||
(flags bitand kObjectTypeFlagBitMask) >> kObjectTypeBitsOffset;
|
||||
return static_cast<ObjectType>(object_type);
|
||||
}
|
||||
|
||||
inline uint8_t GetTransportType(ObjectIDFlagsType flags) {
|
||||
const ObjectIDFlagsType transport_type =
|
||||
(flags bitand kTransportTypeFlagBitMask) >> kTransportTypeBitsOffset;
|
||||
return static_cast<uint8_t>(transport_type);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
template <typename T>
|
||||
void FillNil(T *data) {
|
||||
RAY_CHECK(data != nullptr);
|
||||
for (int i = 0; i < data->size(); i++) {
|
||||
(*data)[i] = static_cast<uint8_t>(0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
WorkerID ComputeDriverIdFromJob(const JobID &job_id) {
|
||||
std::vector<uint8_t> data(WorkerID::Size(), 0);
|
||||
@@ -34,14 +112,44 @@ WorkerID ComputeDriverIdFromJob(const JobID &job_id) {
|
||||
std::string(reinterpret_cast<const char *>(data.data()), data.size()));
|
||||
}
|
||||
|
||||
ObjectID ObjectID::FromPlasmaIdBinary(const std::string &from) {
|
||||
RAY_CHECK(from.size() == kPlasmaIdSize);
|
||||
return ObjectID::FromBinary(from.substr(0, ObjectID::kLength));
|
||||
}
|
||||
|
||||
plasma::UniqueID ObjectID::ToPlasmaId() const {
|
||||
static_assert(ObjectID::kLength <= kPlasmaIdSize,
|
||||
"Currently length of ObjectID must be shorter than plasma's.");
|
||||
|
||||
plasma::UniqueID result;
|
||||
std::memcpy(result.mutable_data(), Data(), kUniqueIDSize);
|
||||
std::memcpy(result.mutable_data(), Data(), ObjectID::Size());
|
||||
std::fill_n(result.mutable_data() + ObjectID::Size(), kPlasmaIdSize - ObjectID::kLength,
|
||||
0xFF);
|
||||
return result;
|
||||
}
|
||||
|
||||
ObjectID::ObjectID(const plasma::UniqueID &from) {
|
||||
std::memcpy(this->MutableData(), from.data(), kUniqueIDSize);
|
||||
RAY_CHECK(from.size() <= ObjectID::Size()) << "Out of size.";
|
||||
std::memcpy(this->MutableData(), from.data(), ObjectID::Size());
|
||||
}
|
||||
|
||||
ObjectIDFlagsType ObjectID::GetFlags() const {
|
||||
ObjectIDFlagsType flags;
|
||||
std::memcpy(&flags, id_ + TaskID::kLength, sizeof(flags));
|
||||
return flags;
|
||||
}
|
||||
bool ObjectID::CreatedByTask() const { return ::ray::CreatedByTask(this->GetFlags()); }
|
||||
|
||||
bool ObjectID::IsPutObject() const {
|
||||
return ::ray::GetObjectType(this->GetFlags()) == ObjectType::PUT_OBJECT;
|
||||
}
|
||||
|
||||
bool ObjectID::IsReturnObject() const {
|
||||
return ::ray::GetObjectType(this->GetFlags()) == ObjectType::RETURN_OBJECT;
|
||||
}
|
||||
|
||||
uint8_t ObjectID::GetTransportType() const {
|
||||
return ::ray::GetTransportType(this->GetFlags());
|
||||
}
|
||||
|
||||
// This code is from https://sites.google.com/site/murmurhash/
|
||||
@@ -93,6 +201,78 @@ uint64_t MurmurHash64A(const void *key, int len, unsigned int seed) {
|
||||
return h;
|
||||
}
|
||||
|
||||
ActorID ActorID::Of(const JobID &job_id, const TaskID &parent_task_id,
|
||||
const size_t parent_task_counter) {
|
||||
auto data = GenerateUniqueBytes(job_id, parent_task_id, parent_task_counter,
|
||||
ActorID::kUniqueBytesLength);
|
||||
std::copy_n(job_id.Data(), JobID::kLength, std::back_inserter(data));
|
||||
RAY_CHECK(data.size() == kLength);
|
||||
return ActorID::FromBinary(data);
|
||||
}
|
||||
|
||||
ActorID ActorID::NilFromJob(const JobID &job_id) {
|
||||
std::string data(kUniqueBytesLength, 0);
|
||||
FillNil(&data);
|
||||
std::copy_n(job_id.Data(), JobID::kLength, std::back_inserter(data));
|
||||
RAY_CHECK(data.size() == kLength);
|
||||
return ActorID::FromBinary(data);
|
||||
}
|
||||
|
||||
JobID ActorID::JobId() const {
|
||||
RAY_CHECK(!IsNil());
|
||||
return JobID::FromBinary(std::string(
|
||||
reinterpret_cast<const char *>(this->Data() + kUniqueBytesLength), JobID::kLength));
|
||||
}
|
||||
|
||||
TaskID TaskID::ForDriverTask(const JobID &job_id) {
|
||||
std::string data(kUniqueBytesLength, 0);
|
||||
FillNil(&data);
|
||||
const auto dummy_actor_id = ActorID::NilFromJob(job_id);
|
||||
std::copy_n(dummy_actor_id.Data(), ActorID::kLength, std::back_inserter(data));
|
||||
RAY_CHECK(data.size() == TaskID::kLength);
|
||||
return TaskID::FromBinary(data);
|
||||
}
|
||||
|
||||
TaskID TaskID::ForFakeTask() {
|
||||
std::string data(kLength, 0);
|
||||
FillRandom(&data);
|
||||
return TaskID::FromBinary(data);
|
||||
}
|
||||
|
||||
TaskID TaskID::ForActorCreationTask(const ActorID &actor_id) {
|
||||
std::string data(kUniqueBytesLength, 0);
|
||||
FillNil(&data);
|
||||
std::copy_n(actor_id.Data(), ActorID::kLength, std::back_inserter(data));
|
||||
RAY_CHECK(data.size() == TaskID::kLength);
|
||||
return TaskID::FromBinary(data);
|
||||
}
|
||||
|
||||
TaskID TaskID::ForActorTask(const JobID &job_id, const TaskID &parent_task_id,
|
||||
size_t parent_task_counter, const ActorID &actor_id) {
|
||||
std::string data = GenerateUniqueBytes(job_id, parent_task_id, parent_task_counter,
|
||||
TaskID::kUniqueBytesLength);
|
||||
std::copy_n(actor_id.Data(), ActorID::kLength, std::back_inserter(data));
|
||||
RAY_CHECK(data.size() == TaskID::kLength);
|
||||
return TaskID::FromBinary(data);
|
||||
}
|
||||
|
||||
TaskID TaskID::ForNormalTask(const JobID &job_id, const TaskID &parent_task_id,
|
||||
size_t parent_task_counter) {
|
||||
std::string data = GenerateUniqueBytes(job_id, parent_task_id, parent_task_counter,
|
||||
TaskID::kUniqueBytesLength);
|
||||
const auto dummy_actor_id = ActorID::NilFromJob(job_id);
|
||||
std::copy_n(dummy_actor_id.Data(), ActorID::kLength, std::back_inserter(data));
|
||||
RAY_CHECK(data.size() == TaskID::kLength);
|
||||
return TaskID::FromBinary(data);
|
||||
}
|
||||
|
||||
ActorID TaskID::ActorId() const {
|
||||
return ActorID::FromBinary(std::string(
|
||||
reinterpret_cast<const char *>(id_ + kUniqueBytesLength), ActorID::Size()));
|
||||
}
|
||||
|
||||
JobID TaskID::JobId() const { return ActorId().JobId(); }
|
||||
|
||||
TaskID TaskID::ComputeDriverTaskId(const WorkerID &driver_id) {
|
||||
std::string driver_id_str = driver_id.Binary();
|
||||
driver_id_str.resize(Size());
|
||||
@@ -100,41 +280,70 @@ TaskID TaskID::ComputeDriverTaskId(const WorkerID &driver_id) {
|
||||
}
|
||||
|
||||
TaskID ObjectID::TaskId() const {
|
||||
if (!CreatedByTask()) {
|
||||
// TODO(qwang): Should be RAY_CHECK here.
|
||||
RAY_LOG(WARNING) << "Shouldn't call this on a non-task object id: " << this->Hex();
|
||||
}
|
||||
return TaskID::FromBinary(
|
||||
std::string(reinterpret_cast<const char *>(id_), TaskID::Size()));
|
||||
}
|
||||
|
||||
ObjectID ObjectID::ForPut(const TaskID &task_id, int64_t put_index) {
|
||||
RAY_CHECK(put_index >= 1 && put_index <= kMaxTaskPuts) << "index=" << put_index;
|
||||
ObjectID object_id;
|
||||
std::memcpy(object_id.id_, task_id.Binary().c_str(), task_id.Size());
|
||||
object_id.index_ = -put_index;
|
||||
return object_id;
|
||||
ObjectID ObjectID::ForPut(const TaskID &task_id, ObjectIDIndexType put_index,
|
||||
uint8_t transport_type) {
|
||||
RAY_CHECK(put_index >= 1 && put_index <= kMaxObjectIndex) << "index=" << put_index;
|
||||
|
||||
ObjectIDFlagsType flags = 0x0000;
|
||||
SetCreatedByTaskFlag(true, &flags);
|
||||
SetObjectTypeFlag(ObjectType::PUT_OBJECT, &flags);
|
||||
|
||||
SetTransportTypeFlag(transport_type, &flags);
|
||||
|
||||
return GenerateObjectId(task_id.Binary(), flags, put_index);
|
||||
}
|
||||
|
||||
ObjectID ObjectID::ForTaskReturn(const TaskID &task_id, int64_t return_index) {
|
||||
RAY_CHECK(return_index >= 1 && return_index <= kMaxTaskReturns)
|
||||
ObjectIDIndexType ObjectID::ObjectIndex() const {
|
||||
ObjectIDIndexType index;
|
||||
std::memcpy(&index, id_ + TaskID::kLength + kFlagsBytesLength, sizeof(index));
|
||||
return index;
|
||||
}
|
||||
|
||||
ObjectID ObjectID::ForTaskReturn(const TaskID &task_id, ObjectIDIndexType return_index,
|
||||
uint8_t transport_type) {
|
||||
RAY_CHECK(return_index >= 1 && return_index <= kMaxObjectIndex)
|
||||
<< "index=" << return_index;
|
||||
ObjectID object_id;
|
||||
std::memcpy(object_id.id_, task_id.Binary().c_str(), task_id.Size());
|
||||
object_id.index_ = return_index;
|
||||
return object_id;
|
||||
|
||||
ObjectIDFlagsType flags = 0x0000;
|
||||
SetCreatedByTaskFlag(true, &flags);
|
||||
SetObjectTypeFlag(ObjectType::RETURN_OBJECT, &flags);
|
||||
SetTransportTypeFlag(transport_type, &flags);
|
||||
|
||||
return GenerateObjectId(task_id.Binary(), flags, return_index);
|
||||
}
|
||||
|
||||
const TaskID GenerateTaskId(const JobID &job_id, const TaskID &parent_task_id,
|
||||
int parent_task_counter) {
|
||||
// Compute hashes.
|
||||
SHA256_CTX ctx;
|
||||
sha256_init(&ctx);
|
||||
sha256_update(&ctx, reinterpret_cast<const BYTE *>(job_id.Data()), job_id.Size());
|
||||
sha256_update(&ctx, reinterpret_cast<const BYTE *>(parent_task_id.Data()),
|
||||
parent_task_id.Size());
|
||||
sha256_update(&ctx, (const BYTE *)&parent_task_counter, sizeof(parent_task_counter));
|
||||
ObjectID ObjectID::FromRandom() {
|
||||
ObjectIDFlagsType flags = 0x0000;
|
||||
SetCreatedByTaskFlag(false, &flags);
|
||||
// No need to set transport type for a random object id.
|
||||
// No need to assign put_index/return_index bytes.
|
||||
std::vector<uint8_t> task_id_bytes(TaskID::kLength, 0x0);
|
||||
FillRandom(&task_id_bytes);
|
||||
|
||||
// Compute the final task ID from the hash.
|
||||
BYTE buff[DIGEST_SIZE];
|
||||
sha256_final(&ctx, buff);
|
||||
return TaskID::FromBinary(std::string(buff, buff + TaskID::Size()));
|
||||
return GenerateObjectId(
|
||||
std::string(reinterpret_cast<const char *>(task_id_bytes.data()),
|
||||
task_id_bytes.size()),
|
||||
flags);
|
||||
}
|
||||
|
||||
ObjectID ObjectID::GenerateObjectId(const std::string &task_id_binary,
|
||||
ObjectIDFlagsType flags,
|
||||
ObjectIDIndexType object_index) {
|
||||
RAY_CHECK(task_id_binary.size() == TaskID::Size());
|
||||
ObjectID ret = ObjectID::Nil();
|
||||
std::memcpy(ret.id_, task_id_binary.c_str(), TaskID::kLength);
|
||||
std::memcpy(ret.id_ + TaskID::kLength, &flags, sizeof(flags));
|
||||
std::memcpy(ret.id_ + TaskID::kLength + kFlagsBytesLength, &object_index,
|
||||
sizeof(object_index));
|
||||
return ret;
|
||||
}
|
||||
|
||||
const ActorHandleID ComputeNextActorHandleId(const ActorHandleID &actor_handle_id,
|
||||
@@ -172,6 +381,7 @@ JobID JobID::FromInt(uint32_t value) {
|
||||
|
||||
ID_OSTREAM_OPERATOR(UniqueID);
|
||||
ID_OSTREAM_OPERATOR(JobID);
|
||||
ID_OSTREAM_OPERATOR(ActorID);
|
||||
ID_OSTREAM_OPERATOR(TaskID);
|
||||
ID_OSTREAM_OPERATOR(ObjectID);
|
||||
|
||||
|
||||
+213
-38
@@ -13,10 +13,12 @@
|
||||
#include "plasma/common.h"
|
||||
#include "ray/common/constants.h"
|
||||
#include "ray/util/logging.h"
|
||||
#include "ray/util/util.h"
|
||||
#include "ray/util/visibility.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
class TaskID;
|
||||
class WorkerID;
|
||||
class UniqueID;
|
||||
class JobID;
|
||||
@@ -27,13 +29,29 @@ class JobID;
|
||||
/// A helper function that get the `DriverID` of the given job.
|
||||
WorkerID ComputeDriverIdFromJob(const JobID &job_id);
|
||||
|
||||
/// The type of this object. `PUT_OBJECT` indicates this object
|
||||
/// is generated through `ray.put` during the task's execution.
|
||||
/// And `RETURN_OBJECT` indicates this object is the return value
|
||||
/// of a task.
|
||||
enum class ObjectType : uint8_t {
|
||||
PUT_OBJECT = 0x0,
|
||||
RETURN_OBJECT = 0x1,
|
||||
};
|
||||
|
||||
using ObjectIDFlagsType = uint16_t;
|
||||
using ObjectIDIndexType = uint32_t;
|
||||
|
||||
// Declaration.
|
||||
std::mt19937 RandomlySeededMersenneTwister();
|
||||
uint64_t MurmurHash64A(const void *key, int len, unsigned int seed);
|
||||
|
||||
// Change the compiler alignment to 1 byte (default is 8).
|
||||
#pragma pack(push, 1)
|
||||
|
||||
/// The `ID`s of Ray.
|
||||
///
|
||||
/// Please refer to the specification of Ray UniqueIDs.
|
||||
/// https://github.com/ray-project/ray/blob/master/src/ray/design_docs/id_specification.md
|
||||
|
||||
template <typename T>
|
||||
class BaseID {
|
||||
public:
|
||||
@@ -78,78 +96,251 @@ class UniqueID : public BaseID<UniqueID> {
|
||||
|
||||
class JobID : public BaseID<JobID> {
|
||||
public:
|
||||
static constexpr int64_t length = 4;
|
||||
static constexpr int64_t kLength = 4;
|
||||
|
||||
// TODO(qwang): Use `uint32_t` to store the data.
|
||||
static JobID FromInt(uint32_t value);
|
||||
|
||||
static size_t Size() { return length; }
|
||||
static size_t Size() { return kLength; }
|
||||
|
||||
static JobID FromRandom() = delete;
|
||||
|
||||
JobID() : BaseID() {}
|
||||
|
||||
private:
|
||||
uint8_t id_[length];
|
||||
uint8_t id_[kLength];
|
||||
};
|
||||
|
||||
class ActorID : public BaseID<ActorID> {
|
||||
private:
|
||||
static constexpr size_t kUniqueBytesLength = 4;
|
||||
|
||||
public:
|
||||
/// Length of `ActorID` in bytes.
|
||||
static constexpr size_t kLength = kUniqueBytesLength + JobID::kLength;
|
||||
|
||||
/// Size of `ActorID` in bytes.
|
||||
///
|
||||
/// \return Size of `ActorID` in bytes.
|
||||
static size_t Size() { return kLength; }
|
||||
|
||||
/// Creates an `ActorID` by hashing the given information.
|
||||
///
|
||||
/// \param job_id The job id to which this actor belongs.
|
||||
/// \param parent_task_id The id of the task which created this actor.
|
||||
/// \param parent_task_counter The counter of the parent task.
|
||||
///
|
||||
/// \return The random `ActorID`.
|
||||
static ActorID Of(const JobID &job_id, const TaskID &parent_task_id,
|
||||
const size_t parent_task_counter);
|
||||
|
||||
/// Creates a nil ActorID with the given job.
|
||||
///
|
||||
/// \param job_id The job id to which this actor belongs.
|
||||
///
|
||||
/// \return The `ActorID` with unique bytes being nil.
|
||||
static ActorID NilFromJob(const JobID &job_id);
|
||||
|
||||
static ActorID FromRandom() = delete;
|
||||
|
||||
/// Constructor of `ActorID`.
|
||||
ActorID() : BaseID() {}
|
||||
|
||||
/// Get the job id to which this actor belongs.
|
||||
///
|
||||
/// \return The job id to which this actor belongs.
|
||||
JobID JobId() const;
|
||||
|
||||
private:
|
||||
uint8_t id_[kLength];
|
||||
};
|
||||
|
||||
class TaskID : public BaseID<TaskID> {
|
||||
private:
|
||||
static constexpr size_t kUniqueBytesLength = 6;
|
||||
|
||||
public:
|
||||
static constexpr size_t kLength = kUniqueBytesLength + ActorID::kLength;
|
||||
|
||||
TaskID() : BaseID() {}
|
||||
static size_t Size() { return kTaskIDSize; }
|
||||
|
||||
static size_t Size() { return kLength; }
|
||||
|
||||
static TaskID ComputeDriverTaskId(const WorkerID &driver_id);
|
||||
|
||||
static TaskID FromRandom() = delete;
|
||||
|
||||
/// The ID generated for driver task.
|
||||
static TaskID ForDriverTask(const JobID &job_id);
|
||||
|
||||
/// Generate driver task id for the given job.
|
||||
static TaskID ForFakeTask();
|
||||
|
||||
/// Creates a TaskID for an actor creation task.
|
||||
///
|
||||
/// \param actor_id The ID of the actor that will be created
|
||||
/// by this actor creation task.
|
||||
///
|
||||
/// \return The ID of the actor creation task.
|
||||
static TaskID ForActorCreationTask(const ActorID &actor_id);
|
||||
|
||||
/// Creates a TaskID for actor task.
|
||||
///
|
||||
/// \param job_id The ID of the job to which this task belongs.
|
||||
/// \param parent_task_id The ID of the parent task which submitted this task.
|
||||
/// \param parent_task_counter A count of the number of tasks submitted by the
|
||||
/// parent task before this one.
|
||||
/// \param actor_id The ID of the actor to which this task belongs.
|
||||
///
|
||||
/// \return The ID of the actor task.
|
||||
static TaskID ForActorTask(const JobID &job_id, const TaskID &parent_task_id,
|
||||
size_t parent_task_counter, const ActorID &actor_id);
|
||||
|
||||
/// Creates a TaskID for normal task.
|
||||
///
|
||||
/// \param job_id The ID of the job to which this task belongs.
|
||||
/// \param parent_task_id The ID of the parent task which submitted this task.
|
||||
/// \param parent_task_counter A count of the number of tasks submitted by the
|
||||
/// parent task before this one.
|
||||
///
|
||||
/// \return The ID of the normal task.
|
||||
static TaskID ForNormalTask(const JobID &job_id, const TaskID &parent_task_id,
|
||||
size_t parent_task_counter);
|
||||
|
||||
/// Get the id of the actor to which this task belongs.
|
||||
///
|
||||
/// \return The `ActorID` of the actor which creates this task.
|
||||
ActorID ActorId() const;
|
||||
|
||||
/// Get the id of the job to which this task belongs.
|
||||
///
|
||||
/// \return The `JobID` of the job which creates this task.
|
||||
JobID JobId() const;
|
||||
|
||||
private:
|
||||
uint8_t id_[kTaskIDSize];
|
||||
uint8_t id_[kLength];
|
||||
};
|
||||
|
||||
class ObjectID : public BaseID<ObjectID> {
|
||||
private:
|
||||
static constexpr size_t kIndexBytesLength = sizeof(ObjectIDIndexType);
|
||||
|
||||
static constexpr size_t kFlagsBytesLength = sizeof(ObjectIDFlagsType);
|
||||
|
||||
public:
|
||||
/// The maximum number of objects that can be returned or put by a task.
|
||||
static constexpr int64_t kMaxObjectIndex = ((int64_t)1 << kObjectIdIndexSize) - 1;
|
||||
|
||||
/// The length of ObjectID in bytes.
|
||||
static constexpr size_t kLength =
|
||||
kIndexBytesLength + kFlagsBytesLength + TaskID::kLength;
|
||||
|
||||
ObjectID() : BaseID() {}
|
||||
static size_t Size() { return kUniqueIDSize; }
|
||||
|
||||
/// The maximum index of object.
|
||||
///
|
||||
/// It also means the max number of objects created (put or return) by one task.
|
||||
///
|
||||
/// \return The maximum index of object.
|
||||
static uint64_t MaxObjectIndex() { return kMaxObjectIndex; }
|
||||
|
||||
static size_t Size() { return kLength; }
|
||||
|
||||
/// Generate ObjectID by the given binary string of a plasma id.
|
||||
///
|
||||
/// \param from The binary string of the given plasma id.
|
||||
/// \return The ObjectID converted from a binary string of the plasma id.
|
||||
static ObjectID FromPlasmaIdBinary(const std::string &from);
|
||||
|
||||
plasma::ObjectID ToPlasmaId() const;
|
||||
|
||||
ObjectID(const plasma::UniqueID &from);
|
||||
|
||||
/// Get the index of this object in the task that created it.
|
||||
///
|
||||
/// \return The index of object creation according to the task that created
|
||||
/// this object. This is positive if the task returned the object and negative
|
||||
/// if created by a put.
|
||||
int32_t ObjectIndex() const { return index_; }
|
||||
/// this object.
|
||||
ObjectIDIndexType ObjectIndex() const;
|
||||
|
||||
/// Compute the task ID of the task that created the object.
|
||||
///
|
||||
/// \return The task ID of the task that created this object.
|
||||
TaskID TaskId() const;
|
||||
|
||||
/// Whether this object is created by a task.
|
||||
///
|
||||
/// \return True if this object is created by a task, otherwise false.
|
||||
bool CreatedByTask() const;
|
||||
|
||||
/// Whether this object was created through `ray.put`.
|
||||
///
|
||||
/// \return True if this object was created through `ray.put`.
|
||||
bool IsPutObject() const;
|
||||
|
||||
/// Whether this object was created as a return object of a task.
|
||||
///
|
||||
/// \return True if this object is a return value of a task.
|
||||
bool IsReturnObject() const;
|
||||
|
||||
/// Get the transport type of this object.
|
||||
///
|
||||
/// \return The type of the transport which is used to transfer this object.
|
||||
uint8_t GetTransportType() const;
|
||||
|
||||
/// Compute the object ID of an object put by the task.
|
||||
///
|
||||
/// \param task_id The task ID of the task that created the object.
|
||||
/// \param index What index of the object put in the task.
|
||||
/// \param transport_type Which type of the transport that is used to
|
||||
/// transfer this object.
|
||||
///
|
||||
/// \return The computed object ID.
|
||||
static ObjectID ForPut(const TaskID &task_id, int64_t put_index);
|
||||
static ObjectID ForPut(const TaskID &task_id, ObjectIDIndexType put_index,
|
||||
uint8_t transport_type);
|
||||
|
||||
/// Compute the object ID of an object returned by the task.
|
||||
///
|
||||
/// \param task_id The task ID of the task that created the object.
|
||||
/// \param return_index What index of the object returned by in the task.
|
||||
/// \param transport_type Which type of the transport that is used to
|
||||
/// transfer this object.
|
||||
///
|
||||
/// \return The computed object ID.
|
||||
static ObjectID ForTaskReturn(const TaskID &task_id, int64_t return_index);
|
||||
static ObjectID ForTaskReturn(const TaskID &task_id, ObjectIDIndexType return_index,
|
||||
uint8_t transport_type);
|
||||
|
||||
/// Create an object id randomly.
|
||||
///
|
||||
/// \param transport_type Which type of the transport that is used to
|
||||
/// transfer this object.
|
||||
///
|
||||
/// \return A random object id.
|
||||
static ObjectID FromRandom();
|
||||
|
||||
private:
|
||||
uint8_t id_[kTaskIDSize];
|
||||
int32_t index_;
|
||||
/// A helper method to generate an ObjectID.
|
||||
static ObjectID GenerateObjectId(const std::string &task_id_binary,
|
||||
ObjectIDFlagsType flags,
|
||||
ObjectIDIndexType object_index = 0);
|
||||
|
||||
/// Get the flags out of this object id.
|
||||
ObjectIDFlagsType GetFlags() const;
|
||||
|
||||
private:
|
||||
uint8_t id_[kLength];
|
||||
};
|
||||
|
||||
static_assert(sizeof(JobID) == JobID::length + sizeof(size_t),
|
||||
static_assert(sizeof(JobID) == JobID::kLength + sizeof(size_t),
|
||||
"JobID size is not as expected");
|
||||
static_assert(sizeof(TaskID) == kTaskIDSize + sizeof(size_t),
|
||||
static_assert(sizeof(ActorID) == ActorID::kLength + sizeof(size_t),
|
||||
"ActorID size is not as expected");
|
||||
static_assert(sizeof(TaskID) == TaskID::kLength + sizeof(size_t),
|
||||
"TaskID size is not as expected");
|
||||
static_assert(sizeof(ObjectID) == sizeof(int32_t) + sizeof(TaskID),
|
||||
static_assert(sizeof(ObjectID) == ObjectID::kLength + sizeof(size_t),
|
||||
"ObjectID size is not as expected");
|
||||
|
||||
std::ostream &operator<<(std::ostream &os, const UniqueID &id);
|
||||
std::ostream &operator<<(std::ostream &os, const JobID &id);
|
||||
std::ostream &operator<<(std::ostream &os, const ActorID &id);
|
||||
std::ostream &operator<<(std::ostream &os, const TaskID &id);
|
||||
std::ostream &operator<<(std::ostream &os, const ObjectID &id);
|
||||
|
||||
@@ -178,15 +369,6 @@ std::ostream &operator<<(std::ostream &os, const ObjectID &id);
|
||||
// Restore the compiler alignment to defult (8 bytes).
|
||||
#pragma pack(pop)
|
||||
|
||||
/// Generate a task ID from the given info.
|
||||
///
|
||||
/// \param job_id The job that creates the task.
|
||||
/// \param parent_task_id The parent task of this task.
|
||||
/// \param parent_task_counter The task index of the worker.
|
||||
/// \return The task ID generated from the given info.
|
||||
const TaskID GenerateTaskId(const JobID &job_id, const TaskID &parent_task_id,
|
||||
int parent_task_counter);
|
||||
|
||||
/// Compute the next actor handle ID of a new actor handle during a fork operation.
|
||||
///
|
||||
/// \param actor_handle_id The actor handle ID of original actor.
|
||||
@@ -205,22 +387,14 @@ BaseID<T>::BaseID() {
|
||||
template <typename T>
|
||||
T BaseID<T>::FromRandom() {
|
||||
std::string data(T::Size(), 0);
|
||||
// NOTE(pcm): The right way to do this is to have one std::mt19937 per
|
||||
// thread (using the thread_local keyword), but that's not supported on
|
||||
// older versions of macOS (see https://stackoverflow.com/a/29929949)
|
||||
static std::mutex random_engine_mutex;
|
||||
std::lock_guard<std::mutex> lock(random_engine_mutex);
|
||||
static std::mt19937 generator = RandomlySeededMersenneTwister();
|
||||
std::uniform_int_distribution<uint32_t> dist(0, std::numeric_limits<uint8_t>::max());
|
||||
for (int i = 0; i < T::Size(); i++) {
|
||||
data[i] = static_cast<uint8_t>(dist(generator));
|
||||
}
|
||||
FillRandom(&data);
|
||||
return T::FromBinary(data);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T BaseID<T>::FromBinary(const std::string &binary) {
|
||||
RAY_CHECK(binary.size() == T::Size());
|
||||
RAY_CHECK(binary.size() == T::Size())
|
||||
<< "expected size is " << T::Size() << ", but got " << binary.size();
|
||||
T t = T::Nil();
|
||||
std::memcpy(t.MutableData(), binary.data(), T::Size());
|
||||
return t;
|
||||
@@ -302,6 +476,7 @@ namespace std {
|
||||
|
||||
DEFINE_UNIQUE_ID(UniqueID);
|
||||
DEFINE_UNIQUE_ID(JobID);
|
||||
DEFINE_UNIQUE_ID(ActorID);
|
||||
DEFINE_UNIQUE_ID(TaskID);
|
||||
DEFINE_UNIQUE_ID(ObjectID);
|
||||
#include "id_def.h"
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
DEFINE_UNIQUE_ID(FunctionID)
|
||||
DEFINE_UNIQUE_ID(ActorClassID)
|
||||
DEFINE_UNIQUE_ID(ActorID)
|
||||
DEFINE_UNIQUE_ID(ActorHandleID)
|
||||
DEFINE_UNIQUE_ID(ActorCheckpointID)
|
||||
DEFINE_UNIQUE_ID(WorkerID)
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ray/common/common_protocol.h"
|
||||
#include "ray/common/task/task_spec.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
void TestReturnObjectId(const TaskID &task_id, int64_t return_index,
|
||||
uint8_t transport_type) {
|
||||
// Round trip test for computing the object ID for a task's return value,
|
||||
// then computing the task ID that created the object.
|
||||
ObjectID return_id = ObjectID::ForTaskReturn(task_id, return_index, transport_type);
|
||||
ASSERT_TRUE(return_id.CreatedByTask());
|
||||
ASSERT_TRUE(return_id.IsReturnObject());
|
||||
ASSERT_FALSE(return_id.IsPutObject());
|
||||
ASSERT_EQ(return_id.TaskId(), task_id);
|
||||
ASSERT_TRUE(transport_type == return_id.GetTransportType());
|
||||
ASSERT_EQ(return_id.ObjectIndex(), return_index);
|
||||
}
|
||||
|
||||
void TestPutObjectId(const TaskID &task_id, int64_t put_index) {
|
||||
// Round trip test for computing the object ID for a task's put value, then
|
||||
// computing the task ID that created the object.
|
||||
ObjectID put_id = ObjectID::ForPut(task_id, put_index, 1);
|
||||
ASSERT_TRUE(put_id.CreatedByTask());
|
||||
ASSERT_FALSE(put_id.IsReturnObject());
|
||||
ASSERT_TRUE(put_id.IsPutObject());
|
||||
ASSERT_EQ(put_id.TaskId(), task_id);
|
||||
ASSERT_TRUE(1 == put_id.GetTransportType());
|
||||
ASSERT_EQ(put_id.ObjectIndex(), put_index);
|
||||
}
|
||||
|
||||
void TestRandomObjectId() {
|
||||
// Round trip test for computing the object ID from random.
|
||||
const ObjectID random_object_id = ObjectID::FromRandom();
|
||||
ASSERT_FALSE(random_object_id.CreatedByTask());
|
||||
}
|
||||
|
||||
const static JobID kDefaultJobId = JobID::FromInt(199);
|
||||
|
||||
const static TaskID kDefaultDriverTaskId = TaskID::ForDriverTask(kDefaultJobId);
|
||||
|
||||
TEST(ActorIDTest, TestActorID) {
|
||||
{
|
||||
// test from binary
|
||||
const ActorID actor_id_1 = ActorID::Of(kDefaultJobId, kDefaultDriverTaskId, 1);
|
||||
const auto actor_id_1_binary = actor_id_1.Binary();
|
||||
const auto actor_id_2 = ActorID::FromBinary(actor_id_1_binary);
|
||||
ASSERT_EQ(actor_id_1, actor_id_2);
|
||||
}
|
||||
|
||||
{
|
||||
// test get job id
|
||||
const ActorID actor_id = ActorID::Of(kDefaultJobId, kDefaultDriverTaskId, 1);
|
||||
ASSERT_EQ(kDefaultJobId, actor_id.JobId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TaskIDTest, TestTaskID) {
|
||||
// Round trip test for task ID.
|
||||
{
|
||||
const ActorID actor_id = ActorID::Of(kDefaultJobId, kDefaultDriverTaskId, 1);
|
||||
const TaskID task_id_1 =
|
||||
TaskID::ForActorTask(kDefaultJobId, kDefaultDriverTaskId, 1, actor_id);
|
||||
ASSERT_EQ(actor_id, task_id_1.ActorId());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ObjectIDTest, TestObjectID) {
|
||||
const static ActorID default_actor_id =
|
||||
ActorID::Of(kDefaultJobId, kDefaultDriverTaskId, 1);
|
||||
const static TaskID default_task_id =
|
||||
TaskID::ForActorTask(kDefaultJobId, kDefaultDriverTaskId, 1, default_actor_id);
|
||||
|
||||
{
|
||||
// test for put
|
||||
TestPutObjectId(default_task_id, 1);
|
||||
TestPutObjectId(default_task_id, 2);
|
||||
TestPutObjectId(default_task_id, ObjectID::kMaxObjectIndex);
|
||||
}
|
||||
|
||||
{
|
||||
// test for return
|
||||
TestReturnObjectId(default_task_id, 1, 2);
|
||||
TestReturnObjectId(default_task_id, 2, 3);
|
||||
TestReturnObjectId(default_task_id, ObjectID::kMaxObjectIndex, 4);
|
||||
}
|
||||
|
||||
{
|
||||
// test random object id
|
||||
TestRandomObjectId();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NilTest, TestIsNil) {
|
||||
ASSERT_TRUE(TaskID().IsNil());
|
||||
ASSERT_TRUE(TaskID::Nil().IsNil());
|
||||
ASSERT_TRUE(ObjectID().IsNil());
|
||||
ASSERT_TRUE(ObjectID::Nil().IsNil());
|
||||
}
|
||||
|
||||
} // namespace ray
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -38,7 +38,7 @@ size_t TaskSpecification::NumArgs() const { return message_->args_size(); }
|
||||
size_t TaskSpecification::NumReturns() const { return message_->num_returns(); }
|
||||
|
||||
ObjectID TaskSpecification::ReturnId(size_t return_index) const {
|
||||
return ObjectID::ForTaskReturn(TaskId(), return_index + 1);
|
||||
return ObjectID::ForTaskReturn(TaskId(), return_index + 1, /*transport_type=*/0);
|
||||
}
|
||||
|
||||
bool TaskSpecification::ArgByRef(size_t arg_index) const {
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "ray/common/common_protocol.h"
|
||||
#include "ray/common/task/task_spec.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
void TestTaskReturnId(const TaskID &task_id, int64_t return_index) {
|
||||
// Round trip test for computing the object ID for a task's return value,
|
||||
// then computing the task ID that created the object.
|
||||
ObjectID return_id = ObjectID::ForTaskReturn(task_id, return_index);
|
||||
ASSERT_EQ(return_id.TaskId(), task_id);
|
||||
ASSERT_EQ(return_id.ObjectIndex(), return_index);
|
||||
}
|
||||
|
||||
void TestTaskPutId(const TaskID &task_id, int64_t put_index) {
|
||||
// Round trip test for computing the object ID for a task's put value, then
|
||||
// computing the task ID that created the object.
|
||||
ObjectID put_id = ObjectID::ForPut(task_id, put_index);
|
||||
ASSERT_EQ(put_id.TaskId(), task_id);
|
||||
ASSERT_EQ(put_id.ObjectIndex(), -1 * put_index);
|
||||
}
|
||||
|
||||
TEST(TaskSpecTest, TestTaskReturnIds) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
|
||||
// Check that we can compute between a task ID and the object IDs of its
|
||||
// return values and puts.
|
||||
TestTaskReturnId(task_id, 1);
|
||||
TestTaskReturnId(task_id, 2);
|
||||
TestTaskReturnId(task_id, kMaxTaskReturns);
|
||||
TestTaskPutId(task_id, 1);
|
||||
TestTaskPutId(task_id, 2);
|
||||
TestTaskPutId(task_id, kMaxTaskPuts);
|
||||
}
|
||||
|
||||
TEST(IdPropertyTest, TestIdProperty) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
ASSERT_EQ(task_id, TaskID::FromBinary(task_id.Binary()));
|
||||
ObjectID object_id = ObjectID::FromRandom();
|
||||
ASSERT_EQ(object_id, ObjectID::FromBinary(object_id.Binary()));
|
||||
|
||||
ASSERT_TRUE(TaskID().IsNil());
|
||||
ASSERT_TRUE(TaskID::Nil().IsNil());
|
||||
ASSERT_TRUE(ObjectID().IsNil());
|
||||
ASSERT_TRUE(ObjectID::Nil().IsNil());
|
||||
}
|
||||
|
||||
} // namespace ray
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
@@ -22,9 +22,9 @@ class TaskSpecBuilder {
|
||||
///
|
||||
/// \return Reference to the builder object itself.
|
||||
TaskSpecBuilder &SetCommonTaskSpec(
|
||||
const Language &language, const std::vector<std::string> &function_descriptor,
|
||||
const JobID &job_id, const TaskID &parent_task_id, uint64_t parent_counter,
|
||||
uint64_t num_returns,
|
||||
const TaskID &task_id, const Language &language,
|
||||
const std::vector<std::string> &function_descriptor, const JobID &job_id,
|
||||
const TaskID &parent_task_id, uint64_t parent_counter, uint64_t num_returns,
|
||||
const std::unordered_map<std::string, double> &required_resources,
|
||||
const std::unordered_map<std::string, double> &required_placement_resources) {
|
||||
message_->set_type(TaskType::NORMAL_TASK);
|
||||
@@ -33,8 +33,7 @@ class TaskSpecBuilder {
|
||||
message_->add_function_descriptor(fd);
|
||||
}
|
||||
message_->set_job_id(job_id.Binary());
|
||||
message_->set_task_id(
|
||||
GenerateTaskId(job_id, parent_task_id, parent_counter).Binary());
|
||||
message_->set_task_id(task_id.Binary());
|
||||
message_->set_parent_task_id(parent_task_id.Binary());
|
||||
message_->set_parent_counter(parent_counter);
|
||||
message_->set_num_returns(num_returns);
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace ray {
|
||||
/// per-thread context for core worker.
|
||||
struct WorkerThreadContext {
|
||||
WorkerThreadContext()
|
||||
: current_task_id_(TaskID::FromRandom()), task_index_(0), put_index_(0) {}
|
||||
: current_task_id_(TaskID::ForFakeTask()), task_index_(0), put_index_(0) {}
|
||||
|
||||
int GetNextTaskIndex() { return ++task_index_; }
|
||||
|
||||
@@ -54,8 +54,9 @@ WorkerContext::WorkerContext(WorkerType worker_type, const JobID &job_id)
|
||||
// For worker main thread which initializes the WorkerContext,
|
||||
// set task_id according to whether current worker is a driver.
|
||||
// (For other threads it's set to random ID via GetThreadContext).
|
||||
GetThreadContext().SetCurrentTaskId(
|
||||
(worker_type_ == WorkerType::DRIVER) ? TaskID::FromRandom() : TaskID::Nil());
|
||||
GetThreadContext().SetCurrentTaskId((worker_type_ == WorkerType::DRIVER)
|
||||
? TaskID::ForDriverTask(job_id)
|
||||
: TaskID::Nil());
|
||||
}
|
||||
|
||||
const WorkerType WorkerContext::GetWorkerType() const { return worker_type_; }
|
||||
@@ -76,7 +77,6 @@ void WorkerContext::SetCurrentTask(const TaskSpecification &task_spec) {
|
||||
current_job_id_ = task_spec.JobId();
|
||||
GetThreadContext().SetCurrentTask(task_spec);
|
||||
}
|
||||
|
||||
std::shared_ptr<const TaskSpecification> WorkerContext::GetCurrentTask() const {
|
||||
return GetThreadContext().GetCurrentTask();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ CoreWorkerObjectInterface::CoreWorkerObjectInterface(
|
||||
|
||||
Status CoreWorkerObjectInterface::Put(const RayObject &object, ObjectID *object_id) {
|
||||
ObjectID put_id = ObjectID::ForPut(worker_context_.GetCurrentTaskID(),
|
||||
worker_context_.GetNextPutIndex());
|
||||
worker_context_.GetNextPutIndex(),
|
||||
/*transport_type=*/0);
|
||||
*object_id = put_id;
|
||||
return Put(object, put_id);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,11 @@ ActorHandle::ActorHandle(
|
||||
*inner_.mutable_actor_creation_task_function_descriptor() = {
|
||||
actor_creation_task_function_descriptor.begin(),
|
||||
actor_creation_task_function_descriptor.end()};
|
||||
inner_.set_actor_cursor(actor_id.Data(), actor_id.Size());
|
||||
const auto &actor_creation_task_id = TaskID::ForActorCreationTask(actor_id);
|
||||
const auto &actor_creation_dummy_object_id =
|
||||
ObjectID::ForTaskReturn(actor_creation_task_id, /*index=*/1, /*transport_type=*/0);
|
||||
inner_.set_actor_cursor(actor_creation_dummy_object_id.Data(),
|
||||
actor_creation_dummy_object_id.Size());
|
||||
inner_.set_is_direct_call(is_direct_call);
|
||||
}
|
||||
|
||||
@@ -109,17 +113,16 @@ CoreWorkerTaskInterface::CoreWorkerTaskInterface(
|
||||
}
|
||||
|
||||
void CoreWorkerTaskInterface::BuildCommonTaskSpec(
|
||||
TaskSpecBuilder &builder, const RayFunction &function,
|
||||
const std::vector<TaskArg> &args, uint64_t num_returns,
|
||||
TaskSpecBuilder &builder, const TaskID &task_id, const int task_index,
|
||||
const RayFunction &function, const std::vector<TaskArg> &args, uint64_t num_returns,
|
||||
const std::unordered_map<std::string, double> &required_resources,
|
||||
const std::unordered_map<std::string, double> &required_placement_resources,
|
||||
std::vector<ObjectID> *return_ids) {
|
||||
auto next_task_index = worker_context_.GetNextTaskIndex();
|
||||
// Build common task spec.
|
||||
builder.SetCommonTaskSpec(
|
||||
function.language, function.function_descriptor, worker_context_.GetCurrentJobID(),
|
||||
worker_context_.GetCurrentTaskID(), next_task_index, num_returns,
|
||||
required_resources, required_placement_resources);
|
||||
builder.SetCommonTaskSpec(task_id, function.language, function.function_descriptor,
|
||||
worker_context_.GetCurrentJobID(),
|
||||
worker_context_.GetCurrentTaskID(), task_index, num_returns,
|
||||
required_resources, required_placement_resources);
|
||||
// Set task arguments.
|
||||
for (const auto &arg : args) {
|
||||
if (arg.IsPassedByReference()) {
|
||||
@@ -130,10 +133,9 @@ void CoreWorkerTaskInterface::BuildCommonTaskSpec(
|
||||
}
|
||||
|
||||
// Compute return IDs.
|
||||
const auto task_id = TaskID::FromBinary(builder.GetMessage().task_id());
|
||||
(*return_ids).resize(num_returns);
|
||||
for (int i = 0; i < num_returns; i++) {
|
||||
(*return_ids)[i] = ObjectID::ForTaskReturn(task_id, i + 1);
|
||||
(*return_ids)[i] = ObjectID::ForTaskReturn(task_id, i + 1, /*transport_type=*/0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,8 +144,12 @@ Status CoreWorkerTaskInterface::SubmitTask(const RayFunction &function,
|
||||
const TaskOptions &task_options,
|
||||
std::vector<ObjectID> *return_ids) {
|
||||
TaskSpecBuilder builder;
|
||||
BuildCommonTaskSpec(builder, function, args, task_options.num_returns,
|
||||
task_options.resources, {}, return_ids);
|
||||
const int next_task_index = worker_context_.GetNextTaskIndex();
|
||||
const auto task_id =
|
||||
TaskID::ForNormalTask(worker_context_.GetCurrentJobID(),
|
||||
worker_context_.GetCurrentTaskID(), next_task_index);
|
||||
BuildCommonTaskSpec(builder, task_id, next_task_index, function, args,
|
||||
task_options.num_returns, task_options.resources, {}, return_ids);
|
||||
return task_submitters_[TaskTransportType::RAYLET]->SubmitTask(builder.Build());
|
||||
}
|
||||
|
||||
@@ -151,12 +157,16 @@ Status CoreWorkerTaskInterface::CreateActor(
|
||||
const RayFunction &function, const std::vector<TaskArg> &args,
|
||||
const ActorCreationOptions &actor_creation_options,
|
||||
std::unique_ptr<ActorHandle> *actor_handle) {
|
||||
const int next_task_index = worker_context_.GetNextTaskIndex();
|
||||
const ActorID actor_id =
|
||||
ActorID::Of(worker_context_.GetCurrentJobID(), worker_context_.GetCurrentTaskID(),
|
||||
next_task_index);
|
||||
const TaskID actor_creation_task_id = TaskID::ForActorCreationTask(actor_id);
|
||||
std::vector<ObjectID> return_ids;
|
||||
TaskSpecBuilder builder;
|
||||
BuildCommonTaskSpec(builder, function, args, 1, actor_creation_options.resources,
|
||||
actor_creation_options.resources, &return_ids);
|
||||
|
||||
const ActorID actor_id = ActorID::FromBinary(return_ids[0].Binary());
|
||||
BuildCommonTaskSpec(builder, actor_creation_task_id, next_task_index, function, args, 1,
|
||||
actor_creation_options.resources, actor_creation_options.resources,
|
||||
&return_ids);
|
||||
builder.SetActorCreationTaskSpec(actor_id, actor_creation_options.max_reconstructions,
|
||||
{});
|
||||
|
||||
@@ -179,13 +189,19 @@ Status CoreWorkerTaskInterface::SubmitActorTask(ActorHandle &actor_handle,
|
||||
|
||||
// Build common task spec.
|
||||
TaskSpecBuilder builder;
|
||||
BuildCommonTaskSpec(builder, function, args, num_returns, task_options.resources, {},
|
||||
return_ids);
|
||||
const int next_task_index = worker_context_.GetNextTaskIndex();
|
||||
const auto actor_task_id = TaskID::ForActorTask(
|
||||
worker_context_.GetCurrentJobID(), worker_context_.GetCurrentTaskID(),
|
||||
next_task_index, actor_handle.ActorID());
|
||||
BuildCommonTaskSpec(builder, actor_task_id, next_task_index, function, args,
|
||||
num_returns, task_options.resources, {}, return_ids);
|
||||
|
||||
std::unique_lock<std::mutex> guard(actor_handle.mutex_);
|
||||
// Build actor task spec.
|
||||
const auto actor_creation_task_id =
|
||||
TaskID::ForActorCreationTask(actor_handle.ActorID());
|
||||
const auto actor_creation_dummy_object_id =
|
||||
ObjectID::FromBinary(actor_handle.ActorID().Binary());
|
||||
ObjectID::ForTaskReturn(actor_creation_task_id, /*index=*/1, /*transport_type=*/0);
|
||||
builder.SetActorTaskSpec(
|
||||
actor_handle.ActorID(), actor_handle.ActorHandleID(),
|
||||
actor_creation_dummy_object_id,
|
||||
|
||||
@@ -170,6 +170,8 @@ class CoreWorkerTaskInterface {
|
||||
/// Build common attributes of the task spec, and compute return ids.
|
||||
///
|
||||
/// \param[in] builder Builder to build a `TaskSpec`.
|
||||
/// \param[in] task_id The ID of this task.
|
||||
/// \param[in] task_index The task index used to build this task.
|
||||
/// \param[in] function The remote function to execute.
|
||||
/// \param[in] args Arguments of this task.
|
||||
/// \param[in] num_returns Number of returns.
|
||||
@@ -179,8 +181,8 @@ class CoreWorkerTaskInterface {
|
||||
/// \param[out] return_ids Return IDs.
|
||||
/// \return Void.
|
||||
void BuildCommonTaskSpec(
|
||||
TaskSpecBuilder &builder, const RayFunction &function,
|
||||
const std::vector<TaskArg> &args, uint64_t num_returns,
|
||||
TaskSpecBuilder &builder, const TaskID &task_id, const int task_index,
|
||||
const RayFunction &function, const std::vector<TaskArg> &args, uint64_t num_returns,
|
||||
const std::unordered_map<std::string, double> &required_resources,
|
||||
const std::unordered_map<std::string, double> &required_placement_resources,
|
||||
std::vector<ObjectID> *return_ids);
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "ray/thirdparty/hiredis/async.h"
|
||||
#include "ray/thirdparty/hiredis/hiredis.h"
|
||||
#include "ray/util/test_util.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
@@ -104,6 +105,11 @@ class CoreWorkerTest : public ::testing::Test {
|
||||
}
|
||||
}
|
||||
|
||||
JobID NextJobId() const {
|
||||
static uint32_t job_counter = 1;
|
||||
return JobID::FromInt(job_counter++);
|
||||
}
|
||||
|
||||
std::string StartStore() {
|
||||
std::string store_socket_name = "/tmp/store" + RandomObjectID().Hex();
|
||||
std::string store_pid = store_socket_name + ".pid";
|
||||
@@ -213,7 +219,7 @@ bool CoreWorkerTest::WaitForDirectCallActorState(CoreWorker &worker,
|
||||
void CoreWorkerTest::TestNormalTask(
|
||||
const std::unordered_map<std::string, double> &resources) {
|
||||
CoreWorker driver(WorkerType::DRIVER, Language::PYTHON, raylet_store_socket_names_[0],
|
||||
raylet_socket_names_[0], JobID::FromInt(1), gcs_options_, nullptr);
|
||||
raylet_socket_names_[0], NextJobId(), gcs_options_, nullptr);
|
||||
|
||||
// Test for tasks with by-value and by-ref args.
|
||||
{
|
||||
@@ -254,7 +260,7 @@ void CoreWorkerTest::TestNormalTask(
|
||||
void CoreWorkerTest::TestActorTask(
|
||||
const std::unordered_map<std::string, double> &resources, bool is_direct_call) {
|
||||
CoreWorker driver(WorkerType::DRIVER, Language::PYTHON, raylet_store_socket_names_[0],
|
||||
raylet_socket_names_[0], JobID::FromInt(1), gcs_options_, nullptr);
|
||||
raylet_socket_names_[0], NextJobId(), gcs_options_, nullptr);
|
||||
|
||||
auto actor_handle = CreateActorHelper(driver, resources, is_direct_call, 1000);
|
||||
|
||||
@@ -336,7 +342,7 @@ void CoreWorkerTest::TestActorTask(
|
||||
void CoreWorkerTest::TestActorReconstruction(
|
||||
const std::unordered_map<std::string, double> &resources, bool is_direct_call) {
|
||||
CoreWorker driver(WorkerType::DRIVER, Language::PYTHON, raylet_store_socket_names_[0],
|
||||
raylet_socket_names_[0], JobID::FromInt(1), gcs_options_, nullptr);
|
||||
raylet_socket_names_[0], NextJobId(), gcs_options_, nullptr);
|
||||
|
||||
// creating actor.
|
||||
auto actor_handle = CreateActorHelper(driver, resources, is_direct_call, 1000);
|
||||
@@ -393,7 +399,7 @@ void CoreWorkerTest::TestActorReconstruction(
|
||||
void CoreWorkerTest::TestActorFailure(
|
||||
const std::unordered_map<std::string, double> &resources, bool is_direct_call) {
|
||||
CoreWorker driver(WorkerType::DRIVER, Language::PYTHON, raylet_store_socket_names_[0],
|
||||
raylet_socket_names_[0], JobID::FromInt(1), gcs_options_, nullptr);
|
||||
raylet_socket_names_[0], NextJobId(), gcs_options_, nullptr);
|
||||
|
||||
// creating actor.
|
||||
auto actor_handle =
|
||||
@@ -499,13 +505,13 @@ void CoreWorkerTest::TestStoreProvider(StoreProviderType type) {
|
||||
wait_ids.push_back(non_existent_id);
|
||||
|
||||
std::vector<bool> wait_results;
|
||||
RAY_CHECK_OK(provider.Wait(wait_ids, 5, 100, TaskID::FromRandom(), &wait_results));
|
||||
RAY_CHECK_OK(provider.Wait(wait_ids, 5, 100, RandomTaskId(), &wait_results));
|
||||
ASSERT_EQ(wait_results.size(), 5);
|
||||
ASSERT_EQ(wait_results, std::vector<bool>({true, true, true, true, false}));
|
||||
|
||||
// Test Get().
|
||||
std::vector<std::shared_ptr<RayObject>> results;
|
||||
RAY_CHECK_OK(provider.Get(ids_with_duplicate, -1, TaskID::FromRandom(), &results));
|
||||
RAY_CHECK_OK(provider.Get(ids_with_duplicate, -1, RandomTaskId(), &results));
|
||||
|
||||
ASSERT_EQ(results.size(), ids_with_duplicate.size());
|
||||
for (size_t i = 0; i < ids_with_duplicate.size(); i++) {
|
||||
@@ -527,7 +533,7 @@ void CoreWorkerTest::TestStoreProvider(StoreProviderType type) {
|
||||
RAY_CHECK_OK(provider.Delete(ids, true, false));
|
||||
|
||||
usleep(200 * 1000);
|
||||
RAY_CHECK_OK(provider.Get(ids, 0, TaskID::FromRandom(), &results));
|
||||
RAY_CHECK_OK(provider.Get(ids, 0, RandomTaskId(), &results));
|
||||
ASSERT_EQ(results.size(), 2);
|
||||
ASSERT_TRUE(!results[0]);
|
||||
ASSERT_TRUE(!results[1]);
|
||||
@@ -576,9 +582,10 @@ TEST_F(ZeroNodeTest, TestTaskSpecPerf) {
|
||||
|
||||
std::unordered_map<std::string, double> resources;
|
||||
ActorCreationOptions actor_options{0, /* is_direct_call */ true, resources};
|
||||
|
||||
ActorHandle actor_handle(ActorID::FromRandom(), ActorHandleID::Nil(), function.language,
|
||||
true, function.function_descriptor);
|
||||
const auto job_id = NextJobId();
|
||||
ActorHandle actor_handle(ActorID::Of(job_id, TaskID::ForDriverTask(job_id), 1),
|
||||
ActorHandleID::Nil(), function.language, true,
|
||||
function.function_descriptor);
|
||||
|
||||
// Manually create `num_tasks` task specs, and for each of them create a
|
||||
// `PushTaskRequest`, this is to batch performance of TaskSpec
|
||||
@@ -592,9 +599,9 @@ TEST_F(ZeroNodeTest, TestTaskSpecPerf) {
|
||||
auto num_returns = options.num_returns;
|
||||
|
||||
TaskSpecBuilder builder;
|
||||
builder.SetCommonTaskSpec(function.language, function.function_descriptor,
|
||||
JobID::FromInt(1), TaskID::FromRandom(), 0, num_returns,
|
||||
resources, resources);
|
||||
builder.SetCommonTaskSpec(RandomTaskId(), function.language,
|
||||
function.function_descriptor, job_id, RandomTaskId(), 0,
|
||||
num_returns, resources, resources);
|
||||
// Set task arguments.
|
||||
for (const auto &arg : args) {
|
||||
if (arg.IsPassedByReference()) {
|
||||
@@ -605,7 +612,8 @@ TEST_F(ZeroNodeTest, TestTaskSpecPerf) {
|
||||
}
|
||||
|
||||
const auto actor_creation_dummy_object_id =
|
||||
ObjectID::FromBinary(actor_handle.ActorID().Binary());
|
||||
ObjectID::ForTaskReturn(TaskID::ForActorCreationTask(actor_handle.ActorID()),
|
||||
/*index=*/1, /*transport_type=*/0);
|
||||
builder.SetActorTaskSpec(
|
||||
actor_handle.ActorID(), actor_handle.ActorHandleID(),
|
||||
actor_creation_dummy_object_id,
|
||||
@@ -624,27 +632,22 @@ TEST_F(ZeroNodeTest, TestTaskSpecPerf) {
|
||||
TEST_F(SingleNodeTest, TestDirectActorTaskSubmissionPerf) {
|
||||
CoreWorker driver(WorkerType::DRIVER, Language::PYTHON, raylet_store_socket_names_[0],
|
||||
raylet_socket_names_[0], JobID::FromInt(1), gcs_options_, nullptr);
|
||||
|
||||
std::unique_ptr<ActorHandle> actor_handle;
|
||||
|
||||
// Test creating actor.
|
||||
uint8_t array[] = {1, 2, 3};
|
||||
auto buffer = std::make_shared<LocalMemoryBuffer>(array, sizeof(array));
|
||||
|
||||
RayFunction func{ray::Language::PYTHON, {}};
|
||||
std::vector<TaskArg> args;
|
||||
args.emplace_back(TaskArg::PassByValue(buffer));
|
||||
|
||||
std::unordered_map<std::string, double> resources;
|
||||
ActorCreationOptions actor_options{0, /* is_direct_call */ true, resources};
|
||||
|
||||
// Create an actor.
|
||||
RAY_CHECK_OK(driver.Tasks().CreateActor(func, args, actor_options, &actor_handle));
|
||||
|
||||
// wait for actor creation finish.
|
||||
ASSERT_TRUE(WaitForDirectCallActorState(driver, actor_handle->ActorID(), true,
|
||||
30 * 1000 /* 30s */));
|
||||
|
||||
// Test submitting some tasks with by-value args for that actor.
|
||||
int64_t start_ms = current_time_ms();
|
||||
const int num_tasks = 10000;
|
||||
@@ -667,7 +670,7 @@ TEST_F(SingleNodeTest, TestDirectActorTaskSubmissionPerf) {
|
||||
}
|
||||
|
||||
TEST_F(ZeroNodeTest, TestWorkerContext) {
|
||||
auto job_id = JobID::JobID::FromInt(1);
|
||||
auto job_id = NextJobId();
|
||||
|
||||
WorkerContext context(WorkerType::WORKER, job_id);
|
||||
ASSERT_TRUE(context.GetCurrentTaskID().IsNil());
|
||||
@@ -692,8 +695,9 @@ TEST_F(ZeroNodeTest, TestWorkerContext) {
|
||||
}
|
||||
|
||||
TEST_F(ZeroNodeTest, TestActorHandle) {
|
||||
ActorHandle handle1(ActorID::FromRandom(), ActorHandleID::FromRandom(), Language::JAVA,
|
||||
false,
|
||||
const auto job_id = NextJobId();
|
||||
ActorHandle handle1(ActorID::Of(job_id, TaskID::ForDriverTask(job_id), 1),
|
||||
ActorHandleID::FromRandom(), Language::JAVA, false,
|
||||
{"org.ray.exampleClass", "exampleMethod", "exampleSignature"});
|
||||
|
||||
auto forkedHandle1 = handle1.Fork();
|
||||
@@ -788,10 +792,10 @@ TEST_F(SingleNodeTest, TestObjectInterface) {
|
||||
|
||||
TEST_F(TwoNodeTest, TestObjectInterfaceCrossNodes) {
|
||||
CoreWorker worker1(WorkerType::DRIVER, Language::PYTHON, raylet_store_socket_names_[0],
|
||||
raylet_socket_names_[0], JobID::FromInt(1), gcs_options_, nullptr);
|
||||
raylet_socket_names_[0], NextJobId(), gcs_options_, nullptr);
|
||||
|
||||
CoreWorker worker2(WorkerType::DRIVER, Language::PYTHON, raylet_store_socket_names_[1],
|
||||
raylet_socket_names_[1], JobID::FromInt(1), gcs_options_, nullptr);
|
||||
raylet_socket_names_[1], NextJobId(), gcs_options_, nullptr);
|
||||
|
||||
uint8_t array1[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
uint8_t array2[] = {10, 11, 12, 13, 14, 15};
|
||||
|
||||
@@ -158,7 +158,8 @@ Status CoreWorkerDirectActorTaskSubmitter::PushTask(rpc::DirectActorClient &clie
|
||||
void CoreWorkerDirectActorTaskSubmitter::TreatTaskAsFailed(
|
||||
const TaskID &task_id, int num_returns, const rpc::ErrorType &error_type) {
|
||||
for (int i = 0; i < num_returns; i++) {
|
||||
const auto object_id = ObjectID::ForTaskReturn(task_id, i + 1);
|
||||
const auto object_id =
|
||||
ObjectID::ForTaskReturn(task_id, /*index=*/i + 1, /*transport_type=*/0);
|
||||
std::string meta = std::to_string(static_cast<int>(error_type));
|
||||
auto metadata = const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(meta.data()));
|
||||
auto meta_buffer = std::make_shared<LocalMemoryBuffer>(metadata, meta.size());
|
||||
@@ -204,7 +205,8 @@ void CoreWorkerDirectActorTaskReceiver::HandlePushTask(
|
||||
|
||||
for (int i = 0; i < results.size(); i++) {
|
||||
auto return_object = (*reply).add_return_objects();
|
||||
ObjectID id = ObjectID::ForTaskReturn(task_spec.TaskId(), i + 1);
|
||||
ObjectID id = ObjectID::ForTaskReturn(task_spec.TaskId(), /*index=*/i + 1,
|
||||
/*transport_type=*/0);
|
||||
return_object->set_object_id(id.Binary());
|
||||
const auto &result = results[i];
|
||||
if (result->GetData() != nullptr) {
|
||||
|
||||
@@ -41,7 +41,8 @@ void CoreWorkerRayletTaskReceiver::HandleAssignTask(
|
||||
|
||||
RAY_CHECK(results.size() == num_returns);
|
||||
for (int i = 0; i < num_returns; i++) {
|
||||
ObjectID id = ObjectID::ForTaskReturn(task_spec.TaskId(), i + 1);
|
||||
ObjectID id = ObjectID::ForTaskReturn(task_spec.TaskId(), /*index=*/i + 1,
|
||||
/*transport_type=*/0);
|
||||
object_interface_.Put(*results[i], id);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
Ray ID Specification
|
||||
============================================
|
||||
```
|
||||
|
||||
high bits low bits
|
||||
<--------------------------------------------------------------------------------------------
|
||||
|
||||
4B
|
||||
+-----------------+
|
||||
| unique bytes | JobID 4B
|
||||
+-----------------+
|
||||
|
||||
4B 4B
|
||||
+-----------------+-----------------+
|
||||
| unique bytes | JobID | ActorID 8B
|
||||
+-----------------+-----------------+
|
||||
|
||||
6B 8B
|
||||
+---------------------------+-----------------------------------+
|
||||
| unique bytes | ActorID | TaskID 14B
|
||||
+---------------------------+-----------------------------------+
|
||||
|
||||
4B 2B 14B
|
||||
+---------------------------+---------------------------------------------------------------+
|
||||
| index bytes |flags bytes| TaskID | ObjectID 20B
|
||||
+---------------------------+---------------------------------------------------------------+
|
||||
|
||||
```
|
||||
#### JobID (4 bytes)
|
||||
`JobID` is generated by `GCS` to ensure uniqueness. Its length is 4 bytes.
|
||||
|
||||
#### ActorID (8 bytes)
|
||||
An `ActorID` contains two parts: 1) 4 unique bytes, and 2) its `JobID`.
|
||||
|
||||
#### TaskID (14 bytes)
|
||||
A `TaskID` contains two parts: 1) 6 unique bytes, and 2) its `ActorID`.
|
||||
If the task is a normal task or a driver task, the part 2 is its dummy actor id.
|
||||
|
||||
The following table shows the layouts of all kinds of task id.
|
||||
```
|
||||
+-------------------+-----------------+------------+---------------------------+-----------------+
|
||||
| | Normal Task | Actor Task | Actor Creation Task | Driver Task |
|
||||
+-------------------+-----------------+------------+---------------------------+-----------------+
|
||||
| task unique bytes | random | random | nil | nil |
|
||||
+-------------------+-----------------+------------+---------------------------+-----------------+
|
||||
| actor id | dummy actor id* | actor id | Id of the actor to create | dummy actor id* |
|
||||
+-------------------+-----------------+------------+---------------------------+-----------------+
|
||||
Note: Dummy actor id is an `ActorID` whose unique part is nil.
|
||||
```
|
||||
|
||||
#### ObjectID (20 bytes)
|
||||
An `ObjectID` contains 3 parts:
|
||||
- `index bytes`: 4 bytes to indicate the index of the object.
|
||||
- `flags bytes`: 2 bytes to indicate the flags of this object. We have 3 flags now: `created_by_task`, `object_type` and `transport_type`.
|
||||
- `TaskID`: 14 bytes to indicate the ID of the task to which this object belongs.
|
||||
|
||||
**flags bytes format**
|
||||
```
|
||||
1b 1b 3b 11b
|
||||
+-------------------------------------------------------------------------+
|
||||
| (1) | (2) | (3) | (4)unused |
|
||||
+-------------------------------------------------------------------------+
|
||||
```
|
||||
- The (1) `created_by_task` part is one bit to indicate whether this `ObjectID` is generated (put or returned) from a task.
|
||||
|
||||
- The (2) `object_type` part is one bit to indicate the type of this object, whether a `PUT_OBJECT` or a `RETURN_OBJECT`.
|
||||
- `PUT_OBJECT` indicates this object is generated through `ray.put` during the task's execution.
|
||||
- `RETURN_OBJECT` indicates this object is the return value of a task.
|
||||
|
||||
- The (3) `transport_type` part is 3 bits to indicate the type of the transport which is used to transfer this object. So it can support 8 types.
|
||||
|
||||
- There are 11 bits unused in `flags bytes`.
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
#include "gtest/gtest.h"
|
||||
#include "ray/gcs/redis_gcs_client.h"
|
||||
#include "ray/util/test_util.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
@@ -45,13 +46,13 @@ class ActorStateAccessorTest : public ::testing::Test {
|
||||
void GenActorData() {
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
std::shared_ptr<ActorTableData> actor = std::make_shared<ActorTableData>();
|
||||
ActorID actor_id = ActorID::FromRandom();
|
||||
actor->set_actor_id(actor_id.Binary());
|
||||
actor->set_max_reconstructions(1);
|
||||
actor->set_remaining_reconstructions(1);
|
||||
JobID job_id = JobID::FromInt(i);
|
||||
actor->set_job_id(job_id.Binary());
|
||||
actor->set_state(ActorTableData::ALIVE);
|
||||
ActorID actor_id = ActorID::Of(job_id, RandomTaskId(), /*parent_task_counter=*/i);
|
||||
actor->set_actor_id(actor_id.Binary());
|
||||
actor_datas_[actor_id] = actor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ extern "C" {
|
||||
#include "ray/common/ray_config.h"
|
||||
#include "ray/gcs/redis_gcs_client.h"
|
||||
#include "ray/gcs/tables.h"
|
||||
#include "ray/util/test_util.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
@@ -104,7 +105,7 @@ bool TaskTableDataEqual(const TaskTableData &data1, const TaskTableData &data2)
|
||||
}
|
||||
|
||||
void TestTableLookup(const JobID &job_id, std::shared_ptr<gcs::RedisGcsClient> client) {
|
||||
const auto task_id = TaskID::FromRandom();
|
||||
const auto task_id = RandomTaskId();
|
||||
const auto data = CreateTaskTableData(task_id);
|
||||
|
||||
// Check that we added the correct task.
|
||||
@@ -151,7 +152,7 @@ TEST_MACRO(TestGcsWithChainAsio, TestTableLookup);
|
||||
|
||||
void TestLogLookup(const JobID &job_id, std::shared_ptr<gcs::RedisGcsClient> client) {
|
||||
// Append some entries to the log at an object ID.
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
TaskID task_id = RandomTaskId();
|
||||
std::vector<std::string> node_manager_ids = {"abc", "def", "ghi"};
|
||||
for (auto &node_manager_id : node_manager_ids) {
|
||||
auto data = std::make_shared<TaskReconstructionData>();
|
||||
@@ -196,7 +197,7 @@ TEST_F(TestGcsWithAsio, TestLogLookup) {
|
||||
|
||||
void TestTableLookupFailure(const JobID &job_id,
|
||||
std::shared_ptr<gcs::RedisGcsClient> client) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
TaskID task_id = RandomTaskId();
|
||||
|
||||
// Check that the lookup does not return data.
|
||||
auto lookup_callback = [](gcs::RedisGcsClient *client, const TaskID &id,
|
||||
@@ -222,7 +223,7 @@ TEST_MACRO(TestGcsWithChainAsio, TestTableLookupFailure);
|
||||
#endif
|
||||
|
||||
void TestLogAppendAt(const JobID &job_id, std::shared_ptr<gcs::RedisGcsClient> client) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
TaskID task_id = RandomTaskId();
|
||||
std::vector<std::string> node_manager_ids = {"A", "B"};
|
||||
std::vector<std::shared_ptr<TaskReconstructionData>> data_log;
|
||||
for (const auto &node_manager_id : node_manager_ids) {
|
||||
@@ -352,7 +353,7 @@ void TestDeleteKeysFromLog(
|
||||
std::vector<TaskID> ids;
|
||||
TaskID task_id;
|
||||
for (auto &data : data_vector) {
|
||||
task_id = TaskID::FromRandom();
|
||||
task_id = RandomTaskId();
|
||||
ids.push_back(task_id);
|
||||
// Check that we added the correct object entries.
|
||||
auto add_callback = [task_id, data](gcs::RedisGcsClient *client, const TaskID &id,
|
||||
@@ -400,7 +401,7 @@ void TestDeleteKeysFromTable(const JobID &job_id,
|
||||
std::vector<TaskID> ids;
|
||||
TaskID task_id;
|
||||
for (auto &data : data_vector) {
|
||||
task_id = TaskID::FromRandom();
|
||||
task_id = RandomTaskId();
|
||||
ids.push_back(task_id);
|
||||
// Check that we added the correct object entries.
|
||||
auto add_callback = [task_id, data](gcs::RedisGcsClient *client, const TaskID &id,
|
||||
@@ -521,7 +522,7 @@ void TestDeleteKeys(const JobID &job_id, std::shared_ptr<gcs::RedisGcsClient> cl
|
||||
std::vector<std::shared_ptr<TaskTableData>> task_vector;
|
||||
auto AppendTaskData = [&task_vector](size_t add_count) {
|
||||
for (size_t i = 0; i < add_count; ++i) {
|
||||
task_vector.push_back(CreateTaskTableData(TaskID::FromRandom()));
|
||||
task_vector.push_back(CreateTaskTableData(RandomTaskId()));
|
||||
}
|
||||
};
|
||||
AppendTaskData(1);
|
||||
@@ -703,10 +704,10 @@ void TestTableSubscribeId(const JobID &job_id,
|
||||
int num_modifications = 3;
|
||||
|
||||
// Add a table entry.
|
||||
TaskID task_id1 = TaskID::FromRandom();
|
||||
TaskID task_id1 = RandomTaskId();
|
||||
|
||||
// Add a table entry at a second key.
|
||||
TaskID task_id2 = TaskID::FromRandom();
|
||||
TaskID task_id2 = RandomTaskId();
|
||||
|
||||
// The callback for a notification from the table. This should only be
|
||||
// received for keys that we requested notifications for.
|
||||
@@ -927,7 +928,7 @@ TEST_F(TestGcsWithAsio, TestSetSubscribeId) {
|
||||
void TestTableSubscribeCancel(const JobID &job_id,
|
||||
std::shared_ptr<gcs::RedisGcsClient> client) {
|
||||
// Add a table entry.
|
||||
const auto task_id = TaskID::FromRandom();
|
||||
const auto task_id = RandomTaskId();
|
||||
const int num_modifications = 3;
|
||||
const auto data = CreateTaskTableData(task_id, 0);
|
||||
RAY_CHECK_OK(client->raylet_task_table().Add(job_id, task_id, data, nullptr));
|
||||
|
||||
@@ -685,7 +685,7 @@ Status ActorCheckpointIdTable::AddCheckpointId(const JobID &job_id,
|
||||
const ActorID &actor_id,
|
||||
const ActorCheckpointID &checkpoint_id) {
|
||||
auto lookup_callback = [this, checkpoint_id, job_id, actor_id](
|
||||
ray::gcs::RedisGcsClient *client, const UniqueID &id,
|
||||
ray::gcs::RedisGcsClient *client, const ActorID &id,
|
||||
const ActorCheckpointIdData &data) {
|
||||
std::shared_ptr<ActorCheckpointIdData> copy =
|
||||
std::make_shared<ActorCheckpointIdData>(data);
|
||||
@@ -695,7 +695,6 @@ Status ActorCheckpointIdTable::AddCheckpointId(const JobID &job_id,
|
||||
while (copy->timestamps().size() > num_to_keep) {
|
||||
// Delete the checkpoint from actor checkpoint table.
|
||||
const auto &to_delete = ActorCheckpointID::FromBinary(copy->checkpoint_ids(0));
|
||||
RAY_LOG(DEBUG) << "Deleting checkpoint " << to_delete << " for actor " << actor_id;
|
||||
copy->mutable_checkpoint_ids()->erase(copy->mutable_checkpoint_ids()->begin());
|
||||
copy->mutable_timestamps()->erase(copy->mutable_timestamps()->begin());
|
||||
client_->actor_checkpoint_table().Delete(job_id, to_delete);
|
||||
@@ -703,7 +702,7 @@ Status ActorCheckpointIdTable::AddCheckpointId(const JobID &job_id,
|
||||
RAY_CHECK_OK(Add(job_id, actor_id, copy, nullptr));
|
||||
};
|
||||
auto failure_callback = [this, checkpoint_id, job_id, actor_id](
|
||||
ray::gcs::RedisGcsClient *client, const UniqueID &id) {
|
||||
ray::gcs::RedisGcsClient *client, const ActorID &id) {
|
||||
std::shared_ptr<ActorCheckpointIdData> data =
|
||||
std::make_shared<ActorCheckpointIdData>();
|
||||
data->set_actor_id(id.Binary());
|
||||
|
||||
@@ -61,7 +61,7 @@ void ObjectManager::StopRpcService() {
|
||||
void ObjectManager::HandleObjectAdded(
|
||||
const object_manager::protocol::ObjectInfoT &object_info) {
|
||||
// Notify the object directory that the object has been added to this node.
|
||||
ObjectID object_id = ObjectID::FromBinary(object_info.object_id);
|
||||
ObjectID object_id = ObjectID::FromPlasmaIdBinary(object_info.object_id);
|
||||
RAY_LOG(DEBUG) << "Object added " << object_id;
|
||||
RAY_CHECK(local_objects_.count(object_id) == 0);
|
||||
local_objects_[object_id].object_info = object_info;
|
||||
|
||||
@@ -63,7 +63,8 @@ void ObjectStoreNotificationManager::ProcessStoreNotification(
|
||||
|
||||
const auto &object_info =
|
||||
flatbuffers::GetRoot<object_manager::protocol::ObjectInfo>(notification_.data());
|
||||
const auto &object_id = from_flatbuf<ObjectID>(*object_info->object_id());
|
||||
const ObjectID object_id =
|
||||
ObjectID::FromPlasmaIdBinary(object_info->object_id()->str());
|
||||
if (object_info->is_deletion()) {
|
||||
ProcessStoreRemove(object_id);
|
||||
} else {
|
||||
|
||||
@@ -147,24 +147,71 @@ Java_org_ray_runtime_raylet_RayletClientImpl_nativeWaitObject(
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativeGenerateTaskId
|
||||
* Method: nativeGenerateActorCreationTaskId
|
||||
* Signature: ([B[BI)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativeGenerateTaskId(
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativeGenerateActorCreationTaskId(
|
||||
JNIEnv *env, jclass, jbyteArray jobId, jbyteArray parentTaskId,
|
||||
jint parent_task_counter) {
|
||||
const auto job_id = JavaByteArrayToId<JobID>(env, jobId);
|
||||
const auto parent_task_id = JavaByteArrayToId<TaskID>(env, parentTaskId);
|
||||
|
||||
TaskID task_id = ray::GenerateTaskId(job_id, parent_task_id, parent_task_counter);
|
||||
const ActorID actor_id = ray::ActorID::Of(job_id, parent_task_id, parent_task_counter);
|
||||
const TaskID actor_creation_task_id = ray::TaskID::ForActorCreationTask(actor_id);
|
||||
jbyteArray result = env->NewByteArray(actor_creation_task_id.Size());
|
||||
if (nullptr == result) {
|
||||
return nullptr;
|
||||
}
|
||||
env->SetByteArrayRegion(result, 0, actor_creation_task_id.Size(),
|
||||
reinterpret_cast<const jbyte *>(actor_creation_task_id.Data()));
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativeGenerateActorTaskId
|
||||
* Signature: ([B[BI[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativeGenerateActorTaskId(
|
||||
JNIEnv *env, jclass, jbyteArray jobId, jbyteArray parentTaskId,
|
||||
jint parent_task_counter, jbyteArray actorId) {
|
||||
const auto job_id = JavaByteArrayToId<JobID>(env, jobId);
|
||||
const auto parent_task_id = JavaByteArrayToId<TaskID>(env, parentTaskId);
|
||||
const auto actor_id = JavaByteArrayToId<ActorID>(env, actorId);
|
||||
const TaskID actor_task_id =
|
||||
ray::TaskID::ForActorTask(job_id, parent_task_id, parent_task_counter, actor_id);
|
||||
|
||||
jbyteArray result = env->NewByteArray(actor_task_id.Size());
|
||||
if (nullptr == result) {
|
||||
return nullptr;
|
||||
}
|
||||
env->SetByteArrayRegion(result, 0, actor_task_id.Size(),
|
||||
reinterpret_cast<const jbyte *>(actor_task_id.Data()));
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativeGenerateNormalTaskId
|
||||
* Signature: ([B[BI)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativeGenerateNormalTaskId(
|
||||
JNIEnv *env, jclass, jbyteArray jobId, jbyteArray parentTaskId,
|
||||
jint parent_task_counter) {
|
||||
const auto job_id = JavaByteArrayToId<JobID>(env, jobId);
|
||||
const auto parent_task_id = JavaByteArrayToId<TaskID>(env, parentTaskId);
|
||||
const TaskID task_id =
|
||||
ray::TaskID::ForNormalTask(job_id, parent_task_id, parent_task_counter);
|
||||
|
||||
jbyteArray result = env->NewByteArray(task_id.Size());
|
||||
if (nullptr == result) {
|
||||
return nullptr;
|
||||
}
|
||||
env->SetByteArrayRegion(result, 0, task_id.Size(),
|
||||
reinterpret_cast<const jbyte *>(task_id.Data()));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,13 +51,33 @@ Java_org_ray_runtime_raylet_RayletClientImpl_nativeWaitObject(JNIEnv *, jclass,
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativeGenerateTaskId
|
||||
* Method: nativeGenerateActorCreationTaskId
|
||||
* Signature: ([B[BI)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativeGenerateTaskId(JNIEnv *, jclass,
|
||||
jbyteArray, jbyteArray,
|
||||
jint);
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativeGenerateActorCreationTaskId(
|
||||
JNIEnv *, jclass, jbyteArray, jbyteArray, jint);
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativeGenerateActorTaskId
|
||||
* Signature: ([B[BI[B)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativeGenerateActorTaskId(JNIEnv *, jclass,
|
||||
jbyteArray,
|
||||
jbyteArray, jint,
|
||||
jbyteArray);
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
* Method: nativeGenerateNormalTaskId
|
||||
* Signature: ([B[BI)[B
|
||||
*/
|
||||
JNIEXPORT jbyteArray JNICALL
|
||||
Java_org_ray_runtime_raylet_RayletClientImpl_nativeGenerateNormalTaskId(JNIEnv *, jclass,
|
||||
jbyteArray,
|
||||
jbyteArray, jint);
|
||||
|
||||
/*
|
||||
* Class: org_ray_runtime_raylet_RayletClientImpl
|
||||
|
||||
@@ -8,11 +8,16 @@
|
||||
#include "ray/common/task/task_spec.h"
|
||||
#include "ray/common/task/task_util.h"
|
||||
#include "ray/raylet/lineage_cache.h"
|
||||
#include "ray/util/test_util.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
namespace raylet {
|
||||
|
||||
const static JobID kDefaultJobId = JobID::FromInt(1);
|
||||
|
||||
const static TaskID kDefaultDriverTaskId = TaskID::ForDriverTask(kDefaultJobId);
|
||||
|
||||
class MockGcs : public gcs::TableInterface<TaskID, TaskTableData>,
|
||||
public gcs::PubsubInterface<TaskID> {
|
||||
public:
|
||||
@@ -127,8 +132,8 @@ class LineageCacheTest : public ::testing::Test {
|
||||
static inline Task ExampleTask(const std::vector<ObjectID> &arguments,
|
||||
uint64_t num_returns) {
|
||||
TaskSpecBuilder builder;
|
||||
builder.SetCommonTaskSpec(Language::PYTHON, {"", "", ""}, JobID::Nil(),
|
||||
TaskID::FromRandom(), 0, num_returns, {}, {});
|
||||
builder.SetCommonTaskSpec(RandomTaskId(), Language::PYTHON, {"", "", ""}, JobID::Nil(),
|
||||
RandomTaskId(), 0, num_returns, {}, {});
|
||||
for (const auto &arg : arguments) {
|
||||
builder.AddByRefArg(arg);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ NodeManager::NodeManager(boost::asio::io_service &io_service,
|
||||
|
||||
RAY_CHECK_OK(object_manager_.SubscribeObjAdded(
|
||||
[this](const object_manager::protocol::ObjectInfoT &object_info) {
|
||||
ObjectID object_id = ObjectID::FromBinary(object_info.object_id);
|
||||
ObjectID object_id = ObjectID::FromPlasmaIdBinary(object_info.object_id);
|
||||
HandleObjectLocal(object_id);
|
||||
}));
|
||||
RAY_CHECK_OK(object_manager_.SubscribeObjDeleted(
|
||||
|
||||
@@ -15,6 +15,15 @@ namespace raylet {
|
||||
|
||||
using rpc::TaskLeaseData;
|
||||
|
||||
// A helper function to get a normal task id.
|
||||
inline TaskID ForNormalTask() {
|
||||
const static JobID job_id = JobID::FromInt(1);
|
||||
const static TaskID driver_task_id = TaskID::ForDriverTask(job_id);
|
||||
static TaskID task_id =
|
||||
TaskID::ForNormalTask(job_id, driver_task_id, /*parent_task_counter=*/1);
|
||||
return task_id;
|
||||
}
|
||||
|
||||
class MockObjectDirectory : public ObjectDirectoryInterface {
|
||||
public:
|
||||
MockObjectDirectory() {}
|
||||
@@ -226,8 +235,9 @@ class ReconstructionPolicyTest : public ::testing::Test {
|
||||
};
|
||||
|
||||
TEST_F(ReconstructionPolicyTest, TestReconstructionSimple) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
ObjectID object_id = ObjectID::ForTaskReturn(task_id, 1);
|
||||
TaskID task_id = ForNormalTask();
|
||||
ObjectID object_id =
|
||||
ObjectID::ForTaskReturn(task_id, /*index=*/1, /*transport_type=*/0);
|
||||
|
||||
// Listen for an object.
|
||||
reconstruction_policy_->ListenAndMaybeReconstruct(object_id);
|
||||
@@ -244,8 +254,9 @@ TEST_F(ReconstructionPolicyTest, TestReconstructionSimple) {
|
||||
}
|
||||
|
||||
TEST_F(ReconstructionPolicyTest, TestReconstructionEvicted) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
ObjectID object_id = ObjectID::ForTaskReturn(task_id, 1);
|
||||
TaskID task_id = ForNormalTask();
|
||||
ObjectID object_id =
|
||||
ObjectID::ForTaskReturn(task_id, /*index=*/1, /*transport_type=*/0);
|
||||
mock_object_directory_->SetObjectLocations(object_id, {ClientID::FromRandom()});
|
||||
|
||||
// Listen for both objects.
|
||||
@@ -267,8 +278,9 @@ TEST_F(ReconstructionPolicyTest, TestReconstructionEvicted) {
|
||||
}
|
||||
|
||||
TEST_F(ReconstructionPolicyTest, TestReconstructionObjectLost) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
ObjectID object_id = ObjectID::ForTaskReturn(task_id, 1);
|
||||
TaskID task_id = ForNormalTask();
|
||||
ObjectID object_id =
|
||||
ObjectID::ForTaskReturn(task_id, /*index=*/1, /*transport_type=*/0);
|
||||
ClientID client_id = ClientID::FromRandom();
|
||||
mock_object_directory_->SetObjectLocations(object_id, {client_id});
|
||||
|
||||
@@ -291,9 +303,11 @@ TEST_F(ReconstructionPolicyTest, TestReconstructionObjectLost) {
|
||||
|
||||
TEST_F(ReconstructionPolicyTest, TestDuplicateReconstruction) {
|
||||
// Create two object IDs produced by the same task.
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
ObjectID object_id1 = ObjectID::ForTaskReturn(task_id, 1);
|
||||
ObjectID object_id2 = ObjectID::ForTaskReturn(task_id, 2);
|
||||
TaskID task_id = ForNormalTask();
|
||||
ObjectID object_id1 =
|
||||
ObjectID::ForTaskReturn(task_id, /*index=*/1, /*transport_type=*/0);
|
||||
ObjectID object_id2 =
|
||||
ObjectID::ForTaskReturn(task_id, /*index=*/2, /*transport_type=*/0);
|
||||
|
||||
// Listen for both objects.
|
||||
reconstruction_policy_->ListenAndMaybeReconstruct(object_id1);
|
||||
@@ -311,8 +325,9 @@ TEST_F(ReconstructionPolicyTest, TestDuplicateReconstruction) {
|
||||
}
|
||||
|
||||
TEST_F(ReconstructionPolicyTest, TestReconstructionSuppressed) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
ObjectID object_id = ObjectID::ForTaskReturn(task_id, 1);
|
||||
TaskID task_id = ForNormalTask();
|
||||
ObjectID object_id =
|
||||
ObjectID::ForTaskReturn(task_id, /*index=*/1, /*transport_type=*/0);
|
||||
// Run the test for much longer than the reconstruction timeout.
|
||||
int64_t test_period = 2 * reconstruction_timeout_ms_;
|
||||
|
||||
@@ -337,8 +352,9 @@ TEST_F(ReconstructionPolicyTest, TestReconstructionSuppressed) {
|
||||
}
|
||||
|
||||
TEST_F(ReconstructionPolicyTest, TestReconstructionContinuallySuppressed) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
ObjectID object_id = ObjectID::ForTaskReturn(task_id, 1);
|
||||
TaskID task_id = ForNormalTask();
|
||||
ObjectID object_id =
|
||||
ObjectID::ForTaskReturn(task_id, /*index=*/1, /*transport_type=*/0);
|
||||
|
||||
// Listen for an object.
|
||||
reconstruction_policy_->ListenAndMaybeReconstruct(object_id);
|
||||
@@ -364,8 +380,9 @@ TEST_F(ReconstructionPolicyTest, TestReconstructionContinuallySuppressed) {
|
||||
}
|
||||
|
||||
TEST_F(ReconstructionPolicyTest, TestReconstructionCanceled) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
ObjectID object_id = ObjectID::ForTaskReturn(task_id, 1);
|
||||
TaskID task_id = ForNormalTask();
|
||||
ObjectID object_id =
|
||||
ObjectID::ForTaskReturn(task_id, /*index=*/1, /*transport_type=*/0);
|
||||
|
||||
// Listen for an object.
|
||||
reconstruction_policy_->ListenAndMaybeReconstruct(object_id);
|
||||
@@ -390,8 +407,9 @@ TEST_F(ReconstructionPolicyTest, TestReconstructionCanceled) {
|
||||
}
|
||||
|
||||
TEST_F(ReconstructionPolicyTest, TestSimultaneousReconstructionSuppressed) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
ObjectID object_id = ObjectID::ForTaskReturn(task_id, 1);
|
||||
TaskID task_id = ForNormalTask();
|
||||
ObjectID object_id =
|
||||
ObjectID::ForTaskReturn(task_id, /*index=*/1, /*transport_type=*/0);
|
||||
|
||||
// Log a reconstruction attempt to simulate a different node attempting the
|
||||
// reconstruction first. This should suppress this node's first attempt at
|
||||
|
||||
@@ -204,6 +204,8 @@ void TaskDependencyManager::SubscribeWaitDependencies(
|
||||
auto inserted = worker_entry.insert(object_id);
|
||||
if (inserted.second) {
|
||||
// Get the ID of the task that creates the dependency.
|
||||
// TODO(qwang): Refine here to:
|
||||
// if (object_id.CreatedByTask()) {// ...}
|
||||
TaskID creating_task_id = object_id.TaskId();
|
||||
// Add the subscribed worker to the mapping from object ID to list of
|
||||
// dependent workers.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "ray/common/task/task_util.h"
|
||||
#include "ray/raylet/task_dependency_manager.h"
|
||||
#include "ray/util/test_util.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
@@ -14,6 +15,10 @@ namespace raylet {
|
||||
|
||||
using ::testing::_;
|
||||
|
||||
const static JobID kDefaultJobId = JobID::FromInt(1);
|
||||
|
||||
const static TaskID kDefaultDriverTaskId = TaskID::ForDriverTask(kDefaultJobId);
|
||||
|
||||
class MockObjectManager : public ObjectManagerInterface {
|
||||
public:
|
||||
MOCK_METHOD1(Pull, ray::Status(const ObjectID &object_id));
|
||||
@@ -70,8 +75,8 @@ class TaskDependencyManagerTest : public ::testing::Test {
|
||||
static inline Task ExampleTask(const std::vector<ObjectID> &arguments,
|
||||
uint64_t num_returns) {
|
||||
TaskSpecBuilder builder;
|
||||
builder.SetCommonTaskSpec(Language::PYTHON, {"", "", ""}, JobID::Nil(),
|
||||
TaskID::FromRandom(), 0, num_returns, {}, {});
|
||||
builder.SetCommonTaskSpec(RandomTaskId(), Language::PYTHON, {"", "", ""}, JobID::Nil(),
|
||||
RandomTaskId(), 0, num_returns, {}, {});
|
||||
for (const auto &arg : arguments) {
|
||||
builder.AddByRefArg(arg);
|
||||
}
|
||||
@@ -103,7 +108,7 @@ TEST_F(TaskDependencyManagerTest, TestSimpleTask) {
|
||||
for (int i = 0; i < num_arguments; i++) {
|
||||
arguments.push_back(ObjectID::FromRandom());
|
||||
}
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
TaskID task_id = RandomTaskId();
|
||||
// No objects have been registered in the task dependency manager, so all
|
||||
// arguments should be remote.
|
||||
for (const auto &argument_id : arguments) {
|
||||
@@ -135,7 +140,7 @@ TEST_F(TaskDependencyManagerTest, TestSimpleTask) {
|
||||
|
||||
TEST_F(TaskDependencyManagerTest, TestDuplicateSubscribeGetDependencies) {
|
||||
// Create a task with 3 arguments.
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
TaskID task_id = RandomTaskId();
|
||||
int num_arguments = 3;
|
||||
std::vector<ObjectID> arguments;
|
||||
for (int i = 0; i < num_arguments; i++) {
|
||||
@@ -180,7 +185,7 @@ TEST_F(TaskDependencyManagerTest, TestMultipleTasks) {
|
||||
EXPECT_CALL(object_manager_mock_, Pull(argument_id));
|
||||
EXPECT_CALL(reconstruction_policy_mock_, ListenAndMaybeReconstruct(argument_id));
|
||||
for (int i = 0; i < num_dependent_tasks; i++) {
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
TaskID task_id = RandomTaskId();
|
||||
dependent_tasks.push_back(task_id);
|
||||
// Subscribe to each of the task's dependencies.
|
||||
bool ready =
|
||||
@@ -263,7 +268,8 @@ TEST_F(TaskDependencyManagerTest, TestTaskChain) {
|
||||
TEST_F(TaskDependencyManagerTest, TestDependentPut) {
|
||||
// Create a task with 3 arguments.
|
||||
auto task1 = ExampleTask({}, 0);
|
||||
ObjectID put_id = ObjectID::ForPut(task1.GetTaskSpecification().TaskId(), 1);
|
||||
ObjectID put_id = ObjectID::ForPut(task1.GetTaskSpecification().TaskId(), /*index=*/1,
|
||||
/*transport_type=*/0);
|
||||
auto task2 = ExampleTask({put_id}, 0);
|
||||
|
||||
// No objects have been registered in the task dependency manager, so the put
|
||||
@@ -325,7 +331,7 @@ TEST_F(TaskDependencyManagerTest, TestEviction) {
|
||||
for (int i = 0; i < num_arguments; i++) {
|
||||
arguments.push_back(ObjectID::FromRandom());
|
||||
}
|
||||
TaskID task_id = TaskID::FromRandom();
|
||||
TaskID task_id = RandomTaskId();
|
||||
// No objects have been registered in the task dependency manager, so all
|
||||
// arguments should be remote.
|
||||
for (const auto &argument_id : arguments) {
|
||||
|
||||
@@ -186,7 +186,8 @@ TEST_F(WorkerPoolTest, PopActorWorker) {
|
||||
// Assign an actor ID to the worker.
|
||||
const auto task_spec = ExampleTaskSpec();
|
||||
auto actor = worker_pool_.PopWorker(task_spec);
|
||||
auto actor_id = ActorID::FromRandom();
|
||||
const auto job_id = JobID::FromInt(1);
|
||||
auto actor_id = ActorID::Of(job_id, TaskID::ForDriverTask(job_id), 1);
|
||||
actor->AssignActorId(actor_id);
|
||||
worker_pool_.PushWorker(actor);
|
||||
|
||||
@@ -223,8 +224,10 @@ TEST_F(WorkerPoolTest, StartWorkerWithDynamicOptionsCommand) {
|
||||
SetWorkerCommands({{Language::PYTHON, {"dummy_py_worker_command"}},
|
||||
{Language::JAVA, java_worker_command}});
|
||||
|
||||
const auto job_id = JobID::FromInt(1);
|
||||
TaskSpecification task_spec = ExampleTaskSpec(
|
||||
ActorID::Nil(), Language::JAVA, ActorID::FromRandom(), {"test_op_0", "test_op_1"});
|
||||
ActorID::Nil(), Language::JAVA,
|
||||
ActorID::Of(job_id, TaskID::ForDriverTask(job_id), 1), {"test_op_0", "test_op_1"});
|
||||
worker_pool_.StartWorkerProcess(Language::JAVA, task_spec.DynamicWorkerOptions());
|
||||
const auto real_command =
|
||||
worker_pool_.GetWorkerCommand(worker_pool_.LastStartedWorkerProcess());
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "ray/util/util.h"
|
||||
|
||||
namespace ray {
|
||||
|
||||
/// Wait until the condition is met, or timeout is reached.
|
||||
@@ -28,6 +30,13 @@ bool WaitForCondition(std::function<bool()> condition, int timeout_ms) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// A helper function to return a random task id.
|
||||
inline TaskID RandomTaskId() {
|
||||
std::string data(TaskID::Size(), 0);
|
||||
FillRandom(&data);
|
||||
return TaskID::FromBinary(data);
|
||||
}
|
||||
|
||||
} // namespace ray
|
||||
|
||||
#endif // RAY_UTIL_TEST_UTIL_H
|
||||
|
||||
+26
-1
@@ -4,7 +4,10 @@
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <chrono>
|
||||
#include <iterator>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "ray/common/status.h"
|
||||
@@ -100,8 +103,30 @@ struct EnumClassHash {
|
||||
}
|
||||
};
|
||||
|
||||
/// unodered_map for enum class type.
|
||||
/// unordered_map for enum class type.
|
||||
template <typename Key, typename T>
|
||||
using EnumUnorderedMap = std::unordered_map<Key, T, EnumClassHash>;
|
||||
|
||||
/// A helper function to fill random bytes into the `data`.
|
||||
template <typename T>
|
||||
void FillRandom(T *data) {
|
||||
RAY_CHECK(data != nullptr);
|
||||
auto randomly_seeded_mersenne_twister = []() {
|
||||
auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
|
||||
std::mt19937 seeded_engine(seed);
|
||||
return seeded_engine;
|
||||
};
|
||||
|
||||
// NOTE(pcm): The right way to do this is to have one std::mt19937 per
|
||||
// thread (using the thread_local keyword), but that's not supported on
|
||||
// older versions of macOS (see https://stackoverflow.com/a/29929949)
|
||||
static std::mutex random_engine_mutex;
|
||||
std::lock_guard<std::mutex> lock(random_engine_mutex);
|
||||
static std::mt19937 generator = randomly_seeded_mersenne_twister();
|
||||
std::uniform_int_distribution<uint32_t> dist(0, std::numeric_limits<uint8_t>::max());
|
||||
for (int i = 0; i < data->size(); i++) {
|
||||
(*data)[i] = static_cast<uint8_t>(dist(generator));
|
||||
}
|
||||
}
|
||||
|
||||
#endif // RAY_UTIL_UTIL_H
|
||||
|
||||
Reference in New Issue
Block a user