-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move message queue to Consumer #87
base: master
Are you sure you want to change the base?
Conversation
b27874f
to
4264e10
Compare
4264e10
to
8c592d2
Compare
Sorry for the second force-push. I used an old |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't look into the code in much detail yet.
May I suggest a change of perspective? The PR title reads like this is a simple refactoring step, while the proposed changes completely change the way BASP operates. Hence, this is in fact a major redesign. Shifting BASP to a message-oriented design opens up a lot of design space that seems mostly ignored. As a result, many pieces seem out of place to me and if there has been some thought put into it, there isn't any documentation or comment that communicates it.
On a side note, we moved away from the endpoint-manager design, because it forced BASP-specific notations into the lower API layers. Reusing code may be a good thing, but only after establishing a cohesive design.
It may also be a good idea to file non-architectural changes separately. For example, it seems like length_prefix_framing
received a lot of changes (fixes?) and there's a new message_oriented_layer_ptr
class. Those changes ought to be much less impactful and discussing/merging these changes may help keeping this PR focused.
@@ -37,7 +37,7 @@ class actor_proxy_impl : public actor_proxy { | |||
void kill_proxy(execution_unit* ctx, error rsn) override; | |||
|
|||
private: | |||
endpoint_manager_ptr dst_; | |||
basp::application* app_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a very serious shift in semantics. Previously, the proxy participated in shared ownership of the endpoint manager. Now, it only keeps a raw pointer to the BASP app directly. How is CAF making sure that the proxy never accesses a pointer past the lifetime of the pointed-to object now?
I couldn't find any comments going in to detail on this, and actor_proxy_impl::enqueue
calls into the object without any safeguarding. Furthermore, what is the rationale behind keeping this proxy implementation in the public API when it's clearly bound to BASP?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is CAF making sure that the proxy never accesses a pointer past the lifetime of the pointed-to object now
It doesn't. The proxy would have to hold a socket_manager_ptr
to ensure the lifetime of the BASP app, which is definitely possible. I'll add that.
using hub_type = detail::worker_hub<worker>; | ||
using input_tag = tag::message_oriented; | ||
|
||
using byte_span = span<const byte>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's caf/byte_span.hpp
now that defined const_byte_span
.
parent.transport().configure_read(receive_policy::exactly(next_read_size)); | ||
return none; | ||
template <class LowerLayerPtr> | ||
bool prepare_send(LowerLayerPtr& down) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function opts to not call can_send_more()
on the lower layer and instead drain the queues completely. Is there some benchmarking data that suggests simply writing to the buffer no matter what results in better performance overall? If so, the code should contain some comments that explain this brute-force approach to the reader so that this knowledge also guides future writers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no benchmark that gives such distinct insight into the stack. At least not as of right now.
I used this approach, since it was used libcaf_io
with the basp_broker
.
// -- handling of outgoing messages and events ------------------------------- | ||
|
||
template <class LowerLayerPtr> | ||
error dequeue_events(LowerLayerPtr& down) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function is named "dequeue events", but instead of events, it returns an error
. Since there's also no output parameter for events, this function name only helps confusing readers and requires to actual look at the implementation to figure out what the function does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about consume_events
/consume_messages
then? That would match the naming scheme used within actors and the new actor_shell
.
error handle_resolve_response(packet_writer& writer, header received_hdr, | ||
byte_span received); | ||
template <class LowerLayerPtr> | ||
error dequeue_messages(LowerLayerPtr& down) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have the same reservations regarding function name as I have for dequeue_events
.
@@ -30,7 +30,7 @@ namespace caf::net::basp { | |||
constexpr uint64_t version = 1; | |||
|
|||
/// Size of a BASP header in serialized form. | |||
constexpr size_t header_size = 13; | |||
constexpr size_t header_size = 9; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this PR, you push for a complete paradigm shift by making BASP message-oriented. Why stick to a fixed header size in this case? BASP already had some message types that pushed fields that semantically belonged to the header into the payload. Now that we no longer need to support a fixed-size header to begin with, why stick to this poor design?
@@ -34,7 +34,7 @@ | |||
|
|||
namespace caf::net { | |||
|
|||
class CAF_NET_EXPORT endpoint_manager_queue { | |||
class CAF_NET_EXPORT consumer_queue { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name suggests to me that this class is very generic queue type for (any number of?) producers to write to that belongs to a single consumer. But that just isn't the case. The implementation is in fact very specifically tailored to the needs of the BASP application. I think it shouldn't be in the public caf::net
API to begin with and the name gives no guidance as to what role this class actually addresses.
@@ -155,6 +159,7 @@ class stream_transport { | |||
CAF_LOG_ERROR("send_buffer_size: " << socket_buf_size.error()); | |||
return std::move(socket_buf_size.error()); | |||
} | |||
owner->register_reading(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should the transport unconditionally decide that the application has to read something right away?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The lifetime of socket_manager
instances is bound to them being registered for reading or writing. As soon as a socket_manager
is not registered for either of both, it is dereferenced by the multiplexer and hence, removed. Managers are only registered for writing, when they actually have to write data which leaves registering any manager for reading to keep them from being removed right away.
This PR moves the message and event queues from its previous location in the
endpoint_manager
to the consumer.This PR is based on #86 and should be merged after that PR has been merged.