Skip to content
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

Draft
wants to merge 28 commits into
base: master
Choose a base branch
from
Draft

Move message queue to Consumer #87

wants to merge 28 commits into from

Conversation

jakobod
Copy link
Member

@jakobod jakobod commented Oct 1, 2020

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.

@jakobod
Copy link
Member Author

jakobod commented Oct 2, 2020

Sorry for the second force-push. I used an old master for the first rebase..
Ready for review now though!

Copy link
Member

@Neverlord Neverlord left a 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_;
Copy link
Member

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?

Copy link
Member Author

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>;
Copy link
Member

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) {
Copy link
Member

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.

Copy link
Member Author

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) {
Copy link
Member

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.

Copy link
Member Author

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) {
Copy link
Member

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;
Copy link
Member

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 {
Copy link
Member

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();
Copy link
Member

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?

Copy link
Member Author

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.

@Neverlord Neverlord marked this pull request as draft October 5, 2020 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants