mirror of
https://github.com/wassname/ray.git
synced 2026-08-02 13:01:01 +08:00
[Streaming] Streaming data transfer and python integration (#6185)
This commit is contained in:
@@ -0,0 +1,240 @@
|
||||
#include "message.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
const uint32_t Message::MagicNum = 0xBABA0510;
|
||||
|
||||
std::unique_ptr<LocalMemoryBuffer> Message::ToBytes() {
|
||||
uint8_t *bytes = nullptr;
|
||||
|
||||
std::string pboutput;
|
||||
ToProtobuf(&pboutput);
|
||||
int64_t fbs_length = pboutput.length();
|
||||
|
||||
queue::protobuf::StreamingQueueMessageType type = Type();
|
||||
size_t total_len =
|
||||
sizeof(Message::MagicNum) + sizeof(type) + sizeof(fbs_length) + fbs_length;
|
||||
if (buffer_ != nullptr) {
|
||||
total_len += buffer_->Size();
|
||||
}
|
||||
bytes = new uint8_t[total_len];
|
||||
STREAMING_CHECK(bytes != nullptr) << "allocate bytes fail.";
|
||||
|
||||
uint8_t *p_cur = bytes;
|
||||
memcpy(p_cur, &Message::MagicNum, sizeof(Message::MagicNum));
|
||||
|
||||
p_cur += sizeof(Message::MagicNum);
|
||||
memcpy(p_cur, &type, sizeof(type));
|
||||
|
||||
p_cur += sizeof(type);
|
||||
memcpy(p_cur, &fbs_length, sizeof(fbs_length));
|
||||
|
||||
p_cur += sizeof(fbs_length);
|
||||
uint8_t *fbs_bytes = (uint8_t *)pboutput.data();
|
||||
memcpy(p_cur, fbs_bytes, fbs_length);
|
||||
p_cur += fbs_length;
|
||||
|
||||
if (buffer_ != nullptr) {
|
||||
memcpy(p_cur, buffer_->Data(), buffer_->Size());
|
||||
}
|
||||
|
||||
// COPY
|
||||
std::unique_ptr<LocalMemoryBuffer> buffer =
|
||||
std::unique_ptr<LocalMemoryBuffer>(new LocalMemoryBuffer(bytes, total_len, true));
|
||||
delete bytes;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void DataMessage::ToProtobuf(std::string *output) {
|
||||
queue::protobuf::StreamingQueueDataMsg msg;
|
||||
msg.set_src_actor_id(actor_id_.Binary());
|
||||
msg.set_dst_actor_id(peer_actor_id_.Binary());
|
||||
msg.set_queue_id(queue_id_.Binary());
|
||||
msg.set_seq_id(seq_id_);
|
||||
msg.set_length(buffer_->Size());
|
||||
msg.set_raw(raw_);
|
||||
msg.SerializeToString(output);
|
||||
}
|
||||
|
||||
std::shared_ptr<DataMessage> DataMessage::FromBytes(uint8_t *bytes) {
|
||||
bytes += sizeof(uint32_t) + sizeof(queue::protobuf::StreamingQueueMessageType);
|
||||
uint64_t *fbs_length = (uint64_t *)bytes;
|
||||
bytes += sizeof(uint64_t);
|
||||
|
||||
std::string inputpb(reinterpret_cast<char const *>(bytes), *fbs_length);
|
||||
queue::protobuf::StreamingQueueDataMsg message;
|
||||
message.ParseFromString(inputpb);
|
||||
ActorID src_actor_id = ActorID::FromBinary(message.src_actor_id());
|
||||
ActorID dst_actor_id = ActorID::FromBinary(message.dst_actor_id());
|
||||
ObjectID queue_id = ObjectID::FromBinary(message.queue_id());
|
||||
uint64_t seq_id = message.seq_id();
|
||||
uint64_t length = message.length();
|
||||
bool raw = message.raw();
|
||||
bytes += *fbs_length;
|
||||
|
||||
/// Copy data and create a new buffer for streaming queue.
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer =
|
||||
std::make_shared<LocalMemoryBuffer>(bytes, (size_t)length, true);
|
||||
std::shared_ptr<DataMessage> data_msg = std::make_shared<DataMessage>(
|
||||
src_actor_id, dst_actor_id, queue_id, seq_id, buffer, raw);
|
||||
|
||||
return data_msg;
|
||||
}
|
||||
|
||||
void NotificationMessage::ToProtobuf(std::string *output) {
|
||||
queue::protobuf::StreamingQueueNotificationMsg msg;
|
||||
msg.set_src_actor_id(actor_id_.Binary());
|
||||
msg.set_dst_actor_id(peer_actor_id_.Binary());
|
||||
msg.set_queue_id(queue_id_.Binary());
|
||||
msg.set_seq_id(seq_id_);
|
||||
msg.SerializeToString(output);
|
||||
}
|
||||
|
||||
std::shared_ptr<NotificationMessage> NotificationMessage::FromBytes(uint8_t *bytes) {
|
||||
bytes += sizeof(uint32_t) + sizeof(queue::protobuf::StreamingQueueMessageType);
|
||||
uint64_t *length = (uint64_t *)bytes;
|
||||
bytes += sizeof(uint64_t);
|
||||
|
||||
std::string inputpb(reinterpret_cast<char const *>(bytes), *length);
|
||||
queue::protobuf::StreamingQueueNotificationMsg message;
|
||||
message.ParseFromString(inputpb);
|
||||
STREAMING_LOG(INFO) << "message.src_actor_id: " << message.src_actor_id();
|
||||
ActorID src_actor_id = ActorID::FromBinary(message.src_actor_id());
|
||||
ActorID dst_actor_id = ActorID::FromBinary(message.dst_actor_id());
|
||||
ObjectID queue_id = ObjectID::FromBinary(message.queue_id());
|
||||
uint64_t seq_id = message.seq_id();
|
||||
|
||||
std::shared_ptr<NotificationMessage> notify_msg =
|
||||
std::make_shared<NotificationMessage>(src_actor_id, dst_actor_id, queue_id, seq_id);
|
||||
|
||||
return notify_msg;
|
||||
}
|
||||
|
||||
void CheckMessage::ToProtobuf(std::string *output) {
|
||||
queue::protobuf::StreamingQueueCheckMsg msg;
|
||||
msg.set_src_actor_id(actor_id_.Binary());
|
||||
msg.set_dst_actor_id(peer_actor_id_.Binary());
|
||||
msg.set_queue_id(queue_id_.Binary());
|
||||
msg.SerializeToString(output);
|
||||
}
|
||||
|
||||
std::shared_ptr<CheckMessage> CheckMessage::FromBytes(uint8_t *bytes) {
|
||||
bytes += sizeof(uint32_t) + sizeof(queue::protobuf::StreamingQueueMessageType);
|
||||
uint64_t *length = (uint64_t *)bytes;
|
||||
bytes += sizeof(uint64_t);
|
||||
|
||||
std::string inputpb(reinterpret_cast<char const *>(bytes), *length);
|
||||
queue::protobuf::StreamingQueueCheckMsg message;
|
||||
message.ParseFromString(inputpb);
|
||||
ActorID src_actor_id = ActorID::FromBinary(message.src_actor_id());
|
||||
ActorID dst_actor_id = ActorID::FromBinary(message.dst_actor_id());
|
||||
ObjectID queue_id = ObjectID::FromBinary(message.queue_id());
|
||||
|
||||
std::shared_ptr<CheckMessage> check_msg =
|
||||
std::make_shared<CheckMessage>(src_actor_id, dst_actor_id, queue_id);
|
||||
|
||||
return check_msg;
|
||||
}
|
||||
|
||||
void CheckRspMessage::ToProtobuf(std::string *output) {
|
||||
queue::protobuf::StreamingQueueCheckRspMsg msg;
|
||||
msg.set_src_actor_id(actor_id_.Binary());
|
||||
msg.set_dst_actor_id(peer_actor_id_.Binary());
|
||||
msg.set_queue_id(queue_id_.Binary());
|
||||
msg.set_err_code(err_code_);
|
||||
msg.SerializeToString(output);
|
||||
}
|
||||
|
||||
std::shared_ptr<CheckRspMessage> CheckRspMessage::FromBytes(uint8_t *bytes) {
|
||||
bytes += sizeof(uint32_t) + sizeof(queue::protobuf::StreamingQueueMessageType);
|
||||
uint64_t *length = (uint64_t *)bytes;
|
||||
bytes += sizeof(uint64_t);
|
||||
|
||||
std::string inputpb(reinterpret_cast<char const *>(bytes), *length);
|
||||
queue::protobuf::StreamingQueueCheckRspMsg message;
|
||||
message.ParseFromString(inputpb);
|
||||
ActorID src_actor_id = ActorID::FromBinary(message.src_actor_id());
|
||||
ActorID dst_actor_id = ActorID::FromBinary(message.dst_actor_id());
|
||||
ObjectID queue_id = ObjectID::FromBinary(message.queue_id());
|
||||
queue::protobuf::StreamingQueueError err_code = message.err_code();
|
||||
|
||||
std::shared_ptr<CheckRspMessage> check_rsp_msg =
|
||||
std::make_shared<CheckRspMessage>(src_actor_id, dst_actor_id, queue_id, err_code);
|
||||
|
||||
return check_rsp_msg;
|
||||
}
|
||||
|
||||
void TestInitMessage::ToProtobuf(std::string *output) {
|
||||
queue::protobuf::StreamingQueueTestInitMsg msg;
|
||||
msg.set_role(role_);
|
||||
msg.set_src_actor_id(actor_id_.Binary());
|
||||
msg.set_dst_actor_id(peer_actor_id_.Binary());
|
||||
msg.set_actor_handle(actor_handle_serialized_);
|
||||
for (auto &queue_id : queue_ids_) {
|
||||
msg.add_queue_ids(queue_id.Binary());
|
||||
}
|
||||
for (auto &queue_id : rescale_queue_ids_) {
|
||||
msg.add_rescale_queue_ids(queue_id.Binary());
|
||||
}
|
||||
msg.set_test_suite_name(test_suite_name_);
|
||||
msg.set_test_name(test_name_);
|
||||
msg.set_param(param_);
|
||||
msg.SerializeToString(output);
|
||||
}
|
||||
|
||||
std::shared_ptr<TestInitMessage> TestInitMessage::FromBytes(uint8_t *bytes) {
|
||||
bytes += sizeof(uint32_t) + sizeof(queue::protobuf::StreamingQueueMessageType);
|
||||
uint64_t *length = (uint64_t *)bytes;
|
||||
bytes += sizeof(uint64_t);
|
||||
|
||||
std::string inputpb(reinterpret_cast<char const *>(bytes), *length);
|
||||
queue::protobuf::StreamingQueueTestInitMsg message;
|
||||
message.ParseFromString(inputpb);
|
||||
queue::protobuf::StreamingQueueTestRole role = message.role();
|
||||
ActorID src_actor_id = ActorID::FromBinary(message.src_actor_id());
|
||||
ActorID dst_actor_id = ActorID::FromBinary(message.dst_actor_id());
|
||||
std::string actor_handle_serialized = message.actor_handle();
|
||||
std::vector<ObjectID> queue_ids;
|
||||
for (int i = 0; i < message.queue_ids_size(); i++) {
|
||||
queue_ids.push_back(ObjectID::FromBinary(message.queue_ids(i)));
|
||||
}
|
||||
std::vector<ObjectID> rescale_queue_ids;
|
||||
for (int i = 0; i < message.rescale_queue_ids_size(); i++) {
|
||||
rescale_queue_ids.push_back(ObjectID::FromBinary(message.rescale_queue_ids(i)));
|
||||
}
|
||||
std::string test_suite_name = message.test_suite_name();
|
||||
std::string test_name = message.test_name();
|
||||
uint64_t param = message.param();
|
||||
|
||||
std::shared_ptr<TestInitMessage> test_init_msg = std::make_shared<TestInitMessage>(
|
||||
role, src_actor_id, dst_actor_id, actor_handle_serialized, queue_ids,
|
||||
rescale_queue_ids, test_suite_name, test_name, param);
|
||||
|
||||
return test_init_msg;
|
||||
}
|
||||
|
||||
void TestCheckStatusRspMsg::ToProtobuf(std::string *output) {
|
||||
queue::protobuf::StreamingQueueTestCheckStatusRspMsg msg;
|
||||
msg.set_test_name(test_name_);
|
||||
msg.set_status(status_);
|
||||
msg.SerializeToString(output);
|
||||
}
|
||||
|
||||
std::shared_ptr<TestCheckStatusRspMsg> TestCheckStatusRspMsg::FromBytes(uint8_t *bytes) {
|
||||
bytes += sizeof(uint32_t) + sizeof(queue::protobuf::StreamingQueueMessageType);
|
||||
uint64_t *length = (uint64_t *)bytes;
|
||||
bytes += sizeof(uint64_t);
|
||||
|
||||
std::string inputpb(reinterpret_cast<char const *>(bytes), *length);
|
||||
queue::protobuf::StreamingQueueTestCheckStatusRspMsg message;
|
||||
message.ParseFromString(inputpb);
|
||||
std::string test_name = message.test_name();
|
||||
bool status = message.status();
|
||||
|
||||
std::shared_ptr<TestCheckStatusRspMsg> test_check_msg =
|
||||
std::make_shared<TestCheckStatusRspMsg>(test_name, status);
|
||||
|
||||
return test_check_msg;
|
||||
}
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,235 @@
|
||||
#ifndef _STREAMING_QUEUE_MESSAGE_H_
|
||||
#define _STREAMING_QUEUE_MESSAGE_H_
|
||||
|
||||
#include "protobuf/streaming_queue.pb.h"
|
||||
#include "ray/common/buffer.h"
|
||||
#include "ray/common/id.h"
|
||||
#include "util/streaming_logging.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
/// Base class of all message classes.
|
||||
/// All payloads transferred through direct actor call are packed into a unified package,
|
||||
/// consisting of protobuf-formatted metadata and data, including data and control
|
||||
/// messages. These message classes wrap the package defined in
|
||||
/// protobuf/streaming_queue.proto respectively.
|
||||
class Message {
|
||||
public:
|
||||
/// Construct a Message instance.
|
||||
/// \param[in] actor_id ActorID of message sender.
|
||||
/// \param[in] peer_actor_id ActorID of message receiver.
|
||||
/// \param[in] queue_id queue id to identify which queue the message is sent to.
|
||||
/// \param[in] buffer an optional param, a chunk of data to send.
|
||||
Message(const ActorID &actor_id, const ActorID &peer_actor_id, const ObjectID &queue_id,
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer = nullptr)
|
||||
: actor_id_(actor_id),
|
||||
peer_actor_id_(peer_actor_id),
|
||||
queue_id_(queue_id),
|
||||
buffer_(buffer) {}
|
||||
Message() {}
|
||||
virtual ~Message() {}
|
||||
ActorID ActorId() { return actor_id_; }
|
||||
ActorID PeerActorId() { return peer_actor_id_; }
|
||||
ObjectID QueueId() { return queue_id_; }
|
||||
std::shared_ptr<LocalMemoryBuffer> Buffer() { return buffer_; }
|
||||
|
||||
/// Serialize all meta data and data to a LocalMemoryBuffer, which can be sent through
|
||||
/// direct actor call. \return serialized buffer .
|
||||
std::unique_ptr<LocalMemoryBuffer> ToBytes();
|
||||
|
||||
/// Get message type.
|
||||
/// \return message type.
|
||||
virtual queue::protobuf::StreamingQueueMessageType Type() = 0;
|
||||
|
||||
/// All subclasses should implement `ToProtobuf` to serialize its own protobuf data.
|
||||
virtual void ToProtobuf(std::string *output) = 0;
|
||||
|
||||
protected:
|
||||
ActorID actor_id_;
|
||||
ActorID peer_actor_id_;
|
||||
ObjectID queue_id_;
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer_;
|
||||
|
||||
public:
|
||||
/// A magic number to identify a valid message.
|
||||
static const uint32_t MagicNum;
|
||||
};
|
||||
|
||||
/// Wrap StreamingQueueDataMsg in streaming_queue.proto.
|
||||
/// DataMessage encapsulates the memory buffer of QueueItem, a one-to-one relationship
|
||||
/// exists between DataMessage and QueueItem.
|
||||
class DataMessage : public Message {
|
||||
public:
|
||||
DataMessage(const ActorID &actor_id, const ActorID &peer_actor_id, ObjectID queue_id,
|
||||
uint64_t seq_id, std::shared_ptr<LocalMemoryBuffer> buffer, bool raw)
|
||||
: Message(actor_id, peer_actor_id, queue_id, buffer), seq_id_(seq_id), raw_(raw) {}
|
||||
virtual ~DataMessage() {}
|
||||
|
||||
static std::shared_ptr<DataMessage> FromBytes(uint8_t *bytes);
|
||||
virtual void ToProtobuf(std::string *output);
|
||||
uint64_t SeqId() { return seq_id_; }
|
||||
bool IsRaw() { return raw_; }
|
||||
queue::protobuf::StreamingQueueMessageType Type() { return type_; }
|
||||
|
||||
private:
|
||||
uint64_t seq_id_;
|
||||
bool raw_;
|
||||
|
||||
const queue::protobuf::StreamingQueueMessageType type_ =
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueDataMsgType;
|
||||
};
|
||||
|
||||
/// Wrap StreamingQueueNotificationMsg in streaming_queue.proto.
|
||||
/// NotificationMessage, downstream queues sends to upstream queues, for the data reader
|
||||
/// to inform the data writer of the consumed offset.
|
||||
class NotificationMessage : public Message {
|
||||
public:
|
||||
NotificationMessage(const ActorID &actor_id, const ActorID &peer_actor_id,
|
||||
const ObjectID &queue_id, uint64_t seq_id)
|
||||
: Message(actor_id, peer_actor_id, queue_id), seq_id_(seq_id) {}
|
||||
|
||||
virtual ~NotificationMessage() {}
|
||||
|
||||
static std::shared_ptr<NotificationMessage> FromBytes(uint8_t *bytes);
|
||||
virtual void ToProtobuf(std::string *output);
|
||||
|
||||
uint64_t SeqId() { return seq_id_; }
|
||||
queue::protobuf::StreamingQueueMessageType Type() { return type_; }
|
||||
|
||||
private:
|
||||
uint64_t seq_id_;
|
||||
const queue::protobuf::StreamingQueueMessageType type_ =
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueNotificationMsgType;
|
||||
};
|
||||
|
||||
/// Wrap StreamingQueueCheckMsg in streaming_queue.proto.
|
||||
/// CheckMessage, upstream queues sends to downstream queues, fot the data writer to check
|
||||
/// whether the corresponded downstream queue is read or not.
|
||||
class CheckMessage : public Message {
|
||||
public:
|
||||
CheckMessage(const ActorID &actor_id, const ActorID &peer_actor_id,
|
||||
const ObjectID &queue_id)
|
||||
: Message(actor_id, peer_actor_id, queue_id) {}
|
||||
virtual ~CheckMessage() {}
|
||||
|
||||
static std::shared_ptr<CheckMessage> FromBytes(uint8_t *bytes);
|
||||
virtual void ToProtobuf(std::string *output);
|
||||
|
||||
queue::protobuf::StreamingQueueMessageType Type() { return type_; }
|
||||
|
||||
private:
|
||||
const queue::protobuf::StreamingQueueMessageType type_ =
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueCheckMsgType;
|
||||
};
|
||||
|
||||
/// Wrap StreamingQueueCheckRspMsg in streaming_queue.proto.
|
||||
/// CheckRspMessage, downstream queues sends to upstream queues, the response message to
|
||||
/// CheckMessage to indicate whether downstream queue is ready or not.
|
||||
class CheckRspMessage : public Message {
|
||||
public:
|
||||
CheckRspMessage(const ActorID &actor_id, const ActorID &peer_actor_id,
|
||||
const ObjectID &queue_id, queue::protobuf::StreamingQueueError err_code)
|
||||
: Message(actor_id, peer_actor_id, queue_id), err_code_(err_code) {}
|
||||
virtual ~CheckRspMessage() {}
|
||||
|
||||
static std::shared_ptr<CheckRspMessage> FromBytes(uint8_t *bytes);
|
||||
virtual void ToProtobuf(std::string *output);
|
||||
queue::protobuf::StreamingQueueMessageType Type() { return type_; }
|
||||
queue::protobuf::StreamingQueueError Error() { return err_code_; }
|
||||
|
||||
private:
|
||||
queue::protobuf::StreamingQueueError err_code_;
|
||||
const queue::protobuf::StreamingQueueMessageType type_ =
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueCheckRspMsgType;
|
||||
};
|
||||
|
||||
/// Wrap StreamingQueueTestInitMsg in streaming_queue.proto.
|
||||
/// TestInitMessage, used for test, driver sends to test workers to init test suite.
|
||||
class TestInitMessage : public Message {
|
||||
public:
|
||||
TestInitMessage(const queue::protobuf::StreamingQueueTestRole role,
|
||||
const ActorID &actor_id, const ActorID &peer_actor_id,
|
||||
const std::string actor_handle_serialized,
|
||||
const std::vector<ObjectID> &queue_ids,
|
||||
const std::vector<ObjectID> &rescale_queue_ids,
|
||||
std::string test_suite_name, std::string test_name, uint64_t param)
|
||||
: Message(actor_id, peer_actor_id, queue_ids[0]),
|
||||
actor_handle_serialized_(actor_handle_serialized),
|
||||
queue_ids_(queue_ids),
|
||||
rescale_queue_ids_(rescale_queue_ids),
|
||||
role_(role),
|
||||
test_suite_name_(test_suite_name),
|
||||
test_name_(test_name),
|
||||
param_(param) {}
|
||||
virtual ~TestInitMessage() {}
|
||||
|
||||
static std::shared_ptr<TestInitMessage> FromBytes(uint8_t *bytes);
|
||||
virtual void ToProtobuf(std::string *output);
|
||||
queue::protobuf::StreamingQueueMessageType Type() { return type_; }
|
||||
std::string ActorHandleSerialized() { return actor_handle_serialized_; }
|
||||
queue::protobuf::StreamingQueueTestRole Role() { return role_; }
|
||||
std::vector<ObjectID> QueueIds() { return queue_ids_; }
|
||||
std::vector<ObjectID> RescaleQueueIds() { return rescale_queue_ids_; }
|
||||
std::string TestSuiteName() { return test_suite_name_; }
|
||||
std::string TestName() { return test_name_; }
|
||||
uint64_t Param() { return param_; }
|
||||
|
||||
std::string ToString() {
|
||||
std::ostringstream os;
|
||||
os << "actor_handle_serialized: " << actor_handle_serialized_;
|
||||
os << " actor_id: " << ActorId();
|
||||
os << " peer_actor_id: " << PeerActorId();
|
||||
os << " queue_ids:[";
|
||||
for (auto &qid : queue_ids_) {
|
||||
os << qid << ",";
|
||||
}
|
||||
os << "], rescale_queue_ids:[";
|
||||
for (auto &qid : rescale_queue_ids_) {
|
||||
os << qid << ",";
|
||||
}
|
||||
os << "],";
|
||||
os << " role:" << queue::protobuf::StreamingQueueTestRole_Name(role_);
|
||||
os << " suite_name: " << test_suite_name_;
|
||||
os << " test_name: " << test_name_;
|
||||
os << " param: " << param_;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
private:
|
||||
const queue::protobuf::StreamingQueueMessageType type_ =
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueTestInitMsgType;
|
||||
std::string actor_handle_serialized_;
|
||||
std::vector<ObjectID> queue_ids_;
|
||||
std::vector<ObjectID> rescale_queue_ids_;
|
||||
queue::protobuf::StreamingQueueTestRole role_;
|
||||
std::string test_suite_name_;
|
||||
std::string test_name_;
|
||||
uint64_t param_;
|
||||
};
|
||||
|
||||
/// Wrap StreamingQueueTestCheckStatusRspMsg in streaming_queue.proto.
|
||||
/// TestCheckStatusRspMsg, used for test, driver sends to test workers to check
|
||||
/// whether test has completed or failed.
|
||||
class TestCheckStatusRspMsg : public Message {
|
||||
public:
|
||||
TestCheckStatusRspMsg(const std::string test_name, bool status)
|
||||
: test_name_(test_name), status_(status) {}
|
||||
virtual ~TestCheckStatusRspMsg() {}
|
||||
|
||||
static std::shared_ptr<TestCheckStatusRspMsg> FromBytes(uint8_t *bytes);
|
||||
virtual void ToProtobuf(std::string *output);
|
||||
queue::protobuf::StreamingQueueMessageType Type() { return type_; }
|
||||
std::string TestName() { return test_name_; }
|
||||
bool Status() { return status_; }
|
||||
|
||||
private:
|
||||
const queue::protobuf::StreamingQueueMessageType type_ =
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueTestCheckStatusRspMsgType;
|
||||
std::string test_name_;
|
||||
bool status_;
|
||||
};
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
#endif
|
||||
@@ -0,0 +1,211 @@
|
||||
#include "queue.h"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "queue_handler.h"
|
||||
#include "util/streaming_util.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
bool Queue::Push(QueueItem item) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (max_data_size_ < item.DataSize() + data_size_) return false;
|
||||
|
||||
buffer_queue_.push_back(item);
|
||||
data_size_ += item.DataSize();
|
||||
readable_cv_.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
QueueItem Queue::FrontProcessed() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
STREAMING_CHECK(buffer_queue_.size() != 0) << "WriterQueue Pop fail";
|
||||
|
||||
if (watershed_iter_ == buffer_queue_.begin()) {
|
||||
return InvalidQueueItem();
|
||||
}
|
||||
|
||||
QueueItem item = buffer_queue_.front();
|
||||
return item;
|
||||
}
|
||||
|
||||
QueueItem Queue::PopProcessed() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
STREAMING_CHECK(buffer_queue_.size() != 0) << "WriterQueue Pop fail";
|
||||
|
||||
if (watershed_iter_ == buffer_queue_.begin()) {
|
||||
return InvalidQueueItem();
|
||||
}
|
||||
|
||||
QueueItem item = buffer_queue_.front();
|
||||
buffer_queue_.pop_front();
|
||||
data_size_ -= item.DataSize();
|
||||
data_size_sent_ -= item.DataSize();
|
||||
return item;
|
||||
}
|
||||
|
||||
QueueItem Queue::PopPending() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
auto it = std::next(watershed_iter_);
|
||||
QueueItem item = *it;
|
||||
data_size_sent_ += it->DataSize();
|
||||
buffer_queue_.splice(watershed_iter_, buffer_queue_, it, std::next(it));
|
||||
return item;
|
||||
}
|
||||
|
||||
QueueItem Queue::PopPendingBlockTimeout(uint64_t timeout_us) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
std::chrono::system_clock::time_point point =
|
||||
std::chrono::system_clock::now() + std::chrono::microseconds(timeout_us);
|
||||
if (readable_cv_.wait_until(lock, point, [this] {
|
||||
return std::next(watershed_iter_) != buffer_queue_.end();
|
||||
})) {
|
||||
auto it = std::next(watershed_iter_);
|
||||
QueueItem item = *it;
|
||||
data_size_sent_ += it->DataSize();
|
||||
buffer_queue_.splice(watershed_iter_, buffer_queue_, it, std::next(it));
|
||||
return item;
|
||||
|
||||
} else {
|
||||
uint8_t data[1];
|
||||
return QueueItem(QUEUE_INVALID_SEQ_ID, data, 1, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
QueueItem Queue::BackPending() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (std::next(watershed_iter_) == buffer_queue_.end()) {
|
||||
uint8_t data[1];
|
||||
return QueueItem(QUEUE_INVALID_SEQ_ID, data, 1, 0, true);
|
||||
}
|
||||
return buffer_queue_.back();
|
||||
}
|
||||
|
||||
bool Queue::IsPendingEmpty() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return std::next(watershed_iter_) == buffer_queue_.end();
|
||||
}
|
||||
|
||||
bool Queue::IsPendingFull(uint64_t data_size) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return max_data_size_ < data_size + data_size_;
|
||||
}
|
||||
|
||||
size_t Queue::ProcessedCount() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (watershed_iter_ == buffer_queue_.begin()) return 0;
|
||||
|
||||
auto begin = buffer_queue_.begin();
|
||||
auto end = std::prev(watershed_iter_);
|
||||
|
||||
return end->SeqId() + 1 - begin->SeqId();
|
||||
}
|
||||
|
||||
size_t Queue::PendingCount() {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
if (std::next(watershed_iter_) == buffer_queue_.end()) return 0;
|
||||
|
||||
auto begin = std::next(watershed_iter_);
|
||||
auto end = std::prev(buffer_queue_.end());
|
||||
|
||||
return begin->SeqId() - end->SeqId() + 1;
|
||||
}
|
||||
|
||||
Status WriterQueue::Push(uint64_t seq_id, uint8_t *data, uint32_t data_size,
|
||||
uint64_t timestamp, bool raw) {
|
||||
if (IsPendingFull(data_size)) {
|
||||
return Status::OutOfMemory("Queue Push OutOfMemory");
|
||||
}
|
||||
|
||||
while (is_pulling_) {
|
||||
STREAMING_LOG(INFO) << "This queue is sending pull data, wait.";
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
QueueItem item(seq_id, data, data_size, timestamp, raw);
|
||||
Queue::Push(item);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void WriterQueue::Send() {
|
||||
while (!IsPendingEmpty()) {
|
||||
// FIXME: front -> send -> pop
|
||||
QueueItem item = PopPending();
|
||||
DataMessage msg(actor_id_, peer_actor_id_, queue_id_, item.SeqId(), item.Buffer(),
|
||||
item.IsRaw());
|
||||
std::unique_ptr<LocalMemoryBuffer> buffer = msg.ToBytes();
|
||||
STREAMING_CHECK(transport_ != nullptr);
|
||||
transport_->Send(std::move(buffer),
|
||||
DownstreamQueueMessageHandler::peer_async_function_);
|
||||
}
|
||||
}
|
||||
|
||||
Status WriterQueue::TryEvictItems() {
|
||||
STREAMING_LOG(INFO) << "TryEvictItems";
|
||||
QueueItem item = FrontProcessed();
|
||||
uint64_t first_seq_id = item.SeqId();
|
||||
STREAMING_LOG(INFO) << "TryEvictItems first_seq_id: " << first_seq_id
|
||||
<< " min_consumed_id_: " << min_consumed_id_
|
||||
<< " eviction_limit_: " << eviction_limit_;
|
||||
if (min_consumed_id_ == QUEUE_INVALID_SEQ_ID || first_seq_id > min_consumed_id_) {
|
||||
return Status::OutOfMemory("The queue is full and some reader doesn't consume");
|
||||
}
|
||||
|
||||
if (eviction_limit_ == QUEUE_INVALID_SEQ_ID || first_seq_id > eviction_limit_) {
|
||||
return Status::OutOfMemory("The queue is full and eviction limit block evict");
|
||||
}
|
||||
|
||||
uint64_t evict_target_seq_id = std::min(min_consumed_id_, eviction_limit_);
|
||||
|
||||
while (item.SeqId() <= evict_target_seq_id) {
|
||||
PopProcessed();
|
||||
STREAMING_LOG(INFO) << "TryEvictItems directly " << item.SeqId();
|
||||
item = FrontProcessed();
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void WriterQueue::OnNotify(std::shared_ptr<NotificationMessage> notify_msg) {
|
||||
STREAMING_LOG(INFO) << "OnNotify target seq_id: " << notify_msg->SeqId();
|
||||
min_consumed_id_ = notify_msg->SeqId();
|
||||
}
|
||||
|
||||
void ReaderQueue::OnConsumed(uint64_t seq_id) {
|
||||
STREAMING_LOG(INFO) << "OnConsumed: " << seq_id;
|
||||
QueueItem item = FrontProcessed();
|
||||
while (item.SeqId() <= seq_id) {
|
||||
PopProcessed();
|
||||
item = FrontProcessed();
|
||||
}
|
||||
Notify(seq_id);
|
||||
}
|
||||
|
||||
void ReaderQueue::Notify(uint64_t seq_id) {
|
||||
std::vector<TaskArg> task_args;
|
||||
CreateNotifyTask(seq_id, task_args);
|
||||
// SubmitActorTask
|
||||
|
||||
NotificationMessage msg(actor_id_, peer_actor_id_, queue_id_, seq_id);
|
||||
std::unique_ptr<LocalMemoryBuffer> buffer = msg.ToBytes();
|
||||
|
||||
transport_->Send(std::move(buffer), UpstreamQueueMessageHandler::peer_async_function_);
|
||||
}
|
||||
|
||||
void ReaderQueue::CreateNotifyTask(uint64_t seq_id, std::vector<TaskArg> &task_args) {}
|
||||
|
||||
void ReaderQueue::OnData(QueueItem &item) {
|
||||
if (item.SeqId() != expect_seq_id_) {
|
||||
STREAMING_LOG(WARNING) << "OnData ignore seq_id: " << item.SeqId()
|
||||
<< " expect_seq_id_: " << expect_seq_id_;
|
||||
return;
|
||||
}
|
||||
|
||||
last_recv_seq_id_ = item.SeqId();
|
||||
STREAMING_LOG(DEBUG) << "ReaderQueue::OnData seq_id: " << last_recv_seq_id_;
|
||||
|
||||
Push(item);
|
||||
expect_seq_id_++;
|
||||
}
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,213 @@
|
||||
#ifndef _STREAMING_QUEUE_H_
|
||||
#define _STREAMING_QUEUE_H_
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
#include "ray/common/id.h"
|
||||
#include "ray/util/util.h"
|
||||
|
||||
#include "queue_item.h"
|
||||
#include "transport.h"
|
||||
#include "util/streaming_logging.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
using ray::ObjectID;
|
||||
|
||||
enum QueueType { UPSTREAM = 0, DOWNSTREAM };
|
||||
|
||||
/// A queue-like data structure, which does not delete its items after poped.
|
||||
/// The lifecycle of each item is:
|
||||
/// - Pending, an item is pushed into a queue, but has not been processed (sent out or
|
||||
/// consumed),
|
||||
/// - Processed, has been handled by the user, but should not be deleted.
|
||||
/// - Evicted, useless to the user, should be poped and destroyed.
|
||||
/// At present, this data structure is implemented with one std::list,
|
||||
/// using a watershed iterator to divided.
|
||||
class Queue {
|
||||
public:
|
||||
/// \param[in] queue_id the unique identification of a pair of queues (upstream and
|
||||
/// downstream). \param[in] size max size of the queue in bytes. \param[in] transport
|
||||
/// transport to send items to peer.
|
||||
Queue(ObjectID queue_id, uint64_t size, std::shared_ptr<Transport> transport)
|
||||
: queue_id_(queue_id), max_data_size_(size), data_size_(0), data_size_sent_(0) {
|
||||
buffer_queue_.push_back(InvalidQueueItem());
|
||||
watershed_iter_ = buffer_queue_.begin();
|
||||
}
|
||||
|
||||
virtual ~Queue() {}
|
||||
|
||||
/// Push an item into the queue.
|
||||
/// \param[in] item the QueueItem object to be send to peer.
|
||||
/// \return false if the queue is full.
|
||||
bool Push(QueueItem item);
|
||||
|
||||
/// Get the front of item which in processed state.
|
||||
QueueItem FrontProcessed();
|
||||
|
||||
/// Pop the front of item which in processed state.
|
||||
QueueItem PopProcessed();
|
||||
|
||||
/// Pop the front of item which in pending state, the item
|
||||
/// will not be evicted at this moment, its state turn to
|
||||
/// processed.
|
||||
QueueItem PopPending();
|
||||
|
||||
/// PopPending with timeout in microseconds.
|
||||
QueueItem PopPendingBlockTimeout(uint64_t timeout_us);
|
||||
|
||||
/// Return the last item in pending state.
|
||||
QueueItem BackPending();
|
||||
|
||||
bool IsPendingEmpty();
|
||||
bool IsPendingFull(uint64_t data_size = 0);
|
||||
|
||||
/// Return the size in bytes of all items in queue.
|
||||
uint64_t QueueSize() { return data_size_; }
|
||||
|
||||
/// Return the size in bytes of all items in pending state.
|
||||
uint64_t PendingDataSize() { return data_size_ - data_size_sent_; }
|
||||
|
||||
/// Return the size in bytes of all items in processed state.
|
||||
uint64_t ProcessedDataSize() { return data_size_sent_; }
|
||||
|
||||
/// Return item count of the queue.
|
||||
size_t Count() { return buffer_queue_.size(); }
|
||||
|
||||
/// Return item count in pending state.
|
||||
size_t PendingCount();
|
||||
|
||||
/// Return item count in processed state.
|
||||
size_t ProcessedCount();
|
||||
|
||||
protected:
|
||||
ObjectID queue_id_;
|
||||
std::list<QueueItem> buffer_queue_;
|
||||
std::list<QueueItem>::iterator watershed_iter_;
|
||||
|
||||
/// max data size in bytes
|
||||
uint64_t max_data_size_;
|
||||
uint64_t data_size_;
|
||||
uint64_t data_size_sent_;
|
||||
|
||||
std::mutex mutex_;
|
||||
std::condition_variable readable_cv_;
|
||||
};
|
||||
|
||||
/// Queue in upstream.
|
||||
class WriterQueue : public Queue {
|
||||
public:
|
||||
/// \param queue_id, the unique ObjectID to identify a queue
|
||||
/// \param actor_id, the actor id of upstream worker
|
||||
/// \param peer_actor_id, the actor id of downstream worker
|
||||
/// \param size, max data size in bytes
|
||||
/// \param transport, transport
|
||||
WriterQueue(const ObjectID &queue_id, const ActorID &actor_id,
|
||||
const ActorID &peer_actor_id, uint64_t size,
|
||||
std::shared_ptr<Transport> transport)
|
||||
: Queue(queue_id, size, transport),
|
||||
actor_id_(actor_id),
|
||||
peer_actor_id_(peer_actor_id),
|
||||
eviction_limit_(QUEUE_INVALID_SEQ_ID),
|
||||
min_consumed_id_(QUEUE_INVALID_SEQ_ID),
|
||||
peer_last_msg_id_(0),
|
||||
peer_last_seq_id_(QUEUE_INVALID_SEQ_ID),
|
||||
transport_(transport),
|
||||
is_pulling_(false) {}
|
||||
|
||||
/// Push a continuous buffer into queue.
|
||||
/// NOTE: the buffer should be copied.
|
||||
Status Push(uint64_t seq_id, uint8_t *data, uint32_t data_size, uint64_t timestamp,
|
||||
bool raw = false);
|
||||
|
||||
/// Callback function, will be called when downstream queue notifies
|
||||
/// it has consumed some items.
|
||||
/// NOTE: this callback function is called in queue thread.
|
||||
void OnNotify(std::shared_ptr<NotificationMessage> notify_msg);
|
||||
|
||||
/// Send items through direct call.
|
||||
void Send();
|
||||
|
||||
/// Called when user pushs item into queue. The count of items
|
||||
/// can be evicted, determined by eviction_limit_ and min_consumed_id_.
|
||||
Status TryEvictItems();
|
||||
|
||||
void SetQueueEvictionLimit(uint64_t eviction_limit) {
|
||||
eviction_limit_ = eviction_limit;
|
||||
}
|
||||
|
||||
uint64_t EvictionLimit() { return eviction_limit_; }
|
||||
|
||||
uint64_t GetMinConsumedSeqID() { return min_consumed_id_; }
|
||||
|
||||
void SetPeerLastIds(uint64_t msg_id, uint64_t seq_id) {
|
||||
peer_last_msg_id_ = msg_id;
|
||||
peer_last_seq_id_ = seq_id;
|
||||
}
|
||||
|
||||
uint64_t GetPeerLastMsgId() { return peer_last_msg_id_; }
|
||||
|
||||
uint64_t GetPeerLastSeqId() { return peer_last_seq_id_; }
|
||||
|
||||
private:
|
||||
ActorID actor_id_;
|
||||
ActorID peer_actor_id_;
|
||||
uint64_t eviction_limit_;
|
||||
uint64_t min_consumed_id_;
|
||||
uint64_t peer_last_msg_id_;
|
||||
uint64_t peer_last_seq_id_;
|
||||
std::shared_ptr<Transport> transport_;
|
||||
|
||||
std::atomic<bool> is_pulling_;
|
||||
};
|
||||
|
||||
/// Queue in downstream.
|
||||
class ReaderQueue : public Queue {
|
||||
public:
|
||||
/// \param queue_id, the unique ObjectID to identify a queue
|
||||
/// \param actor_id, the actor id of upstream worker
|
||||
/// \param peer_actor_id, the actor id of downstream worker
|
||||
/// \param transport, transport
|
||||
/// NOTE: we do not restrict queue size of ReaderQueue
|
||||
ReaderQueue(const ObjectID &queue_id, const ActorID &actor_id,
|
||||
const ActorID &peer_actor_id, std::shared_ptr<Transport> transport)
|
||||
: Queue(queue_id, std::numeric_limits<uint64_t>::max(), transport),
|
||||
actor_id_(actor_id),
|
||||
peer_actor_id_(peer_actor_id),
|
||||
min_consumed_id_(QUEUE_INVALID_SEQ_ID),
|
||||
last_recv_seq_id_(QUEUE_INVALID_SEQ_ID),
|
||||
expect_seq_id_(1),
|
||||
transport_(transport) {}
|
||||
|
||||
/// Delete processed items whose seq id <= seq_id,
|
||||
/// then notify upstream queue.
|
||||
void OnConsumed(uint64_t seq_id);
|
||||
|
||||
void OnData(QueueItem &item);
|
||||
|
||||
uint64_t GetMinConsumedSeqID() { return min_consumed_id_; }
|
||||
|
||||
uint64_t GetLastRecvSeqId() { return last_recv_seq_id_; }
|
||||
|
||||
void SetExpectSeqId(uint64_t expect) { expect_seq_id_ = expect; }
|
||||
|
||||
private:
|
||||
void Notify(uint64_t seq_id);
|
||||
void CreateNotifyTask(uint64_t seq_id, std::vector<TaskArg> &task_args);
|
||||
|
||||
private:
|
||||
ActorID actor_id_;
|
||||
ActorID peer_actor_id_;
|
||||
uint64_t min_consumed_id_;
|
||||
uint64_t last_recv_seq_id_;
|
||||
uint64_t expect_seq_id_;
|
||||
std::shared_ptr<PromiseWrapper> promise_for_pull_;
|
||||
std::shared_ptr<Transport> transport_;
|
||||
};
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
#endif
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "queue_client.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
void WriterClient::OnWriterMessage(std::shared_ptr<LocalMemoryBuffer> buffer) {
|
||||
upstream_handler_->DispatchMessageAsync(buffer);
|
||||
}
|
||||
|
||||
std::shared_ptr<LocalMemoryBuffer> WriterClient::OnWriterMessageSync(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer) {
|
||||
return upstream_handler_->DispatchMessageSync(buffer);
|
||||
}
|
||||
|
||||
void ReaderClient::OnReaderMessage(std::shared_ptr<LocalMemoryBuffer> buffer) {
|
||||
downstream_handler_->DispatchMessageAsync(buffer);
|
||||
}
|
||||
|
||||
std::shared_ptr<LocalMemoryBuffer> ReaderClient::OnReaderMessageSync(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer) {
|
||||
return downstream_handler_->DispatchMessageSync(buffer);
|
||||
}
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef _STREAMING_QUEUE_CLIENT_H_
|
||||
#define _STREAMING_QUEUE_CLIENT_H_
|
||||
#include "queue_handler.h"
|
||||
#include "transport.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
/// The interface of the streaming queue for DataReader.
|
||||
/// A ReaderClient should be created before DataReader created in Cython/Jni, and hold by
|
||||
/// Jobworker. When DataReader receive a buffer from upstream DataWriter (DataReader's
|
||||
/// raycall function is called), it calls `OnReaderMessage` to pass the buffer to its own
|
||||
/// downstream queue, or `OnReaderMessageSync` to wait for handle result.
|
||||
class ReaderClient {
|
||||
public:
|
||||
/// Construct a ReaderClient object.
|
||||
/// \param[in] core_worker CoreWorker C++ pointer of current actor
|
||||
/// \param[in] async_func DataReader's raycall function descriptor to be called by
|
||||
/// DataWriter, asynchronous semantics \param[in] sync_func DataReader's raycall
|
||||
/// function descriptor to be called by DataWriter, synchronous semantics
|
||||
ReaderClient(CoreWorker *core_worker, RayFunction &async_func, RayFunction &sync_func)
|
||||
: core_worker_(core_worker) {
|
||||
DownstreamQueueMessageHandler::peer_async_function_ = async_func;
|
||||
DownstreamQueueMessageHandler::peer_sync_function_ = sync_func;
|
||||
downstream_handler_ = ray::streaming::DownstreamQueueMessageHandler::CreateService(
|
||||
core_worker_, core_worker_->GetWorkerContext().GetCurrentActorID());
|
||||
}
|
||||
|
||||
/// Post buffer to downstream queue service, asynchronously.
|
||||
void OnReaderMessage(std::shared_ptr<LocalMemoryBuffer> buffer);
|
||||
/// Post buffer to downstream queue service, synchronously.
|
||||
/// \return handle result.
|
||||
std::shared_ptr<LocalMemoryBuffer> OnReaderMessageSync(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer);
|
||||
|
||||
private:
|
||||
CoreWorker *core_worker_;
|
||||
std::shared_ptr<DownstreamQueueMessageHandler> downstream_handler_;
|
||||
};
|
||||
|
||||
/// Interface of streaming queue for DataWriter. Similar to ReaderClient.
|
||||
class WriterClient {
|
||||
public:
|
||||
WriterClient(CoreWorker *core_worker, RayFunction &async_func, RayFunction &sync_func)
|
||||
: core_worker_(core_worker) {
|
||||
UpstreamQueueMessageHandler::peer_async_function_ = async_func;
|
||||
UpstreamQueueMessageHandler::peer_sync_function_ = sync_func;
|
||||
upstream_handler_ = ray::streaming::UpstreamQueueMessageHandler::CreateService(
|
||||
core_worker, core_worker_->GetWorkerContext().GetCurrentActorID());
|
||||
}
|
||||
|
||||
void OnWriterMessage(std::shared_ptr<LocalMemoryBuffer> buffer);
|
||||
std::shared_ptr<LocalMemoryBuffer> OnWriterMessageSync(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer);
|
||||
|
||||
private:
|
||||
CoreWorker *core_worker_;
|
||||
std::shared_ptr<UpstreamQueueMessageHandler> upstream_handler_;
|
||||
};
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
#endif
|
||||
@@ -0,0 +1,358 @@
|
||||
#include "queue_handler.h"
|
||||
#include "util/streaming_util.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
constexpr uint64_t COMMON_SYNC_CALL_TIMEOUTT_MS = 5 * 1000;
|
||||
|
||||
std::shared_ptr<UpstreamQueueMessageHandler>
|
||||
UpstreamQueueMessageHandler::upstream_handler_ = nullptr;
|
||||
std::shared_ptr<DownstreamQueueMessageHandler>
|
||||
DownstreamQueueMessageHandler::downstream_handler_ = nullptr;
|
||||
|
||||
RayFunction UpstreamQueueMessageHandler::peer_sync_function_;
|
||||
RayFunction UpstreamQueueMessageHandler::peer_async_function_;
|
||||
RayFunction DownstreamQueueMessageHandler::peer_sync_function_;
|
||||
RayFunction DownstreamQueueMessageHandler::peer_async_function_;
|
||||
|
||||
std::shared_ptr<Message> QueueMessageHandler::ParseMessage(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer) {
|
||||
uint8_t *bytes = buffer->Data();
|
||||
uint8_t *p_cur = bytes;
|
||||
uint32_t *magic_num = (uint32_t *)p_cur;
|
||||
STREAMING_CHECK(*magic_num == Message::MagicNum)
|
||||
<< *magic_num << " " << Message::MagicNum;
|
||||
|
||||
p_cur += sizeof(Message::MagicNum);
|
||||
queue::protobuf::StreamingQueueMessageType *type =
|
||||
(queue::protobuf::StreamingQueueMessageType *)p_cur;
|
||||
|
||||
std::shared_ptr<Message> message = nullptr;
|
||||
switch (*type) {
|
||||
case queue::protobuf::StreamingQueueMessageType::StreamingQueueNotificationMsgType:
|
||||
message = NotificationMessage::FromBytes(bytes);
|
||||
break;
|
||||
case queue::protobuf::StreamingQueueMessageType::StreamingQueueDataMsgType:
|
||||
message = DataMessage::FromBytes(bytes);
|
||||
break;
|
||||
case queue::protobuf::StreamingQueueMessageType::StreamingQueueCheckMsgType:
|
||||
message = CheckMessage::FromBytes(bytes);
|
||||
break;
|
||||
case queue::protobuf::StreamingQueueMessageType::StreamingQueueCheckRspMsgType:
|
||||
message = CheckRspMessage::FromBytes(bytes);
|
||||
break;
|
||||
default:
|
||||
STREAMING_CHECK(false) << "nonsupport message type: "
|
||||
<< queue::protobuf::StreamingQueueMessageType_Name(*type);
|
||||
break;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
void QueueMessageHandler::DispatchMessageAsync(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer) {
|
||||
queue_service_.post(
|
||||
boost::bind(&QueueMessageHandler::DispatchMessageInternal, this, buffer, nullptr));
|
||||
}
|
||||
|
||||
std::shared_ptr<LocalMemoryBuffer> QueueMessageHandler::DispatchMessageSync(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer) {
|
||||
std::shared_ptr<LocalMemoryBuffer> result = nullptr;
|
||||
std::shared_ptr<PromiseWrapper> promise = std::make_shared<PromiseWrapper>();
|
||||
queue_service_.post(
|
||||
boost::bind(&QueueMessageHandler::DispatchMessageInternal, this, buffer,
|
||||
[&promise, &result](std::shared_ptr<LocalMemoryBuffer> rst) {
|
||||
result = rst;
|
||||
promise->Notify(ray::Status::OK());
|
||||
}));
|
||||
Status st = promise->Wait();
|
||||
STREAMING_CHECK(st.ok());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::shared_ptr<Transport> QueueMessageHandler::GetOutTransport(
|
||||
const ObjectID &queue_id) {
|
||||
auto it = out_transports_.find(queue_id);
|
||||
if (it == out_transports_.end()) return nullptr;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void QueueMessageHandler::SetPeerActorID(const ObjectID &queue_id,
|
||||
const ActorID &actor_id) {
|
||||
actors_.emplace(queue_id, actor_id);
|
||||
out_transports_.emplace(
|
||||
queue_id, std::make_shared<ray::streaming::Transport>(core_worker_, actor_id));
|
||||
}
|
||||
|
||||
ActorID QueueMessageHandler::GetPeerActorID(const ObjectID &queue_id) {
|
||||
auto it = actors_.find(queue_id);
|
||||
STREAMING_CHECK(it != actors_.end());
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void QueueMessageHandler::Release() {
|
||||
actors_.clear();
|
||||
out_transports_.clear();
|
||||
}
|
||||
|
||||
void QueueMessageHandler::Start() {
|
||||
queue_thread_ = std::thread(&QueueMessageHandler::QueueThreadCallback, this);
|
||||
}
|
||||
|
||||
void QueueMessageHandler::Stop() {
|
||||
STREAMING_LOG(INFO) << "QueueMessageHandler Stop.";
|
||||
queue_service_.stop();
|
||||
if (queue_thread_.joinable()) {
|
||||
queue_thread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<UpstreamQueueMessageHandler> UpstreamQueueMessageHandler::CreateService(
|
||||
CoreWorker *core_worker, const ActorID &actor_id) {
|
||||
if (nullptr == upstream_handler_) {
|
||||
upstream_handler_ =
|
||||
std::make_shared<UpstreamQueueMessageHandler>(core_worker, actor_id);
|
||||
}
|
||||
return upstream_handler_;
|
||||
}
|
||||
|
||||
std::shared_ptr<UpstreamQueueMessageHandler> UpstreamQueueMessageHandler::GetService() {
|
||||
return upstream_handler_;
|
||||
}
|
||||
|
||||
std::shared_ptr<WriterQueue> UpstreamQueueMessageHandler::CreateUpstreamQueue(
|
||||
const ObjectID &queue_id, const ActorID &peer_actor_id, uint64_t size) {
|
||||
STREAMING_LOG(INFO) << "CreateUpstreamQueue: " << queue_id << " " << actor_id_ << "->"
|
||||
<< peer_actor_id;
|
||||
std::shared_ptr<WriterQueue> queue = GetUpQueue(queue_id);
|
||||
if (queue != nullptr) {
|
||||
STREAMING_LOG(WARNING) << "Duplicate to create up queue." << queue_id;
|
||||
return queue;
|
||||
}
|
||||
|
||||
queue = std::unique_ptr<streaming::WriterQueue>(new streaming::WriterQueue(
|
||||
queue_id, actor_id_, peer_actor_id, size, GetOutTransport(queue_id)));
|
||||
upstream_queues_[queue_id] = queue;
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
bool UpstreamQueueMessageHandler::UpstreamQueueExists(const ObjectID &queue_id) {
|
||||
return nullptr != GetUpQueue(queue_id);
|
||||
}
|
||||
|
||||
std::shared_ptr<streaming::WriterQueue> UpstreamQueueMessageHandler::GetUpQueue(
|
||||
const ObjectID &queue_id) {
|
||||
auto it = upstream_queues_.find(queue_id);
|
||||
if (it == upstream_queues_.end()) return nullptr;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
bool UpstreamQueueMessageHandler::CheckQueueSync(const ObjectID &queue_id) {
|
||||
ActorID peer_actor_id = GetPeerActorID(queue_id);
|
||||
STREAMING_LOG(INFO) << "CheckQueueSync queue_id: " << queue_id
|
||||
<< " peer_actor_id: " << peer_actor_id;
|
||||
|
||||
CheckMessage msg(actor_id_, peer_actor_id, queue_id);
|
||||
std::unique_ptr<LocalMemoryBuffer> buffer = msg.ToBytes();
|
||||
|
||||
auto transport_it = GetOutTransport(queue_id);
|
||||
STREAMING_CHECK(transport_it != nullptr);
|
||||
std::shared_ptr<LocalMemoryBuffer> result_buffer = transport_it->SendForResultWithRetry(
|
||||
std::move(buffer), DownstreamQueueMessageHandler::peer_sync_function_, 10,
|
||||
COMMON_SYNC_CALL_TIMEOUTT_MS);
|
||||
if (result_buffer == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::shared_ptr<Message> result_msg = ParseMessage(result_buffer);
|
||||
STREAMING_CHECK(
|
||||
result_msg->Type() ==
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueCheckRspMsgType);
|
||||
std::shared_ptr<CheckRspMessage> check_rsp_msg =
|
||||
std::dynamic_pointer_cast<CheckRspMessage>(result_msg);
|
||||
STREAMING_LOG(INFO) << "CheckQueueSync return queue_id: " << check_rsp_msg->QueueId();
|
||||
STREAMING_CHECK(check_rsp_msg->PeerActorId() == actor_id_);
|
||||
|
||||
return queue::protobuf::StreamingQueueError::OK == check_rsp_msg->Error();
|
||||
}
|
||||
|
||||
void UpstreamQueueMessageHandler::WaitQueues(const std::vector<ObjectID> &queue_ids,
|
||||
int64_t timeout_ms,
|
||||
std::vector<ObjectID> &failed_queues) {
|
||||
failed_queues.insert(failed_queues.begin(), queue_ids.begin(), queue_ids.end());
|
||||
uint64_t start_time_us = current_time_ms();
|
||||
uint64_t current_time_us = start_time_us;
|
||||
while (!failed_queues.empty() && current_time_us < start_time_us + timeout_ms * 1000) {
|
||||
for (auto it = failed_queues.begin(); it != failed_queues.end();) {
|
||||
if (CheckQueueSync(*it)) {
|
||||
STREAMING_LOG(INFO) << "Check queue: " << *it << " return, ready.";
|
||||
it = failed_queues.erase(it);
|
||||
} else {
|
||||
STREAMING_LOG(INFO) << "Check queue: " << *it << " return, not ready.";
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
it++;
|
||||
}
|
||||
}
|
||||
current_time_us = current_time_ms();
|
||||
}
|
||||
}
|
||||
|
||||
void UpstreamQueueMessageHandler::DispatchMessageInternal(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer,
|
||||
std::function<void(std::shared_ptr<LocalMemoryBuffer>)> callback) {
|
||||
std::shared_ptr<Message> msg = ParseMessage(buffer);
|
||||
STREAMING_LOG(DEBUG) << "QueueMessageHandler::DispatchMessageInternal: "
|
||||
<< " qid: " << msg->QueueId() << " actorid " << msg->ActorId()
|
||||
<< " peer actorid: " << msg->PeerActorId() << " type: "
|
||||
<< queue::protobuf::StreamingQueueMessageType_Name(msg->Type());
|
||||
|
||||
if (msg->Type() ==
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueNotificationMsgType) {
|
||||
OnNotify(std::dynamic_pointer_cast<NotificationMessage>(msg));
|
||||
} else if (msg->Type() ==
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueCheckRspMsgType) {
|
||||
STREAMING_CHECK(false) << "Should not receive StreamingQueueCheckRspMsg";
|
||||
} else {
|
||||
STREAMING_CHECK(false) << "message type should be added: "
|
||||
<< queue::protobuf::StreamingQueueMessageType_Name(
|
||||
msg->Type());
|
||||
}
|
||||
}
|
||||
|
||||
void UpstreamQueueMessageHandler::OnNotify(
|
||||
std::shared_ptr<NotificationMessage> notify_msg) {
|
||||
auto queue = GetUpQueue(notify_msg->QueueId());
|
||||
if (queue == nullptr) {
|
||||
STREAMING_LOG(WARNING) << "Can not find queue for "
|
||||
<< queue::protobuf::StreamingQueueMessageType_Name(
|
||||
notify_msg->Type())
|
||||
<< ", maybe queue has been destroyed, ignore it."
|
||||
<< " seq id: " << notify_msg->SeqId();
|
||||
return;
|
||||
}
|
||||
queue->OnNotify(notify_msg);
|
||||
}
|
||||
|
||||
void UpstreamQueueMessageHandler::ReleaseAllUpQueues() {
|
||||
STREAMING_LOG(INFO) << "ReleaseAllUpQueues";
|
||||
upstream_queues_.clear();
|
||||
Release();
|
||||
}
|
||||
|
||||
std::shared_ptr<DownstreamQueueMessageHandler>
|
||||
DownstreamQueueMessageHandler::CreateService(CoreWorker *core_worker,
|
||||
const ActorID &actor_id) {
|
||||
if (nullptr == downstream_handler_) {
|
||||
downstream_handler_ =
|
||||
std::make_shared<DownstreamQueueMessageHandler>(core_worker, actor_id);
|
||||
}
|
||||
return downstream_handler_;
|
||||
}
|
||||
|
||||
std::shared_ptr<DownstreamQueueMessageHandler>
|
||||
DownstreamQueueMessageHandler::GetService() {
|
||||
return downstream_handler_;
|
||||
}
|
||||
|
||||
bool DownstreamQueueMessageHandler::DownstreamQueueExists(const ObjectID &queue_id) {
|
||||
return nullptr != GetDownQueue(queue_id);
|
||||
}
|
||||
|
||||
std::shared_ptr<ReaderQueue> DownstreamQueueMessageHandler::CreateDownstreamQueue(
|
||||
const ObjectID &queue_id, const ActorID &peer_actor_id) {
|
||||
STREAMING_LOG(INFO) << "CreateDownstreamQueue: " << queue_id << " " << peer_actor_id
|
||||
<< "->" << actor_id_;
|
||||
auto it = downstream_queues_.find(queue_id);
|
||||
if (it != downstream_queues_.end()) {
|
||||
STREAMING_LOG(WARNING) << "Duplicate to create down queue!!!! " << queue_id;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::shared_ptr<streaming::ReaderQueue> queue =
|
||||
std::unique_ptr<streaming::ReaderQueue>(new streaming::ReaderQueue(
|
||||
queue_id, actor_id_, peer_actor_id, GetOutTransport(queue_id)));
|
||||
downstream_queues_[queue_id] = queue;
|
||||
return queue;
|
||||
}
|
||||
|
||||
std::shared_ptr<streaming::ReaderQueue> DownstreamQueueMessageHandler::GetDownQueue(
|
||||
const ObjectID &queue_id) {
|
||||
auto it = downstream_queues_.find(queue_id);
|
||||
if (it == downstream_queues_.end()) return nullptr;
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::shared_ptr<LocalMemoryBuffer> DownstreamQueueMessageHandler::OnCheckQueue(
|
||||
std::shared_ptr<CheckMessage> check_msg) {
|
||||
queue::protobuf::StreamingQueueError err_code =
|
||||
queue::protobuf::StreamingQueueError::OK;
|
||||
|
||||
auto down_queue = downstream_queues_.find(check_msg->QueueId());
|
||||
if (down_queue == downstream_queues_.end()) {
|
||||
STREAMING_LOG(WARNING) << "OnCheckQueue " << check_msg->QueueId() << " not found.";
|
||||
err_code = queue::protobuf::StreamingQueueError::QUEUE_NOT_EXIST;
|
||||
}
|
||||
|
||||
CheckRspMessage msg(check_msg->PeerActorId(), check_msg->ActorId(),
|
||||
check_msg->QueueId(), err_code);
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer = msg.ToBytes();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void DownstreamQueueMessageHandler::ReleaseAllDownQueues() {
|
||||
STREAMING_LOG(INFO) << "ReleaseAllDownQueues size: " << downstream_queues_.size();
|
||||
downstream_queues_.clear();
|
||||
Release();
|
||||
}
|
||||
|
||||
void DownstreamQueueMessageHandler::DispatchMessageInternal(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer,
|
||||
std::function<void(std::shared_ptr<LocalMemoryBuffer>)> callback) {
|
||||
std::shared_ptr<Message> msg = ParseMessage(buffer);
|
||||
STREAMING_LOG(DEBUG) << "QueueMessageHandler::DispatchMessageInternal: "
|
||||
<< " qid: " << msg->QueueId() << " actorid " << msg->ActorId()
|
||||
<< " peer actorid: " << msg->PeerActorId() << " type: "
|
||||
<< queue::protobuf::StreamingQueueMessageType_Name(msg->Type());
|
||||
|
||||
if (msg->Type() ==
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueDataMsgType) {
|
||||
OnData(std::dynamic_pointer_cast<DataMessage>(msg));
|
||||
} else if (msg->Type() ==
|
||||
queue::protobuf::StreamingQueueMessageType::StreamingQueueCheckMsgType) {
|
||||
std::shared_ptr<LocalMemoryBuffer> check_result =
|
||||
this->OnCheckQueue(std::dynamic_pointer_cast<CheckMessage>(msg));
|
||||
if (callback != nullptr) {
|
||||
callback(check_result);
|
||||
}
|
||||
} else {
|
||||
STREAMING_CHECK(false) << "message type should be added: "
|
||||
<< queue::protobuf::StreamingQueueMessageType_Name(
|
||||
msg->Type());
|
||||
}
|
||||
}
|
||||
|
||||
void DownstreamQueueMessageHandler::OnData(std::shared_ptr<DataMessage> msg) {
|
||||
auto queue = GetDownQueue(msg->QueueId());
|
||||
if (queue == nullptr) {
|
||||
STREAMING_LOG(WARNING) << "Can not find queue for "
|
||||
<< queue::protobuf::StreamingQueueMessageType_Name(msg->Type())
|
||||
<< ", maybe queue has been destroyed, ignore it."
|
||||
<< " seq id: " << msg->SeqId();
|
||||
return;
|
||||
}
|
||||
|
||||
QueueItem item(msg);
|
||||
queue->OnData(item);
|
||||
}
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,194 @@
|
||||
#ifndef _QUEUE_SERVICE_H_
|
||||
#define _QUEUE_SERVICE_H_
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <thread>
|
||||
|
||||
#include "queue.h"
|
||||
#include "util/streaming_logging.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
/// Base class of UpstreamQueueMessageHandler and DownstreamQueueMessageHandler.
|
||||
/// A queue service manages a group of queues, upstream queues or downstream queues of
|
||||
/// the current actor. Each queue service holds a boost.asio io_service, to handle
|
||||
/// messages asynchronously. When a message received by Writer/Reader in ray call thread,
|
||||
/// the message was delivered to
|
||||
/// UpstreamQueueMessageHandler/DownstreamQueueMessageHandler, then the ray call thread
|
||||
/// returns immediately. The queue service parses meta infomation from the message,
|
||||
/// including queue_id actor_id, etc, and dispatchs message to queue according to
|
||||
/// queue_id.
|
||||
class QueueMessageHandler {
|
||||
public:
|
||||
/// Construct a QueueMessageHandler instance.
|
||||
/// \param[in] core_worker CoreWorker C++ pointer of current actor, used to call Core
|
||||
/// Worker's api.
|
||||
/// For Python worker, the pointer can be obtained from
|
||||
/// ray.worker.global_worker.core_worker; For Java worker, obtained from
|
||||
/// RayNativeRuntime object through java reflection.
|
||||
/// \param[in] actor_id actor id of current actor.
|
||||
QueueMessageHandler(CoreWorker *core_worker, const ActorID &actor_id)
|
||||
: core_worker_(core_worker),
|
||||
actor_id_(actor_id),
|
||||
queue_dummy_work_(queue_service_) {
|
||||
Start();
|
||||
}
|
||||
|
||||
virtual ~QueueMessageHandler() { Stop(); }
|
||||
|
||||
/// Dispatch message buffer to asio service.
|
||||
/// \param[in] buffer serialized message received from peer actor.
|
||||
void DispatchMessageAsync(std::shared_ptr<LocalMemoryBuffer> buffer);
|
||||
|
||||
/// Dispatch message buffer to asio service synchronously, and wait for handle result.
|
||||
/// \param[in] buffer serialized message received from peer actor.
|
||||
/// \return handle result.
|
||||
std::shared_ptr<LocalMemoryBuffer> DispatchMessageSync(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer);
|
||||
|
||||
/// Get transport to a peer actor specified by actor_id.
|
||||
/// \param[in] actor_id actor id of peer actor
|
||||
/// \return transport
|
||||
std::shared_ptr<Transport> GetOutTransport(const ObjectID &actor_id);
|
||||
|
||||
/// The actual function where message being dispatched, called by DispatchMessageAsync
|
||||
/// and DispatchMessageSync.
|
||||
/// \param[in] buffer serialized message received from peer actor.
|
||||
/// \param[in] callback the callback function used by DispatchMessageSync, called
|
||||
/// after message processed complete. The std::shared_ptr<LocalMemoryBuffer>
|
||||
/// parameter is the return value.
|
||||
virtual void DispatchMessageInternal(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer,
|
||||
std::function<void(std::shared_ptr<LocalMemoryBuffer>)> callback) = 0;
|
||||
|
||||
/// Save actor_id of the peer actor specified by queue_id. For a upstream queue, the
|
||||
/// peer actor refer specifically to the actor in current ray cluster who has a
|
||||
/// downstream queue with same queue_id, and vice versa.
|
||||
/// \param[in] queue_id queue id of current queue.
|
||||
/// \param[in] actor_id actor_id actor id of corresponded peer actor.
|
||||
void SetPeerActorID(const ObjectID &queue_id, const ActorID &actor_id);
|
||||
|
||||
/// Obtain the actor id of the peer actor specified by queue_id.
|
||||
/// \return actor id
|
||||
ActorID GetPeerActorID(const ObjectID &queue_id);
|
||||
|
||||
/// Release all queues in current queue service.
|
||||
void Release();
|
||||
|
||||
private:
|
||||
/// Start asio service
|
||||
void Start();
|
||||
/// Stop asio service
|
||||
void Stop();
|
||||
/// The callback function of internal thread.
|
||||
void QueueThreadCallback() { queue_service_.run(); }
|
||||
|
||||
protected:
|
||||
/// CoreWorker C++ pointer of current actor
|
||||
CoreWorker *core_worker_;
|
||||
/// actor_id actor id of current actor
|
||||
ActorID actor_id_;
|
||||
/// Helper function, parse message buffer to Message object.
|
||||
std::shared_ptr<Message> ParseMessage(std::shared_ptr<LocalMemoryBuffer> buffer);
|
||||
|
||||
private:
|
||||
/// Map from queue id to a actor id of the queue's peer actor.
|
||||
std::unordered_map<ObjectID, ActorID> actors_;
|
||||
/// Map from queue id to a transport of the queue's peer actor.
|
||||
std::unordered_map<ObjectID, std::shared_ptr<Transport>> out_transports_;
|
||||
/// The internal thread which asio service run with.
|
||||
std::thread queue_thread_;
|
||||
/// The internal asio service.
|
||||
boost::asio::io_service queue_service_;
|
||||
/// The asio work which keeps queue_service_ alive.
|
||||
boost::asio::io_service::work queue_dummy_work_;
|
||||
};
|
||||
|
||||
/// UpstreamQueueMessageHandler holds and manages all upstream queues of current actor.
|
||||
class UpstreamQueueMessageHandler : public QueueMessageHandler {
|
||||
public:
|
||||
/// Construct a UpstreamQueueMessageHandler instance.
|
||||
UpstreamQueueMessageHandler(CoreWorker *core_worker, const ActorID &actor_id)
|
||||
: QueueMessageHandler(core_worker, actor_id) {}
|
||||
/// Create a upstream queue.
|
||||
/// \param[in] queue_id queue id of the queue to be created.
|
||||
/// \param[in] peer_actor_id actor id of peer actor.
|
||||
/// \param[in] size the max memory size of the queue.
|
||||
std::shared_ptr<WriterQueue> CreateUpstreamQueue(const ObjectID &queue_id,
|
||||
const ActorID &peer_actor_id,
|
||||
uint64_t size);
|
||||
/// Check whether the upstream queue specified by queue_id exists or not.
|
||||
bool UpstreamQueueExists(const ObjectID &queue_id);
|
||||
/// Wait all queues in queue_ids vector ready, until timeout.
|
||||
/// \param[in] queue_ids a group of queues.
|
||||
/// \param[in] timeout_ms max timeout time interval for wait all queues.
|
||||
/// \param[out] failed_queues a group of queues which are not ready when timeout.
|
||||
void WaitQueues(const std::vector<ObjectID> &queue_ids, int64_t timeout_ms,
|
||||
std::vector<ObjectID> &failed_queues);
|
||||
/// Handle notify message from corresponded downstream queue.
|
||||
void OnNotify(std::shared_ptr<NotificationMessage> notify_msg);
|
||||
/// Obtain upstream queue specified by queue_id.
|
||||
std::shared_ptr<streaming::WriterQueue> GetUpQueue(const ObjectID &queue_id);
|
||||
/// Release all upstream queues
|
||||
void ReleaseAllUpQueues();
|
||||
|
||||
virtual void DispatchMessageInternal(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer,
|
||||
std::function<void(std::shared_ptr<LocalMemoryBuffer>)> callback) override;
|
||||
|
||||
static std::shared_ptr<UpstreamQueueMessageHandler> CreateService(
|
||||
CoreWorker *core_worker, const ActorID &actor_id);
|
||||
static std::shared_ptr<UpstreamQueueMessageHandler> GetService();
|
||||
|
||||
static RayFunction peer_sync_function_;
|
||||
static RayFunction peer_async_function_;
|
||||
|
||||
private:
|
||||
bool CheckQueueSync(const ObjectID &queue_ids);
|
||||
|
||||
private:
|
||||
std::unordered_map<ObjectID, std::shared_ptr<streaming::WriterQueue>> upstream_queues_;
|
||||
static std::shared_ptr<UpstreamQueueMessageHandler> upstream_handler_;
|
||||
};
|
||||
|
||||
/// UpstreamQueueMessageHandler holds and manages all downstream queues of current actor.
|
||||
class DownstreamQueueMessageHandler : public QueueMessageHandler {
|
||||
public:
|
||||
DownstreamQueueMessageHandler(CoreWorker *core_worker, const ActorID &actor_id)
|
||||
: QueueMessageHandler(core_worker, actor_id) {}
|
||||
std::shared_ptr<ReaderQueue> CreateDownstreamQueue(const ObjectID &queue_id,
|
||||
const ActorID &peer_actor_id);
|
||||
bool DownstreamQueueExists(const ObjectID &queue_id);
|
||||
|
||||
void UpdateDownActor(const ObjectID &queue_id, const ActorID &actor_id);
|
||||
|
||||
std::shared_ptr<LocalMemoryBuffer> OnCheckQueue(
|
||||
std::shared_ptr<CheckMessage> check_msg);
|
||||
|
||||
std::shared_ptr<streaming::ReaderQueue> GetDownQueue(const ObjectID &queue_id);
|
||||
|
||||
void ReleaseAllDownQueues();
|
||||
|
||||
void OnData(std::shared_ptr<DataMessage> msg);
|
||||
virtual void DispatchMessageInternal(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer,
|
||||
std::function<void(std::shared_ptr<LocalMemoryBuffer>)> callback);
|
||||
|
||||
static std::shared_ptr<DownstreamQueueMessageHandler> CreateService(
|
||||
CoreWorker *core_worker, const ActorID &actor_id);
|
||||
static std::shared_ptr<DownstreamQueueMessageHandler> GetService();
|
||||
static RayFunction peer_sync_function_;
|
||||
static RayFunction peer_async_function_;
|
||||
|
||||
private:
|
||||
std::unordered_map<ObjectID, std::shared_ptr<streaming::ReaderQueue>>
|
||||
downstream_queues_;
|
||||
static std::shared_ptr<DownstreamQueueMessageHandler> downstream_handler_;
|
||||
};
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
#ifndef _STREAMING_QUEUE_ITEM_H_
|
||||
#define _STREAMING_QUEUE_ITEM_H_
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "ray/common/id.h"
|
||||
|
||||
#include "message.h"
|
||||
#include "message/message_bundle.h"
|
||||
#include "util/streaming_logging.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
using ray::ObjectID;
|
||||
const uint64_t QUEUE_INVALID_SEQ_ID = std::numeric_limits<uint64_t>::max();
|
||||
|
||||
/// QueueItem is the element stored in `Queue`. Actually, when DataWriter pushes a message
|
||||
/// bundle into a queue, the bundle is packed into one QueueItem, so a one-to-one
|
||||
/// relationship exists between message bundle and QueueItem. Meanwhile, the QueueItem is
|
||||
/// also the minimum unit to send through direct actor call. Each QueueItem holds a
|
||||
/// LocalMemoryBuffer shared_ptr, which will be sent out by Transport.
|
||||
class QueueItem {
|
||||
public:
|
||||
/// Construct a QueueItem object.
|
||||
/// \param[in] seq_id the sequential id assigned by DataWriter for a message bundle and
|
||||
/// QueueItem.
|
||||
/// \param[in] data the data buffer to be stored in this QueueItem.
|
||||
/// \param[in] data_size the data size in bytes.
|
||||
/// \param[in] timestamp the time when this QueueItem created.
|
||||
/// \param[in] raw whether the data content is raw bytes, only used in some tests.
|
||||
QueueItem(uint64_t seq_id, uint8_t *data, uint32_t data_size, uint64_t timestamp,
|
||||
bool raw = false)
|
||||
: seq_id_(seq_id),
|
||||
timestamp_(timestamp),
|
||||
raw_(raw),
|
||||
/*COPY*/ buffer_(std::make_shared<LocalMemoryBuffer>(data, data_size, true)) {}
|
||||
|
||||
QueueItem(uint64_t seq_id, std::shared_ptr<LocalMemoryBuffer> buffer,
|
||||
uint64_t timestamp, bool raw = false)
|
||||
: seq_id_(seq_id), timestamp_(timestamp), raw_(raw), buffer_(buffer) {}
|
||||
|
||||
QueueItem(std::shared_ptr<DataMessage> data_msg)
|
||||
: seq_id_(data_msg->SeqId()),
|
||||
raw_(data_msg->IsRaw()),
|
||||
buffer_(data_msg->Buffer()) {}
|
||||
|
||||
QueueItem(const QueueItem &&item) {
|
||||
buffer_ = item.buffer_;
|
||||
seq_id_ = item.seq_id_;
|
||||
timestamp_ = item.timestamp_;
|
||||
raw_ = item.raw_;
|
||||
}
|
||||
|
||||
QueueItem(const QueueItem &item) {
|
||||
buffer_ = item.buffer_;
|
||||
seq_id_ = item.seq_id_;
|
||||
timestamp_ = item.timestamp_;
|
||||
raw_ = item.raw_;
|
||||
}
|
||||
|
||||
QueueItem &operator=(const QueueItem &item) {
|
||||
buffer_ = item.buffer_;
|
||||
seq_id_ = item.seq_id_;
|
||||
timestamp_ = item.timestamp_;
|
||||
raw_ = item.raw_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual ~QueueItem() = default;
|
||||
|
||||
uint64_t SeqId() { return seq_id_; }
|
||||
bool IsRaw() { return raw_; }
|
||||
uint64_t TimeStamp() { return timestamp_; }
|
||||
size_t DataSize() { return buffer_->Size(); }
|
||||
std::shared_ptr<LocalMemoryBuffer> Buffer() { return buffer_; }
|
||||
|
||||
/// Get max message id in this item.
|
||||
/// \return max message id.
|
||||
uint64_t MaxMsgId() {
|
||||
if (raw_) {
|
||||
return 0;
|
||||
}
|
||||
auto message_bundle = StreamingMessageBundleMeta::FromBytes(buffer_->Data());
|
||||
return message_bundle->GetLastMessageId();
|
||||
}
|
||||
|
||||
protected:
|
||||
uint64_t seq_id_;
|
||||
uint64_t timestamp_;
|
||||
bool raw_;
|
||||
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer_;
|
||||
};
|
||||
|
||||
class InvalidQueueItem : public QueueItem {
|
||||
public:
|
||||
InvalidQueueItem() : QueueItem(QUEUE_INVALID_SEQ_ID, data_, 1, 0) {}
|
||||
|
||||
private:
|
||||
uint8_t data_[1];
|
||||
};
|
||||
typedef std::shared_ptr<QueueItem> QueueItemPtr;
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "transport.h"
|
||||
#include "utils.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
static constexpr int TASK_OPTION_RETURN_NUM_0 = 0;
|
||||
static constexpr int TASK_OPTION_RETURN_NUM_1 = 1;
|
||||
|
||||
void Transport::SendInternal(std::shared_ptr<LocalMemoryBuffer> buffer,
|
||||
RayFunction &function, int return_num,
|
||||
std::vector<ObjectID> &return_ids) {
|
||||
std::unordered_map<std::string, double> resources;
|
||||
TaskOptions options{return_num, true, resources};
|
||||
|
||||
char meta_data[3] = {'R', 'A', 'W'};
|
||||
std::shared_ptr<LocalMemoryBuffer> meta =
|
||||
std::make_shared<LocalMemoryBuffer>((uint8_t *)meta_data, 3, true);
|
||||
|
||||
std::vector<TaskArg> args;
|
||||
if (function.GetLanguage() == Language::PYTHON) {
|
||||
auto dummy = "__RAY_DUMMY__";
|
||||
std::shared_ptr<LocalMemoryBuffer> dummyBuffer =
|
||||
std::make_shared<LocalMemoryBuffer>((uint8_t *)dummy, 13, true);
|
||||
args.emplace_back(TaskArg::PassByValue(
|
||||
std::make_shared<RayObject>(std::move(dummyBuffer), meta, true)));
|
||||
}
|
||||
args.emplace_back(
|
||||
TaskArg::PassByValue(std::make_shared<RayObject>(std::move(buffer), meta, true)));
|
||||
|
||||
STREAMING_CHECK(core_worker_ != nullptr);
|
||||
std::vector<std::shared_ptr<RayObject>> results;
|
||||
ray::Status st =
|
||||
core_worker_->SubmitActorTask(peer_actor_id_, function, args, options, &return_ids);
|
||||
if (!st.ok()) {
|
||||
STREAMING_LOG(ERROR) << "SubmitActorTask failed. " << st;
|
||||
}
|
||||
}
|
||||
|
||||
void Transport::Send(std::shared_ptr<LocalMemoryBuffer> buffer, RayFunction &function) {
|
||||
STREAMING_LOG(INFO) << "Transport::Send buffer size: " << buffer->Size();
|
||||
std::vector<ObjectID> return_ids;
|
||||
SendInternal(std::move(buffer), function, TASK_OPTION_RETURN_NUM_0, return_ids);
|
||||
}
|
||||
|
||||
std::shared_ptr<LocalMemoryBuffer> Transport::SendForResult(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer, RayFunction &function,
|
||||
int64_t timeout_ms) {
|
||||
std::vector<ObjectID> return_ids;
|
||||
SendInternal(buffer, function, TASK_OPTION_RETURN_NUM_1, return_ids);
|
||||
|
||||
std::vector<std::shared_ptr<RayObject>> results;
|
||||
Status get_st = core_worker_->Get(return_ids, timeout_ms, &results);
|
||||
if (!get_st.ok()) {
|
||||
STREAMING_LOG(ERROR) << "Get fail.";
|
||||
return nullptr;
|
||||
}
|
||||
STREAMING_CHECK(results.size() >= 1);
|
||||
if (results[0]->IsException()) {
|
||||
STREAMING_LOG(ERROR) << "peer actor may has exceptions, should retry.";
|
||||
return nullptr;
|
||||
}
|
||||
STREAMING_CHECK(results[0]->HasData());
|
||||
if (results[0]->GetData()->Size() == 4) {
|
||||
STREAMING_LOG(WARNING) << "peer actor may not ready yet, should retry.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Buffer> result_buffer = results[0]->GetData();
|
||||
std::shared_ptr<LocalMemoryBuffer> return_buffer = std::make_shared<LocalMemoryBuffer>(
|
||||
result_buffer->Data(), result_buffer->Size(), true);
|
||||
return return_buffer;
|
||||
}
|
||||
|
||||
std::shared_ptr<LocalMemoryBuffer> Transport::SendForResultWithRetry(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer, RayFunction &function, int retry_cnt,
|
||||
int64_t timeout_ms) {
|
||||
STREAMING_LOG(INFO) << "SendForResultWithRetry retry_cnt: " << retry_cnt
|
||||
<< " timeout_ms: " << timeout_ms
|
||||
<< " function: " << function.GetFunctionDescriptor()[0];
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer_shared = std::move(buffer);
|
||||
for (int cnt = 0; cnt < retry_cnt; cnt++) {
|
||||
auto result = SendForResult(buffer_shared, function, timeout_ms);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
STREAMING_LOG(WARNING) << "SendForResultWithRetry fail after retry.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
@@ -0,0 +1,63 @@
|
||||
#ifndef _STREAMING_QUEUE_TRANSPORT_H_
|
||||
#define _STREAMING_QUEUE_TRANSPORT_H_
|
||||
|
||||
#include "ray/common/id.h"
|
||||
#include "ray/core_worker/core_worker.h"
|
||||
#include "util/streaming_logging.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
/// Transport is the transfer endpoint to a specific actor, buffers can be sent to peer
|
||||
/// through direct actor call.
|
||||
class Transport {
|
||||
public:
|
||||
/// Construct a Transport object.
|
||||
/// \param[in] core_worker CoreWorker C++ pointer of current actor, which we call direct
|
||||
/// actor call interface with.
|
||||
/// \param[in] peer_actor_id actor id of peer actor.
|
||||
Transport(CoreWorker *core_worker, const ActorID &peer_actor_id)
|
||||
: core_worker_(core_worker), peer_actor_id_(peer_actor_id) {}
|
||||
virtual ~Transport() = default;
|
||||
|
||||
/// Send buffer asynchronously, peer's `function` will be called.
|
||||
/// \param[in] buffer buffer to be sent.
|
||||
/// \param[in] function the function descriptor of peer's function.
|
||||
virtual void Send(std::shared_ptr<LocalMemoryBuffer> buffer, RayFunction &function);
|
||||
/// Send buffer synchronously, peer's `function` will be called, and return the peer
|
||||
/// function's return value.
|
||||
/// \param[in] buffer buffer to be sent.
|
||||
/// \param[in] function the function descriptor of peer's function.
|
||||
/// \param[in] timeout_ms max time to wait for result.
|
||||
/// \return peer function's result.
|
||||
virtual std::shared_ptr<LocalMemoryBuffer> SendForResult(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer, RayFunction &function,
|
||||
int64_t timeout_ms);
|
||||
/// Send buffer and get result with retry.
|
||||
/// return value.
|
||||
/// \param[in] buffer buffer to be sent.
|
||||
/// \param[in] function the function descriptor of peer's function.
|
||||
/// \param[in] max retry count
|
||||
/// \param[in] timeout_ms max time to wait for result.
|
||||
/// \return peer function's result.
|
||||
std::shared_ptr<LocalMemoryBuffer> SendForResultWithRetry(
|
||||
std::shared_ptr<LocalMemoryBuffer> buffer, RayFunction &function, int retry_cnt,
|
||||
int64_t timeout_ms);
|
||||
|
||||
private:
|
||||
/// Send buffer internal
|
||||
/// \param[in] buffer buffer to be sent.
|
||||
/// \param[in] function the function descriptor of peer's function.
|
||||
/// \param[in] return_num return value number of the call.
|
||||
/// \param[out] return_ids return ids from SubmitActorTask.
|
||||
virtual void SendInternal(std::shared_ptr<LocalMemoryBuffer> buffer,
|
||||
RayFunction &function, int return_num,
|
||||
std::vector<ObjectID> &return_ids);
|
||||
|
||||
private:
|
||||
CoreWorker *core_worker_;
|
||||
ActorID peer_actor_id_;
|
||||
};
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
#ifndef _STREAMING_QUEUE_UTILS_H_
|
||||
#define _STREAMING_QUEUE_UTILS_H_
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include "ray/util/util.h"
|
||||
|
||||
namespace ray {
|
||||
namespace streaming {
|
||||
|
||||
/// Helper class encapulate std::future to help multithread async wait.
|
||||
class PromiseWrapper {
|
||||
public:
|
||||
Status Wait() {
|
||||
std::future<bool> fut = promise_.get_future();
|
||||
fut.get();
|
||||
return status_;
|
||||
}
|
||||
|
||||
Status WaitFor(uint64_t timeout_ms) {
|
||||
std::future<bool> fut = promise_.get_future();
|
||||
std::future_status status;
|
||||
do {
|
||||
status = fut.wait_for(std::chrono::milliseconds(timeout_ms));
|
||||
if (status == std::future_status::deferred) {
|
||||
} else if (status == std::future_status::timeout) {
|
||||
return Status::Invalid("timeout");
|
||||
} else if (status == std::future_status::ready) {
|
||||
return status_;
|
||||
}
|
||||
} while (status == std::future_status::deferred);
|
||||
|
||||
return status_;
|
||||
}
|
||||
|
||||
void Notify(Status status) {
|
||||
status_ = status;
|
||||
promise_.set_value(true);
|
||||
}
|
||||
|
||||
Status GetResultStatus() { return status_; }
|
||||
|
||||
private:
|
||||
std::promise<bool> promise_;
|
||||
Status status_;
|
||||
};
|
||||
|
||||
} // namespace streaming
|
||||
} // namespace ray
|
||||
#endif
|
||||
Reference in New Issue
Block a user