From f8605943a1a66213d3f67112f81401b042918733 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 6 Oct 2020 20:53:20 +0000 Subject: [PATCH 01/88] format Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 125 +++++ source/common/network/BUILD | 25 + .../network/buffered_io_socket_handle_impl.cc | 196 ++++++++ .../network/buffered_io_socket_handle_impl.h | 159 ++++++ source/common/network/io_socket_error_impl.h | 19 + source/common/network/peer_buffer.h | 77 +++ test/common/network/BUILD | 11 + .../buffered_io_socket_handle_impl_test.cc | 475 ++++++++++++++++++ tools/spelling/spelling_dictionary.txt | 1 + 9 files changed, 1088 insertions(+) create mode 100644 source/common/network/buffered_io_socket_handle_impl.cc create mode 100644 source/common/network/buffered_io_socket_handle_impl.h create mode 100644 source/common/network/peer_buffer.h create mode 100644 test/common/network/buffered_io_socket_handle_impl_test.cc diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index cc3e505d788bb..ae8ace64d2f8f 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -8,6 +8,10 @@ #include "common/event/event_impl_base.h" namespace Envoy { + +namespace Network { +class BufferedIoSocketHandleImpl; +} namespace Event { /** @@ -41,5 +45,126 @@ class FileEventImpl : public FileEvent, ImplBase { // polling and activating new fd events. const bool activate_fd_events_next_event_loop_; }; + +// Forward declare for friend class. +class UserSpaceFileEventFactory; + +// The interface of populating event watcher and obtaining the active events. The events includes +// Read, Write and Closed. +class EventListener { +public: + virtual ~EventListener() = default; + + // Provide the activated events. + virtual uint32_t triggeredEvents() PURE; + virtual uint32_t getAndClearEphemeralEvents() PURE; + + // Callbacks of the event operation. + virtual void onEventEnabled(uint32_t enabled_events) PURE; + virtual void onEventActivated(uint32_t activated_events) PURE; +}; + +// Return the enabled events except EV_CLOSED. This implementation is generally good since only +// epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner +// must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify +// events which are not actually triggered. +class DefaultEventListener : public EventListener { +public: + ~DefaultEventListener() override = default; + uint32_t triggeredEvents() override { + ENVOY_LOG_MISC(debug, + "lambdai: user file event listener triggered events {} on {} and schedule next", + pending_events_, static_cast(this)); + + return pending_events_ & (~Event::FileReadyType::Closed); + } + void onEventEnabled(uint32_t enabled_events) override { + ENVOY_LOG_MISC( + debug, "lambdai: user file event listener set enabled events {} on {} and schedule next", + pending_events_, static_cast(this)); + pending_events_ = enabled_events; + } + void onEventActivated(uint32_t activated_events) override { + ephermal_events_ |= activated_events; + } + uint32_t getAndClearEphemeralEvents() override { + auto res = ephermal_events_; + ephermal_events_ = 0; + return res; + } + +private: + // The persisted interested events and ready events. + uint32_t pending_events_{}; + // The events set by activate() and will be cleared after the io callback. + uint32_t ephermal_events_{}; +}; + +// A FileEvent implementation which is +class UserSpaceFileEventImpl : public FileEvent { +public: + ~UserSpaceFileEventImpl() override { + // if (schedulable_.enabled()) { + schedulable_.cancel(); + //} + ASSERT(event_counter_ == 1); + --event_counter_; + } + + // Event::FileEvent + void activate(uint32_t events) override { + event_listener_.onEventActivated(events); + if (!schedulable_.enabled()) { + schedulable_.scheduleCallbackNextIteration(); + } + } + + void setEnabled(uint32_t events) override { + event_listener_.onEventEnabled(events); + if (!schedulable_.enabled()) { + schedulable_.scheduleCallbackNextIteration(); + ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and schedule next", + events, static_cast(this)); + return; + } + ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and but not schedule next", + events, static_cast(this)); + } + + EventListener& getEventListener() { return event_listener_; } + void onEvents() { cb_(); } + friend class UserSpaceFileEventFactory; + friend class Network::BufferedIoSocketHandleImpl; + +private: + UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, + SchedulableCallback& schedulable_cb, int& event_counter) + : schedulable_(schedulable_cb), cb_([this, cb]() { + auto all_events = getEventListener().triggeredEvents(); + auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); + ENVOY_LOG_MISC(debug, "lambdai: us event {} cb allevents = {}, ephermal events = {}", + static_cast(this), all_events, ephemeral_events); + cb(all_events | ephemeral_events); + }), + event_counter_(event_counter) { + event_listener_.onEventEnabled(events); + } + DefaultEventListener event_listener_; + SchedulableCallback& schedulable_; + std::function cb_; + int& event_counter_; +}; + +class UserSpaceFileEventFactory { +public: + static std::unique_ptr + createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, + uint32_t events, SchedulableCallback& scheduable_cb, + int& event_counter) { + return std::unique_ptr( + new UserSpaceFileEventImpl(cb, events, scheduable_cb, event_counter)); + } +}; + } // namespace Event } // namespace Envoy diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 6def5e024a4cb..6f6634020d14d 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -145,6 +145,7 @@ envoy_cc_library( hdrs = ["io_socket_error_impl.h"], deps = [ "//include/envoy/api:io_error_interface", + "//include/envoy/api:os_sys_calls_interface", "//source/common/common:assert_lib", "//source/common/common:utility_lib", ], @@ -448,3 +449,27 @@ envoy_cc_library( "//source/common/common:macros", ], ) + +envoy_cc_library( + name = "peer_buffer_lib", + hdrs = ["peer_buffer.h"], + deps = [ + ":utility_lib", + "//include/envoy/network:connection_interface", + "//include/envoy/network:transport_socket_interface", + "//source/common/buffer:buffer_lib", + "//source/common/buffer:watermark_buffer_lib", + "//source/common/common:empty_string", + "//source/common/http:headers_lib", + ], +) + +envoy_cc_library( + name = "buffered_io_socket_handle_lib", + srcs = ["buffered_io_socket_handle_impl.cc"], + hdrs = ["buffered_io_socket_handle_impl.h"], + deps = [ + "default_socket_interface_lib", + ":peer_buffer_lib", + ], +) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc new file mode 100644 index 0000000000000..f56b4ff27c552 --- /dev/null +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -0,0 +1,196 @@ +#include "common/network/buffered_io_socket_handle_impl.h" + +#include "envoy/buffer/buffer.h" +#include "envoy/common/platform.h" + +#include "common/api/os_sys_calls_impl.h" +#include "common/common/assert.h" +#include "common/common/utility.h" +#include "common/event/file_event_impl.h" +#include "common/network/address_impl.h" + +#include "absl/container/fixed_array.h" +#include "absl/types/optional.h" + +namespace Envoy { +namespace Network { + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { + ASSERT(!closed_); + if (!write_shutdown_) { + ASSERT(writable_peer_); + // Notify the peer we won't write more data. shutdown(WRITE). + writable_peer_->setWriteEnd(); + // Notify the peer that we no longer accept data. shutdown(RD). + writable_peer_->onPeerDestroy(); + writable_peer_->maybeSetNewData(); + writable_peer_ = nullptr; + write_shutdown_ = true; + } + closed_ = true; + return Api::ioCallUint64ResultNoError(); +} + +bool BufferedIoSocketHandleImpl::isOpen() const { return !closed_; } + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, + Buffer::RawSlice* slices, + uint64_t num_slice) { + if (owned_buffer_.length() == 0) { + if (read_end_stream_) { + return Api::ioCallUint64ResultNoError(); + } else { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + } else { + absl::FixedArray iov(num_slice); + uint64_t num_slices_to_read = 0; + uint64_t num_bytes_to_read = 0; + for (; num_slices_to_read < num_slice && num_bytes_to_read < max_length; num_slices_to_read++) { + auto min_len = std::min(std::min(owned_buffer_.length(), max_length) - num_bytes_to_read, + uint64_t(slices[num_slices_to_read].len_)); + owned_buffer_.copyOut(num_bytes_to_read, min_len, slices[num_slices_to_read].mem_); + num_bytes_to_read += min_len; + } + ASSERT(num_bytes_to_read <= max_length); + owned_buffer_.drain(num_bytes_to_read); + ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), num_bytes_to_read); + return {num_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + } +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, + uint64_t num_slice) { + if (!writable_peer_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } + if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + // Write along with iteration. Buffer guarantee the fragment is always append-able. + uint64_t num_bytes_to_write = 0; + for (uint64_t i = 0; i < num_slice; i++) { + if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { + writable_peer_->getWriteBuffer()->add(slices[i].mem_, slices[i].len_); + num_bytes_to_write += slices[i].len_; + } + } + writable_peer_->maybeSetNewData(); + ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), num_bytes_to_write); + return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, + const Address::Ip*, + const Address::Instance&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmsg(Buffer::RawSlice*, const uint64_t, + uint32_t, RecvMsgOutput&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmmsg(RawSliceArrays&, uint32_t, + RecvMsgOutput&) { + return IoSocketError::ioResultSocketInvalidAddress(); +} + +Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { + // No data and the writer closed. + if (owned_buffer_.length() == 0) { + if (read_end_stream_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } else { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + } else { + auto min_len = std::min(owned_buffer_.length(), length); + owned_buffer_.copyOut(0, min_len, buffer); + if (!(flags & MSG_PEEK)) { + owned_buffer_.drain(min_len); + } + return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + } +} + +bool BufferedIoSocketHandleImpl::supportsMmsg() const { return false; } + +bool BufferedIoSocketHandleImpl::supportsUdpGro() const { return false; } + +Api::SysCallIntResult makeInvalidSyscall() { + return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP /*SOCKET_ERROR_NOT_SUP*/}; +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Address::InstanceConstSharedPtr) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::listen(int) { return makeInvalidSyscall(); } + +IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { + // Buffered Io handle should always be considered as connected. Use write to determine if peer is + // closed. + return {0, 0}; +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::setOption(int, int, const void*, socklen_t) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::getOption(int, int, void*, socklen_t*) { + return makeInvalidSyscall(); +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::setBlocking(bool) { return makeInvalidSyscall(); } + +absl::optional BufferedIoSocketHandleImpl::domain() { return absl::nullopt; } + +Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { + throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); +} + +Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { + + throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); +} + +Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatcher& dispatcher, + Event::FileReadyCb cb, + Event::FileTriggerType trigger_type, + uint32_t events) { + ASSERT(event_counter_ == 0); + ++event_counter_; + io_callback_ = dispatcher.createSchedulableCallback([this]() { user_file_event_->onEvents(); }); + auto res = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + dispatcher, cb, trigger_type, events, *io_callback_, event_counter_); + user_file_event_ = res.get(); + // Blindly activate the events. + io_callback_->scheduleCallbackNextIteration(); + return res; +} + +Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { + // Support shutdown write. + if ((how == ENVOY_SHUT_WR) || (how == ENVOY_SHUT_RDWR)) { + ASSERT(!closed_); + if (!write_shutdown_) { + ASSERT(writable_peer_); + // Notify the peer we won't write more data. shutdown(WRITE). + writable_peer_->setWriteEnd(); + writable_peer_->maybeSetNewData(); + write_shutdown_ = true; + } + } + return {0, 0}; +} + +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h new file mode 100644 index 0000000000000..57c2380bc7e66 --- /dev/null +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -0,0 +1,159 @@ +#pragma once + +#include + +#include "envoy/api/io_error.h" +#include "envoy/api/os_sys_calls.h" +#include "envoy/common/platform.h" +#include "envoy/event/dispatcher.h" +#include "envoy/network/io_handle.h" + +#include "common/buffer/watermark_buffer.h" +#include "common/common/logger.h" +#include "common/event/file_event_impl.h" +#include "common/network/io_socket_error_impl.h" +#include "common/network/peer_buffer.h" + +namespace Envoy { +namespace Network { + +/** + * IoHandle implementation which provides a buffer as data source. It is designed to used by + * Network::ConnectionImpl. Some known limitations include + * 1. It doesn't not include a file descriptor. Do not use "fdDoNotUse". + * 2. It doesn't suppose socket options. Wrap this in ConnectionSocket and implement the socket + * getter/setter options. + * 3. It doesn't suppose UDP interface. + * 4. The peer BufferedIoSocket must be scheduled by the same scheduler to avoid data race. + */ +class BufferedIoSocketHandleImpl : public IoHandle, + public WritablePeer, + public ReadableSource, + protected Logger::Loggable { +public: + BufferedIoSocketHandleImpl() + : closed_{false}, + owned_buffer_( + [this]() -> void { + over_high_watermark_ = false; + if (writable_peer_) { + ENVOY_LOG(debug, "Socket {} switches to low watermark. Notify {}.", + static_cast(this), static_cast(writable_peer_)); + writable_peer_->onPeerBufferWritable(); + } + }, + [this]() -> void { + over_high_watermark_ = true; + // Low to high is checked by peer after peer writes data. + }, + []() -> void {}) {} + + ~BufferedIoSocketHandleImpl() override { ASSERT(closed_); } + + // IoHandle + os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } + + Api::IoCallUint64Result close() override; + + bool isOpen() const override; + + Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, + uint64_t num_slice) override; + + Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; + + Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, + const Address::Ip* self_ip, + const Address::Instance& peer_address) override; + + Api::IoCallUint64Result recvmsg(Buffer::RawSlice* slices, const uint64_t num_slice, + uint32_t self_port, RecvMsgOutput& output) override; + + Api::IoCallUint64Result recvmmsg(RawSliceArrays& slices, uint32_t self_port, + RecvMsgOutput& output) override; + Api::IoCallUint64Result recv(void* buffer, size_t length, int flags) override; + + bool supportsMmsg() const override; + bool supportsUdpGro() const override; + + Api::SysCallIntResult bind(Address::InstanceConstSharedPtr address) override; + Api::SysCallIntResult listen(int backlog) override; + IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; + Api::SysCallIntResult connect(Address::InstanceConstSharedPtr address) override; + Api::SysCallIntResult setOption(int level, int optname, const void* optval, + socklen_t optlen) override; + Api::SysCallIntResult getOption(int level, int optname, void* optval, socklen_t* optlen) override; + Api::SysCallIntResult setBlocking(bool blocking) override; + absl::optional domain() override; + Address::InstanceConstSharedPtr localAddress() override; + Address::InstanceConstSharedPtr peerAddress() override; + Event::FileEventPtr createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + Event::FileTriggerType trigger, uint32_t events) override; + Api::SysCallIntResult shutdown(int how) override; + + Buffer::WatermarkBuffer& getBufferForTest() { return owned_buffer_; } + + void scheduleNextEvent() { + // It's possible there is no pending file event so as no io_callback. + if (io_callback_) { + ENVOY_LOG(trace, "Schedule IO callback on {}", static_cast(this)); + io_callback_->scheduleCallbackNextIteration(); + } + } + + void setWritablePeer(WritablePeer* writable_peer) { + // Swapping writable peer is undefined behavior. + ASSERT(!writable_peer_); + ASSERT(!write_shutdown_); + writable_peer_ = writable_peer; + } + + // WritablePeer + void setWriteEnd() override { read_end_stream_ = true; } + bool isWriteEndSet() override { return read_end_stream_; } + void maybeSetNewData() override { + ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); + scheduleNextEvent(); + } + void onPeerDestroy() override { + writable_peer_ = nullptr; + write_shutdown_ = true; + } + void onPeerBufferWritable() override { scheduleNextEvent(); } + bool isWritable() const override { return !isOverHighWatermark(); } + Buffer::Instance* getWriteBuffer() override { return &owned_buffer_; } + + // ReadableSource + bool isPeerShutDownWrite() const override { return read_end_stream_; } + bool isOverHighWatermark() const override { return over_high_watermark_; } + bool isReadable() const override { return isPeerShutDownWrite() || owned_buffer_.length() > 0; } + +private: + // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource + // leak. + bool closed_; + + // The attached file event with this socket. The event is not owned by the socket. + Event::UserSpaceFileEventImpl* user_file_event_; + + // Envoy never schedule two independent IO event on the same socket. Use this counter to verify. + int event_counter_{0}; + + // The schedulable handle of the above event. + Event::SchedulableCallbackPtr io_callback_; + + // True if owned_buffer_ is not addable. Note that owned_buffer_ may have pending data to drain. + bool read_end_stream_{false}; + Buffer::WatermarkBuffer owned_buffer_; + + // Destination of the write(). + WritablePeer* writable_peer_{nullptr}; + + // The flag whether the peer is valid. Any write attempt must check this flag. + bool write_shutdown_{false}; + + bool over_high_watermark_{false}; +}; + +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/io_socket_error_impl.h b/source/common/network/io_socket_error_impl.h index 50d08b55f26a0..b98d51f1caf33 100644 --- a/source/common/network/io_socket_error_impl.h +++ b/source/common/network/io_socket_error_impl.h @@ -1,6 +1,7 @@ #pragma once #include "envoy/api/io_error.h" +#include "envoy/api/os_sys_calls_common.h" #include "common/common/assert.h" @@ -33,5 +34,23 @@ class IoSocketError : public Api::IoError { int errno_; }; +// Converts a SysCallSizeResult to IoCallUint64Result. +template +Api::IoCallUint64Result sysCallResultToIoCallResult(const Api::SysCallResult& result) { + if (result.rc_ >= 0) { + // Return nullptr as IoError upon success. + return Api::IoCallUint64Result(result.rc_, + Api::IoErrorPtr(nullptr, IoSocketError::deleteIoError)); + } + RELEASE_ASSERT(result.errno_ != SOCKET_ERROR_INVAL, "Invalid argument passed in."); + return Api::IoCallUint64Result( + /*rc=*/0, + (result.errno_ == SOCKET_ERROR_AGAIN + // EAGAIN is frequent enough that its memory allocation should be avoided. + ? Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError) + : Api::IoErrorPtr(new IoSocketError(result.errno_), IoSocketError::deleteIoError))); +} + } // namespace Network } // namespace Envoy diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h new file mode 100644 index 0000000000000..6e0da2dc022c2 --- /dev/null +++ b/source/common/network/peer_buffer.h @@ -0,0 +1,77 @@ +#include + +#include "envoy/buffer/buffer.h" +#include "envoy/common/pure.h" +#include "envoy/network/io_handle.h" +#include "envoy/network/proxy_protocol.h" +#include "envoy/ssl/connection.h" + +#include "common/common/assert.h" +#include "common/common/logger.h" + +#include "absl/types/optional.h" + +namespace Envoy { +namespace Network { + +/** + * The interface for the writer. + */ +class WritablePeer { +public: + virtual ~WritablePeer() = default; + + /** + * Set the flag to indicate no further write from peer. + */ + virtual void setWriteEnd() PURE; + virtual bool isWriteEndSet() PURE; + + /** + * Raised when peer is destroyed. No further write to peer is allowed. + */ + virtual void onPeerDestroy() PURE; + + /** + * Notify that consumable data arrives. The consumable data can be either data to read, or the end + * of stream event. + */ + virtual void maybeSetNewData() PURE; + + /** + * @return the buffer to be written. + */ + virtual Buffer::Instance* getWriteBuffer() PURE; + + /** + * @return false more data is acceptable. + */ + virtual bool isWritable() const PURE; + + /** + * Raised by the peer when the peer switch from high water mark to low. + */ + virtual void onPeerBufferWritable() PURE; + + // virtual bool triggeredHighToLowWatermark() const PURE; + // virtual void clearTriggeredHighToLowWatermark() PURE; + // virtual void setTriggeredHighToLowWatermark() PURE; +}; + +/** + * The interface for the buffer owner who want to consume the buffer. + */ +class ReadableSource { +public: + virtual ~ReadableSource() = default; + + /** + * Read the flag to indicate no further write. Used by early close detection. + */ + virtual bool isPeerShutDownWrite() const PURE; + + virtual bool isOverHighWatermark() const PURE; + virtual bool isReadable() const PURE; +}; +} // namespace Network +} // namespace Envoy \ No newline at end of file diff --git a/test/common/network/BUILD b/test/common/network/BUILD index 31b558b10c50c..2fde212fa1b5c 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -399,3 +399,14 @@ envoy_cc_test( "//test/mocks/network:network_mocks", ], ) + +envoy_cc_test( + name = "buffered_io_socket_handle_impl_test", + srcs = ["buffered_io_socket_handle_impl_test.cc"], + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/common/network:buffered_io_socket_handle_lib", + "//test/mocks/event:event_mocks", + ], +) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc new file mode 100644 index 0000000000000..361edd6752485 --- /dev/null +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -0,0 +1,475 @@ +#include + +#include "envoy/event/file_event.h" + +#include "common/buffer/buffer_impl.h" +#include "common/network/buffered_io_socket_handle_impl.h" + +#include "test/mocks/event/mocks.h" + +#include "absl/container/fixed_array.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using testing::_; +using testing::NiceMock; + +namespace Envoy { +namespace Network { +namespace { + +class MockFileEventCallback { +public: + MOCK_METHOD(void, called, (uint32_t arg)); +}; + +class BufferedIoSocketHandleTest : public testing::Test { +public: + BufferedIoSocketHandleTest() : buf_(1024) { + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setWritablePeer(io_handle_peer_.get()); + io_handle_peer_->setWritablePeer(io_handle_.get()); + } + ~BufferedIoSocketHandleTest() override { + if (io_handle_->isOpen()) { + io_handle_->close(); + } + if (io_handle_peer_->isOpen()) { + io_handle_peer_->close(); + } + } + void expectAgain() { + auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + } + NiceMock dispatcher_{}; + + // Owned by BufferedIoSocketHandle. + NiceMock* scheduable_cb_; + MockFileEventCallback cb_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; + absl::FixedArray buf_; +}; + +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + // EAGAIN. + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + io_handle_->setWriteEnd(); + res = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_FALSE(res.ok()); + EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); +} + +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + // EAGAIN. + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + io_handle_->setWriteEnd(); + res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_FALSE(res.ok()); + EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); +} + +TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(4, res.rc_); + EXPECT_EQ(absl::string_view(buf_.data(), 4), "abcd"); + EXPECT_EQ(0, internal_buffer.length()); + expectAgain(); +} + +TEST_F(BufferedIoSocketHandleTest, FlowControl) { + auto& internal_buffer = io_handle_->getBufferForTest(); + WritablePeer* handle_as_peer = io_handle_.get(); + internal_buffer.setWatermarks(128); + EXPECT_FALSE(io_handle_->isReadable()); + EXPECT_TRUE(io_handle_peer_->isWritable()); + + std::string big_chunk(256, 'a'); + internal_buffer.add(big_chunk); + EXPECT_TRUE(io_handle_->isReadable()); + EXPECT_FALSE(handle_as_peer->isWritable()); + + bool writable_flipped = false; + // During the repeated recv, the writable flag must switch to true. + while (internal_buffer.length() > 0) { + SCOPED_TRACE(internal_buffer.length()); + EXPECT_TRUE(io_handle_->isReadable()); + bool writable = handle_as_peer->isWritable(); + if (writable) { + writable_flipped = true; + } else { + ASSERT_FALSE(writable_flipped); + } + auto res = io_handle_->recv(buf_.data(), 32, 0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(32, res.rc_); + } + ASSERT_EQ(0, internal_buffer.length()); + ASSERT_TRUE(writable_flipped); + + // Finally the buffer is empty. + EXPECT_FALSE(io_handle_->isReadable()); + EXPECT_TRUE(handle_as_peer->isWritable()); +} + +TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + ev->setEnabled(Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + ev->setEnabled(Event::FileReadyType::Write); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + ev->setEnabled(Event::FileReadyType::Write | Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Read)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + + // Neither read and write will trigger self readiness. + EXPECT_CALL(cb_, called(_)).Times(0); + + // Drain 1 bytes. + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + auto res = io_handle_->recv(buf_.data(), 1, 0); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(1, res.rc_); + + ASSERT_FALSE(scheduable_cb_->enabled()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + + ev->setEnabled(0); + + EXPECT_CALL(cb_, called(0)); + scheduable_cb_->invokeCallback(); + + ASSERT_FALSE(scheduable_cb_->enabled()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + + ev.reset(); + ASSERT_FALSE(scheduable_cb_->enabled()); +} + +TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { + auto& internal_buffer = io_handle_->getBufferForTest(); + WritablePeer* handle_as_peer = io_handle_.get(); + internal_buffer.setWatermarks(128); + EXPECT_FALSE(io_handle_->isReadable()); + EXPECT_TRUE(io_handle_peer_->isWritable()); + + std::string big_chunk(256, 'a'); + internal_buffer.add(big_chunk); + EXPECT_TRUE(io_handle_->isReadable()); + EXPECT_FALSE(handle_as_peer->isWritable()); + + // Clear invoke callback on peer. + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_peer_->createFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + + { + auto res = io_handle_->recv(buf_.data(), 1, 0); + EXPECT_FALSE(handle_as_peer->isWritable()); + } + { + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); + auto res = io_handle_->recv(buf_.data(), 232, 0); + EXPECT_TRUE(handle_as_peer->isWritable()); + } + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); + io_handle_->close(); +} + +TEST_F(BufferedIoSocketHandleTest, TestClose) { + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (res.ok()) { + accumulator += absl::string_view(buf_.data(), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + + // Not closed yet. + ASSERT_FALSE(should_close); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->close(); + + ASSERT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + ASSERT_TRUE(should_close); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(0); + io_handle_->close(); + EXPECT_EQ(4, accumulator.size()); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestShutdown) { + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcd"); + + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (res.ok()) { + accumulator += absl::string_view(buf_.data(), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + + // Not closed yet. + ASSERT_FALSE(should_close); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->shutdown(ENVOY_SHUT_WR); + + ASSERT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + ASSERT_TRUE(should_close); + EXPECT_EQ(4, accumulator.size()); + io_handle_->close(); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestWriteToPeer) { + std::string raw_data("0123456789"); + absl::InlinedVector slices{ + // Contains 1 byte. + Buffer::RawSlice{static_cast(raw_data.data()), 1}, + // Contains 0 byte. + Buffer::RawSlice{nullptr, 1}, + // Contains 0 byte. + Buffer::RawSlice{raw_data.data() + 1, 0}, + // Contains 2 byte. + Buffer::RawSlice{raw_data.data() + 1, 2}, + }; + io_handle_peer_->writev(slices.data(), slices.size()); + auto& internal_buffer = io_handle_->getBufferForTest(); + EXPECT_EQ(3, internal_buffer.length()); + EXPECT_EQ("012", internal_buffer.toString()); +} + +TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + Buffer::OwnedImpl buf; + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + auto res = handle->readv(1024, &slice, 1); + if (res.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + + std::string raw_data("0123456789"); + Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->writev(&slice, 1); + + EXPECT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + EXPECT_EQ("0123456789", accumulator); + EXPECT_FALSE(should_close); + + io_handle_->close(); +} + +TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { + io_handle_peer_->shutdown(ENVOY_SHUT_WR); + ENVOY_LOG_MISC(debug, "lambdai: after {} shutdown write ", + static_cast(io_handle_peer_.get())); + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_peer_->createFileEvent( + dispatcher_, + [&should_close, handle = io_handle_peer_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + Buffer::OwnedImpl buf; + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + auto res = handle->readv(1024, &slice, 1); + if (res.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + + EXPECT_FALSE(scheduable_cb_->enabled()); + std::string raw_data("0123456789"); + Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_->writev(&slice, 1); + EXPECT_TRUE(scheduable_cb_->enabled()); + + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + EXPECT_EQ(raw_data, accumulator); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_->close(); + ev.reset(); +} + +TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { + auto& peer_internal_buffer = io_handle_peer_->getBufferForTest(); + peer_internal_buffer.setWatermarks(128); + std::string big_chunk(256, 'a'); + peer_internal_buffer.add(big_chunk); + EXPECT_FALSE(io_handle_peer_->isWritable()); + + io_handle_peer_->shutdown(ENVOY_SHUT_WR); + ENVOY_LOG_MISC(debug, "lambdai: after {} shutdown write ", + static_cast(io_handle_peer_.get())); + + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto ev = io_handle_->createFileEvent( + dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::PlatformDefaultTriggerType, + Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + peer_internal_buffer.drain(peer_internal_buffer.length()); + EXPECT_TRUE(scheduable_cb_->enabled()); + + io_handle_->close(); +} + +} // namespace +} // namespace Network +} // namespace Envoy diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index 12cf11d0bf2b8..d544211aa4496 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -876,6 +876,7 @@ pkey plaintext pluggable pointee +poller popen pos posix From d90cbea28ce7bcb812633e51a1a206d380a52db4 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 6 Oct 2020 22:23:05 +0000 Subject: [PATCH 02/88] amend Signed-off-by: Yuchen Dai --- source/common/network/BUILD | 4 ---- source/common/network/peer_buffer.h | 14 +------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 6f6634020d14d..e2b11398130f4 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -454,13 +454,9 @@ envoy_cc_library( name = "peer_buffer_lib", hdrs = ["peer_buffer.h"], deps = [ - ":utility_lib", - "//include/envoy/network:connection_interface", - "//include/envoy/network:transport_socket_interface", "//source/common/buffer:buffer_lib", "//source/common/buffer:watermark_buffer_lib", "//source/common/common:empty_string", - "//source/common/http:headers_lib", ], ) diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 6e0da2dc022c2..9c0db4ef9f7cc 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -1,15 +1,7 @@ -#include +#pragma once #include "envoy/buffer/buffer.h" #include "envoy/common/pure.h" -#include "envoy/network/io_handle.h" -#include "envoy/network/proxy_protocol.h" -#include "envoy/ssl/connection.h" - -#include "common/common/assert.h" -#include "common/common/logger.h" - -#include "absl/types/optional.h" namespace Envoy { namespace Network { @@ -52,10 +44,6 @@ class WritablePeer { * Raised by the peer when the peer switch from high water mark to low. */ virtual void onPeerBufferWritable() PURE; - - // virtual bool triggeredHighToLowWatermark() const PURE; - // virtual void clearTriggeredHighToLowWatermark() PURE; - // virtual void setTriggeredHighToLowWatermark() PURE; }; /** From 622ab925c1a1dbaaa0940fdbc2b83aa39e4220b3 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 7 Oct 2020 01:04:15 +0000 Subject: [PATCH 03/88] clean up and add impl ::read() Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 35 ++++++++----------- .../network/buffered_io_socket_handle_impl.cc | 19 +++++++++- .../network/buffered_io_socket_handle_impl.h | 3 ++ .../buffered_io_socket_handle_impl_test.cc | 35 ++++++++++++++++--- 4 files changed, 66 insertions(+), 26 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index ae8ace64d2f8f..005368cabf2c6 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -71,22 +71,16 @@ class EventListener { class DefaultEventListener : public EventListener { public: ~DefaultEventListener() override = default; - uint32_t triggeredEvents() override { - ENVOY_LOG_MISC(debug, - "lambdai: user file event listener triggered events {} on {} and schedule next", - pending_events_, static_cast(this)); - return pending_events_ & (~Event::FileReadyType::Closed); - } - void onEventEnabled(uint32_t enabled_events) override { - ENVOY_LOG_MISC( - debug, "lambdai: user file event listener set enabled events {} on {} and schedule next", - pending_events_, static_cast(this)); - pending_events_ = enabled_events; - } + // Return both read and write. + uint32_t triggeredEvents() override { return pending_events_ & (~Event::FileReadyType::Closed); } + + void onEventEnabled(uint32_t enabled_events) override { pending_events_ = enabled_events; } + void onEventActivated(uint32_t activated_events) override { ephermal_events_ |= activated_events; } + uint32_t getAndClearEphemeralEvents() override { auto res = ephermal_events_; ephermal_events_ = 0; @@ -101,7 +95,7 @@ class DefaultEventListener : public EventListener { }; // A FileEvent implementation which is -class UserSpaceFileEventImpl : public FileEvent { +class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { public: ~UserSpaceFileEventImpl() override { // if (schedulable_.enabled()) { @@ -121,14 +115,12 @@ class UserSpaceFileEventImpl : public FileEvent { void setEnabled(uint32_t events) override { event_listener_.onEventEnabled(events); - if (!schedulable_.enabled()) { + bool was_enabled = schedulable_.enabled(); + if (!was_enabled) { schedulable_.scheduleCallbackNextIteration(); - ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and schedule next", - events, static_cast(this)); - return; } - ENVOY_LOG_MISC(debug, "lambdai: user file event setEnabled {} on {} and but not schedule next", - events, static_cast(this)); + ENVOY_LOG(trace, "User space file event {} setEnabled {} on {}. Will {} reschedule.", + static_cast(this), was_enabled ? "not " : ""); } EventListener& getEventListener() { return event_listener_; } @@ -142,8 +134,9 @@ class UserSpaceFileEventImpl : public FileEvent { : schedulable_(schedulable_cb), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); - ENVOY_LOG_MISC(debug, "lambdai: us event {} cb allevents = {}, ephermal events = {}", - static_cast(this), all_events, ephemeral_events); + ENVOY_LOG(trace, + "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", + static_cast(this), all_events, ephemeral_events); cb(all_events | ephemeral_events); }), event_counter_(event_counter) { diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index f56b4ff27c552..8d5ad9655ebc4 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -38,7 +38,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, uint64_t num_slice) { if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return Api::ioCallUint64ResultNoError(); + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; @@ -60,6 +60,23 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, } } +Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, + uint64_t max_length) { + if (owned_buffer_.length() == 0) { + if (read_end_stream_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } else { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + } else { + // TODO(lambdai): Move at slice boundary to move to reduce the copy. + uint64_t min_len = std::min(max_length, owned_buffer_.length()); + buffer.move(owned_buffer_, min_len); + return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + } +} + Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, uint64_t num_slice) { if (!writable_peer_) { diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 57c2380bc7e66..cc6405cb8724d 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -60,6 +60,8 @@ class BufferedIoSocketHandleImpl : public IoHandle, Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, uint64_t num_slice) override; + Api::IoCallUint64Result read(Buffer::Instance& buffer, uint64_t max_length) override; + Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, @@ -90,6 +92,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, Event::FileEventPtr createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, Event::FileTriggerType trigger, uint32_t events) override; Api::SysCallIntResult shutdown(int how) override; + absl::optional lastRoundTripTime() override { return absl::nullopt; } Buffer::WatermarkBuffer& getBufferForTest() { return owned_buffer_; } diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 361edd6752485..4212c8bbbe79d 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -66,6 +66,35 @@ TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); } +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { + Buffer::OwnedImpl buf; + auto res = io_handle_->read(buf, 10); + EXPECT_FALSE(res.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + io_handle_->setWriteEnd(); + res = io_handle_->read(buf, 10); + EXPECT_FALSE(res.ok()); + EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); +} + +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestReadContent) { + Buffer::OwnedImpl buf; + auto& internal_buffer = io_handle_->getBufferForTest(); + internal_buffer.add("abcdefg"); + auto res = io_handle_->read(buf, 3); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(3, res.rc_); + ASSERT_EQ(3, buf.length()); + ASSERT_EQ(4, internal_buffer.length()); + res = io_handle_->read(buf, 10); + EXPECT_TRUE(res.ok()); + EXPECT_EQ(4, res.rc_); + ASSERT_EQ(7, buf.length()); + ASSERT_EQ(0, internal_buffer.length()); +} + // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); @@ -401,8 +430,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { io_handle_peer_->shutdown(ENVOY_SHUT_WR); - ENVOY_LOG_MISC(debug, "lambdai: after {} shutdown write ", - static_cast(io_handle_peer_.get())); + ENVOY_LOG_MISC(debug, "after {} shutdown write ", static_cast(io_handle_peer_.get())); std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); @@ -452,8 +480,7 @@ TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { EXPECT_FALSE(io_handle_peer_->isWritable()); io_handle_peer_->shutdown(ENVOY_SHUT_WR); - ENVOY_LOG_MISC(debug, "lambdai: after {} shutdown write ", - static_cast(io_handle_peer_.get())); + ENVOY_LOG_MISC(debug, "after {} shutdown write", static_cast(io_handle_peer_.get())); scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); From 420e4984c963f218e3bf3c66352a6916066a9d96 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 8 Oct 2020 19:23:43 +0000 Subject: [PATCH 04/88] clang tidy Signed-off-by: Yuchen Dai --- source/common/network/buffered_io_socket_handle_impl.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index cc6405cb8724d..6a1257ffd9407 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -32,8 +32,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, protected Logger::Loggable { public: BufferedIoSocketHandleImpl() - : closed_{false}, - owned_buffer_( + : owned_buffer_( [this]() -> void { over_high_watermark_ = false; if (writable_peer_) { @@ -134,7 +133,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, private: // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource // leak. - bool closed_; + bool closed_{false}; // The attached file event with this socket. The event is not owned by the socket. Event::UserSpaceFileEventImpl* user_file_event_; From 4c53d54718a8bbac3c5f5d54525d1c32e4effad5 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 8 Oct 2020 20:13:01 +0000 Subject: [PATCH 05/88] impl BufferedIoSocketHandleImpl:write Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 15 ++++++ .../network/buffered_io_socket_handle_impl.h | 2 + .../buffered_io_socket_handle_impl_test.cc | 50 ++++++++++++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 8d5ad9655ebc4..5f283ce5c59dd 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -99,6 +99,21 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } +Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buffer) { + if (!writable_peer_) { + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + } + if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { + return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), + IoSocketError::deleteIoError)}; + } + uint64_t num_bytes_to_write = buffer.length(); + writable_peer_->getWriteBuffer()->move(buffer); + writable_peer_->maybeSetNewData(); + ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), num_bytes_to_write); + return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; +} + Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, const Address::Ip*, const Address::Instance&) { diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 6a1257ffd9407..c9fa910f757f0 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -63,6 +63,8 @@ class BufferedIoSocketHandleImpl : public IoHandle, Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; + Api::IoCallUint64Result write(Buffer::Instance& buffer) override; + Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, const Address::Ip* self_ip, const Address::Instance& peer_address) override; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 4212c8bbbe79d..c9741059eec34 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -370,7 +370,15 @@ TEST_F(BufferedIoSocketHandleTest, TestShutdown) { ev.reset(); } -TEST_F(BufferedIoSocketHandleTest, TestWriteToPeer) { +TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { + Buffer::OwnedImpl buf("0123456789"); + io_handle_peer_->write(buf); + auto& internal_buffer = io_handle_->getBufferForTest(); + EXPECT_EQ("0123456789", internal_buffer.toString()); + EXPECT_EQ(0, buf.length()); +} + +TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { std::string raw_data("0123456789"); absl::InlinedVector slices{ // Contains 1 byte. @@ -415,6 +423,46 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); + Buffer::OwnedImpl data_to_write("0123456789"); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_peer_->write(data_to_write); + EXPECT_EQ(0, data_to_write.length()); + + EXPECT_TRUE(scheduable_cb_->enabled()); + scheduable_cb_->invokeCallback(); + EXPECT_EQ("0123456789", accumulator); + EXPECT_FALSE(should_close); + + io_handle_->close(); +} + +TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { + std::string accumulator; + scheduable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + bool should_close = false; + auto ev = io_handle_->createFileEvent( + dispatcher_, + [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { + if (events & Event::FileReadyType::Read) { + Buffer::OwnedImpl buf; + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + auto res = handle->readv(1024, &slice, 1); + if (res.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); + } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + } + } + }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + scheduable_cb_->invokeCallback(); + EXPECT_FALSE(scheduable_cb_->enabled()); + std::string raw_data("0123456789"); Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); From 812a288bde474cc3ddea4bb36097ebd38c524709 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 8 Oct 2020 21:32:32 +0000 Subject: [PATCH 06/88] comment Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 005368cabf2c6..1c1b3058c2ebb 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -98,9 +98,9 @@ class DefaultEventListener : public EventListener { class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { public: ~UserSpaceFileEventImpl() override { - // if (schedulable_.enabled()) { - schedulable_.cancel(); - //} + if (schedulable_.enabled()) { + schedulable_.cancel(); + } ASSERT(event_counter_ == 1); --event_counter_; } From 273447d2303fb67f896495a6e201cb7fc5e1e0d1 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 8 Oct 2020 22:55:36 +0000 Subject: [PATCH 07/88] remove posix header file Signed-off-by: Yuchen Dai --- test/common/network/buffered_io_socket_handle_impl_test.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index c9741059eec34..dca696aff79ff 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -1,5 +1,3 @@ -#include - #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" From 9f810f2733adc00c83f3cefbf2e810352d33e2fa Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 9 Oct 2020 02:07:13 +0000 Subject: [PATCH 08/88] fix error code on read EOS Signed-off-by: Yuchen Dai --- source/common/network/buffered_io_socket_handle_impl.cc | 4 ++-- test/common/network/buffered_io_socket_handle_impl_test.cc | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 5f283ce5c59dd..9fa72f22e4ccc 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -38,7 +38,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, uint64_t num_slice) { if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; @@ -64,7 +64,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe uint64_t max_length) { if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index dca696aff79ff..a05f096a9767c 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -72,8 +72,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); io_handle_->setWriteEnd(); res = io_handle_->read(buf, 10); - EXPECT_FALSE(res.ok()); - EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + EXPECT_TRUE(res.ok()); } // Test recv side effects. From 6422a4f7d8d90c35f9618f551775193789c3c570 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 13 Oct 2020 09:01:20 +0000 Subject: [PATCH 09/88] address comments Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 40 ++++++++++++----- .../network/buffered_io_socket_handle_impl.cc | 43 +++++++++++++------ .../network/buffered_io_socket_handle_impl.h | 33 +++----------- 3 files changed, 65 insertions(+), 51 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 1c1b3058c2ebb..05ef260d9ea29 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -49,18 +49,30 @@ class FileEventImpl : public FileEvent, ImplBase { // Forward declare for friend class. class UserSpaceFileEventFactory; -// The interface of populating event watcher and obtaining the active events. The events includes -// Read, Write and Closed. +// The interface of populating event watcher and obtaining the active events. The events are the +// combination of FileReadyType values. The event listener is populated by user event registration +// and io events passively. Also the owner of this listener query the activated events by calling +// triggeredEvents and getAndClearEphemeralEvents. class EventListener { public: virtual ~EventListener() = default; - // Provide the activated events. + // Get the events which are enabled and triggered. virtual uint32_t triggeredEvents() PURE; + // Get the events which are ephemerally activated. Upon returning the ephemeral events are + // cleared. virtual uint32_t getAndClearEphemeralEvents() PURE; - // Callbacks of the event operation. + /** + * FileEvent::setEnabled is invoked. + * @param enabled_events supplied the event of setEnabled. + */ virtual void onEventEnabled(uint32_t enabled_events) PURE; + + /** + * FileEvent::activate is invoked. + * @param enabled_events supplied the event of activate(). + */ virtual void onEventActivated(uint32_t activated_events) PURE; }; @@ -68,6 +80,7 @@ class EventListener { // epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner // must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify // events which are not actually triggered. +// TODO(lambdai): Add support of delivering EV_CLOSED. class DefaultEventListener : public EventListener { public: ~DefaultEventListener() override = default; @@ -81,11 +94,7 @@ class DefaultEventListener : public EventListener { ephermal_events_ |= activated_events; } - uint32_t getAndClearEphemeralEvents() override { - auto res = ephermal_events_; - ephermal_events_ = 0; - return res; - } + uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephermal_events_, 0); } private: // The persisted interested events and ready events. @@ -94,7 +103,7 @@ class DefaultEventListener : public EventListener { uint32_t ephermal_events_{}; }; -// A FileEvent implementation which is +// A FileEvent implementation which is used to drive BufferedIoSocketHandle. class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { public: ~UserSpaceFileEventImpl() override { @@ -142,9 +151,20 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable cb_; + + // The counter owned by io handle. This counter is used to track if more than one file event is + // attached to the same io handle. + // TODO(lambdai): remove this when the full internal connection implementation is landed. int& event_counter_; }; diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 9fa72f22e4ccc..08d5751e67da6 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -15,6 +15,22 @@ namespace Envoy { namespace Network { +BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() + : owned_buffer_( + [this]() -> void { + over_high_watermark_ = false; + if (writable_peer_) { + ENVOY_LOG(debug, "Socket {} switches to low watermark. Notify {}.", + static_cast(this), static_cast(writable_peer_)); + writable_peer_->onPeerBufferWritable(); + } + }, + [this]() -> void { + over_high_watermark_ = true; + // Low to high is checked by peer after peer writes data. + }, + []() -> void {}) {} + Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { ASSERT(!closed_); if (!write_shutdown_) { @@ -46,17 +62,18 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, } else { absl::FixedArray iov(num_slice); uint64_t num_slices_to_read = 0; - uint64_t num_bytes_to_read = 0; - for (; num_slices_to_read < num_slice && num_bytes_to_read < max_length; num_slices_to_read++) { - auto min_len = std::min(std::min(owned_buffer_.length(), max_length) - num_bytes_to_read, - uint64_t(slices[num_slices_to_read].len_)); - owned_buffer_.copyOut(num_bytes_to_read, min_len, slices[num_slices_to_read].mem_); - num_bytes_to_read += min_len; + uint64_t bytes_to_read = 0; + for (; num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { + auto max_bytes_to_read = + std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, + uint64_t(slices[num_slices_to_read].len_)); + owned_buffer_.copyOut(bytes_to_read, max_bytes_to_read, slices[num_slices_to_read].mem_); + bytes_to_read += max_bytes_to_read; } - ASSERT(num_bytes_to_read <= max_length); - owned_buffer_.drain(num_bytes_to_read); - ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), num_bytes_to_read); - return {num_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + ASSERT(bytes_to_read <= max_length); + owned_buffer_.drain(bytes_to_read); + ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_to_read); + return {bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } } @@ -71,9 +88,9 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe } } else { // TODO(lambdai): Move at slice boundary to move to reduce the copy. - uint64_t min_len = std::min(max_length, owned_buffer_.length()); - buffer.move(owned_buffer_, min_len); - return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + uint64_t max_bytes_to_read = std::min(max_length, owned_buffer_.length()); + buffer.move(owned_buffer_, max_bytes_to_read); + return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } } diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index c9fa910f757f0..a78852c22c041 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -23,62 +23,38 @@ namespace Network { * 1. It doesn't not include a file descriptor. Do not use "fdDoNotUse". * 2. It doesn't suppose socket options. Wrap this in ConnectionSocket and implement the socket * getter/setter options. - * 3. It doesn't suppose UDP interface. - * 4. The peer BufferedIoSocket must be scheduled by the same scheduler to avoid data race. + * 3. It doesn't support UDP interface. + * 4. The peer BufferedIoSocket must be scheduled in the same thread to avoid data race because + * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ class BufferedIoSocketHandleImpl : public IoHandle, public WritablePeer, public ReadableSource, protected Logger::Loggable { public: - BufferedIoSocketHandleImpl() - : owned_buffer_( - [this]() -> void { - over_high_watermark_ = false; - if (writable_peer_) { - ENVOY_LOG(debug, "Socket {} switches to low watermark. Notify {}.", - static_cast(this), static_cast(writable_peer_)); - writable_peer_->onPeerBufferWritable(); - } - }, - [this]() -> void { - over_high_watermark_ = true; - // Low to high is checked by peer after peer writes data. - }, - []() -> void {}) {} + BufferedIoSocketHandleImpl(); ~BufferedIoSocketHandleImpl() override { ASSERT(closed_); } // IoHandle os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } - Api::IoCallUint64Result close() override; - bool isOpen() const override; - Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, uint64_t num_slice) override; - Api::IoCallUint64Result read(Buffer::Instance& buffer, uint64_t max_length) override; - Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; - Api::IoCallUint64Result write(Buffer::Instance& buffer) override; - Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, const Address::Ip* self_ip, const Address::Instance& peer_address) override; - Api::IoCallUint64Result recvmsg(Buffer::RawSlice* slices, const uint64_t num_slice, uint32_t self_port, RecvMsgOutput& output) override; - Api::IoCallUint64Result recvmmsg(RawSliceArrays& slices, uint32_t self_port, RecvMsgOutput& output) override; Api::IoCallUint64Result recv(void* buffer, size_t length, int flags) override; - bool supportsMmsg() const override; bool supportsUdpGro() const override; - Api::SysCallIntResult bind(Address::InstanceConstSharedPtr address) override; Api::SysCallIntResult listen(int backlog) override; IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; @@ -141,6 +117,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, Event::UserSpaceFileEventImpl* user_file_event_; // Envoy never schedule two independent IO event on the same socket. Use this counter to verify. + // TODO(lambdai): Remove this when the entire #13361 is done. int event_counter_{0}; // The schedulable handle of the above event. From a978ced52a25841c130ad03811f7905956a8a63a Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 13 Oct 2020 11:20:57 +0000 Subject: [PATCH 10/88] fix TestShutdown and close Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 47 ++++-- .../buffered_io_socket_handle_impl_test.cc | 155 +++++++++++------- 2 files changed, 129 insertions(+), 73 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 08d5751e67da6..cc97ab3561b3a 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -52,6 +52,10 @@ bool BufferedIoSocketHandleImpl::isOpen() const { return !closed_; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, Buffer::RawSlice* slices, uint64_t num_slice) { + if (!isOpen()) { + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } if (owned_buffer_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; @@ -79,6 +83,10 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, uint64_t max_length) { + if (!isOpen()) { + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } if (owned_buffer_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; @@ -96,39 +104,48 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, uint64_t num_slice) { + if (!isOpen()) { + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } if (!writable_peer_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INVAL}); } if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } // Write along with iteration. Buffer guarantee the fragment is always append-able. - uint64_t num_bytes_to_write = 0; + uint64_t total_bytes_to_write = 0; for (uint64_t i = 0; i < num_slice; i++) { if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { writable_peer_->getWriteBuffer()->add(slices[i].mem_, slices[i].len_); - num_bytes_to_write += slices[i].len_; + total_bytes_to_write += slices[i].len_; } } writable_peer_->maybeSetNewData(); ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), num_bytes_to_write); - return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buffer) { + if (!isOpen()) { + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } if (!writable_peer_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } - uint64_t num_bytes_to_write = buffer.length(); + uint64_t total_bytes_to_write = buffer.length(); writable_peer_->getWriteBuffer()->move(buffer); writable_peer_->maybeSetNewData(); - ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), num_bytes_to_write); - return {num_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), total_bytes_to_write); + return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, @@ -148,21 +165,25 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmmsg(RawSliceArrays&, ui } Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { + if (!isOpen()) { + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } // No data and the writer closed. if (owned_buffer_.length() == 0) { if (read_end_stream_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INTR}); + return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } } else { - auto min_len = std::min(owned_buffer_.length(), length); - owned_buffer_.copyOut(0, min_len, buffer); + auto max_bytes_to_read = std::min(owned_buffer_.length(), length); + owned_buffer_.copyOut(0, max_bytes_to_read, buffer); if (!(flags & MSG_PEEK)) { - owned_buffer_.drain(min_len); + owned_buffer_.drain(max_bytes_to_read); } - return {min_len, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } } diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index a05f096a9767c..03e3186182784 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -38,9 +38,9 @@ class BufferedIoSocketHandleTest : public testing::Test { } } void expectAgain() { - auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); - EXPECT_FALSE(res.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } NiceMock dispatcher_{}; @@ -52,27 +52,54 @@ class BufferedIoSocketHandleTest : public testing::Test { absl::FixedArray buf_; }; +TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { + io_handle_->close(); + Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + result = io_handle_->recv(buf_.data(), buf_.size(), 0); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + Buffer::OwnedImpl buf("0123456789"); + + result = io_handle_->read(buf, 10); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + result = io_handle_->readv(1024, &slice, 1); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + result = io_handle_->write(buf); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + result = io_handle_->writev(&slice, 1); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); +} + // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { - auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); // EAGAIN. - EXPECT_FALSE(res.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); io_handle_->setWriteEnd(); - res = io_handle_->recv(buf_.data(), buf_.size(), 0); - EXPECT_FALSE(res.ok()); - EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + result = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_TRUE(result.ok()); } // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { Buffer::OwnedImpl buf; - auto res = io_handle_->read(buf, 10); - EXPECT_FALSE(res.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + auto result = io_handle_->read(buf, 10); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); io_handle_->setWriteEnd(); - res = io_handle_->read(buf, 10); - EXPECT_TRUE(res.ok()); + result = io_handle_->read(buf, 10); + EXPECT_TRUE(result.ok()); } // Test recv side effects. @@ -80,36 +107,35 @@ TEST_F(BufferedIoSocketHandleTest, TestReadContent) { Buffer::OwnedImpl buf; auto& internal_buffer = io_handle_->getBufferForTest(); internal_buffer.add("abcdefg"); - auto res = io_handle_->read(buf, 3); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(3, res.rc_); + auto result = io_handle_->read(buf, 3); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(3, result.rc_); ASSERT_EQ(3, buf.length()); ASSERT_EQ(4, internal_buffer.length()); - res = io_handle_->read(buf, 10); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(4, res.rc_); + result = io_handle_->read(buf, 10); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(4, result.rc_); ASSERT_EQ(7, buf.length()); ASSERT_EQ(0, internal_buffer.length()); } // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { - auto res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); // EAGAIN. - EXPECT_FALSE(res.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); io_handle_->setWriteEnd(); - res = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); - EXPECT_FALSE(res.ok()); - EXPECT_NE(Api::IoError::IoErrorCode::Again, res.err_->getErrorCode()); + result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_TRUE(result.ok()); } TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { auto& internal_buffer = io_handle_->getBufferForTest(); internal_buffer.add("abcd"); - auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(4, res.rc_); + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(4, result.rc_); EXPECT_EQ(absl::string_view(buf_.data(), 4), "abcd"); EXPECT_EQ(0, internal_buffer.length()); expectAgain(); @@ -138,9 +164,9 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { } else { ASSERT_FALSE(writable_flipped); } - auto res = io_handle_->recv(buf_.data(), 32, 0); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(32, res.rc_); + auto result = io_handle_->recv(buf_.data(), 32, 0); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(32, result.rc_); } ASSERT_EQ(0, internal_buffer.length()); ASSERT_TRUE(writable_flipped); @@ -213,9 +239,9 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { // Drain 1 bytes. auto& internal_buffer = io_handle_->getBufferForTest(); internal_buffer.add("abcd"); - auto res = io_handle_->recv(buf_.data(), 1, 0); - EXPECT_TRUE(res.ok()); - EXPECT_EQ(1, res.rc_); + auto result = io_handle_->recv(buf_.data(), 1, 0); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(1, result.rc_); ASSERT_FALSE(scheduable_cb_->enabled()); ev.reset(); @@ -273,12 +299,12 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { ASSERT_FALSE(scheduable_cb_->enabled()); { - auto res = io_handle_->recv(buf_.data(), 1, 0); + auto result = io_handle_->recv(buf_.data(), 1, 0); EXPECT_FALSE(handle_as_peer->isWritable()); } { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); - auto res = io_handle_->recv(buf_.data(), 232, 0); + auto result = io_handle_->recv(buf_.data(), 232, 0); EXPECT_TRUE(handle_as_peer->isWritable()); } @@ -297,18 +323,25 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { dispatcher_, [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { - auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); - if (res.ok()) { - accumulator += absl::string_view(buf_.data(), res.rc_); - } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (result.ok()) { + accumulator += absl::string_view(buf_.data(), result.rc_); + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { ENVOY_LOG_MISC(debug, "will close"); should_close = true; } } + if (events & Event::FileReadyType::Write) { + Buffer::OwnedImpl buf(""); + auto result = io_handle_->write(buf); + if (!result.ok() && result.err_->getErrorCode() != Api::IoError::IoErrorCode::Again) { + should_close = true; + } + } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read | Event::FileReadyType::Write); scheduable_cb_->invokeCallback(); // Not closed yet. @@ -327,7 +360,9 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { ev.reset(); } -TEST_F(BufferedIoSocketHandleTest, TestShutdown) { +// Test that a readable event is raised when peer shutdown write. Also confirm read will return +// EAGAIN. +TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { auto& internal_buffer = io_handle_->getBufferForTest(); internal_buffer.add("abcd"); @@ -339,10 +374,10 @@ TEST_F(BufferedIoSocketHandleTest, TestShutdown) { dispatcher_, [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { - auto res = io_handle_->recv(buf_.data(), buf_.size(), 0); - if (res.ok()) { - accumulator += absl::string_view(buf_.data(), res.rc_); - } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (result.ok()) { + accumulator += absl::string_view(buf_.data(), result.rc_); + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { ENVOY_LOG_MISC(debug, "will close"); @@ -361,7 +396,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutdown) { ASSERT_TRUE(scheduable_cb_->enabled()); scheduable_cb_->invokeCallback(); - ASSERT_TRUE(should_close); + ASSERT_FALSE(should_close); EXPECT_EQ(4, accumulator.size()); io_handle_->close(); ev.reset(); @@ -405,10 +440,10 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { Buffer::OwnedImpl buf; Buffer::RawSlice slice; buf.reserve(1024, &slice, 1); - auto res = handle->readv(1024, &slice, 1); - if (res.ok()) { - accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); - } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + auto result = handle->readv(1024, &slice, 1); + if (result.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { ENVOY_LOG_MISC(debug, "will close"); @@ -445,10 +480,10 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { Buffer::OwnedImpl buf; Buffer::RawSlice slice; buf.reserve(1024, &slice, 1); - auto res = handle->readv(1024, &slice, 1); - if (res.ok()) { - accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); - } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + auto result = handle->readv(1024, &slice, 1); + if (result.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { ENVOY_LOG_MISC(debug, "will close"); @@ -487,10 +522,10 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { Buffer::OwnedImpl buf; Buffer::RawSlice slice; buf.reserve(1024, &slice, 1); - auto res = handle->readv(1024, &slice, 1); - if (res.ok()) { - accumulator += absl::string_view(static_cast(slice.mem_), res.rc_); - } else if (res.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + auto result = handle->readv(1024, &slice, 1); + if (result.ok()) { + accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { ENVOY_LOG_MISC(debug, "will close"); From 0cf62b4b8d8434ce492c11f2b2dab6d3e2b95ebc Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 13 Oct 2020 16:01:28 +0000 Subject: [PATCH 11/88] fix Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 6 ++++++ source/common/network/buffered_io_socket_handle_impl.cc | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 05ef260d9ea29..5f0615feb02d8 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -116,6 +116,9 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::LoggablemaybeSetNewData(); - ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), num_bytes_to_write); + ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), total_bytes_to_write); return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } From 09c1adfe2782190c69fa94d2c3ef18a15d3fbd8b Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 14 Oct 2020 06:54:35 +0000 Subject: [PATCH 12/88] fix log and comments Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 4 ++-- source/common/network/buffered_io_socket_handle_impl.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 5f0615feb02d8..8ef95f1a3d8e4 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -134,8 +134,8 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable(this), was_enabled ? "not " : ""); + ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", + static_cast(this), events, was_enabled ? "not " : ""); } EventListener& getEventListener() { return event_listener_; } diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index a78852c22c041..38d82d129fab6 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -21,7 +21,7 @@ namespace Network { * IoHandle implementation which provides a buffer as data source. It is designed to used by * Network::ConnectionImpl. Some known limitations include * 1. It doesn't not include a file descriptor. Do not use "fdDoNotUse". - * 2. It doesn't suppose socket options. Wrap this in ConnectionSocket and implement the socket + * 2. It doesn't support socket options. Wrap this in ConnectionSocket and implement the socket * getter/setter options. * 3. It doesn't support UDP interface. * 4. The peer BufferedIoSocket must be scheduled in the same thread to avoid data race because From b73ced39e8894d03cbdc96e03a01e826993f85de Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 14 Oct 2020 22:08:19 +0000 Subject: [PATCH 13/88] addressing comment Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 95 ++++++++++--------- .../network/buffered_io_socket_handle_impl.h | 4 - .../buffered_io_socket_handle_impl_test.cc | 70 ++++++++++++++ 3 files changed, 119 insertions(+), 50 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index e4533f6701df9..efeb9793cd967 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -15,6 +15,11 @@ namespace Envoy { namespace Network { +namespace { +Api::SysCallIntResult makeInvalidSyscall() { + return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP}; +} +} // namespace BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() : owned_buffer_( [this]() -> void { @@ -63,22 +68,20 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } - } else { - absl::FixedArray iov(num_slice); - uint64_t num_slices_to_read = 0; - uint64_t bytes_to_read = 0; - for (; num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { - auto max_bytes_to_read = - std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, - uint64_t(slices[num_slices_to_read].len_)); - owned_buffer_.copyOut(bytes_to_read, max_bytes_to_read, slices[num_slices_to_read].mem_); - bytes_to_read += max_bytes_to_read; - } - ASSERT(bytes_to_read <= max_length); - owned_buffer_.drain(bytes_to_read); - ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_to_read); - return {bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } + absl::FixedArray iov(num_slice); + uint64_t num_slices_to_read = 0; + uint64_t bytes_to_read = 0; + for (; num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { + auto max_bytes_to_read = std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, + uint64_t(slices[num_slices_to_read].len_)); + owned_buffer_.copyOut(bytes_to_read, max_bytes_to_read, slices[num_slices_to_read].mem_); + bytes_to_read += max_bytes_to_read; + } + ASSERT(bytes_to_read <= max_length); + owned_buffer_.drain(bytes_to_read); + ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_to_read); + return {bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, @@ -94,12 +97,11 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } - } else { - // TODO(lambdai): Move at slice boundary to move to reduce the copy. - uint64_t max_bytes_to_read = std::min(max_length, owned_buffer_.length()); - buffer.move(owned_buffer_, max_bytes_to_read); - return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } + // TODO(lambdai): Move at slice boundary to move to reduce the copy. + uint64_t max_bytes_to_read = std::min(max_length, owned_buffer_.length()); + buffer.move(owned_buffer_, max_bytes_to_read); + return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, @@ -111,7 +113,11 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic if (!writable_peer_) { return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INVAL}); } - if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { + if (writable_peer_->isWriteEndSet()) { + // EPIPE or ENOTCONN + return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } + if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } @@ -137,7 +143,11 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - if (writable_peer_->isWriteEndSet() || !writable_peer_->isWritable()) { + if (writable_peer_->isWriteEndSet()) { + // EPIPE or ENOTCONN + return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + } + if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } @@ -177,24 +187,19 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t le return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; } - } else { - auto max_bytes_to_read = std::min(owned_buffer_.length(), length); - owned_buffer_.copyOut(0, max_bytes_to_read, buffer); - if (!(flags & MSG_PEEK)) { - owned_buffer_.drain(max_bytes_to_read); - } - return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } + auto max_bytes_to_read = std::min(owned_buffer_.length(), length); + owned_buffer_.copyOut(0, max_bytes_to_read, buffer); + if (!(flags & MSG_PEEK)) { + owned_buffer_.drain(max_bytes_to_read); + } + return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } bool BufferedIoSocketHandleImpl::supportsMmsg() const { return false; } bool BufferedIoSocketHandleImpl::supportsUdpGro() const { return false; } -Api::SysCallIntResult makeInvalidSyscall() { - return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP /*SOCKET_ERROR_NOT_SUP*/}; -} - Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Address::InstanceConstSharedPtr) { return makeInvalidSyscall(); } @@ -206,8 +211,8 @@ IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { } Api::SysCallIntResult BufferedIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { - // Buffered Io handle should always be considered as connected. Use write to determine if peer is - // closed. + // Buffered Io handle should always be considered as connected. + // Use write or read to determine if peer is closed. return {0, 0}; } @@ -228,7 +233,6 @@ Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { } Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { - throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); } @@ -249,18 +253,17 @@ Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatche Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { // Support shutdown write. - if ((how == ENVOY_SHUT_WR) || (how == ENVOY_SHUT_RDWR)) { - ASSERT(!closed_); - if (!write_shutdown_) { - ASSERT(writable_peer_); - // Notify the peer we won't write more data. shutdown(WRITE). - writable_peer_->setWriteEnd(); - writable_peer_->maybeSetNewData(); - write_shutdown_ = true; - } + ASSERT(how == ENVOY_SHUT_WR); + ASSERT(!closed_); + if (!write_shutdown_) { + ASSERT(writable_peer_); + // Notify the peer we won't write more data. + writable_peer_->setWriteEnd(); + writable_peer_->maybeSetNewData(); + write_shutdown_ = true; } return {0, 0}; -} +} // namespace Network } // namespace Network } // namespace Envoy \ No newline at end of file diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index a78852c22c041..0789232aa2608 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -116,10 +116,6 @@ class BufferedIoSocketHandleImpl : public IoHandle, // The attached file event with this socket. The event is not owned by the socket. Event::UserSpaceFileEventImpl* user_file_event_; - // Envoy never schedule two independent IO event on the same socket. Use this counter to verify. - // TODO(lambdai): Remove this when the entire #13361 is done. - int event_counter_{0}; - // The schedulable handle of the above event. Event::SchedulableCallbackPtr io_callback_; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 03e3186182784..d6a970cea9f64 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -2,6 +2,7 @@ #include "common/buffer/buffer_impl.h" #include "common/network/buffered_io_socket_handle_impl.h" +#include "common/network/address_impl.h" #include "test/mocks/event/mocks.h" @@ -16,6 +17,11 @@ namespace Envoy { namespace Network { namespace { +MATCHER(IsInvalidateAddress, "") { + return arg.err_->getErrorCode() == Api::IoError::IoErrorCode::NoSupport; +} + +MATCHER(IsNotSupportedResult, "") { return arg.errno_ == SOCKET_ERROR_NOT_SUP; } class MockFileEventCallback { public: MOCK_METHOD(void, called, (uint32_t arg)); @@ -402,6 +408,16 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { ev.reset(); } +TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { + EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); + EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); +} + +TEST_F(BufferedIoSocketHandleTest, TestShutDownOptionsNotSupported) { + ASSERT_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RD), ""); + ASSERT_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RDWR), ""); +} + TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { Buffer::OwnedImpl buf("0123456789"); io_handle_peer_->write(buf); @@ -577,6 +593,60 @@ TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { io_handle_->close(); } +TEST_F(BufferedIoSocketHandleTest, TestNotSupportingMmsg) { + EXPECT_FALSE(io_handle_->supportsMmsg()); +} + +TEST_F(BufferedIoSocketHandleTest, TestNotSupportsUdpGro) { + EXPECT_FALSE(io_handle_->supportsUdpGro()); +} + +class BufferedIoSocketHandleNotImplementedTest : public testing::Test { +public: + BufferedIoSocketHandleNotImplementedTest() { + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setWritablePeer(io_handle_peer_.get()); + io_handle_peer_->setWritablePeer(io_handle_.get()); + } + ~BufferedIoSocketHandleNotImplementedTest() override { + if (io_handle_->isOpen()) { + io_handle_->close(); + } + if (io_handle_peer_->isOpen()) { + io_handle_peer_->close(); + } + } + + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; + Buffer::RawSlice slice_; +}; + +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSendmsg) { + EXPECT_THAT(io_handle_->sendmsg(&slice_, 0, 0, nullptr, + Network::Address::EnvoyInternalInstance("listener_id")), + IsInvalidateAddress()); +} +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmsg) { + Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); + EXPECT_THAT(io_handle_->recvmsg(&slice_, 0, 0, output_is_ignored), IsInvalidateAddress()); +} +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmmsg) { + RawSliceArrays slices_is_ignored(1, absl::FixedArray({slice_})); + Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); + EXPECT_THAT(io_handle_->recvmmsg(slices_is_ignored, 0, output_is_ignored), IsInvalidateAddress()); +} +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnBind) { + auto address_is_ignored = + std::make_shared("listener_id"); + EXPECT_THAT(io_handle_->bind(address_is_ignored), IsNotSupportedResult()); +} + +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnListen) { + int back_log_is_ignored = 0; + EXPECT_THAT(io_handle_->listen(back_log_is_ignored), IsNotSupportedResult()); +} } // namespace } // namespace Network } // namespace Envoy From 49bd8d6406b961f5b0eb6a724c4c5b680f861dea Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 14 Oct 2020 22:08:31 +0000 Subject: [PATCH 14/88] remove event counter Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 5f0615feb02d8..c0dd4b77d8989 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -110,8 +110,6 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable(this), all_events, ephemeral_events); cb(all_events | ephemeral_events); - }), - event_counter_(event_counter) { + }) { event_listener_.onEventEnabled(events); } @@ -167,11 +164,6 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable cb_; - - // The counter owned by io handle. This counter is used to track if more than one file event is - // attached to the same io handle. - // TODO(lambdai): remove this when the full internal connection implementation is landed. - int& event_counter_; }; class UserSpaceFileEventFactory { From 55b9acca7478385293d6d2983264739270b70965 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 14 Oct 2020 22:32:45 +0000 Subject: [PATCH 15/88] more test and event counter fix Signed-off-by: Yuchen Dai --- source/common/event/file_event_impl.h | 5 ++--- .../network/buffered_io_socket_handle_impl.cc | 7 ++++--- .../buffered_io_socket_handle_impl_test.cc | 21 +++++++++++++++++++ 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index c0dd4b77d8989..ac2d56ecbc106 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -170,10 +170,9 @@ class UserSpaceFileEventFactory { public: static std::unique_ptr createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, - uint32_t events, SchedulableCallback& scheduable_cb, - int& event_counter) { + uint32_t events, SchedulableCallback& scheduable_cb) { return std::unique_ptr( - new UserSpaceFileEventImpl(cb, events, scheduable_cb, event_counter)); + new UserSpaceFileEventImpl(cb, events, scheduable_cb)); } }; diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index efeb9793cd967..dc34bfa369abd 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -139,14 +139,17 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // Closed peer. if (!writable_peer_) { return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // Write to a shutdown peer. if (writable_peer_->isWriteEndSet()) { // EPIPE or ENOTCONN return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // Buffer is full. Cannot write anymore. if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; @@ -240,11 +243,9 @@ Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatche Event::FileReadyCb cb, Event::FileTriggerType trigger_type, uint32_t events) { - ASSERT(event_counter_ == 0); - ++event_counter_; io_callback_ = dispatcher.createSchedulableCallback([this]() { user_file_event_->onEvents(); }); auto res = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - dispatcher, cb, trigger_type, events, *io_callback_, event_counter_); + dispatcher, cb, trigger_type, events, *io_callback_); user_file_event_ = res.get(); // Blindly activate the events. io_callback_->scheduleCallbackNextIteration(); diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index d6a970cea9f64..f8dfc343e071d 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -444,6 +444,27 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { EXPECT_EQ("012", internal_buffer.toString()); } +TEST_F(BufferedIoSocketHandleTest, TestWriteAfteShutdown) { + Buffer::OwnedImpl data_to_write("0123456789"); + Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + result = io_handle_->write(data_to_write); + EXPECT_TRUE(result.ok()); + io_handle_->shutdown(ENVOY_SHUT_WR); + result = io_handle_->write(data_to_write); + EXPECT_FALSE(result.ok()); +} + +TEST_F(BufferedIoSocketHandleTest, TestWritevAfteShutdown) { + std::string raw_data("0123456789"); + Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; + Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + result = io_handle_peer_->writev(&slice, 1); + EXPECT_TRUE(result.ok()); + io_handle_->shutdown(ENVOY_SHUT_WR); + result = io_handle_->writev(&slice, 1); + EXPECT_FALSE(result.ok()); +} + TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); From fb32d3037109fc9f7f58e2c4a0b1e02a8318ed0c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 14 Oct 2020 23:59:53 +0000 Subject: [PATCH 16/88] format Signed-off-by: Yuchen Dai --- .../common/network/buffered_io_socket_handle_impl.cc | 12 +++++++----- .../network/buffered_io_socket_handle_impl_test.cc | 2 +- tools/spelling/spelling_dictionary.txt | 2 ++ 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index dc34bfa369abd..64e8481da7ebe 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -115,7 +115,8 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic } if (writable_peer_->isWriteEndSet()) { // EPIPE or ENOTCONN - return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), @@ -144,10 +145,11 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - // Write to a shutdown peer. + // Write to a shutdown peer. if (writable_peer_->isWriteEndSet()) { // EPIPE or ENOTCONN - return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } // Buffer is full. Cannot write anymore. if (!writable_peer_->isWritable()) { @@ -214,8 +216,8 @@ IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { } Api::SysCallIntResult BufferedIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { - // Buffered Io handle should always be considered as connected. - // Use write or read to determine if peer is closed. + // Buffered Io handle should always be considered as connected. + // Use write or read to determine if peer is closed. return {0, 0}; } diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index f8dfc343e071d..1463cd6000d82 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -1,8 +1,8 @@ #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" -#include "common/network/buffered_io_socket_handle_impl.h" #include "common/network/address_impl.h" +#include "common/network/buffered_io_socket_handle_impl.h" #include "test/mocks/event/mocks.h" diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index 1b99501fec108..c7207ecb5d4ca 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -28,6 +28,8 @@ CDN CDS CEL DSR +ENOTCONN +EPIPE HEXDIG HEXDIGIT LTT From 9361c49289cde4bddb35b7f819e5119a70feecbc Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 05:16:53 +0000 Subject: [PATCH 17/88] add missing Signed-off-by: Yuchen Dai --- .../common/network/buffered_io_socket_handle_impl.cc | 11 +++++------ .../common/network/buffered_io_socket_handle_impl.h | 3 ++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 64e8481da7ebe..a5726e01fba47 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -246,16 +246,16 @@ Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatche Event::FileTriggerType trigger_type, uint32_t events) { io_callback_ = dispatcher.createSchedulableCallback([this]() { user_file_event_->onEvents(); }); - auto res = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + auto event = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( dispatcher, cb, trigger_type, events, *io_callback_); - user_file_event_ = res.get(); + user_file_event_ = event.get(); // Blindly activate the events. io_callback_->scheduleCallbackNextIteration(); - return res; + return event; } Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { - // Support shutdown write. + // Support only shutdown write. ASSERT(how == ENVOY_SHUT_WR); ASSERT(!closed_); if (!write_shutdown_) { @@ -266,7 +266,6 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { write_shutdown_ = true; } return {0, 0}; -} // namespace Network - +} } // namespace Network } // namespace Envoy \ No newline at end of file diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 97d2186b4c41f..b12582488e474 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -113,7 +113,8 @@ class BufferedIoSocketHandleImpl : public IoHandle, // leak. bool closed_{false}; - // The attached file event with this socket. The event is not owned by the socket. + // The attached file event with this socket. The event is not owned by the socket in the current + // Envoy model. Event::UserSpaceFileEventImpl* user_file_event_; // The schedulable handle of the above event. From baf755a606d84bbb0250e5d0791ad2a39b37a51c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 16:36:18 +0000 Subject: [PATCH 18/88] ASSERT_DEBUG_DEATH Signed-off-by: Yuchen Dai --- test/common/network/buffered_io_socket_handle_impl_test.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 1463cd6000d82..d1f514a1b7759 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -414,8 +414,8 @@ TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { } TEST_F(BufferedIoSocketHandleTest, TestShutDownOptionsNotSupported) { - ASSERT_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RD), ""); - ASSERT_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RDWR), ""); + ASSERT_DEBUG_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RD), ""); + ASSERT_DEBUG_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RDWR), ""); } TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { From a6686b499a2edefd1fb13ffa23e3f81652503e9f Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 19:33:13 +0000 Subject: [PATCH 19/88] coverage Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl.cc | 3 ++- source/common/network/io_socket_error_impl.h | 19 ------------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index a5726e01fba47..be1409f1bc294 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -111,7 +111,8 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } if (!writable_peer_) { - return sysCallResultToIoCallResult(Api::SysCallSizeResult{-1, SOCKET_ERROR_INVAL}); + return {0, + Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } if (writable_peer_->isWriteEndSet()) { // EPIPE or ENOTCONN diff --git a/source/common/network/io_socket_error_impl.h b/source/common/network/io_socket_error_impl.h index b98d51f1caf33..e101ee4ee4998 100644 --- a/source/common/network/io_socket_error_impl.h +++ b/source/common/network/io_socket_error_impl.h @@ -33,24 +33,5 @@ class IoSocketError : public Api::IoError { private: int errno_; }; - -// Converts a SysCallSizeResult to IoCallUint64Result. -template -Api::IoCallUint64Result sysCallResultToIoCallResult(const Api::SysCallResult& result) { - if (result.rc_ >= 0) { - // Return nullptr as IoError upon success. - return Api::IoCallUint64Result(result.rc_, - Api::IoErrorPtr(nullptr, IoSocketError::deleteIoError)); - } - RELEASE_ASSERT(result.errno_ != SOCKET_ERROR_INVAL, "Invalid argument passed in."); - return Api::IoCallUint64Result( - /*rc=*/0, - (result.errno_ == SOCKET_ERROR_AGAIN - // EAGAIN is frequent enough that its memory allocation should be avoided. - ? Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError) - : Api::IoErrorPtr(new IoSocketError(result.errno_), IoSocketError::deleteIoError))); -} - } // namespace Network } // namespace Envoy From 2d93b61988ae84ae7397b45a92d0a21d7b19fafe Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 21:15:19 +0000 Subject: [PATCH 20/88] coverage, cont Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index d1f514a1b7759..90079a6d4f41b 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -1,3 +1,4 @@ +#include "envoy/common/platform.h" #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" @@ -426,6 +427,31 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { EXPECT_EQ(0, buf.length()); } +// Test write return error code without event +TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { + Buffer::OwnedImpl buf("0123456789"); + Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + + { + // Populate write destiniation with massive data so as to not writable. + auto& internal_buffer = io_handle_peer_->getBufferForTest(); + internal_buffer.setWatermarks(1024); + internal_buffer.add(std::string(2048, ' ')); + + result = io_handle_->write(buf); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); + EXPECT_EQ(10, buf.length()); + } + + { + // Write after shutdown. + io_handle_->shutdown(ENVOY_SHUT_WR); + result = io_handle_->write(buf); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); + EXPECT_EQ(10, buf.length()); + } +} + TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { std::string raw_data("0123456789"); absl::InlinedVector slices{ @@ -622,6 +648,10 @@ TEST_F(BufferedIoSocketHandleTest, TestNotSupportsUdpGro) { EXPECT_FALSE(io_handle_->supportsUdpGro()); } +TEST_F(BufferedIoSocketHandleTest, TestDomainNullOpt) { + EXPECT_FALSE(io_handle_->domain().has_value()); +} + class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { @@ -644,20 +674,28 @@ class BufferedIoSocketHandleNotImplementedTest : public testing::Test { Buffer::RawSlice slice_; }; +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSetBlocking) { + EXPECT_THAT(io_handle_->setBlocking(false), IsNotSupportedResult()); + EXPECT_THAT(io_handle_->setBlocking(true), IsNotSupportedResult()); +} + TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSendmsg) { EXPECT_THAT(io_handle_->sendmsg(&slice_, 0, 0, nullptr, Network::Address::EnvoyInternalInstance("listener_id")), IsInvalidateAddress()); } + TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmsg) { Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); EXPECT_THAT(io_handle_->recvmsg(&slice_, 0, 0, output_is_ignored), IsInvalidateAddress()); } + TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmmsg) { RawSliceArrays slices_is_ignored(1, absl::FixedArray({slice_})); Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); EXPECT_THAT(io_handle_->recvmmsg(slices_is_ignored, 0, output_is_ignored), IsInvalidateAddress()); } + TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnBind) { auto address_is_ignored = std::make_shared("listener_id"); @@ -668,6 +706,19 @@ TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnListen) { int back_log_is_ignored = 0; EXPECT_THAT(io_handle_->listen(back_log_is_ignored), IsNotSupportedResult()); } + +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnAddress) { + ASSERT_THROW(io_handle_->peerAddress(), EnvoyException); + ASSERT_THROW(io_handle_->localAddress(), EnvoyException); +} + +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSetOption) { + EXPECT_THAT(io_handle_->setOption(0, 0, nullptr, 0), IsNotSupportedResult()); +} + +TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnGetOption) { + EXPECT_THAT(io_handle_->getOption(0, 0, nullptr, nullptr), IsNotSupportedResult()); +} } // namespace } // namespace Network } // namespace Envoy From 992c37723099c8db1d3d96c07e73eb7f72ae1eb8 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 21:15:59 +0000 Subject: [PATCH 21/88] coverage, cont Signed-off-by: Yuchen Dai --- test/common/network/buffered_io_socket_handle_impl_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 90079a6d4f41b..8e73140b3d9f0 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -433,7 +433,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; { - // Populate write destiniation with massive data so as to not writable. + // Populate write destination with massive data so as to not writable. auto& internal_buffer = io_handle_peer_->getBufferForTest(); internal_buffer.setWatermarks(1024); internal_buffer.add(std::string(2048, ' ')); From d1a695dd0adad5f44cdcf54d10d7c7eafab096b1 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 15 Oct 2020 21:52:04 +0000 Subject: [PATCH 22/88] more Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 71 +++++++++++++------ 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 8e73140b3d9f0..52f8b6bc92051 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -36,6 +36,7 @@ class BufferedIoSocketHandleTest : public testing::Test { io_handle_->setWritablePeer(io_handle_peer_.get()); io_handle_peer_->setWritablePeer(io_handle_.get()); } + ~BufferedIoSocketHandleTest() override { if (io_handle_->isOpen()) { io_handle_->close(); @@ -44,11 +45,13 @@ class BufferedIoSocketHandleTest : public testing::Test { io_handle_peer_->close(); } } + void expectAgain() { auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); EXPECT_FALSE(result.ok()); EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } + NiceMock dispatcher_{}; // Owned by BufferedIoSocketHandle. @@ -427,7 +430,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { EXPECT_EQ(0, buf.length()); } -// Test write return error code without event +// Test write return error code. Ignoring the side effect of event scheduling. TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { Buffer::OwnedImpl buf("0123456789"); Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; @@ -450,6 +453,44 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); EXPECT_EQ(10, buf.length()); } + + { + io_handle_peer_->close(); + EXPECT_TRUE(io_handle_->isOpen()); + result = io_handle_->write(buf); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); + } +} + +// Test writev return error code. Ignoring the side effect of event scheduling. +TEST_F(BufferedIoSocketHandleTest, TestWritevErrorCode) { + std::string buf(10, 'a'); + Buffer::RawSlice slice{static_cast(buf.data()), 10}; + Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + + { + // Populate write destination with massive data so as to not writable. + auto& internal_buffer = io_handle_peer_->getBufferForTest(); + internal_buffer.setWatermarks(1024); + internal_buffer.add(std::string(2048, ' ')); + result = io_handle_->writev(&slice, 1); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); + } + + { + // Writev after shutdown. + io_handle_->shutdown(ENVOY_SHUT_WR); + result = io_handle_->writev(&slice, 1); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); + } + + { + // Close the peer. + io_handle_peer_->close(); + EXPECT_TRUE(io_handle_->isOpen()); + result = io_handle_->writev(&slice, 1); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); + } } TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { @@ -470,27 +511,6 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { EXPECT_EQ("012", internal_buffer.toString()); } -TEST_F(BufferedIoSocketHandleTest, TestWriteAfteShutdown) { - Buffer::OwnedImpl data_to_write("0123456789"); - Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; - result = io_handle_->write(data_to_write); - EXPECT_TRUE(result.ok()); - io_handle_->shutdown(ENVOY_SHUT_WR); - result = io_handle_->write(data_to_write); - EXPECT_FALSE(result.ok()); -} - -TEST_F(BufferedIoSocketHandleTest, TestWritevAfteShutdown) { - std::string raw_data("0123456789"); - Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; - Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; - result = io_handle_peer_->writev(&slice, 1); - EXPECT_TRUE(result.ok()); - io_handle_->shutdown(ENVOY_SHUT_WR); - result = io_handle_->writev(&slice, 1); - EXPECT_FALSE(result.ok()); -} - TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); @@ -652,6 +672,12 @@ TEST_F(BufferedIoSocketHandleTest, TestDomainNullOpt) { EXPECT_FALSE(io_handle_->domain().has_value()); } +TEST_F(BufferedIoSocketHandleTest, TestConnect) { + auto address_is_ignored = + std::make_shared("listener_id"); + EXPECT_EQ(0, io_handle_->connect(address_is_ignored).rc_); +} + class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { @@ -660,6 +686,7 @@ class BufferedIoSocketHandleNotImplementedTest : public testing::Test { io_handle_->setWritablePeer(io_handle_peer_.get()); io_handle_peer_->setWritablePeer(io_handle_.get()); } + ~BufferedIoSocketHandleNotImplementedTest() override { if (io_handle_->isOpen()) { io_handle_->close(); From 683ad7f5ee6ad75681d02585deb2d66e26f06bcd Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 21 Oct 2020 18:30:35 +0000 Subject: [PATCH 23/88] split userspacefileeventimpl Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 2 + source/common/event/file_event_impl.h | 137 +----------------- .../network/buffered_io_socket_handle_impl.cc | 2 +- .../network/buffered_io_socket_handle_impl.h | 2 +- 4 files changed, 5 insertions(+), 138 deletions(-) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index e84aeb0cde04d..56b55676b5a20 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -13,6 +13,7 @@ envoy_cc_library( srcs = [ "dispatcher_impl.cc", "file_event_impl.cc", + "user_space_file_event_impl.cc", "signal_impl.cc", ], hdrs = [ @@ -68,6 +69,7 @@ envoy_cc_library( "dispatcher_impl.h", "event_impl_base.h", "file_event_impl.h", + "user_space_file_event_impl.h", "schedulable_cb_impl.h", ], deps = [ diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index 395bbbda52d77..cb55214831832 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -8,10 +8,6 @@ #include "common/event/event_impl_base.h" namespace Envoy { - -namespace Network { -class BufferedIoSocketHandleImpl; -} namespace Event { /** @@ -45,136 +41,5 @@ class FileEventImpl : public FileEvent, ImplBase { // polling and activating new fd events. const bool activate_fd_events_next_event_loop_; }; - -// Forward declare for friend class. -class UserSpaceFileEventFactory; - -// The interface of populating event watcher and obtaining the active events. The events are the -// combination of FileReadyType values. The event listener is populated by user event registration -// and io events passively. Also the owner of this listener query the activated events by calling -// triggeredEvents and getAndClearEphemeralEvents. -class EventListener { -public: - virtual ~EventListener() = default; - - // Get the events which are enabled and triggered. - virtual uint32_t triggeredEvents() PURE; - // Get the events which are ephemerally activated. Upon returning the ephemeral events are - // cleared. - virtual uint32_t getAndClearEphemeralEvents() PURE; - - /** - * FileEvent::setEnabled is invoked. - * @param enabled_events supplied the event of setEnabled. - */ - virtual void onEventEnabled(uint32_t enabled_events) PURE; - - /** - * FileEvent::activate is invoked. - * @param enabled_events supplied the event of activate(). - */ - virtual void onEventActivated(uint32_t activated_events) PURE; -}; - -// Return the enabled events except EV_CLOSED. This implementation is generally good since only -// epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner -// must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify -// events which are not actually triggered. -// TODO(lambdai): Add support of delivering EV_CLOSED. -class DefaultEventListener : public EventListener { -public: - ~DefaultEventListener() override = default; - - // Return both read and write. - uint32_t triggeredEvents() override { return pending_events_ & (~Event::FileReadyType::Closed); } - - void onEventEnabled(uint32_t enabled_events) override { pending_events_ = enabled_events; } - - void onEventActivated(uint32_t activated_events) override { - ephermal_events_ |= activated_events; - } - - uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephermal_events_, 0); } - -private: - // The persisted interested events and ready events. - uint32_t pending_events_{}; - // The events set by activate() and will be cleared after the io callback. - uint32_t ephermal_events_{}; -}; - -// A FileEvent implementation which is used to drive BufferedIoSocketHandle. -class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { -public: - ~UserSpaceFileEventImpl() override { - if (schedulable_.enabled()) { - schedulable_.cancel(); - } - } - - // Event::FileEvent - void activate(uint32_t events) override { - // Only supported event types are set. - ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == - events); - event_listener_.onEventActivated(events); - if (!schedulable_.enabled()) { - schedulable_.scheduleCallbackNextIteration(); - } - } - - void setEnabled(uint32_t events) override { - // Only supported event types are set. - ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == - events); - event_listener_.onEventEnabled(events); - bool was_enabled = schedulable_.enabled(); - if (!was_enabled) { - schedulable_.scheduleCallbackNextIteration(); - } - ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", - static_cast(this), events, was_enabled ? "not " : ""); - } - - EventListener& getEventListener() { return event_listener_; } - void onEvents() { cb_(); } - friend class UserSpaceFileEventFactory; - friend class Network::BufferedIoSocketHandleImpl; - -private: - UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, - SchedulableCallback& schedulable_cb) - : schedulable_(schedulable_cb), cb_([this, cb]() { - auto all_events = getEventListener().triggeredEvents(); - auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); - ENVOY_LOG(trace, - "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", - static_cast(this), all_events, ephemeral_events); - cb(all_events | ephemeral_events); - }) { - event_listener_.onEventEnabled(events); - } - - // Used to populate the event operations of enable and activate. - DefaultEventListener event_listener_; - - // The handle to registered async callback from dispatcher. - SchedulableCallback& schedulable_; - - // The registered callback of this event. This callback is usually on top of the frame of - // Dispatcher::run(). - std::function cb_; -}; - -class UserSpaceFileEventFactory { -public: - static std::unique_ptr - createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, - uint32_t events, SchedulableCallback& scheduable_cb) { - return std::unique_ptr( - new UserSpaceFileEventImpl(cb, events, scheduable_cb)); - } -}; - } // namespace Event -} // namespace Envoy +} // namespace Envoy \ No newline at end of file diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index be1409f1bc294..069f0ce861187 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -6,7 +6,7 @@ #include "common/api/os_sys_calls_impl.h" #include "common/common/assert.h" #include "common/common/utility.h" -#include "common/event/file_event_impl.h" +#include "common/event/user_space_file_event_impl.h" #include "common/network/address_impl.h" #include "absl/container/fixed_array.h" diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index b12582488e474..5df9d3129f4c5 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -10,7 +10,7 @@ #include "common/buffer/watermark_buffer.h" #include "common/common/logger.h" -#include "common/event/file_event_impl.h" +#include "common/event/user_space_file_event_impl.h" #include "common/network/io_socket_error_impl.h" #include "common/network/peer_buffer.h" From 673bca0c9fd2a009424ef1e1e51cd1d478ba4f4a Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 21 Oct 2020 21:02:10 +0000 Subject: [PATCH 24/88] add missing files forgot to add to git Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 52 ++++++++ .../common/event/user_space_file_event_impl.h | 116 ++++++++++++++++++ .../network/buffered_io_socket_handle_impl.h | 3 +- 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 source/common/event/user_space_file_event_impl.cc create mode 100644 source/common/event/user_space_file_event_impl.h diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc new file mode 100644 index 0000000000000..b246d4870b43f --- /dev/null +++ b/source/common/event/user_space_file_event_impl.cc @@ -0,0 +1,52 @@ +#include "common/event/user_space_file_event_impl.h" + +#include + +#include "common/common/assert.h" +namespace Envoy { +namespace Event { + +void UserSpaceFileEventImpl::activate(uint32_t events) { + // Only supported event types are set. + ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); + event_listener_.onEventActivated(events); + if (!schedulable_.enabled()) { + schedulable_.scheduleCallbackNextIteration(); + } +} + +void UserSpaceFileEventImpl::setEnabled(uint32_t events) { + // Only supported event types are set. + ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); + event_listener_.onEventEnabled(events); + bool was_enabled = schedulable_.enabled(); + if (!was_enabled) { + schedulable_.scheduleCallbackNextIteration(); + } + ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", + static_cast(this), events, was_enabled ? "not " : ""); +} + +UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, + SchedulableCallback& schedulable_cb) + : schedulable_(schedulable_cb), cb_([this, cb]() { + auto all_events = getEventListener().triggeredEvents(); + auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); + ENVOY_LOG(trace, + "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", + static_cast(this), all_events, ephemeral_events); + cb(all_events | ephemeral_events); + }) { + event_listener_.onEventEnabled(events); +} + +std::unique_ptr +UserSpaceFileEventFactory::createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, + Event::FileTriggerType, uint32_t events, + SchedulableCallback& scheduable_cb) { + return std::unique_ptr( + new UserSpaceFileEventImpl(cb, events, scheduable_cb)); +} + +} // namespace Event +} // namespace Envoy \ No newline at end of file diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h new file mode 100644 index 0000000000000..7fd3a2b1f6756 --- /dev/null +++ b/source/common/event/user_space_file_event_impl.h @@ -0,0 +1,116 @@ +#pragma once + +#include + +#include "envoy/event/file_event.h" + +#include "common/event/dispatcher_impl.h" +#include "common/event/event_impl_base.h" + +namespace Envoy { + +namespace Network { +class BufferedIoSocketHandleImpl; +} +namespace Event { + +// Forward declare for friend class. +class UserSpaceFileEventFactory; + +// The interface of populating event watcher and obtaining the active events. The events are the +// combination of FileReadyType values. The event listener is populated by user event registration +// and io events passively. Also the owner of this listener query the activated events by calling +// triggeredEvents and getAndClearEphemeralEvents. +class EventListener { +public: + virtual ~EventListener() = default; + + // Get the events which are enabled and triggered. + virtual uint32_t triggeredEvents() PURE; + // Get the events which are ephemerally activated. Upon returning the ephemeral events are + // cleared. + virtual uint32_t getAndClearEphemeralEvents() PURE; + + /** + * FileEvent::setEnabled is invoked. + * @param enabled_events supplied the event of setEnabled. + */ + virtual void onEventEnabled(uint32_t enabled_events) PURE; + + /** + * FileEvent::activate is invoked. + * @param enabled_events supplied the event of activate(). + */ + virtual void onEventActivated(uint32_t activated_events) PURE; +}; + +// Return the enabled events except EV_CLOSED. This implementation is generally good since only +// epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner +// must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify +// events which are not actually triggered. +// TODO(lambdai): Add support of delivering EV_CLOSED. +class DefaultEventListener : public EventListener { +public: + ~DefaultEventListener() override = default; + + // Return both read and write if enabled. Note that this implmenetation is inefficient. Read and + // write events are supposed to be independent. + uint32_t triggeredEvents() override { return enabled_events_ & (~Event::FileReadyType::Closed); } + + void onEventEnabled(uint32_t enabled_events) override { enabled_events_ = enabled_events; } + + void onEventActivated(uint32_t activated_events) override { + ephermal_events_ |= activated_events; + } + + uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephermal_events_, 0); } + +private: + // The persisted interested events. The name on libevent document is pending event. + uint32_t enabled_events_{}; + // The events set by activate() and will be cleared after the io callback. + uint32_t ephermal_events_{}; +}; + +// A FileEvent implementation which is used to drive BufferedIoSocketHandle. +class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { +public: + ~UserSpaceFileEventImpl() override { + if (schedulable_.enabled()) { + schedulable_.cancel(); + } + } + + // Event::FileEvent + void activate(uint32_t events) override; + void setEnabled(uint32_t events) override; + + EventListener& getEventListener() { return event_listener_; } + void onEvents() { cb_(); } + friend class UserSpaceFileEventFactory; + friend class Network::BufferedIoSocketHandleImpl; + +private: + UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, + SchedulableCallback& schedulable_cb); + + // Used to populate the event operations of enable and activate. + DefaultEventListener event_listener_; + + // The handle to registered async callback from dispatcher. + SchedulableCallback& schedulable_; + + // The registered callback of this event. This callback is usually on top of the frame of + // Dispatcher::run(). + std::function cb_; +}; + +class UserSpaceFileEventFactory { +public: + static std::unique_ptr + createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, + uint32_t events, SchedulableCallback& scheduable_cb); +}; + +} // namespace Event +} // namespace Envoy diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 5df9d3129f4c5..dc56967aec733 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -114,7 +114,8 @@ class BufferedIoSocketHandleImpl : public IoHandle, bool closed_{false}; // The attached file event with this socket. The event is not owned by the socket in the current - // Envoy model. + // Envoy model. Multiple events can be created during the life time of this IO handle but at any + // moment at most 1 event is attached. Event::UserSpaceFileEventImpl* user_file_event_; // The schedulable handle of the above event. From e59fa57acf731e77ff5d6c980090bd4d9f4ab3ed Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 22 Oct 2020 00:25:40 +0000 Subject: [PATCH 25/88] add scaffold of user space event test Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 14 +++++++++ .../common/event/user_space_file_event_impl.h | 9 ++---- .../network/buffered_io_socket_handle_impl.cc | 27 ++++++++++------ test/common/event/BUILD | 16 ++++++++++ .../event/user_space_file_event_impl_test.cc | 31 +++++++++++++++++++ 5 files changed, 81 insertions(+), 16 deletions(-) create mode 100644 test/common/event/user_space_file_event_impl_test.cc diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index b246d4870b43f..3c2fcfb97f6e0 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -6,6 +6,20 @@ namespace Envoy { namespace Event { +void DefaultEventListener::onEventEnabled(uint32_t enabled_events) { + enabled_events_ = enabled_events; + // Clear ephermal events to align with FileEventImpl::setEnable(). + ephermal_events_ = 0; +} + +void DefaultEventListener::onEventActivated(uint32_t activated_events) { + // Event owner should not activate any event which is disabled. + // Also see onEventEnabled which clears ephermal events. + // The overall prevents callback on disabled events. + ASSERT((ephermal_events_ & ~enabled_events_) == 0); + ephermal_events_ |= activated_events; +} + void UserSpaceFileEventImpl::activate(uint32_t events) { // Only supported event types are set. ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 7fd3a2b1f6756..89ce5d73f595e 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -54,14 +54,11 @@ class DefaultEventListener : public EventListener { ~DefaultEventListener() override = default; // Return both read and write if enabled. Note that this implmenetation is inefficient. Read and - // write events are supposed to be independent. + // write events are supposed to be independent. uint32_t triggeredEvents() override { return enabled_events_ & (~Event::FileReadyType::Closed); } - void onEventEnabled(uint32_t enabled_events) override { enabled_events_ = enabled_events; } - - void onEventActivated(uint32_t activated_events) override { - ephermal_events_ |= activated_events; - } + void onEventEnabled(uint32_t enabled_events) override; + void onEventActivated(uint32_t activated_events) override; uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephermal_events_, 0); } diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 069f0ce861187..3051c2b0a99a8 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -20,6 +20,7 @@ Api::SysCallIntResult makeInvalidSyscall() { return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP}; } } // namespace + BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() : owned_buffer_( [this]() -> void { @@ -59,6 +60,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, uint64_t num_slice) { if (!isOpen()) { return {0, + // TODO(lambdai): Add EBADF in IoSocketError and adopt it here. Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } if (owned_buffer_.length() == 0) { @@ -70,13 +72,15 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, } } absl::FixedArray iov(num_slice); - uint64_t num_slices_to_read = 0; uint64_t bytes_to_read = 0; - for (; num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { - auto max_bytes_to_read = std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, - uint64_t(slices[num_slices_to_read].len_)); - owned_buffer_.copyOut(bytes_to_read, max_bytes_to_read, slices[num_slices_to_read].mem_); - bytes_to_read += max_bytes_to_read; + for (uint64_t num_slices_to_read = 0; + num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { + auto bytes_to_write_in_this_slice = + std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, + uint64_t(slices[num_slices_to_read].len_)); + owned_buffer_.copyOut(bytes_to_read, bytes_to_write_in_this_slice, + slices[num_slices_to_read].mem_); + bytes_to_read += bytes_to_write_in_this_slice; } ASSERT(bytes_to_read <= max_length); owned_buffer_.drain(bytes_to_read); @@ -110,15 +114,18 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // Closed peer. if (!writable_peer_) { return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // Error: write after close. if (writable_peer_->isWriteEndSet()) { - // EPIPE or ENOTCONN + // TODO(lambdai): EPIPE or ENOTCONN return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } + // The peer is valid but temporary not accepts new data. Likely due to flow control. if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; @@ -146,13 +153,13 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - // Write to a shutdown peer. + // Error: write after close. if (writable_peer_->isWriteEndSet()) { - // EPIPE or ENOTCONN + // TODO(lambdai): EPIPE or ENOTCONN return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - // Buffer is full. Cannot write anymore. + // The peer is valid but temporary not accepts new data. Likely due to flow control. if (!writable_peer_->isWritable()) { return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), IoSocketError::deleteIoError)}; diff --git a/test/common/event/BUILD b/test/common/event/BUILD index 036d0f424359b..f53d41216e19f 100644 --- a/test/common/event/BUILD +++ b/test/common/event/BUILD @@ -42,6 +42,22 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "user_space_file_event_impl_test", + srcs = ["user_space_file_event_impl_test.cc"], + #tags = ["fails_on_windows"], + deps = [ + "//include/envoy/event:file_event_interface", + "//source/common/event:dispatcher_includes", + "//source/common/event:dispatcher_lib", + "//source/common/stats:isolated_store_lib", + "//test/mocks:common_lib", + "//test/test_common:environment_lib", + "//test/test_common:test_runtime_lib", + "//test/test_common:utility_lib", + ], +) + envoy_cc_test( name = "scaled_range_timer_manager_test", srcs = ["scaled_range_timer_manager_test.cc"], diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc new file mode 100644 index 0000000000000..5b2471e0b1fa9 --- /dev/null +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -0,0 +1,31 @@ +#include + +#include "envoy/event/file_event.h" + +#include "common/api/os_sys_calls_impl.h" +#include "common/event/dispatcher_impl.h" +#include "common/stats/isolated_store_impl.h" + +#include "test/mocks/common.h" +#include "test/test_common/environment.h" +#include "test/test_common/test_runtime.h" +#include "test/test_common/utility.h" + +#include "gtest/gtest.h" + +namespace Envoy { +namespace Event { +namespace { + +class UserSpaceFileEventImplTest : public testing::Test { +public: + UserSpaceFileEventImplTest() + : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} + +protected: + Api::ApiPtr api_; + DispatcherPtr dispatcher_; +}; +} // namespace +} // namespace Event +} // namespace Envoy \ No newline at end of file From b65e5409deced727654383c21675a7073ba4b952 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 22 Oct 2020 02:00:34 +0000 Subject: [PATCH 26/88] various fix: file event test not ready yet Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 4 +- .../event/user_space_file_event_impl.cc | 13 ++-- .../common/event/user_space_file_event_impl.h | 2 +- .../network/buffered_io_socket_handle_impl.cc | 73 ++++++++++--------- .../network/buffered_io_socket_handle_impl.h | 13 ++-- tools/spelling/spelling_dictionary.txt | 1 + 6 files changed, 57 insertions(+), 49 deletions(-) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index 56b55676b5a20..5ada7848b0a30 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -13,8 +13,8 @@ envoy_cc_library( srcs = [ "dispatcher_impl.cc", "file_event_impl.cc", - "user_space_file_event_impl.cc", "signal_impl.cc", + "user_space_file_event_impl.cc", ], hdrs = [ "signal_impl.h", @@ -69,8 +69,8 @@ envoy_cc_library( "dispatcher_impl.h", "event_impl_base.h", "file_event_impl.h", - "user_space_file_event_impl.h", "schedulable_cb_impl.h", + "user_space_file_event_impl.h", ], deps = [ ":libevent_lib", diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 3c2fcfb97f6e0..5e7164c5d3f7e 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -3,18 +3,19 @@ #include #include "common/common/assert.h" + namespace Envoy { namespace Event { void DefaultEventListener::onEventEnabled(uint32_t enabled_events) { enabled_events_ = enabled_events; - // Clear ephermal events to align with FileEventImpl::setEnable(). + // Clear ephemeral events to align with FileEventImpl::setEnable(). ephermal_events_ = 0; } void DefaultEventListener::onEventActivated(uint32_t activated_events) { // Event owner should not activate any event which is disabled. - // Also see onEventEnabled which clears ephermal events. + // Also see onEventEnabled which clears ephemeral events. // The overall prevents callback on disabled events. ASSERT((ephermal_events_ & ~enabled_events_) == 0); ephermal_events_ |= activated_events; @@ -54,10 +55,10 @@ UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t e event_listener_.onEventEnabled(events); } -std::unique_ptr -UserSpaceFileEventFactory::createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, - Event::FileTriggerType, uint32_t events, - SchedulableCallback& scheduable_cb) { +std::unique_ptr UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType trigger_type, uint32_t events, + SchedulableCallback& scheduable_cb) { + ASSERT(trigger_type == Event::FileTriggerType::Edge); return std::unique_ptr( new UserSpaceFileEventImpl(cb, events, scheduable_cb)); } diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 89ce5d73f595e..7579b2a1fff07 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -53,7 +53,7 @@ class DefaultEventListener : public EventListener { public: ~DefaultEventListener() override = default; - // Return both read and write if enabled. Note that this implmenetation is inefficient. Read and + // Return both read and write if enabled. Note that this implementation is inefficient. Read and // write events are supposed to be independent. uint32_t triggeredEvents() override { return enabled_events_ & (~Event::FileReadyType::Closed); } diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 3051c2b0a99a8..b2a68deb59c01 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -22,7 +22,7 @@ Api::SysCallIntResult makeInvalidSyscall() { } // namespace BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() - : owned_buffer_( + : pending_received_data_( [this]() -> void { over_high_watermark_ = false; if (writable_peer_) { @@ -39,15 +39,19 @@ BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { ASSERT(!closed_); - if (!write_shutdown_) { - ASSERT(writable_peer_); - // Notify the peer we won't write more data. shutdown(WRITE). - writable_peer_->setWriteEnd(); - // Notify the peer that we no longer accept data. shutdown(RD). - writable_peer_->onPeerDestroy(); - writable_peer_->maybeSetNewData(); - writable_peer_ = nullptr; - write_shutdown_ = true; + if (!closed_) { + if (writable_peer_) { + ENVOY_LOG(trace, "socket {} close before peer {} closes.", static_cast(this), + static_cast(writable_peer_)); + // Notify the peer we won't write more data. shutdown(WRITE). + writable_peer_->setWriteEnd(); + // Notify the peer that we no longer accept data. shutdown(RD). + writable_peer_->onPeerDestroy(); + writable_peer_->maybeSetNewData(); + writable_peer_ = nullptr; + } else { + ENVOY_LOG(trace, "socket {} close after peer closed.", static_cast(this)); + } } closed_ = true; return Api::ioCallUint64ResultNoError(); @@ -63,7 +67,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, // TODO(lambdai): Add EBADF in IoSocketError and adopt it here. Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - if (owned_buffer_.length() == 0) { + if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { @@ -72,20 +76,19 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, } } absl::FixedArray iov(num_slice); - uint64_t bytes_to_read = 0; - for (uint64_t num_slices_to_read = 0; - num_slices_to_read < num_slice && bytes_to_read < max_length; num_slices_to_read++) { - auto bytes_to_write_in_this_slice = - std::min(std::min(owned_buffer_.length(), max_length) - bytes_to_read, - uint64_t(slices[num_slices_to_read].len_)); - owned_buffer_.copyOut(bytes_to_read, bytes_to_write_in_this_slice, - slices[num_slices_to_read].mem_); - bytes_to_read += bytes_to_write_in_this_slice; + uint64_t bytes_offset = 0; + for (uint64_t i = 0; i < num_slice && bytes_offset < max_length; i++) { + auto bytes_to_read_in_this_slice = + std::min(std::min(pending_received_data_.length(), max_length) - bytes_offset, + uint64_t(slices[i].len_)); + pending_received_data_.copyOut(bytes_offset, bytes_to_read_in_this_slice, slices[i].mem_); + bytes_offset += bytes_to_read_in_this_slice; } - ASSERT(bytes_to_read <= max_length); - owned_buffer_.drain(bytes_to_read); - ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_to_read); - return {bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + auto bytes_read = bytes_offset; + ASSERT(bytes_read <= max_length); + pending_received_data_.drain(bytes_read); + ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_read); + return {bytes_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, @@ -94,7 +97,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe return {0, Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } - if (owned_buffer_.length() == 0) { + if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { @@ -103,8 +106,8 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe } } // TODO(lambdai): Move at slice boundary to move to reduce the copy. - uint64_t max_bytes_to_read = std::min(max_length, owned_buffer_.length()); - buffer.move(owned_buffer_, max_bytes_to_read); + uint64_t max_bytes_to_read = std::min(max_length, pending_received_data_.length()); + buffer.move(pending_received_data_, max_bytes_to_read); return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } @@ -131,16 +134,16 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic IoSocketError::deleteIoError)}; } // Write along with iteration. Buffer guarantee the fragment is always append-able. - uint64_t total_bytes_to_write = 0; + uint64_t bytes_written = 0; for (uint64_t i = 0; i < num_slice; i++) { if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { writable_peer_->getWriteBuffer()->add(slices[i].mem_, slices[i].len_); - total_bytes_to_write += slices[i].len_; + bytes_written += slices[i].len_; } } writable_peer_->maybeSetNewData(); - ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), total_bytes_to_write); - return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; + ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), bytes_written); + return {bytes_written, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buffer) { @@ -193,7 +196,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t le Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; } // No data and the writer closed. - if (owned_buffer_.length() == 0) { + if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { @@ -201,10 +204,10 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t le IoSocketError::deleteIoError)}; } } - auto max_bytes_to_read = std::min(owned_buffer_.length(), length); - owned_buffer_.copyOut(0, max_bytes_to_read, buffer); + auto max_bytes_to_read = std::min(pending_received_data_.length(), length); + pending_received_data_.copyOut(0, max_bytes_to_read, buffer); if (!(flags & MSG_PEEK)) { - owned_buffer_.drain(max_bytes_to_read); + pending_received_data_.drain(max_bytes_to_read); } return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index dc56967aec733..aaba6167784a5 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -71,7 +71,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } - Buffer::WatermarkBuffer& getBufferForTest() { return owned_buffer_; } + Buffer::WatermarkBuffer& getBufferForTest() { return pending_received_data_; } void scheduleNextEvent() { // It's possible there is no pending file event so as no io_callback. @@ -101,12 +101,14 @@ class BufferedIoSocketHandleImpl : public IoHandle, } void onPeerBufferWritable() override { scheduleNextEvent(); } bool isWritable() const override { return !isOverHighWatermark(); } - Buffer::Instance* getWriteBuffer() override { return &owned_buffer_; } + Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } // ReadableSource bool isPeerShutDownWrite() const override { return read_end_stream_; } bool isOverHighWatermark() const override { return over_high_watermark_; } - bool isReadable() const override { return isPeerShutDownWrite() || owned_buffer_.length() > 0; } + bool isReadable() const override { + return isPeerShutDownWrite() || pending_received_data_.length() > 0; + } private: // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource @@ -121,9 +123,10 @@ class BufferedIoSocketHandleImpl : public IoHandle, // The schedulable handle of the above event. Event::SchedulableCallbackPtr io_callback_; - // True if owned_buffer_ is not addable. Note that owned_buffer_ may have pending data to drain. + // True if pending_received_data_ is not addable. Note that pending_received_data_ may have + // pending data to drain. bool read_end_stream_{false}; - Buffer::WatermarkBuffer owned_buffer_; + Buffer::WatermarkBuffer pending_received_data_; // Destination of the write(). WritablePeer* writable_peer_{nullptr}; diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index c7207ecb5d4ca..733c6d425264f 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -28,6 +28,7 @@ CDN CDS CEL DSR +EBADF ENOTCONN EPIPE HEXDIG From 437eb9bde2de704e0392f4e58cbfc4c8bc859a4c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 22 Oct 2020 09:39:47 +0000 Subject: [PATCH 27/88] complete user space file event test Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 2 +- test/common/event/BUILD | 2 - .../event/user_space_file_event_impl_test.cc | 185 +++++++++++++++++- 3 files changed, 183 insertions(+), 6 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 5e7164c5d3f7e..11d1363644190 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -17,7 +17,7 @@ void DefaultEventListener::onEventActivated(uint32_t activated_events) { // Event owner should not activate any event which is disabled. // Also see onEventEnabled which clears ephemeral events. // The overall prevents callback on disabled events. - ASSERT((ephermal_events_ & ~enabled_events_) == 0); + ASSERT((activated_events & ~enabled_events_) == 0); ephermal_events_ |= activated_events; } diff --git a/test/common/event/BUILD b/test/common/event/BUILD index 763d05bb033f8..290f9f80865f9 100644 --- a/test/common/event/BUILD +++ b/test/common/event/BUILD @@ -45,12 +45,10 @@ envoy_cc_test( envoy_cc_test( name = "user_space_file_event_impl_test", srcs = ["user_space_file_event_impl_test.cc"], - #tags = ["fails_on_windows"], deps = [ "//include/envoy/event:file_event_interface", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", - "//source/common/stats:isolated_store_lib", "//test/mocks:common_lib", "//test/test_common:environment_lib", "//test/test_common:test_runtime_lib", diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 5b2471e0b1fa9..31b2286f338bf 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -2,30 +2,209 @@ #include "envoy/event/file_event.h" -#include "common/api/os_sys_calls_impl.h" #include "common/event/dispatcher_impl.h" -#include "common/stats/isolated_store_impl.h" +#include "common/event/user_space_file_event_impl.h" #include "test/mocks/common.h" #include "test/test_common/environment.h" #include "test/test_common/test_runtime.h" #include "test/test_common/utility.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" namespace Envoy { namespace Event { namespace { +constexpr auto event_rw = Event::FileReadyType::Read | Event::FileReadyType::Write; +class MockReadyCb { +public: + MOCK_METHOD(void, called, (uint32_t)); +}; + class UserSpaceFileEventImplTest : public testing::Test { public: UserSpaceFileEventImplTest() - : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} + : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) { + io_callback_ = + dispatcher_->createSchedulableCallback([this]() { user_file_event_->onEvents(); }); + } + + void scheduleNextEvent() { + ASSERT(io_callback_ != nullptr); + io_callback_->scheduleCallbackNextIteration(); + } protected: + MockReadyCb ready_cb_; Api::ApiPtr api_; DispatcherPtr dispatcher_; + std::unique_ptr user_file_event_; + Event::SchedulableCallbackPtr io_callback_; }; + +TEST_F(UserSpaceFileEventImplTest, TestLevelTriggerIsNotSupported) { + ASSERT_DEBUG_DEATH(Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, + Event::FileTriggerType::Level, event_rw, *io_callback_), + "assert failure"); +} + +TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + scheduleNextEvent(); + EXPECT_CALL(ready_cb_, called(event_rw)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); +} + +TEST_F(UserSpaceFileEventImplTest, TestDebugDeathOnActivateDisabledEvents) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read, *io_callback_); + ASSERT_DEBUG_DEATH(user_file_event_->activate(Event::FileReadyType::Write), ""); +} + +TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + { + SCOPED_TRACE("1st schedule"); + scheduleNextEvent(); + EXPECT_CALL(ready_cb_, called(event_rw)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + + { + SCOPED_TRACE("2nd schedule"); + scheduleNextEvent(); + EXPECT_CALL(ready_cb_, called(event_rw)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + { + SCOPED_TRACE("1st schedule"); + scheduleNextEvent(); + scheduleNextEvent(); + EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + + { + SCOPED_TRACE("further dispatcher drive"); + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents) { + std::vector events{Event::FileReadyType::Read, Event::FileReadyType::Write, event_rw}; + for (const auto& e : events) { + SCOPED_TRACE(absl::StrCat("current event:", e)); + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + scheduleNextEvent(); + EXPECT_CALL(ready_cb_, called(event_rw)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + user_file_event_.reset(); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->activate(Event::FileReadyType::Read); + EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->activate(Event::FileReadyType::Write); + EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->activate(Event::FileReadyType::Read); + user_file_event_->activate(Event::FileReadyType::Write); + user_file_event_->activate(Event::FileReadyType::Write); + user_file_event_->activate(Event::FileReadyType::Read); + EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + event_rw, *io_callback_); + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->activate(Event::FileReadyType::Read); + user_file_event_->setEnabled(Event::FileReadyType::Write); + + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyActivated) { + user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Write | Event::FileReadyType::Closed, *io_callback_); + { + scheduleNextEvent(); + // No Closed event bit if enabled by not activated. + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->activate(Event::FileReadyType::Closed); + // Activate could deliver Closed event bit. + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Closed)) + .Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + } // namespace } // namespace Event } // namespace Envoy \ No newline at end of file From 9299130ff6a12c09dbb1b2571c7d57ba1cdea1ed Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 22 Oct 2020 19:29:26 +0000 Subject: [PATCH 28/88] fix destroy order in test Signed-off-by: Yuchen Dai --- test/common/event/user_space_file_event_impl_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 31b2286f338bf..1eabfafe68670 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -40,8 +40,8 @@ class UserSpaceFileEventImplTest : public testing::Test { MockReadyCb ready_cb_; Api::ApiPtr api_; DispatcherPtr dispatcher_; - std::unique_ptr user_file_event_; Event::SchedulableCallbackPtr io_callback_; + std::unique_ptr user_file_event_; }; TEST_F(UserSpaceFileEventImplTest, TestLevelTriggerIsNotSupported) { From 1b4a204df625485bb02be5a80c9b528e193af02b Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 27 Oct 2020 09:02:55 +0000 Subject: [PATCH 29/88] address comment: no schedule next, typo Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 17 ++++++++-------- .../common/event/user_space_file_event_impl.h | 10 +++++----- .../network/buffered_io_socket_handle_impl.cc | 4 +--- .../network/buffered_io_socket_handle_impl.h | 20 +++++++++---------- .../event/user_space_file_event_impl_test.cc | 7 +++---- .../buffered_io_socket_handle_impl_test.cc | 3 +++ 6 files changed, 29 insertions(+), 32 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 11d1363644190..7dc05d9ca686c 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -7,18 +7,17 @@ namespace Envoy { namespace Event { -void DefaultEventListener::onEventEnabled(uint32_t enabled_events) { +void EventListenerImpl::onEventEnabled(uint32_t enabled_events) { enabled_events_ = enabled_events; // Clear ephemeral events to align with FileEventImpl::setEnable(). - ephermal_events_ = 0; + ephemeral_events_ = 0; } -void DefaultEventListener::onEventActivated(uint32_t activated_events) { - // Event owner should not activate any event which is disabled. - // Also see onEventEnabled which clears ephemeral events. - // The overall prevents callback on disabled events. - ASSERT((activated_events & ~enabled_events_) == 0); - ephermal_events_ |= activated_events; +void EventListenerImpl::onEventActivated(uint32_t activated_events) { + // Normally event owner should not activate any event which is disabled. Known exceptions includes + // ConsumerWantsToRead() == true. + // TODO(lambdai): Stricter check. + ephemeral_events_ |= activated_events; } void UserSpaceFileEventImpl::activate(uint32_t events) { @@ -52,7 +51,7 @@ UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t e static_cast(this), all_events, ephemeral_events); cb(all_events | ephemeral_events); }) { - event_listener_.onEventEnabled(events); + setEnabled(events); } std::unique_ptr UserSpaceFileEventFactory::createUserSpaceFileEventImpl( diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 7579b2a1fff07..ed2f3de3409f7 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -49,9 +49,9 @@ class EventListener { // must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify // events which are not actually triggered. // TODO(lambdai): Add support of delivering EV_CLOSED. -class DefaultEventListener : public EventListener { +class EventListenerImpl : public EventListener { public: - ~DefaultEventListener() override = default; + ~EventListenerImpl() override = default; // Return both read and write if enabled. Note that this implementation is inefficient. Read and // write events are supposed to be independent. @@ -60,13 +60,13 @@ class DefaultEventListener : public EventListener { void onEventEnabled(uint32_t enabled_events) override; void onEventActivated(uint32_t activated_events) override; - uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephermal_events_, 0); } + uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephemeral_events_, 0); } private: // The persisted interested events. The name on libevent document is pending event. uint32_t enabled_events_{}; // The events set by activate() and will be cleared after the io callback. - uint32_t ephermal_events_{}; + uint32_t ephemeral_events_{}; }; // A FileEvent implementation which is used to drive BufferedIoSocketHandle. @@ -92,7 +92,7 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable(writable_peer_)); // Notify the peer we won't write more data. shutdown(WRITE). writable_peer_->setWriteEnd(); + writable_peer_->maybeSetNewData(); // Notify the peer that we no longer accept data. shutdown(RD). writable_peer_->onPeerDestroy(); - writable_peer_->maybeSetNewData(); writable_peer_ = nullptr; } else { ENVOY_LOG(trace, "socket {} close after peer closed.", static_cast(this)); @@ -260,8 +260,6 @@ Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatche auto event = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( dispatcher, cb, trigger_type, events, *io_callback_); user_file_event_ = event.get(); - // Blindly activate the events. - io_callback_->scheduleCallbackNextIteration(); return event; } diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index aaba6167784a5..44f438089fa4d 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -73,14 +73,6 @@ class BufferedIoSocketHandleImpl : public IoHandle, Buffer::WatermarkBuffer& getBufferForTest() { return pending_received_data_; } - void scheduleNextEvent() { - // It's possible there is no pending file event so as no io_callback. - if (io_callback_) { - ENVOY_LOG(trace, "Schedule IO callback on {}", static_cast(this)); - io_callback_->scheduleCallbackNextIteration(); - } - } - void setWritablePeer(WritablePeer* writable_peer) { // Swapping writable peer is undefined behavior. ASSERT(!writable_peer_); @@ -93,13 +85,19 @@ class BufferedIoSocketHandleImpl : public IoHandle, bool isWriteEndSet() override { return read_end_stream_; } void maybeSetNewData() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); - scheduleNextEvent(); + if (user_file_event_) { + user_file_event_->activate(Event::FileReadyType::Write); + } } void onPeerDestroy() override { writable_peer_ = nullptr; write_shutdown_ = true; } - void onPeerBufferWritable() override { scheduleNextEvent(); } + void onPeerBufferWritable() override { + if (user_file_event_) { + user_file_event_->activate(Event::FileReadyType::Read); + } + } bool isWritable() const override { return !isOverHighWatermark(); } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } @@ -118,7 +116,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, // The attached file event with this socket. The event is not owned by the socket in the current // Envoy model. Multiple events can be created during the life time of this IO handle but at any // moment at most 1 event is attached. - Event::UserSpaceFileEventImpl* user_file_event_; + Event::UserSpaceFileEventImpl* user_file_event_{}; // The schedulable handle of the above event. Event::SchedulableCallbackPtr io_callback_; diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 1eabfafe68670..a42a35b0bf8a8 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -124,7 +124,7 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, event_rw, *io_callback_); { - EXPECT_CALL(ready_cb_, called(_)).Times(0); + EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { @@ -144,7 +144,7 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, event_rw, *io_callback_); { - EXPECT_CALL(ready_cb_, called(_)).Times(0); + EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { @@ -166,7 +166,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, event_rw, *io_callback_); { - EXPECT_CALL(ready_cb_, called(_)).Times(0); + EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { @@ -187,7 +187,6 @@ TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyAct *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, Event::FileReadyType::Write | Event::FileReadyType::Closed, *io_callback_); { - scheduleNextEvent(); // No Closed event bit if enabled by not activated. EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 52f8b6bc92051..752a65e41a2d9 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -316,6 +316,8 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); auto result = io_handle_->recv(buf_.data(), 232, 0); EXPECT_TRUE(handle_as_peer->isWritable()); + EXPECT_CALL(cb_, called(_)); + scheduable_cb_->invokeCallback(); } EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); @@ -414,6 +416,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); + ENVOY_LOG_MISC(debug, "lambdai: next shutdown"); EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); } From 58971d92cc2aeae20ac91938fab353fdd14e09b6 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 28 Oct 2020 08:51:47 +0000 Subject: [PATCH 30/88] file event owned by io handle Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 23 ++---- .../common/event/user_space_file_event_impl.h | 30 ++++---- .../network/buffered_io_socket_handle_impl.cc | 40 +++++++--- .../network/buffered_io_socket_handle_impl.h | 15 ++-- .../event/user_space_file_event_impl_test.cc | 75 ++++++------------- .../buffered_io_socket_handle_impl_test.cc | 52 ++++++------- 6 files changed, 110 insertions(+), 125 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 7dc05d9ca686c..ae188d5c4ea3b 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -24,8 +24,8 @@ void UserSpaceFileEventImpl::activate(uint32_t events) { // Only supported event types are set. ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); event_listener_.onEventActivated(events); - if (!schedulable_.enabled()) { - schedulable_.scheduleCallbackNextIteration(); + if (!schedulable_->enabled()) { + schedulable_->scheduleCallbackNextIteration(); } } @@ -33,17 +33,18 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { // Only supported event types are set. ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); event_listener_.onEventEnabled(events); - bool was_enabled = schedulable_.enabled(); + bool was_enabled = schedulable_->enabled(); if (!was_enabled) { - schedulable_.scheduleCallbackNextIteration(); + schedulable_->scheduleCallbackNextIteration(); } ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", static_cast(this), events, was_enabled ? "not " : ""); } -UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, - SchedulableCallback& schedulable_cb) - : schedulable_(schedulable_cb), cb_([this, cb]() { +UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events) + : schedulable_( + dispatcher.createSchedulableCallback([this]() { onEvents(); }) + ), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); ENVOY_LOG(trace, @@ -54,13 +55,5 @@ UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t e setEnabled(events); } -std::unique_ptr UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType trigger_type, uint32_t events, - SchedulableCallback& scheduable_cb) { - ASSERT(trigger_type == Event::FileTriggerType::Edge); - return std::unique_ptr( - new UserSpaceFileEventImpl(cb, events, scheduable_cb)); -} - } // namespace Event } // namespace Envoy \ No newline at end of file diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index ed2f3de3409f7..2cab56f53c1f1 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -14,9 +14,6 @@ class BufferedIoSocketHandleImpl; } namespace Event { -// Forward declare for friend class. -class UserSpaceFileEventFactory; - // The interface of populating event watcher and obtaining the active events. The events are the // combination of FileReadyType values. The event listener is populated by user event registration // and io events passively. Also the owner of this listener query the activated events by calling @@ -72,9 +69,11 @@ class EventListenerImpl : public EventListener { // A FileEvent implementation which is used to drive BufferedIoSocketHandle. class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { public: + UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events); + ~UserSpaceFileEventImpl() override { - if (schedulable_.enabled()) { - schedulable_.cancel(); + if (schedulable_->enabled()) { + schedulable_->cancel(); } } @@ -84,30 +83,27 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggableenabled()) { + schedulable_->scheduleCallbackNextIteration(); + } + } + friend class Network::BufferedIoSocketHandleImpl; private: - UserSpaceFileEventImpl(Event::FileReadyCb cb, uint32_t events, - SchedulableCallback& schedulable_cb); - // Used to populate the event operations of enable and activate. EventListenerImpl event_listener_; // The handle to registered async callback from dispatcher. - SchedulableCallback& schedulable_; + Event::SchedulableCallbackPtr schedulable_; // The registered callback of this event. This callback is usually on top of the frame of // Dispatcher::run(). std::function cb_; }; -class UserSpaceFileEventFactory { -public: - static std::unique_ptr - createUserSpaceFileEventImpl(Event::Dispatcher&, Event::FileReadyCb cb, Event::FileTriggerType, - uint32_t events, SchedulableCallback& scheduable_cb); -}; - } // namespace Event } // namespace Envoy diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index e6dae7e5ca378..6e47ab9fb5437 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -252,16 +252,38 @@ Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); } -Event::FileEventPtr BufferedIoSocketHandleImpl::createFileEvent(Event::Dispatcher& dispatcher, - Event::FileReadyCb cb, - Event::FileTriggerType trigger_type, - uint32_t events) { - io_callback_ = dispatcher.createSchedulableCallback([this]() { user_file_event_->onEvents(); }); - auto event = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - dispatcher, cb, trigger_type, events, *io_callback_); - user_file_event_ = event.get(); - return event; +void BufferedIoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatcher, + Event::FileReadyCb cb, + Event::FileTriggerType trigger, + uint32_t events) { + ASSERT(user_file_event_ == nullptr, "Attempting to initialize two `file_event_` for the same " + "file descriptor. This is not allowed."); + ASSERT(trigger == Event::FileTriggerType::Edge, "Only support edge type."); + user_file_event_ = std::make_unique(dispatcher, cb, events); } +IoHandlePtr BufferedIoSocketHandleImpl::duplicate() { + // duplicate() is supposed to be used on listener io handle while this implementation doesn't + // support listen. + NOT_IMPLEMENTED_GCOVR_EXCL_LINE; +} + +void BufferedIoSocketHandleImpl::activateFileEvents(uint32_t events) { + if (user_file_event_) { + user_file_event_->activate(events); + } else { + ENVOY_BUG(false, "Null user_file_event_"); + } +} + +void BufferedIoSocketHandleImpl::enableFileEvents(uint32_t events) { + if (user_file_event_) { + user_file_event_->setEnabled(events); + } else { + ENVOY_BUG(false, "Null user_file_event_"); + } +} + +void BufferedIoSocketHandleImpl::resetFileEvents() { user_file_event_.reset(); } Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { // Support only shutdown write. diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 44f438089fa4d..b87b9baf04a4c 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -66,8 +66,14 @@ class BufferedIoSocketHandleImpl : public IoHandle, absl::optional domain() override; Address::InstanceConstSharedPtr localAddress() override; Address::InstanceConstSharedPtr peerAddress() override; - Event::FileEventPtr createFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - Event::FileTriggerType trigger, uint32_t events) override; + + void initializeFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + Event::FileTriggerType trigger, uint32_t events) override; + IoHandlePtr duplicate() override; + void activateFileEvents(uint32_t events) override; + void enableFileEvents(uint32_t events) override; + void resetFileEvents() override; + Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } @@ -116,10 +122,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, // The attached file event with this socket. The event is not owned by the socket in the current // Envoy model. Multiple events can be created during the life time of this IO handle but at any // moment at most 1 event is attached. - Event::UserSpaceFileEventImpl* user_file_event_{}; - - // The schedulable handle of the above event. - Event::SchedulableCallbackPtr io_callback_; + std::unique_ptr user_file_event_; // True if pending_received_data_ is not addable. Note that pending_received_data_ may have // pending data to drain. diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index a42a35b0bf8a8..53914c9f3f195 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -27,73 +27,48 @@ class UserSpaceFileEventImplTest : public testing::Test { public: UserSpaceFileEventImplTest() : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) { - io_callback_ = - dispatcher_->createSchedulableCallback([this]() { user_file_event_->onEvents(); }); - } - - void scheduleNextEvent() { - ASSERT(io_callback_ != nullptr); - io_callback_->scheduleCallbackNextIteration(); } protected: MockReadyCb ready_cb_; Api::ApiPtr api_; DispatcherPtr dispatcher_; - Event::SchedulableCallbackPtr io_callback_; std::unique_ptr user_file_event_; }; -TEST_F(UserSpaceFileEventImplTest, TestLevelTriggerIsNotSupported) { - ASSERT_DEBUG_DEATH(Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, - Event::FileTriggerType::Level, event_rw, *io_callback_), - "assert failure"); -} - TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); - scheduleNextEvent(); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } -TEST_F(UserSpaceFileEventImplTest, TestDebugDeathOnActivateDisabledEvents) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read, *io_callback_); - ASSERT_DEBUG_DEATH(user_file_event_->activate(Event::FileReadyType::Write), ""); -} - TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { SCOPED_TRACE("1st schedule"); - scheduleNextEvent(); + user_file_event_->activate(event_rw); EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { SCOPED_TRACE("2nd schedule"); - scheduleNextEvent(); + user_file_event_->activate(event_rw); EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } } TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { SCOPED_TRACE("1st schedule"); - scheduleNextEvent(); - scheduleNextEvent(); + user_file_event_->activate(event_rw); + + user_file_event_->activate(event_rw); EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } @@ -109,10 +84,9 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents std::vector events{Event::FileReadyType::Read, Event::FileReadyType::Write, event_rw}; for (const auto& e : events) { SCOPED_TRACE(absl::StrCat("current event:", e)); - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); - scheduleNextEvent(); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + user_file_event_->activate(e); EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); user_file_event_.reset(); @@ -120,9 +94,8 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents } TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); @@ -140,9 +113,8 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { } TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); @@ -162,9 +134,8 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { } TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - event_rw, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { EXPECT_CALL(ready_cb_, called(_)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); @@ -183,9 +154,9 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { } TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyActivated) { - user_file_event_ = Event::UserSpaceFileEventFactory::createUserSpaceFileEventImpl( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Write | Event::FileReadyType::Closed, *io_callback_); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, + Event::FileReadyType::Write | Event::FileReadyType::Closed); { // No Closed event bit if enabled by not activated. EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 752a65e41a2d9..7bd72fde5671f 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -189,19 +189,19 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); @@ -211,32 +211,32 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { ASSERT_FALSE(scheduable_cb_->enabled()); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - ev->setEnabled(Event::FileReadyType::Read); + io_handle_->enableFileEvents(Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - ev->setEnabled(Event::FileReadyType::Write); + io_handle_->enableFileEvents(Event::FileReadyType::Write); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - ev->setEnabled(Event::FileReadyType::Write | Event::FileReadyType::Read); + io_handle_->enableFileEvents(Event::FileReadyType::Write | Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Read)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); @@ -254,35 +254,35 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { EXPECT_EQ(1, result.rc_); ASSERT_FALSE(scheduable_cb_->enabled()); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); - ev->setEnabled(0); + io_handle_->enableFileEvents(0); EXPECT_CALL(cb_, called(0)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); - - ev.reset(); - ASSERT_FALSE(scheduable_cb_->enabled()); + + EXPECT_CALL(cb_, called(_)).Times(0); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { @@ -300,7 +300,7 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { // Clear invoke callback on peer. scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_peer_->createFileEvent( + io_handle_peer_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); @@ -331,7 +331,7 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { @@ -369,7 +369,7 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(0); io_handle_->close(); EXPECT_EQ(4, accumulator.size()); - ev.reset(); + io_handle_->resetFileEvents(); } // Test that a readable event is raised when peer shutdown write. Also confirm read will return @@ -382,7 +382,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { @@ -411,7 +411,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { ASSERT_FALSE(should_close); EXPECT_EQ(4, accumulator.size()); io_handle_->close(); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { @@ -519,7 +519,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { @@ -559,7 +559,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { @@ -601,7 +601,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; - auto ev = io_handle_peer_->createFileEvent( + io_handle_peer_->initializeFileEvent( dispatcher_, [&should_close, handle = io_handle_peer_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { @@ -635,7 +635,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->close(); - ev.reset(); + io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { @@ -650,7 +650,7 @@ TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - auto ev = io_handle_->createFileEvent( + io_handle_->initializeFileEvent( dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); From 119a9cb2fdaed919b002d14b233651319a238582 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 28 Oct 2020 08:53:50 +0000 Subject: [PATCH 31/88] fix format Signed-off-by: Yuchen Dai --- source/common/event/user_space_file_event_impl.cc | 8 ++++---- source/common/version/BUILD | 6 +++--- test/common/event/user_space_file_event_impl_test.cc | 5 ++--- .../common/network/buffered_io_socket_handle_impl_test.cc | 2 +- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index ae188d5c4ea3b..f372273faf1f7 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -41,10 +41,10 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { static_cast(this), events, was_enabled ? "not " : ""); } -UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events) - : schedulable_( - dispatcher.createSchedulableCallback([this]() { onEvents(); }) - ), cb_([this, cb]() { +UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + uint32_t events) + : schedulable_(dispatcher.createSchedulableCallback([this]() { onEvents(); })), + cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); ENVOY_LOG(trace, diff --git a/source/common/version/BUILD b/source/common/version/BUILD index 9d726567378a4..85f29b8ed9ed3 100644 --- a/source/common/version/BUILD +++ b/source/common/version/BUILD @@ -14,7 +14,7 @@ genrule( name = "generate_version_number", srcs = ["//:VERSION"], outs = ["version_number.h"], - cmd = """echo "#define BUILD_VERSION_NUMBER \\"$$(cat $<)\\"" >$@""", + cmd = """echo "#define BUILD_VERSION_NUMBER \"$$(cat $<)\"" >$@""", visibility = ["//visibility:private"], ) @@ -50,8 +50,8 @@ envoy_cc_library( name = "version_lib", srcs = ["version.cc"], copts = envoy_select_boringssl( - ["-DENVOY_SSL_VERSION=\\\"BoringSSL-FIPS\\\""], - ["-DENVOY_SSL_VERSION=\\\"BoringSSL\\\""], + ["-DENVOY_SSL_VERSION=\"BoringSSL-FIPS\""], + ["-DENVOY_SSL_VERSION=\"BoringSSL\""], ), deps = [ ":version_includes", diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 53914c9f3f195..6942b1e0b9da3 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -26,8 +26,7 @@ class MockReadyCb { class UserSpaceFileEventImplTest : public testing::Test { public: UserSpaceFileEventImplTest() - : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) { - } + : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} protected: MockReadyCb ready_cb_; @@ -66,7 +65,7 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); { SCOPED_TRACE("1st schedule"); - user_file_event_->activate(event_rw); + user_file_event_->activate(event_rw); user_file_event_->activate(event_rw); EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 7bd72fde5671f..801b0a599216d 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -280,7 +280,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); - + EXPECT_CALL(cb_, called(_)).Times(0); io_handle_->resetFileEvents(); } From f18fb59d5e9a5d124c1243bd26a638ee2b4b4cd6 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 28 Oct 2020 18:47:40 +0000 Subject: [PATCH 32/88] address comment: also add fails_on_windows to track Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 32 +++++------ .../common/event/user_space_file_event_impl.h | 13 +---- source/common/version/BUILD | 6 +- test/common/network/BUILD | 12 ++++ ...red_io_socket_handle_impl_platform_test.cc | 57 +++++++++++++++++++ .../buffered_io_socket_handle_impl_test.cc | 37 +++++++----- 6 files changed, 111 insertions(+), 46 deletions(-) create mode 100644 test/common/network/buffered_io_socket_handle_impl_platform_test.cc diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index f372273faf1f7..5ddfc5a55b626 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -7,6 +7,20 @@ namespace Envoy { namespace Event { +UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + uint32_t events) + : schedulable_(dispatcher.createSchedulableCallback([this]() { onEvents(); })), + cb_([this, cb]() { + auto all_events = getEventListener().triggeredEvents(); + auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); + ENVOY_LOG(trace, + "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", + static_cast(this), all_events, ephemeral_events); + cb(all_events | ephemeral_events); + }) { + setEnabled(events); +} + void EventListenerImpl::onEventEnabled(uint32_t enabled_events) { enabled_events_ = enabled_events; // Clear ephemeral events to align with FileEventImpl::setEnable(). @@ -24,9 +38,7 @@ void UserSpaceFileEventImpl::activate(uint32_t events) { // Only supported event types are set. ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); event_listener_.onEventActivated(events); - if (!schedulable_->enabled()) { - schedulable_->scheduleCallbackNextIteration(); - } + schedulable_->scheduleCallbackNextIteration(); } void UserSpaceFileEventImpl::setEnabled(uint32_t events) { @@ -41,19 +53,5 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { static_cast(this), events, was_enabled ? "not " : ""); } -UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - uint32_t events) - : schedulable_(dispatcher.createSchedulableCallback([this]() { onEvents(); })), - cb_([this, cb]() { - auto all_events = getEventListener().triggeredEvents(); - auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); - ENVOY_LOG(trace, - "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", - static_cast(this), all_events, ephemeral_events); - cb(all_events | ephemeral_events); - }) { - setEnabled(events); -} - } // namespace Event } // namespace Envoy \ No newline at end of file diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 2cab56f53c1f1..a75eede180f99 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -71,11 +71,7 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggableenabled()) { - schedulable_->cancel(); - } - } + ~UserSpaceFileEventImpl() override = default; // Event::FileEvent void activate(uint32_t events) override; @@ -84,13 +80,6 @@ class UserSpaceFileEventImpl : public FileEvent, Logger::Loggableenabled()) { - schedulable_->scheduleCallbackNextIteration(); - } - } - friend class Network::BufferedIoSocketHandleImpl; private: diff --git a/source/common/version/BUILD b/source/common/version/BUILD index 85f29b8ed9ed3..9d726567378a4 100644 --- a/source/common/version/BUILD +++ b/source/common/version/BUILD @@ -14,7 +14,7 @@ genrule( name = "generate_version_number", srcs = ["//:VERSION"], outs = ["version_number.h"], - cmd = """echo "#define BUILD_VERSION_NUMBER \"$$(cat $<)\"" >$@""", + cmd = """echo "#define BUILD_VERSION_NUMBER \\"$$(cat $<)\\"" >$@""", visibility = ["//visibility:private"], ) @@ -50,8 +50,8 @@ envoy_cc_library( name = "version_lib", srcs = ["version.cc"], copts = envoy_select_boringssl( - ["-DENVOY_SSL_VERSION=\"BoringSSL-FIPS\""], - ["-DENVOY_SSL_VERSION=\"BoringSSL\""], + ["-DENVOY_SSL_VERSION=\\\"BoringSSL-FIPS\\\""], + ["-DENVOY_SSL_VERSION=\\\"BoringSSL\\\""], ), deps = [ ":version_includes", diff --git a/test/common/network/BUILD b/test/common/network/BUILD index da5018861c43e..7ccb038ed1cb3 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -462,3 +462,15 @@ envoy_cc_test( "//test/mocks/event:event_mocks", ], ) + +envoy_cc_test( + name = "buffered_io_socket_handle_impl_platform_test", + srcs = ["buffered_io_socket_handle_impl_platform_test.cc"], + tags = ["fails_on_windows"], + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/common/network:buffered_io_socket_handle_lib", + "//test/mocks/event:event_mocks", + ], +) diff --git a/test/common/network/buffered_io_socket_handle_impl_platform_test.cc b/test/common/network/buffered_io_socket_handle_impl_platform_test.cc new file mode 100644 index 0000000000000..2614aab70873e --- /dev/null +++ b/test/common/network/buffered_io_socket_handle_impl_platform_test.cc @@ -0,0 +1,57 @@ +#include "envoy/common/platform.h" +#include "envoy/event/file_event.h" + +#include "common/network/buffered_io_socket_handle_impl.h" + +#include "test/mocks/event/mocks.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +namespace Envoy { +namespace Network { +namespace { + +using testing::NiceMock; + +class MockFileEventCallback { +public: + MOCK_METHOD(void, called, (uint32_t arg)); +}; + +// Explicitly mark the test failing on windows and will be fixed. +class BufferedIoSocketHandlePlatformTest : public testing::Test { +public: + BufferedIoSocketHandlePlatformTest() { + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setWritablePeer(io_handle_peer_.get()); + io_handle_peer_->setWritablePeer(io_handle_.get()); + } + + ~BufferedIoSocketHandlePlatformTest() override { + if (io_handle_->isOpen()) { + io_handle_->close(); + } + if (io_handle_peer_->isOpen()) { + io_handle_peer_->close(); + } + } + + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; + NiceMock dispatcher_; + MockFileEventCallback cb_; +}; + +TEST_F(BufferedIoSocketHandlePlatformTest, TestCreatePlatformDefaultTriggerTypeFailOnWindows) { + auto scheduable_cb = new NiceMock(&dispatcher_); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + io_handle_->initializeFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, + Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); +} + +} // namespace +} // namespace Network +} // namespace Envoy diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 801b0a599216d..aa7165b9e2327 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -1,4 +1,3 @@ -#include "envoy/common/platform.h" #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" @@ -52,7 +51,7 @@ class BufferedIoSocketHandleTest : public testing::Test { EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } - NiceMock dispatcher_{}; + NiceMock dispatcher_; // Owned by BufferedIoSocketHandle. NiceMock* scheduable_cb_; @@ -191,7 +190,7 @@ TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -203,7 +202,7 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); @@ -238,7 +237,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -262,7 +261,7 @@ TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); io_handle_->enableFileEvents(0); @@ -278,7 +277,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)).Times(0); @@ -302,7 +301,7 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_peer_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -353,7 +352,7 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { } } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read | Event::FileReadyType::Write); + Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); scheduable_cb_->invokeCallback(); // Not closed yet. @@ -397,7 +396,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { } } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); // Not closed yet. @@ -537,7 +536,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { } } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -577,7 +576,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { } } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -619,7 +618,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { } } }, - Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -651,7 +650,7 @@ TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::PlatformDefaultTriggerType, + dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::FileTriggerType::Edge, Event::FileReadyType::Read); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -681,6 +680,16 @@ TEST_F(BufferedIoSocketHandleTest, TestConnect) { EXPECT_EQ(0, io_handle_->connect(address_is_ignored).rc_); } +TEST_F(BufferedIoSocketHandleTest, TestDeathOnActivatingDestroyedEvents) { + io_handle_->resetFileEvents(); + ASSERT_DEBUG_DEATH(io_handle_->activateFileEvents(Event::FileReadyType::Read), "Null user_file_event_"); +} + +TEST_F(BufferedIoSocketHandleTest, TestDeathOnEnablingDestroyedEvents) { + io_handle_->resetFileEvents(); + ASSERT_DEBUG_DEATH(io_handle_->enableFileEvents(Event::FileReadyType::Read), "Null user_file_event_"); +} + class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { From b3e126495cfa196fed2a2339c8455f6dae55006c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 28 Oct 2020 20:05:17 +0000 Subject: [PATCH 33/88] fix cc format Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index aa7165b9e2327..182e598724939 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -189,8 +189,8 @@ TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -201,8 +201,8 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); @@ -236,8 +236,8 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -260,8 +260,8 @@ TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); io_handle_->enableFileEvents(0); @@ -276,8 +276,8 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)).Times(0); @@ -300,8 +300,8 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { scheduable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_peer_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -682,12 +682,14 @@ TEST_F(BufferedIoSocketHandleTest, TestConnect) { TEST_F(BufferedIoSocketHandleTest, TestDeathOnActivatingDestroyedEvents) { io_handle_->resetFileEvents(); - ASSERT_DEBUG_DEATH(io_handle_->activateFileEvents(Event::FileReadyType::Read), "Null user_file_event_"); + ASSERT_DEBUG_DEATH(io_handle_->activateFileEvents(Event::FileReadyType::Read), + "Null user_file_event_"); } TEST_F(BufferedIoSocketHandleTest, TestDeathOnEnablingDestroyedEvents) { io_handle_->resetFileEvents(); - ASSERT_DEBUG_DEATH(io_handle_->enableFileEvents(Event::FileReadyType::Read), "Null user_file_event_"); + ASSERT_DEBUG_DEATH(io_handle_->enableFileEvents(Event::FileReadyType::Read), + "Null user_file_event_"); } class BufferedIoSocketHandleNotImplementedTest : public testing::Test { From 7fb8f79ff6b416cb6a2ddbbdabc2636444579d8e Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 28 Oct 2020 23:19:17 +0000 Subject: [PATCH 34/88] declare UserSpaceFileEventImpl final Signed-off-by: Yuchen Dai --- source/common/event/user_space_file_event_impl.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index a75eede180f99..468b6be401a43 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -67,7 +67,8 @@ class EventListenerImpl : public EventListener { }; // A FileEvent implementation which is used to drive BufferedIoSocketHandle. -class UserSpaceFileEventImpl : public FileEvent, Logger::Loggable { +// Declare the class final to safely call virtual function setEnabled in constructor. +class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable { public: UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events); From 1af28883a8abe6a3332e0b8661dddafed4905ee1 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 29 Oct 2020 01:46:26 +0000 Subject: [PATCH 35/88] remove onEvents Signed-off-by: Yuchen Dai --- source/common/event/user_space_file_event_impl.cc | 2 +- source/common/event/user_space_file_event_impl.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 5ddfc5a55b626..74662fbda7a14 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -9,7 +9,7 @@ namespace Event { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events) - : schedulable_(dispatcher.createSchedulableCallback([this]() { onEvents(); })), + : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 468b6be401a43..3ebeb58553371 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -79,7 +79,6 @@ class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable Date: Thu, 29 Oct 2020 04:30:38 +0000 Subject: [PATCH 36/88] fix user space event test Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 1 + .../event/user_space_file_event_impl.cc | 26 +++-- .../common/event/user_space_file_event_impl.h | 11 +- .../network/buffered_io_socket_handle_impl.cc | 2 +- .../network/buffered_io_socket_handle_impl.h | 11 +- source/common/network/peer_buffer.h | 13 +++ test/common/event/BUILD | 1 + .../event/user_space_file_event_impl_test.cc | 102 ++++++++++++++---- 8 files changed, 132 insertions(+), 35 deletions(-) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index 46404075ad0fa..4633bb3887c7d 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -83,6 +83,7 @@ envoy_cc_library( "//source/common/common:minimal_logger_lib", "//source/common/common:thread_lib", "//source/common/signal:fatal_error_handler_lib", + "//source/common/network:peer_buffer_lib", ] + select({ "//bazel:disable_signal_trace": [], "//conditions:default": [ diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 74662fbda7a14..b12b35a530918 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -3,21 +3,22 @@ #include #include "common/common/assert.h" +#include "common/network/peer_buffer.h" namespace Envoy { namespace Event { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - uint32_t events) - : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), - cb_([this, cb]() { + uint32_t events, Network::ReadWritable& io_source) + : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { auto all_events = getEventListener().triggeredEvents(); auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); ENVOY_LOG(trace, "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", static_cast(this), all_events, ephemeral_events); cb(all_events | ephemeral_events); - }) { + }), + io_source_(io_source) { setEnabled(events); } @@ -46,8 +47,21 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); event_listener_.onEventEnabled(events); bool was_enabled = schedulable_->enabled(); - if (!was_enabled) { - schedulable_->scheduleCallbackNextIteration(); + // if (!was_enabled) { + // schedulable_->scheduleCallbackNextIteration(); + // } + // Recalculate activated events. + uint32_t events_to_notify = 0; + if ((events & FileReadyType::Read) && io_source_.isReadable()) { + events_to_notify |= FileReadyType::Read; + } + if ((events & FileReadyType::Write) && io_source_.isPeerWritable()) { + events_to_notify |= FileReadyType::Write; + } + if (events_to_notify != 0) { + activate(events_to_notify); + } else { + schedulable_->cancel(); } ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", static_cast(this), events, was_enabled ? "not " : ""); diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 3ebeb58553371..332adf25cff9a 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -6,6 +6,7 @@ #include "common/event/dispatcher_impl.h" #include "common/event/event_impl_base.h" +#include "common/network/peer_buffer.h" namespace Envoy { @@ -52,7 +53,10 @@ class EventListenerImpl : public EventListener { // Return both read and write if enabled. Note that this implementation is inefficient. Read and // write events are supposed to be independent. - uint32_t triggeredEvents() override { return enabled_events_ & (~Event::FileReadyType::Closed); } + uint32_t triggeredEvents() override { + // return enabled_events_ & (~Event::FileReadyType::Closed); + return 0; + } void onEventEnabled(uint32_t enabled_events) override; void onEventActivated(uint32_t activated_events) override; @@ -70,7 +74,8 @@ class EventListenerImpl : public EventListener { // Declare the class final to safely call virtual function setEnabled in constructor. class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable { public: - UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events); + UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, + Network::ReadWritable& io_source); ~UserSpaceFileEventImpl() override = default; @@ -92,6 +97,8 @@ class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable cb_; + + Network::ReadWritable& io_source_; }; } // namespace Event diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/common/network/buffered_io_socket_handle_impl.cc index 6e47ab9fb5437..00030b61ea1ec 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/common/network/buffered_io_socket_handle_impl.cc @@ -259,7 +259,7 @@ void BufferedIoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatch ASSERT(user_file_event_ == nullptr, "Attempting to initialize two `file_event_` for the same " "file descriptor. This is not allowed."); ASSERT(trigger == Event::FileTriggerType::Edge, "Only support edge type."); - user_file_event_ = std::make_unique(dispatcher, cb, events); + user_file_event_ = std::make_unique(dispatcher, cb, events, *this); } IoHandlePtr BufferedIoSocketHandleImpl::duplicate() { // duplicate() is supposed to be used on listener io handle while this implementation doesn't diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index b87b9baf04a4c..f1e8770053540 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -28,8 +28,7 @@ namespace Network { * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ class BufferedIoSocketHandleImpl : public IoHandle, - public WritablePeer, - public ReadableSource, + public ReadWritable, protected Logger::Loggable { public: BufferedIoSocketHandleImpl(); @@ -92,7 +91,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, void maybeSetNewData() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); if (user_file_event_) { - user_file_event_->activate(Event::FileReadyType::Write); + user_file_event_->activate(Event::FileReadyType::Read); } } void onPeerDestroy() override { @@ -101,10 +100,14 @@ class BufferedIoSocketHandleImpl : public IoHandle, } void onPeerBufferWritable() override { if (user_file_event_) { - user_file_event_->activate(Event::FileReadyType::Read); + user_file_event_->activate(Event::FileReadyType::Write); } } bool isWritable() const override { return !isOverHighWatermark(); } + bool isPeerWritable() const override { + return writable_peer_ != nullptr && !writable_peer_->isWriteEndSet() && + writable_peer_->isWritable(); + } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } // ReadableSource diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 9c0db4ef9f7cc..4cab47848fd2b 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -40,6 +40,11 @@ class WritablePeer { */ virtual bool isWritable() const PURE; + /** + * @return true if peer is valid and writable. + */ + virtual bool isPeerWritable() const PURE; + /** * Raised by the peer when the peer switch from high water mark to low. */ @@ -61,5 +66,13 @@ class ReadableSource { virtual bool isOverHighWatermark() const PURE; virtual bool isReadable() const PURE; }; + +/** + * The interface as the union of ReadableSource and WritablePeer. + */ +class ReadWritable : public virtual ReadableSource, public virtual WritablePeer { +public: + virtual ~ReadWritable() = default; +}; } // namespace Network } // namespace Envoy \ No newline at end of file diff --git a/test/common/event/BUILD b/test/common/event/BUILD index 290f9f80865f9..3095b3600a6b2 100644 --- a/test/common/event/BUILD +++ b/test/common/event/BUILD @@ -49,6 +49,7 @@ envoy_cc_test( "//include/envoy/event:file_event_interface", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", + "//source/common/network:peer_buffer_lib", "//test/mocks:common_lib", "//test/test_common:environment_lib", "//test/test_common:test_runtime_lib", diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 6942b1e0b9da3..0d652ca230744 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -4,6 +4,7 @@ #include "common/event/dispatcher_impl.h" #include "common/event/user_space_file_event_impl.h" +#include "common/network/peer_buffer.h" #include "test/mocks/common.h" #include "test/test_common/environment.h" @@ -17,18 +18,39 @@ namespace Envoy { namespace Event { namespace { +using testing::NiceMock; +using testing::Return; + constexpr auto event_rw = Event::FileReadyType::Read | Event::FileReadyType::Write; class MockReadyCb { public: MOCK_METHOD(void, called, (uint32_t)); }; +class MockReadWritable : public Network::ReadWritable { +public: + MOCK_METHOD(void, setWriteEnd, ()); + MOCK_METHOD(bool, isWriteEndSet, ()); + MOCK_METHOD(void, onPeerDestroy, ()); + MOCK_METHOD(void, maybeSetNewData, ()); + MOCK_METHOD(Buffer::Instance*, getWriteBuffer, ()); + MOCK_METHOD(bool, isWritable, (), (const)); + MOCK_METHOD(bool, isPeerWritable, (), (const)); + MOCK_METHOD(void, onPeerBufferWritable, ()); + MOCK_METHOD(bool, isPeerShutDownWrite, (), (const)); + MOCK_METHOD(bool, isOverHighWatermark, (), (const)); + MOCK_METHOD(bool, isReadable, (), (const)); +}; class UserSpaceFileEventImplTest : public testing::Test { public: UserSpaceFileEventImplTest() : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} + void setWritable() { EXPECT_CALL(io_source_, isPeerWritable()).WillRepeatedly(Return(true)); } + void setReadable() { EXPECT_CALL(io_source_, isReadable()).WillRepeatedly(Return(true)); } + protected: + NiceMock io_source_; MockReadyCb ready_cb_; Api::ApiPtr api_; DispatcherPtr dispatcher_; @@ -36,15 +58,16 @@ class UserSpaceFileEventImplTest : public testing::Test { }; TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { + setWritable(); user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); - EXPECT_CALL(ready_cb_, called(event_rw)); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); + EXPECT_CALL(ready_cb_, called(FileReadyType::Write)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { SCOPED_TRACE("1st schedule"); user_file_event_->activate(event_rw); @@ -62,7 +85,7 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { SCOPED_TRACE("1st schedule"); user_file_event_->activate(event_rw); @@ -80,42 +103,72 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { } TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents) { - std::vector events{Event::FileReadyType::Read, Event::FileReadyType::Write, event_rw}; - for (const auto& e : events) { - SCOPED_TRACE(absl::StrCat("current event:", e)); + { + auto current_event = Event::FileReadyType::Read; + SCOPED_TRACE(absl::StrCat("current event:", current_event)); + EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(true)).RetiresOnSaturation(); + EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(false)).RetiresOnSaturation(); user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); - user_file_event_->activate(e); - EXPECT_CALL(ready_cb_, called(event_rw)); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); + // user_file_event_->activate(e); + EXPECT_CALL(ready_cb_, called(current_event)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + user_file_event_.reset(); + } + + { + auto current_event = Event::FileReadyType::Write; + SCOPED_TRACE(absl::StrCat("current event:", current_event)); + EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(false)).RetiresOnSaturation(); + EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(true)).RetiresOnSaturation(); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); + // user_file_event_->activate(e); + EXPECT_CALL(ready_cb_, called(current_event)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + user_file_event_.reset(); + } + + { + auto current_event = event_rw; + SCOPED_TRACE(absl::StrCat("current event:", current_event)); + EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(true)).RetiresOnSaturation(); + EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(true)).RetiresOnSaturation(); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); + // user_file_event_->activate(e); + EXPECT_CALL(ready_cb_, called(current_event)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); user_file_event_.reset(); } } TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { + // IO is neither readable nor writable. user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { - EXPECT_CALL(ready_cb_, called(_)).Times(1); + EXPECT_CALL(ready_cb_, called(_)).Times(0); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { user_file_event_->activate(Event::FileReadyType::Read); - EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { user_file_event_->activate(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } } TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { + // IO is neither readable nor writable. user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { - EXPECT_CALL(ready_cb_, called(_)).Times(1); + EXPECT_CALL(ready_cb_, called(_)).Times(0); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { @@ -133,16 +186,19 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { } TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { + // IO is neither readable nor writable. user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw); + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { - EXPECT_CALL(ready_cb_, called(_)).Times(1); + EXPECT_CALL(ready_cb_, called(_)).Times(0); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } + { + setWritable(); + setReadable(); user_file_event_->activate(Event::FileReadyType::Read); user_file_event_->setEnabled(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } @@ -155,16 +211,18 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyActivated) { user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, - Event::FileReadyType::Write | Event::FileReadyType::Closed); + Event::FileReadyType::Write | Event::FileReadyType::Closed, io_source_); { // No Closed event bit if enabled by not activated. - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); + EXPECT_CALL(ready_cb_, called(_)).Times(0); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { + setWritable(); + setReadable(); user_file_event_->activate(Event::FileReadyType::Closed); // Activate could deliver Closed event bit. - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Closed)) + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)) .Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } From 6ca32cf24ae57b9185007b01a6a1967abc8ffdb7 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 29 Oct 2020 04:49:24 +0000 Subject: [PATCH 37/88] fix buffer io socket handle test Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 3 - .../common/event/user_space_file_event_impl.h | 8 +- .../event/user_space_file_event_impl_test.cc | 3 +- ...red_io_socket_handle_impl_platform_test.cc | 2 +- .../buffered_io_socket_handle_impl_test.cc | 121 +++++++++--------- 5 files changed, 66 insertions(+), 71 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index b12b35a530918..d41dc060834ba 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -47,9 +47,6 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); event_listener_.onEventEnabled(events); bool was_enabled = schedulable_->enabled(); - // if (!was_enabled) { - // schedulable_->scheduleCallbackNextIteration(); - // } // Recalculate activated events. uint32_t events_to_notify = 0; if ((events & FileReadyType::Read) && io_source_.isReadable()) { diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 332adf25cff9a..15b29b8424d76 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -51,12 +51,8 @@ class EventListenerImpl : public EventListener { public: ~EventListenerImpl() override = default; - // Return both read and write if enabled. Note that this implementation is inefficient. Read and - // write events are supposed to be independent. - uint32_t triggeredEvents() override { - // return enabled_events_ & (~Event::FileReadyType::Closed); - return 0; - } + // The ready events are not preserved. All ready events must be notified by activate(). + uint32_t triggeredEvents() override { return 0; } void onEventEnabled(uint32_t enabled_events) override; void onEventActivated(uint32_t activated_events) override; diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index 0d652ca230744..f4b9fe4c7b116 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -222,8 +222,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyAct setReadable(); user_file_event_->activate(Event::FileReadyType::Closed); // Activate could deliver Closed event bit. - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)) - .Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { diff --git a/test/common/network/buffered_io_socket_handle_impl_platform_test.cc b/test/common/network/buffered_io_socket_handle_impl_platform_test.cc index 2614aab70873e..c7044eacd1ac4 100644 --- a/test/common/network/buffered_io_socket_handle_impl_platform_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_platform_test.cc @@ -46,7 +46,7 @@ class BufferedIoSocketHandlePlatformTest : public testing::Test { TEST_F(BufferedIoSocketHandlePlatformTest, TestCreatePlatformDefaultTriggerTypeFailOnWindows) { auto scheduable_cb = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()).Times(0); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 182e598724939..955759047193a 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -190,7 +190,7 @@ TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); + Event::FileReadyType::Read | Event::FileReadyType::Write); EXPECT_CALL(cb_, called(_)); scheduable_cb_->invokeCallback(); @@ -199,37 +199,33 @@ TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - io_handle_->initializeFileEvent( - dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); - - ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); - scheduable_cb_->invokeCallback(); - ASSERT_FALSE(scheduable_cb_->enabled()); - - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - io_handle_->enableFileEvents(Event::FileReadyType::Read); - ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(_)); - scheduable_cb_->invokeCallback(); - ASSERT_FALSE(scheduable_cb_->enabled()); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - io_handle_->enableFileEvents(Event::FileReadyType::Write); - ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); - scheduable_cb_->invokeCallback(); - ASSERT_FALSE(scheduable_cb_->enabled()); - - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - io_handle_->enableFileEvents(Event::FileReadyType::Write | Event::FileReadyType::Read); - ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(Event::FileReadyType::Write | Event::FileReadyType::Read)); - scheduable_cb_->invokeCallback(); - ASSERT_FALSE(scheduable_cb_->enabled()); - io_handle_->resetFileEvents(); + // No data is available to read. Will not schedule read. + { + SCOPED_TRACE("enable read but no readable."); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(0); + io_handle_->initializeFileEvent( + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); + } + { + SCOPED_TRACE("enable readwrite but only writable."); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_->enableFileEvents(Event::FileReadyType::Read | Event::FileReadyType::Write); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + } + { + SCOPED_TRACE("enable write and writable."); + EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + io_handle_->enableFileEvents(Event::FileReadyType::Write); + ASSERT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); + scheduable_cb_->invokeCallback(); + ASSERT_FALSE(scheduable_cb_->enabled()); + } } TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { @@ -237,12 +233,12 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); + Event::FileReadyType::Read | Event::FileReadyType::Write); - EXPECT_CALL(cb_, called(_)); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); scheduable_cb_->invokeCallback(); - // Neither read and write will trigger self readiness. + // Neither read nor write triggers self readiness. EXPECT_CALL(cb_, called(_)).Times(0); // Drain 1 bytes. @@ -261,12 +257,11 @@ TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); - - io_handle_->enableFileEvents(0); + Event::FileReadyType::Write); + ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(0)); - scheduable_cb_->invokeCallback(); + // The write event is cleared and the read event is not ready. + io_handle_->enableFileEvents(Event::FileReadyType::Read); ASSERT_FALSE(scheduable_cb_->enabled()); io_handle_->resetFileEvents(); @@ -277,7 +272,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); + Event::FileReadyType::Write); ASSERT_TRUE(scheduable_cb_->enabled()); EXPECT_CALL(cb_, called(_)).Times(0); @@ -296,15 +291,11 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { EXPECT_TRUE(io_handle_->isReadable()); EXPECT_FALSE(handle_as_peer->isWritable()); - // Clear invoke callback on peer. scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); io_handle_peer_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, - Event::FileReadyType::Read); - ASSERT_TRUE(scheduable_cb_->enabled()); - EXPECT_CALL(cb_, called(_)); - scheduable_cb_->invokeCallback(); + Event::FileReadyType::Read | Event::FileReadyType::Write); + // Neither readable nor writable. ASSERT_FALSE(scheduable_cb_->enabled()); { @@ -334,14 +325,24 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { dispatcher_, [this, &should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { - auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); - if (result.ok()) { - accumulator += absl::string_view(buf_.data(), result.rc_); - } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { - ENVOY_LOG_MISC(debug, "read returns EAGAIN"); - } else { - ENVOY_LOG_MISC(debug, "will close"); - should_close = true; + while (true) { + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + if (result.ok()) { + // Read EOF. + if (result.rc_ == 0) { + should_close = true; + break; + } else { + accumulator += absl::string_view(buf_.data(), result.rc_); + } + } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { + ENVOY_LOG_MISC(debug, "read returns EAGAIN"); + break; + } else { + ENVOY_LOG_MISC(debug, "will close"); + should_close = true; + break; + } } } if (events & Event::FileReadyType::Write) { @@ -536,7 +537,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { } } }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -576,7 +577,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { } } }, - Event::FileTriggerType::Edge, Event::FileReadyType::Read); + Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); @@ -598,7 +599,6 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { ENVOY_LOG_MISC(debug, "after {} shutdown write ", static_cast(io_handle_peer_.get())); std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); bool should_close = false; io_handle_peer_->initializeFileEvent( dispatcher_, @@ -609,7 +609,11 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { buf.reserve(1024, &slice, 1); auto result = handle->readv(1024, &slice, 1); if (result.ok()) { - accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); + if (result.rc_ == 0) { + should_close = true; + } else { + accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); + } } else if (result.err_->getErrorCode() == Api::IoError::IoErrorCode::Again) { ENVOY_LOG_MISC(debug, "read returns EAGAIN"); } else { @@ -619,7 +623,6 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { } }, Event::FileTriggerType::Edge, Event::FileReadyType::Read); - scheduable_cb_->invokeCallback(); EXPECT_FALSE(scheduable_cb_->enabled()); std::string raw_data("0123456789"); From fd7e7eaaa83927e14bcc92120f3c10c4d19c16f6 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 29 Oct 2020 16:51:26 +0000 Subject: [PATCH 38/88] clang tidy Signed-off-by: Yuchen Dai --- source/common/network/peer_buffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 4cab47848fd2b..9ce027a6eb21f 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -72,7 +72,7 @@ class ReadableSource { */ class ReadWritable : public virtual ReadableSource, public virtual WritablePeer { public: - virtual ~ReadWritable() = default; + virtual ~ReadWritable() override = default; }; } // namespace Network } // namespace Envoy \ No newline at end of file From bd745ab739811b295609288781bf5ad959092edc Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 29 Oct 2020 20:27:38 +0000 Subject: [PATCH 39/88] clang tidy and test coverage Signed-off-by: Yuchen Dai --- source/common/network/peer_buffer.h | 2 +- .../buffered_io_socket_handle_impl_test.cc | 52 +++++++++++++++++-- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 9ce027a6eb21f..2c4f8aafc25f0 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -72,7 +72,7 @@ class ReadableSource { */ class ReadWritable : public virtual ReadableSource, public virtual WritablePeer { public: - virtual ~ReadWritable() override = default; + ~ReadWritable() override = default; }; } // namespace Network } // namespace Envoy \ No newline at end of file diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 955759047193a..b2c9fb4e37351 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -100,7 +100,7 @@ TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { EXPECT_TRUE(result.ok()); } -// Test recv side effects. +// Test read side effects. TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { Buffer::OwnedImpl buf; auto result = io_handle_->read(buf, 10); @@ -111,7 +111,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { EXPECT_TRUE(result.ok()); } -// Test recv side effects. +// Test read side effects. TEST_F(BufferedIoSocketHandleTest, TestReadContent) { Buffer::OwnedImpl buf; auto& internal_buffer = io_handle_->getBufferForTest(); @@ -128,6 +128,31 @@ TEST_F(BufferedIoSocketHandleTest, TestReadContent) { ASSERT_EQ(0, internal_buffer.length()); } +// Test readv behavior. +TEST_F(BufferedIoSocketHandleTest, TestBasicReadv) { + Buffer::OwnedImpl buf_to_write("abc"); + io_handle_peer_->write(buf_to_write); + + Buffer::OwnedImpl buf; + Buffer::RawSlice slice; + buf.reserve(1024, &slice, 1); + auto result = io_handle_->readv(1024, &slice, 1); + + EXPECT_TRUE(result.ok()); + EXPECT_EQ(3, result.rc_); + + result = io_handle_->readv(1024, &slice, 1); + + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); + + io_handle_->setWriteEnd(); + result = io_handle_->readv(1024, &slice, 1); + // EOF + EXPECT_TRUE(result.ok()); + EXPECT_EQ(0, result.rc_); +} + // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); @@ -416,7 +441,6 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); - ENVOY_LOG_MISC(debug, "lambdai: next shutdown"); EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); } @@ -683,6 +707,16 @@ TEST_F(BufferedIoSocketHandleTest, TestConnect) { EXPECT_EQ(0, io_handle_->connect(address_is_ignored).rc_); } +TEST_F(BufferedIoSocketHandleTest, TestActivateEvent) { + scheduable_cb_ = new NiceMock(&dispatcher_); + io_handle_->initializeFileEvent( + dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::FileTriggerType::Edge, + Event::FileReadyType::Read); + EXPECT_FALSE(scheduable_cb_->enabled()); + io_handle_->activateFileEvents(Event::FileReadyType::Read); + ASSERT_TRUE(scheduable_cb_->enabled()); +} + TEST_F(BufferedIoSocketHandleTest, TestDeathOnActivatingDestroyedEvents) { io_handle_->resetFileEvents(); ASSERT_DEBUG_DEATH(io_handle_->activateFileEvents(Event::FileReadyType::Read), @@ -695,6 +729,18 @@ TEST_F(BufferedIoSocketHandleTest, TestDeathOnEnablingDestroyedEvents) { "Null user_file_event_"); } +TEST_F(BufferedIoSocketHandleTest, TestNotImplementDuplicate) { + ASSERT_DEATH(io_handle_->duplicate(), ""); +} + +TEST_F(BufferedIoSocketHandleTest, TestNotImplementAccept) { + ASSERT_DEATH(io_handle_->accept(nullptr, 0), ""); +} + +TEST_F(BufferedIoSocketHandleTest, TestLastRoundtripTimeNullOpt) { + ASSERT_EQ(absl::nullopt, io_handle_->lastRoundTripTime()); +} + class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { From 2e80156d45bedda0b368d195c52b30ffb062cff9 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 30 Oct 2020 05:39:28 +0000 Subject: [PATCH 40/88] ct Signed-off-by: Yuchen Dai --- test/common/network/buffered_io_socket_handle_impl_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index b2c9fb4e37351..2caabfee9f47f 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -734,7 +734,7 @@ TEST_F(BufferedIoSocketHandleTest, TestNotImplementDuplicate) { } TEST_F(BufferedIoSocketHandleTest, TestNotImplementAccept) { - ASSERT_DEATH(io_handle_->accept(nullptr, 0), ""); + ASSERT_DEATH(io_handle_->accept(nullptr, nullptr), ""); } TEST_F(BufferedIoSocketHandleTest, TestLastRoundtripTimeNullOpt) { From 089526f28ad45449ec4761a2160d8ce22f77bf3d Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 30 Oct 2020 22:54:17 +0000 Subject: [PATCH 41/88] address comments Signed-off-by: Yuchen Dai --- .../event/user_space_file_event_impl.cc | 4 +-- .../common/event/user_space_file_event_impl.h | 2 -- .../network/buffered_io_socket_handle_impl.cc | 6 ++++ .../network/buffered_io_socket_handle_impl.h | 24 +++++++------- source/common/network/peer_buffer.h | 23 ++++++------- .../event/user_space_file_event_impl_test.cc | 1 - .../buffered_io_socket_handle_impl_test.cc | 33 +++++++++++-------- 7 files changed, 49 insertions(+), 44 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index d41dc060834ba..0d8da7966e794 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -11,8 +11,8 @@ namespace Event { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, Network::ReadWritable& io_source) : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { - auto all_events = getEventListener().triggeredEvents(); - auto ephemeral_events = getEventListener().getAndClearEphemeralEvents(); + auto all_events = event_listener_.triggeredEvents(); + auto ephemeral_events = event_listener_.getAndClearEphemeralEvents(); ENVOY_LOG(trace, "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", static_cast(this), all_events, ephemeral_events); diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 15b29b8424d76..6ede629e7851f 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -79,8 +79,6 @@ class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable void {}) {} +BufferedIoSocketHandleImpl::~BufferedIoSocketHandleImpl() { + if (!closed_) { + close(); + } +} + Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { ASSERT(!closed_); if (!closed_) { diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index f1e8770053540..259ea30107fdb 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -33,7 +33,7 @@ class BufferedIoSocketHandleImpl : public IoHandle, public: BufferedIoSocketHandleImpl(); - ~BufferedIoSocketHandleImpl() override { ASSERT(closed_); } + ~BufferedIoSocketHandleImpl() override; // IoHandle os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } @@ -76,15 +76,6 @@ class BufferedIoSocketHandleImpl : public IoHandle, Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } - Buffer::WatermarkBuffer& getBufferForTest() { return pending_received_data_; } - - void setWritablePeer(WritablePeer* writable_peer) { - // Swapping writable peer is undefined behavior. - ASSERT(!writable_peer_); - ASSERT(!write_shutdown_); - writable_peer_ = writable_peer; - } - // WritablePeer void setWriteEnd() override { read_end_stream_ = true; } bool isWriteEndSet() override { return read_end_stream_; } @@ -103,20 +94,27 @@ class BufferedIoSocketHandleImpl : public IoHandle, user_file_event_->activate(Event::FileReadyType::Write); } } - bool isWritable() const override { return !isOverHighWatermark(); } + bool isWritable() const override { return !over_high_watermark_; } bool isPeerWritable() const override { return writable_peer_ != nullptr && !writable_peer_->isWriteEndSet() && writable_peer_->isWritable(); } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } - // ReadableSource + // ReadWritable bool isPeerShutDownWrite() const override { return read_end_stream_; } - bool isOverHighWatermark() const override { return over_high_watermark_; } bool isReadable() const override { return isPeerShutDownWrite() || pending_received_data_.length() > 0; } + // Set the peer which will populate the owned pending_received_data. + void setWritablePeer(WritablePeer* writable_peer) { + // Swapping writable peer is undefined behavior. + ASSERT(!writable_peer_); + ASSERT(!write_shutdown_); + writable_peer_ = writable_peer; + } + private: // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource // leak. diff --git a/source/common/network/peer_buffer.h b/source/common/network/peer_buffer.h index 2c4f8aafc25f0..f42592daee939 100644 --- a/source/common/network/peer_buffer.h +++ b/source/common/network/peer_buffer.h @@ -17,6 +17,9 @@ class WritablePeer { * Set the flag to indicate no further write from peer. */ virtual void setWriteEnd() PURE; + /** + * @return true if the peer promise no more write. + */ virtual bool isWriteEndSet() PURE; /** @@ -52,27 +55,21 @@ class WritablePeer { }; /** - * The interface for the buffer owner who want to consume the buffer. + * The interface as the union of ReadableSource and WritablePeer. */ -class ReadableSource { +class ReadWritable : public WritablePeer { public: - virtual ~ReadableSource() = default; + ~ReadWritable() override = default; /** * Read the flag to indicate no further write. Used by early close detection. */ virtual bool isPeerShutDownWrite() const PURE; - virtual bool isOverHighWatermark() const PURE; + /** + * @return true if the pending receive buffer is not full. + */ virtual bool isReadable() const PURE; }; - -/** - * The interface as the union of ReadableSource and WritablePeer. - */ -class ReadWritable : public virtual ReadableSource, public virtual WritablePeer { -public: - ~ReadWritable() override = default; -}; } // namespace Network -} // namespace Envoy \ No newline at end of file +} // namespace Envoy diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/common/event/user_space_file_event_impl_test.cc index f4b9fe4c7b116..b9c350239111c 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/common/event/user_space_file_event_impl_test.cc @@ -38,7 +38,6 @@ class MockReadWritable : public Network::ReadWritable { MOCK_METHOD(bool, isPeerWritable, (), (const)); MOCK_METHOD(void, onPeerBufferWritable, ()); MOCK_METHOD(bool, isPeerShutDownWrite, (), (const)); - MOCK_METHOD(bool, isOverHighWatermark, (), (const)); MOCK_METHOD(bool, isReadable, (), (const)); }; class UserSpaceFileEventImplTest : public testing::Test { diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 2caabfee9f47f..4429a4ceb21e7 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -51,6 +51,11 @@ class BufferedIoSocketHandleTest : public testing::Test { EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } + Buffer::WatermarkBuffer& + getWatermarkBufferHelper(Network::BufferedIoSocketHandleImpl& io_handle) { + return dynamic_cast(*io_handle.getWriteBuffer()); + } + NiceMock dispatcher_; // Owned by BufferedIoSocketHandle. @@ -114,7 +119,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { // Test read side effects. TEST_F(BufferedIoSocketHandleTest, TestReadContent) { Buffer::OwnedImpl buf; - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcdefg"); auto result = io_handle_->read(buf, 3); EXPECT_TRUE(result.ok()); @@ -165,7 +170,7 @@ TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { } TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); EXPECT_TRUE(result.ok()); @@ -176,7 +181,7 @@ TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { } TEST_F(BufferedIoSocketHandleTest, FlowControl) { - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); @@ -267,7 +272,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { EXPECT_CALL(cb_, called(_)).Times(0); // Drain 1 bytes. - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); auto result = io_handle_->recv(buf_.data(), 1, 0); EXPECT_TRUE(result.ok()); @@ -305,7 +310,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { } TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); @@ -340,7 +345,7 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { } TEST_F(BufferedIoSocketHandleTest, TestClose) { - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); @@ -400,7 +405,7 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { // Test that a readable event is raised when peer shutdown write. Also confirm read will return // EAGAIN. TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); std::string accumulator; @@ -451,8 +456,10 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownOptionsNotSupported) { TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { Buffer::OwnedImpl buf("0123456789"); - io_handle_peer_->write(buf); - auto& internal_buffer = io_handle_->getBufferForTest(); + auto result = io_handle_peer_->write(buf); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(10, result.rc_); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); EXPECT_EQ("0123456789", internal_buffer.toString()); EXPECT_EQ(0, buf.length()); } @@ -464,7 +471,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { { // Populate write destination with massive data so as to not writable. - auto& internal_buffer = io_handle_peer_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); internal_buffer.setWatermarks(1024); internal_buffer.add(std::string(2048, ' ')); @@ -497,7 +504,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevErrorCode) { { // Populate write destination with massive data so as to not writable. - auto& internal_buffer = io_handle_peer_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); internal_buffer.setWatermarks(1024); internal_buffer.add(std::string(2048, ' ')); result = io_handle_->writev(&slice, 1); @@ -533,7 +540,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { Buffer::RawSlice{raw_data.data() + 1, 2}, }; io_handle_peer_->writev(slices.data(), slices.size()); - auto& internal_buffer = io_handle_->getBufferForTest(); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); EXPECT_EQ(3, internal_buffer.length()); EXPECT_EQ("012", internal_buffer.toString()); } @@ -665,7 +672,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { } TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { - auto& peer_internal_buffer = io_handle_peer_->getBufferForTest(); + auto& peer_internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); peer_internal_buffer.setWatermarks(128); std::string big_chunk(256, 'a'); peer_internal_buffer.add(big_chunk); From f203b6e93a422aace633680433176ed5e48c2f6c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 30 Oct 2020 22:59:14 +0000 Subject: [PATCH 42/88] simplify test on new dtor Signed-off-by: Yuchen Dai --- .../network/buffered_io_socket_handle_impl_test.cc | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 4429a4ceb21e7..3b9472c799b77 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -36,14 +36,7 @@ class BufferedIoSocketHandleTest : public testing::Test { io_handle_peer_->setWritablePeer(io_handle_.get()); } - ~BufferedIoSocketHandleTest() override { - if (io_handle_->isOpen()) { - io_handle_->close(); - } - if (io_handle_peer_->isOpen()) { - io_handle_peer_->close(); - } - } + ~BufferedIoSocketHandleTest() override = default; void expectAgain() { auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); @@ -255,6 +248,7 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); + io_handle_->close(); } } From 34b18ed2bbfa9ffb6f5335e7d671eedf8df85cf4 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Fri, 30 Oct 2020 23:39:42 +0000 Subject: [PATCH 43/88] erase triggered events Signed-off-by: Yuchen Dai --- source/common/event/user_space_file_event_impl.cc | 11 ++++------- source/common/event/user_space_file_event_impl.h | 7 ------- .../network/buffered_io_socket_handle_impl_test.cc | 2 ++ 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.cc b/source/common/event/user_space_file_event_impl.cc index 0d8da7966e794..87c5c01576f69 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/common/event/user_space_file_event_impl.cc @@ -11,19 +11,16 @@ namespace Event { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, Network::ReadWritable& io_source) : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { - auto all_events = event_listener_.triggeredEvents(); auto ephemeral_events = event_listener_.getAndClearEphemeralEvents(); - ENVOY_LOG(trace, - "User space event {} invokes callbacks on allevents = {}, ephermal events = {}", - static_cast(this), all_events, ephemeral_events); - cb(all_events | ephemeral_events); + ENVOY_LOG(trace, "User space event {} invokes callbacks on events = {}", + static_cast(this), ephemeral_events); + cb(ephemeral_events); }), io_source_(io_source) { setEnabled(events); } -void EventListenerImpl::onEventEnabled(uint32_t enabled_events) { - enabled_events_ = enabled_events; +void EventListenerImpl::onEventEnabled(uint32_t) { // Clear ephemeral events to align with FileEventImpl::setEnable(). ephemeral_events_ = 0; } diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index 6ede629e7851f..b79e538c1fefc 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -23,8 +23,6 @@ class EventListener { public: virtual ~EventListener() = default; - // Get the events which are enabled and triggered. - virtual uint32_t triggeredEvents() PURE; // Get the events which are ephemerally activated. Upon returning the ephemeral events are // cleared. virtual uint32_t getAndClearEphemeralEvents() PURE; @@ -51,17 +49,12 @@ class EventListenerImpl : public EventListener { public: ~EventListenerImpl() override = default; - // The ready events are not preserved. All ready events must be notified by activate(). - uint32_t triggeredEvents() override { return 0; } - void onEventEnabled(uint32_t enabled_events) override; void onEventActivated(uint32_t activated_events) override; uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephemeral_events_, 0); } private: - // The persisted interested events. The name on libevent document is pending event. - uint32_t enabled_events_{}; // The events set by activate() and will be cleared after the io callback. uint32_t ephemeral_events_{}; }; diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/common/network/buffered_io_socket_handle_impl_test.cc index 3b9472c799b77..153b735b91ec9 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/common/network/buffered_io_socket_handle_impl_test.cc @@ -248,7 +248,9 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); scheduable_cb_->invokeCallback(); ASSERT_FALSE(scheduable_cb_->enabled()); + // Close io_handle_ first to prevent events originated from peer close. io_handle_->close(); + io_handle_peer_->close(); } } From 83bd452a057eb2c8d2271e085b6d9339dbeba028 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 08:26:16 +0000 Subject: [PATCH 44/88] final and remove EventListener interface Signed-off-by: Yuchen Dai --- .../common/event/user_space_file_event_impl.h | 36 ++++--------------- .../network/buffered_io_socket_handle_impl.h | 6 ++-- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/source/common/event/user_space_file_event_impl.h b/source/common/event/user_space_file_event_impl.h index b79e538c1fefc..2fc7a20ed65b3 100644 --- a/source/common/event/user_space_file_event_impl.h +++ b/source/common/event/user_space_file_event_impl.h @@ -13,46 +13,22 @@ namespace Envoy { namespace Network { class BufferedIoSocketHandleImpl; } -namespace Event { -// The interface of populating event watcher and obtaining the active events. The events are the -// combination of FileReadyType values. The event listener is populated by user event registration -// and io events passively. Also the owner of this listener query the activated events by calling -// triggeredEvents and getAndClearEphemeralEvents. -class EventListener { -public: - virtual ~EventListener() = default; - - // Get the events which are ephemerally activated. Upon returning the ephemeral events are - // cleared. - virtual uint32_t getAndClearEphemeralEvents() PURE; - - /** - * FileEvent::setEnabled is invoked. - * @param enabled_events supplied the event of setEnabled. - */ - virtual void onEventEnabled(uint32_t enabled_events) PURE; - - /** - * FileEvent::activate is invoked. - * @param enabled_events supplied the event of activate(). - */ - virtual void onEventActivated(uint32_t activated_events) PURE; -}; +namespace Event { // Return the enabled events except EV_CLOSED. This implementation is generally good since only // epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner // must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify // events which are not actually triggered. // TODO(lambdai): Add support of delivering EV_CLOSED. -class EventListenerImpl : public EventListener { +class EventListenerImpl { public: - ~EventListenerImpl() override = default; + ~EventListenerImpl() = default; - void onEventEnabled(uint32_t enabled_events) override; - void onEventActivated(uint32_t activated_events) override; + void onEventEnabled(uint32_t enabled_events); + void onEventActivated(uint32_t activated_events); - uint32_t getAndClearEphemeralEvents() override { return std::exchange(ephemeral_events_, 0); } + uint32_t getAndClearEphemeralEvents() { return std::exchange(ephemeral_events_, 0); } private: // The events set by activate() and will be cleared after the io callback. diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/common/network/buffered_io_socket_handle_impl.h index 259ea30107fdb..d26b9abfed22a 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/common/network/buffered_io_socket_handle_impl.h @@ -27,9 +27,9 @@ namespace Network { * 4. The peer BufferedIoSocket must be scheduled in the same thread to avoid data race because * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ -class BufferedIoSocketHandleImpl : public IoHandle, - public ReadWritable, - protected Logger::Loggable { +class BufferedIoSocketHandleImpl final : public IoHandle, + public ReadWritable, + protected Logger::Loggable { public: BufferedIoSocketHandleImpl(); From c98c4f9f86f709ae198a466ed2e8c52d77b41fe3 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 08:54:47 +0000 Subject: [PATCH 45/88] move to test extensions Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 2 - source/common/network/BUILD | 12 +---- source/extensions/io_socket/BUILD | 19 ++++++++ .../io_socket/buffered_io_socket/BUILD | 26 ++++++++++ .../buffered_io_socket_handle_impl.cc | 4 +- .../buffered_io_socket_handle_impl.h | 2 +- .../user_space_file_event_impl.cc | 2 +- .../user_space_file_event_impl.h | 0 .../extensions/io_socket/well_known_names.h | 34 +++++++++++++ test/common/event/BUILD | 15 ------ test/common/network/BUILD | 25 +--------- .../io_socket/buffered_io_socket/BUILD | 48 +++++++++++++++++++ ...red_io_socket_handle_impl_platform_test.cc | 2 +- .../buffered_io_socket_handle_impl_test.cc | 2 +- .../user_space_file_event_impl_test.cc | 2 +- 15 files changed, 136 insertions(+), 59 deletions(-) create mode 100644 source/extensions/io_socket/BUILD create mode 100644 source/extensions/io_socket/buffered_io_socket/BUILD rename source/{common/network => extensions/io_socket/buffered_io_socket}/buffered_io_socket_handle_impl.cc (98%) rename source/{common/network => extensions/io_socket/buffered_io_socket}/buffered_io_socket_handle_impl.h (98%) rename source/{common/event => extensions/io_socket/buffered_io_socket}/user_space_file_event_impl.cc (96%) rename source/{common/event => extensions/io_socket/buffered_io_socket}/user_space_file_event_impl.h (100%) create mode 100644 source/extensions/io_socket/well_known_names.h create mode 100644 test/extensions/io_socket/buffered_io_socket/BUILD rename test/{common/network => extensions/io_socket/buffered_io_socket}/buffered_io_socket_handle_impl_platform_test.cc (95%) rename test/{common/network => extensions/io_socket/buffered_io_socket}/buffered_io_socket_handle_impl_test.cc (99%) rename test/{common/event => extensions/io_socket/buffered_io_socket}/user_space_file_event_impl_test.cc (99%) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index 4633bb3887c7d..e931c2985ba83 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -14,7 +14,6 @@ envoy_cc_library( "dispatcher_impl.cc", "file_event_impl.cc", "signal_impl.cc", - "user_space_file_event_impl.cc", ], hdrs = [ "signal_impl.h", @@ -70,7 +69,6 @@ envoy_cc_library( "event_impl_base.h", "file_event_impl.h", "schedulable_cb_impl.h", - "user_space_file_event_impl.h", ], deps = [ ":libevent_lib", diff --git a/source/common/network/BUILD b/source/common/network/BUILD index 5f631932eb758..a2d0e26f0600e 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -480,14 +480,4 @@ envoy_cc_library( "//source/common/buffer:watermark_buffer_lib", "//source/common/common:empty_string", ], -) - -envoy_cc_library( - name = "buffered_io_socket_handle_lib", - srcs = ["buffered_io_socket_handle_impl.cc"], - hdrs = ["buffered_io_socket_handle_impl.h"], - deps = [ - "default_socket_interface_lib", - ":peer_buffer_lib", - ], -) +) \ No newline at end of file diff --git a/source/extensions/io_socket/BUILD b/source/extensions/io_socket/BUILD new file mode 100644 index 0000000000000..40a5e79b39d3b --- /dev/null +++ b/source/extensions/io_socket/BUILD @@ -0,0 +1,19 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_extension_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_extension_package() + +envoy_cc_library( + name = "well_known_names", + hdrs = ["well_known_names.h"], + # well known names files are public as long as they exist. + visibility = ["//visibility:public"], + deps = [ + "//source/common/singleton:const_singleton", + ], +) diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD new file mode 100644 index 0000000000000..539f9f1d22471 --- /dev/null +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -0,0 +1,26 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_library", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_library( + name = "buffered_io_socket_handle_lib", + srcs = [ + "buffered_io_socket_handle_impl.cc", + "user_space_file_event_impl.cc", + ], + hdrs = [ + "buffered_io_socket_handle_impl.h", + "user_space_file_event_impl.h", + ], + deps = [ + "//source/common/network:default_socket_interface_lib", + "//source/common/event:dispatcher_includes", + "//source/common/network:peer_buffer_lib", + ], +) diff --git a/source/common/network/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc similarity index 98% rename from source/common/network/buffered_io_socket_handle_impl.cc rename to source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index 1c8cc4fd8892b..0b1b8cf2bcdfb 100644 --- a/source/common/network/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -1,4 +1,4 @@ -#include "common/network/buffered_io_socket_handle_impl.h" +#include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" #include "envoy/buffer/buffer.h" #include "envoy/common/platform.h" @@ -6,7 +6,7 @@ #include "common/api/os_sys_calls_impl.h" #include "common/common/assert.h" #include "common/common/utility.h" -#include "common/event/user_space_file_event_impl.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/address_impl.h" #include "absl/container/fixed_array.h" diff --git a/source/common/network/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h similarity index 98% rename from source/common/network/buffered_io_socket_handle_impl.h rename to source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index d26b9abfed22a..17b4c89f52ea1 100644 --- a/source/common/network/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -10,7 +10,7 @@ #include "common/buffer/watermark_buffer.h" #include "common/common/logger.h" -#include "common/event/user_space_file_event_impl.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/io_socket_error_impl.h" #include "common/network/peer_buffer.h" diff --git a/source/common/event/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc similarity index 96% rename from source/common/event/user_space_file_event_impl.cc rename to source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index 87c5c01576f69..3499c2b905953 100644 --- a/source/common/event/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -1,4 +1,4 @@ -#include "common/event/user_space_file_event_impl.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include diff --git a/source/common/event/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h similarity index 100% rename from source/common/event/user_space_file_event_impl.h rename to source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h diff --git a/source/extensions/io_socket/well_known_names.h b/source/extensions/io_socket/well_known_names.h new file mode 100644 index 0000000000000..86ab21d36be5a --- /dev/null +++ b/source/extensions/io_socket/well_known_names.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +#include "common/singleton/const_singleton.h" + +namespace Envoy { +namespace Extensions { +namespace IoSocket { + +/** + * Well-known io socket names. + * NOTE: New io sockets should use the well known name: envoy.io_socket.name. + */ +class IoSocketNameValues { +public: + const std::string BufferedIoSocket = "envoy.io_socket.buffered_io_socket"; +}; + +using IoSocketNames = ConstSingleton; + +/** + * Well-known io socket names. + */ +class IoSocketShortNameValues { +public: + const std::string BufferedIoSocket = "buffered_io_socket"; +}; + +using IoSocketShortNameValues = ConstSingleton; + +} // namespace IoSocket +} // namespace Extensions +} // namespace Envoy diff --git a/test/common/event/BUILD b/test/common/event/BUILD index 3095b3600a6b2..882d2afa95068 100644 --- a/test/common/event/BUILD +++ b/test/common/event/BUILD @@ -42,21 +42,6 @@ envoy_cc_test( ], ) -envoy_cc_test( - name = "user_space_file_event_impl_test", - srcs = ["user_space_file_event_impl_test.cc"], - deps = [ - "//include/envoy/event:file_event_interface", - "//source/common/event:dispatcher_includes", - "//source/common/event:dispatcher_lib", - "//source/common/network:peer_buffer_lib", - "//test/mocks:common_lib", - "//test/test_common:environment_lib", - "//test/test_common:test_runtime_lib", - "//test/test_common:utility_lib", - ], -) - envoy_cc_test( name = "scaled_range_timer_manager_impl_test", srcs = ["scaled_range_timer_manager_impl_test.cc"], diff --git a/test/common/network/BUILD b/test/common/network/BUILD index 7ccb038ed1cb3..ceed3c112081d 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -450,27 +450,4 @@ envoy_cc_test( "//source/common/network:filter_matcher_lib", "//test/mocks/network:network_mocks", ], -) - -envoy_cc_test( - name = "buffered_io_socket_handle_impl_test", - srcs = ["buffered_io_socket_handle_impl_test.cc"], - deps = [ - "//source/common/common:utility_lib", - "//source/common/network:address_lib", - "//source/common/network:buffered_io_socket_handle_lib", - "//test/mocks/event:event_mocks", - ], -) - -envoy_cc_test( - name = "buffered_io_socket_handle_impl_platform_test", - srcs = ["buffered_io_socket_handle_impl_platform_test.cc"], - tags = ["fails_on_windows"], - deps = [ - "//source/common/common:utility_lib", - "//source/common/network:address_lib", - "//source/common/network:buffered_io_socket_handle_lib", - "//test/mocks/event:event_mocks", - ], -) +) \ No newline at end of file diff --git a/test/extensions/io_socket/buffered_io_socket/BUILD b/test/extensions/io_socket/buffered_io_socket/BUILD new file mode 100644 index 0000000000000..55b7b5d1e2df7 --- /dev/null +++ b/test/extensions/io_socket/buffered_io_socket/BUILD @@ -0,0 +1,48 @@ +load( + "//bazel:envoy_build_system.bzl", + "envoy_cc_test", + "envoy_package", +) + +licenses(["notice"]) # Apache 2 + +envoy_package() + +envoy_cc_test( + name = "buffered_io_socket_handle_impl_test", + srcs = ["buffered_io_socket_handle_impl_test.cc"], + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", + "//test/mocks/event:event_mocks", + ], +) + +envoy_cc_test( + name = "buffered_io_socket_handle_impl_platform_test", + srcs = ["buffered_io_socket_handle_impl_platform_test.cc"], + tags = ["fails_on_windows"], + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", + "//test/mocks/event:event_mocks", + ], +) + +envoy_cc_test( + name = "user_space_file_event_impl_test", + srcs = ["user_space_file_event_impl_test.cc"], + deps = [ + "//include/envoy/event:file_event_interface", + "//source/common/event:dispatcher_includes", + "//source/common/event:dispatcher_lib", + "//source/common/network:peer_buffer_lib", + "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", + "//test/mocks:common_lib", + "//test/test_common:environment_lib", + "//test/test_common:test_runtime_lib", + "//test/test_common:utility_lib", + ], +) diff --git a/test/common/network/buffered_io_socket_handle_impl_platform_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc similarity index 95% rename from test/common/network/buffered_io_socket_handle_impl_platform_test.cc rename to test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc index c7044eacd1ac4..7c56aaee43e50 100644 --- a/test/common/network/buffered_io_socket_handle_impl_platform_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc @@ -1,7 +1,7 @@ #include "envoy/common/platform.h" #include "envoy/event/file_event.h" -#include "common/network/buffered_io_socket_handle_impl.h" +#include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" #include "test/mocks/event/mocks.h" diff --git a/test/common/network/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc similarity index 99% rename from test/common/network/buffered_io_socket_handle_impl_test.cc rename to test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 153b735b91ec9..fdda535be8734 100644 --- a/test/common/network/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -2,7 +2,7 @@ #include "common/buffer/buffer_impl.h" #include "common/network/address_impl.h" -#include "common/network/buffered_io_socket_handle_impl.h" +#include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" #include "test/mocks/event/mocks.h" diff --git a/test/common/event/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc similarity index 99% rename from test/common/event/user_space_file_event_impl_test.cc rename to test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index b9c350239111c..d4704ed861dc6 100644 --- a/test/common/event/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -3,7 +3,7 @@ #include "envoy/event/file_event.h" #include "common/event/dispatcher_impl.h" -#include "common/event/user_space_file_event_impl.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/peer_buffer.h" #include "test/mocks/common.h" From 8d87a543d0348d2a4fddfea35c9ff003f83fef37 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 09:15:14 +0000 Subject: [PATCH 46/88] ns Extensions::IoSocket::BufferedIoSocket Signed-off-by: Yuchen Dai --- .../io_socket/buffered_io_socket/BUILD | 2 +- .../buffered_io_socket_handle_impl.cc | 91 ++++++++++--------- .../buffered_io_socket_handle_impl.h | 56 +++++++----- .../user_space_file_event_impl.cc | 23 +++-- .../user_space_file_event_impl.h | 17 ++-- 5 files changed, 104 insertions(+), 85 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index 539f9f1d22471..ff9a710ff569e 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -19,8 +19,8 @@ envoy_cc_library( "user_space_file_event_impl.h", ], deps = [ - "//source/common/network:default_socket_interface_lib", "//source/common/event:dispatcher_includes", + "//source/common/network:default_socket_interface_lib", "//source/common/network:peer_buffer_lib", ], ) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index 0b1b8cf2bcdfb..25668e00e012b 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -13,8 +13,10 @@ #include "absl/types/optional.h" namespace Envoy { -namespace Network { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { namespace { Api::SysCallIntResult makeInvalidSyscall() { return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP}; @@ -70,15 +72,16 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, uint64_t num_slice) { if (!isOpen()) { return {0, - // TODO(lambdai): Add EBADF in IoSocketError and adopt it here. - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + // TODO(lambdai): Add EBADF in Network::IoSocketError and adopt it here. + Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), + Network::IoSocketError::deleteIoError)}; } } absl::FixedArray iov(num_slice); @@ -100,15 +103,15 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, uint64_t max_length) { if (!isOpen()) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), + Network::IoSocketError::deleteIoError)}; } } // TODO(lambdai): Move at slice boundary to move to reduce the copy. @@ -120,24 +123,24 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, uint64_t num_slice) { if (!isOpen()) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // Closed peer. if (!writable_peer_) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // Error: write after close. if (writable_peer_->isWriteEndSet()) { // TODO(lambdai): EPIPE or ENOTCONN - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // The peer is valid but temporary not accepts new data. Likely due to flow control. if (!writable_peer_->isWritable()) { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), + Network::IoSocketError::deleteIoError)}; } // Write along with iteration. Buffer guarantee the fragment is always append-able. uint64_t bytes_written = 0; @@ -154,24 +157,24 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buffer) { if (!isOpen()) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // Closed peer. if (!writable_peer_) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // Error: write after close. if (writable_peer_->isWriteEndSet()) { // TODO(lambdai): EPIPE or ENOTCONN - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // The peer is valid but temporary not accepts new data. Likely due to flow control. if (!writable_peer_->isWritable()) { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), + Network::IoSocketError::deleteIoError)}; } uint64_t total_bytes_to_write = buffer.length(); writable_peer_->getWriteBuffer()->move(buffer); @@ -181,33 +184,33 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff } Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, - const Address::Ip*, - const Address::Instance&) { - return IoSocketError::ioResultSocketInvalidAddress(); + const Network::Address::Ip*, + const Network::Address::Instance&) { + return Network::IoSocketError::ioResultSocketInvalidAddress(); } Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmsg(Buffer::RawSlice*, const uint64_t, uint32_t, RecvMsgOutput&) { - return IoSocketError::ioResultSocketInvalidAddress(); + return Network::IoSocketError::ioResultSocketInvalidAddress(); } Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmmsg(RawSliceArrays&, uint32_t, RecvMsgOutput&) { - return IoSocketError::ioResultSocketInvalidAddress(); + return Network::IoSocketError::ioResultSocketInvalidAddress(); } Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { if (!isOpen()) { - return {0, - Api::IoErrorPtr(new IoSocketError(SOCKET_ERROR_INVAL), IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), + Network::IoSocketError::deleteIoError)}; } // No data and the writer closed. if (pending_received_data_.length() == 0) { if (read_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { - return {0, Api::IoErrorPtr(IoSocketError::getIoSocketEagainInstance(), - IoSocketError::deleteIoError)}; + return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), + Network::IoSocketError::deleteIoError)}; } } auto max_bytes_to_read = std::min(pending_received_data_.length(), length); @@ -222,17 +225,18 @@ bool BufferedIoSocketHandleImpl::supportsMmsg() const { return false; } bool BufferedIoSocketHandleImpl::supportsUdpGro() const { return false; } -Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Address::InstanceConstSharedPtr) { +Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Network::Address::InstanceConstSharedPtr) { return makeInvalidSyscall(); } Api::SysCallIntResult BufferedIoSocketHandleImpl::listen(int) { return makeInvalidSyscall(); } -IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { +Network::IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } -Api::SysCallIntResult BufferedIoSocketHandleImpl::connect(Address::InstanceConstSharedPtr) { +Api::SysCallIntResult +BufferedIoSocketHandleImpl::connect(Network::Address::InstanceConstSharedPtr) { // Buffered Io handle should always be considered as connected. // Use write or read to determine if peer is closed. return {0, 0}; @@ -250,11 +254,11 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::setBlocking(bool) { return mak absl::optional BufferedIoSocketHandleImpl::domain() { return absl::nullopt; } -Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { +Network::Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); } -Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { +Network::Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); } @@ -265,9 +269,10 @@ void BufferedIoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatch ASSERT(user_file_event_ == nullptr, "Attempting to initialize two `file_event_` for the same " "file descriptor. This is not allowed."); ASSERT(trigger == Event::FileTriggerType::Edge, "Only support edge type."); - user_file_event_ = std::make_unique(dispatcher, cb, events, *this); + user_file_event_ = std::make_unique(dispatcher, cb, events, *this); } -IoHandlePtr BufferedIoSocketHandleImpl::duplicate() { + +Network::IoHandlePtr BufferedIoSocketHandleImpl::duplicate() { // duplicate() is supposed to be used on listener io handle while this implementation doesn't // support listen. NOT_IMPLEMENTED_GCOVR_EXCL_LINE; @@ -304,5 +309,7 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { } return {0, 0}; } -} // namespace Network +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy \ No newline at end of file diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index 17b4c89f52ea1..faadc0672f3c1 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -15,11 +15,12 @@ #include "common/network/peer_buffer.h" namespace Envoy { -namespace Network { - +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { /** - * IoHandle implementation which provides a buffer as data source. It is designed to used by - * Network::ConnectionImpl. Some known limitations include + * Network::IoHandle implementation which provides a buffer as data source. It is designed to used + * by Network::ConnectionImpl. Some known limitations include * 1. It doesn't not include a file descriptor. Do not use "fdDoNotUse". * 2. It doesn't support socket options. Wrap this in ConnectionSocket and implement the socket * getter/setter options. @@ -27,15 +28,15 @@ namespace Network { * 4. The peer BufferedIoSocket must be scheduled in the same thread to avoid data race because * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ -class BufferedIoSocketHandleImpl final : public IoHandle, - public ReadWritable, +class BufferedIoSocketHandleImpl final : public Network::IoHandle, + public Network::ReadWritable, protected Logger::Loggable { public: BufferedIoSocketHandleImpl(); ~BufferedIoSocketHandleImpl() override; - // IoHandle + // Network::IoHandle os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } Api::IoCallUint64Result close() override; bool isOpen() const override; @@ -45,8 +46,8 @@ class BufferedIoSocketHandleImpl final : public IoHandle, Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; Api::IoCallUint64Result write(Buffer::Instance& buffer) override; Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, - const Address::Ip* self_ip, - const Address::Instance& peer_address) override; + const Network::Address::Ip* self_ip, + const Network::Address::Instance& peer_address) override; Api::IoCallUint64Result recvmsg(Buffer::RawSlice* slices, const uint64_t num_slice, uint32_t self_port, RecvMsgOutput& output) override; Api::IoCallUint64Result recvmmsg(RawSliceArrays& slices, uint32_t self_port, @@ -54,21 +55,21 @@ class BufferedIoSocketHandleImpl final : public IoHandle, Api::IoCallUint64Result recv(void* buffer, size_t length, int flags) override; bool supportsMmsg() const override; bool supportsUdpGro() const override; - Api::SysCallIntResult bind(Address::InstanceConstSharedPtr address) override; + Api::SysCallIntResult bind(Network::Address::InstanceConstSharedPtr address) override; Api::SysCallIntResult listen(int backlog) override; - IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; - Api::SysCallIntResult connect(Address::InstanceConstSharedPtr address) override; + Network::IoHandlePtr accept(struct sockaddr* addr, socklen_t* addrlen) override; + Api::SysCallIntResult connect(Network::Address::InstanceConstSharedPtr address) override; Api::SysCallIntResult setOption(int level, int optname, const void* optval, socklen_t optlen) override; Api::SysCallIntResult getOption(int level, int optname, void* optval, socklen_t* optlen) override; Api::SysCallIntResult setBlocking(bool blocking) override; absl::optional domain() override; - Address::InstanceConstSharedPtr localAddress() override; - Address::InstanceConstSharedPtr peerAddress() override; + Network::Address::InstanceConstSharedPtr localAddress() override; + Network::Address::InstanceConstSharedPtr peerAddress() override; void initializeFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, Event::FileTriggerType trigger, uint32_t events) override; - IoHandlePtr duplicate() override; + Network::IoHandlePtr duplicate() override; void activateFileEvents(uint32_t events) override; void enableFileEvents(uint32_t events) override; void resetFileEvents() override; @@ -76,7 +77,7 @@ class BufferedIoSocketHandleImpl final : public IoHandle, Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } - // WritablePeer + // Network::WritablePeer void setWriteEnd() override { read_end_stream_ = true; } bool isWriteEndSet() override { return read_end_stream_; } void maybeSetNewData() override { @@ -101,14 +102,14 @@ class BufferedIoSocketHandleImpl final : public IoHandle, } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } - // ReadWritable + // Network::ReadWritable bool isPeerShutDownWrite() const override { return read_end_stream_; } bool isReadable() const override { return isPeerShutDownWrite() || pending_received_data_.length() > 0; } // Set the peer which will populate the owned pending_received_data. - void setWritablePeer(WritablePeer* writable_peer) { + void setWritablePeer(Network::WritablePeer* writable_peer) { // Swapping writable peer is undefined behavior. ASSERT(!writable_peer_); ASSERT(!write_shutdown_); @@ -116,28 +117,33 @@ class BufferedIoSocketHandleImpl final : public IoHandle, } private: - // Support isOpen() and close(). IoHandle owner must invoke close() to avoid potential resource - // leak. + // Support isOpen() and close(). Network::IoHandle owner must invoke close() to avoid potential + // resource leak. bool closed_{false}; // The attached file event with this socket. The event is not owned by the socket in the current // Envoy model. Multiple events can be created during the life time of this IO handle but at any // moment at most 1 event is attached. - std::unique_ptr user_file_event_; + std::unique_ptr user_file_event_; // True if pending_received_data_ is not addable. Note that pending_received_data_ may have // pending data to drain. bool read_end_stream_{false}; + + // The buffer owned by this socket. This buffer is populated by the write operations of the peer + // socket and drained by read operations of this socket. Buffer::WatermarkBuffer pending_received_data_; - // Destination of the write(). - WritablePeer* writable_peer_{nullptr}; + // Destination of the write(). The value remains non-null until the peer is closed. + Network::WritablePeer* writable_peer_{nullptr}; // The flag whether the peer is valid. Any write attempt must check this flag. bool write_shutdown_{false}; + // The watermark state of pending_received_data_. bool over_high_watermark_{false}; }; - -} // namespace Network +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy \ No newline at end of file diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index 3499c2b905953..03b08ed489f1a 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -6,7 +6,9 @@ #include "common/network/peer_buffer.h" namespace Envoy { -namespace Event { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, Network::ReadWritable& io_source) @@ -34,23 +36,25 @@ void EventListenerImpl::onEventActivated(uint32_t activated_events) { void UserSpaceFileEventImpl::activate(uint32_t events) { // Only supported event types are set. - ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); + ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | + Event::FileReadyType::Closed)) == events); event_listener_.onEventActivated(events); schedulable_->scheduleCallbackNextIteration(); } void UserSpaceFileEventImpl::setEnabled(uint32_t events) { // Only supported event types are set. - ASSERT((events & (FileReadyType::Read | FileReadyType::Write | FileReadyType::Closed)) == events); + ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | + Event::FileReadyType::Closed)) == events); event_listener_.onEventEnabled(events); bool was_enabled = schedulable_->enabled(); // Recalculate activated events. uint32_t events_to_notify = 0; - if ((events & FileReadyType::Read) && io_source_.isReadable()) { - events_to_notify |= FileReadyType::Read; + if ((events & Event::FileReadyType::Read) && io_source_.isReadable()) { + events_to_notify |= Event::FileReadyType::Read; } - if ((events & FileReadyType::Write) && io_source_.isPeerWritable()) { - events_to_notify |= FileReadyType::Write; + if ((events & Event::FileReadyType::Write) && io_source_.isPeerWritable()) { + events_to_notify |= Event::FileReadyType::Write; } if (events_to_notify != 0) { activate(events_to_notify); @@ -60,6 +64,7 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", static_cast(this), events, was_enabled ? "not " : ""); } - -} // namespace Event +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy \ No newline at end of file diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h index 2fc7a20ed65b3..0ad34ca1ff949 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h @@ -10,11 +10,11 @@ namespace Envoy { -namespace Network { -class BufferedIoSocketHandleImpl; -} +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { -namespace Event { +class BufferedIoSocketHandleImpl; // Return the enabled events except EV_CLOSED. This implementation is generally good since only // epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner @@ -37,7 +37,7 @@ class EventListenerImpl { // A FileEvent implementation which is used to drive BufferedIoSocketHandle. // Declare the class final to safely call virtual function setEnabled in constructor. -class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable { +class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::Loggable { public: UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, Network::ReadWritable& io_source); @@ -48,7 +48,7 @@ class UserSpaceFileEventImpl final : public FileEvent, Logger::Loggable Date: Mon, 2 Nov 2020 09:24:18 +0000 Subject: [PATCH 47/88] test: ns Extensions::IoSocket::BufferedIoSocket Signed-off-by: Yuchen Dai --- ...red_io_socket_handle_impl_platform_test.cc | 16 +++++---- .../buffered_io_socket_handle_impl_test.cc | 30 +++++++++------- .../user_space_file_event_impl_test.cc | 34 +++++++++++-------- 3 files changed, 46 insertions(+), 34 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc index 7c56aaee43e50..3fee0d4b13784 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc @@ -9,7 +9,9 @@ #include "gtest/gtest.h" namespace Envoy { -namespace Network { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { namespace { using testing::NiceMock; @@ -23,8 +25,8 @@ class MockFileEventCallback { class BufferedIoSocketHandlePlatformTest : public testing::Test { public: BufferedIoSocketHandlePlatformTest() { - io_handle_ = std::make_unique(); - io_handle_peer_ = std::make_unique(); + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); io_handle_->setWritablePeer(io_handle_peer_.get()); io_handle_peer_->setWritablePeer(io_handle_.get()); } @@ -38,8 +40,8 @@ class BufferedIoSocketHandlePlatformTest : public testing::Test { } } - std::unique_ptr io_handle_; - std::unique_ptr io_handle_peer_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; NiceMock dispatcher_; MockFileEventCallback cb_; }; @@ -53,5 +55,7 @@ TEST_F(BufferedIoSocketHandlePlatformTest, TestCreatePlatformDefaultTriggerTypeF } } // namespace -} // namespace Network +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index fdda535be8734..f099222bcf1e2 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -14,7 +14,9 @@ using testing::_; using testing::NiceMock; namespace Envoy { -namespace Network { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { namespace { MATCHER(IsInvalidateAddress, "") { @@ -30,8 +32,8 @@ class MockFileEventCallback { class BufferedIoSocketHandleTest : public testing::Test { public: BufferedIoSocketHandleTest() : buf_(1024) { - io_handle_ = std::make_unique(); - io_handle_peer_ = std::make_unique(); + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); io_handle_->setWritablePeer(io_handle_peer_.get()); io_handle_peer_->setWritablePeer(io_handle_.get()); } @@ -45,7 +47,7 @@ class BufferedIoSocketHandleTest : public testing::Test { } Buffer::WatermarkBuffer& - getWatermarkBufferHelper(Network::BufferedIoSocketHandleImpl& io_handle) { + getWatermarkBufferHelper(BufferedIoSocketHandleImpl& io_handle) { return dynamic_cast(*io_handle.getWriteBuffer()); } @@ -54,8 +56,8 @@ class BufferedIoSocketHandleTest : public testing::Test { // Owned by BufferedIoSocketHandle. NiceMock* scheduable_cb_; MockFileEventCallback cb_; - std::unique_ptr io_handle_; - std::unique_ptr io_handle_peer_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; absl::FixedArray buf_; }; @@ -175,7 +177,7 @@ TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { TEST_F(BufferedIoSocketHandleTest, FlowControl) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - WritablePeer* handle_as_peer = io_handle_.get(); + Network::WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_peer_->isWritable()); @@ -307,7 +309,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - WritablePeer* handle_as_peer = io_handle_.get(); + Network::WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_peer_->isWritable()); @@ -747,8 +749,8 @@ TEST_F(BufferedIoSocketHandleTest, TestLastRoundtripTimeNullOpt) { class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { - io_handle_ = std::make_unique(); - io_handle_peer_ = std::make_unique(); + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); io_handle_->setWritablePeer(io_handle_peer_.get()); io_handle_peer_->setWritablePeer(io_handle_.get()); } @@ -762,8 +764,8 @@ class BufferedIoSocketHandleNotImplementedTest : public testing::Test { } } - std::unique_ptr io_handle_; - std::unique_ptr io_handle_peer_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; Buffer::RawSlice slice_; }; @@ -813,5 +815,7 @@ TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnGetOption) { EXPECT_THAT(io_handle_->getOption(0, 0, nullptr, nullptr), IsNotSupportedResult()); } } // namespace -} // namespace Network +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index d4704ed861dc6..8285e254473bb 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -15,7 +15,9 @@ #include "gtest/gtest.h" namespace Envoy { -namespace Event { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { namespace { using testing::NiceMock; @@ -52,20 +54,20 @@ class UserSpaceFileEventImplTest : public testing::Test { NiceMock io_source_; MockReadyCb ready_cb_; Api::ApiPtr api_; - DispatcherPtr dispatcher_; - std::unique_ptr user_file_event_; + Event::DispatcherPtr dispatcher_; + std::unique_ptr user_file_event_; }; TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { setWritable(); - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - EXPECT_CALL(ready_cb_, called(FileReadyType::Write)); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { SCOPED_TRACE("1st schedule"); @@ -83,7 +85,7 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { } TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { SCOPED_TRACE("1st schedule"); @@ -107,7 +109,7 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents SCOPED_TRACE(absl::StrCat("current event:", current_event)); EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(true)).RetiresOnSaturation(); EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(false)).RetiresOnSaturation(); - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); // user_file_event_->activate(e); EXPECT_CALL(ready_cb_, called(current_event)); @@ -120,7 +122,7 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents SCOPED_TRACE(absl::StrCat("current event:", current_event)); EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(false)).RetiresOnSaturation(); EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(true)).RetiresOnSaturation(); - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); // user_file_event_->activate(e); EXPECT_CALL(ready_cb_, called(current_event)); @@ -133,7 +135,7 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents SCOPED_TRACE(absl::StrCat("current event:", current_event)); EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(true)).RetiresOnSaturation(); EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(true)).RetiresOnSaturation(); - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); // user_file_event_->activate(e); EXPECT_CALL(ready_cb_, called(current_event)); @@ -144,7 +146,7 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { // IO is neither readable nor writable. - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { EXPECT_CALL(ready_cb_, called(_)).Times(0); @@ -164,7 +166,7 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { // IO is neither readable nor writable. - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { EXPECT_CALL(ready_cb_, called(_)).Times(0); @@ -186,7 +188,7 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { // IO is neither readable nor writable. - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { EXPECT_CALL(ready_cb_, called(_)).Times(0); @@ -208,7 +210,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { } TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyActivated) { - user_file_event_ = std::make_unique( + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileReadyType::Write | Event::FileReadyType::Closed, io_source_); { @@ -231,5 +233,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyAct } } // namespace -} // namespace Event +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy \ No newline at end of file From f780926e81553edb9a0f82239f6dc964bffc7e83 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 09:32:56 +0000 Subject: [PATCH 48/88] codeformat and owners Signed-off-by: Yuchen Dai --- CODEOWNERS | 2 ++ source/common/network/BUILD | 2 +- source/extensions/io_socket/buffered_io_socket/BUILD | 4 ++-- .../buffered_io_socket/buffered_io_socket_handle_impl.cc | 3 ++- .../buffered_io_socket/buffered_io_socket_handle_impl.h | 3 ++- test/common/network/BUILD | 2 +- .../buffered_io_socket/buffered_io_socket_handle_impl_test.cc | 4 ++-- .../buffered_io_socket/user_space_file_event_impl_test.cc | 3 ++- 8 files changed, 14 insertions(+), 9 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 66d902367b362..2e4731444c02f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -152,3 +152,5 @@ extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp # HTTP Local Rate Limit /*/extensions/filters/http/local_ratelimit @rgs1 @mattklein123 /*/extensions/filters/common/local_ratelimit @mattklein123 @rgs1 +# user space socket pair and event +/*/extensions/io_socket/buffered_io_socket @lambdai @antoniovicente \ No newline at end of file diff --git a/source/common/network/BUILD b/source/common/network/BUILD index a2d0e26f0600e..d9a6e7717671d 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -480,4 +480,4 @@ envoy_cc_library( "//source/common/buffer:watermark_buffer_lib", "//source/common/common:empty_string", ], -) \ No newline at end of file +) diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index ff9a710ff569e..5046e7a2f10c9 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -1,12 +1,12 @@ load( "//bazel:envoy_build_system.bzl", "envoy_cc_library", - "envoy_package", + "envoy_extension_package", ) licenses(["notice"]) # Apache 2 -envoy_package() +envoy_extension_package() envoy_cc_library( name = "buffered_io_socket_handle_lib", diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index 25668e00e012b..5cf5bad161bcf 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -6,9 +6,10 @@ #include "common/api/os_sys_calls_impl.h" #include "common/common/assert.h" #include "common/common/utility.h" -#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/address_impl.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" + #include "absl/container/fixed_array.h" #include "absl/types/optional.h" diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index faadc0672f3c1..2dea13134fc3e 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -10,10 +10,11 @@ #include "common/buffer/watermark_buffer.h" #include "common/common/logger.h" -#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/io_socket_error_impl.h" #include "common/network/peer_buffer.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" + namespace Envoy { namespace Extensions { namespace IoSocket { diff --git a/test/common/network/BUILD b/test/common/network/BUILD index ceed3c112081d..e92b72c35af09 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -450,4 +450,4 @@ envoy_cc_test( "//source/common/network:filter_matcher_lib", "//test/mocks/network:network_mocks", ], -) \ No newline at end of file +) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index f099222bcf1e2..7a738911d7c97 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -2,6 +2,7 @@ #include "common/buffer/buffer_impl.h" #include "common/network/address_impl.h" + #include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" #include "test/mocks/event/mocks.h" @@ -46,8 +47,7 @@ class BufferedIoSocketHandleTest : public testing::Test { EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); } - Buffer::WatermarkBuffer& - getWatermarkBufferHelper(BufferedIoSocketHandleImpl& io_handle) { + Buffer::WatermarkBuffer& getWatermarkBufferHelper(BufferedIoSocketHandleImpl& io_handle) { return dynamic_cast(*io_handle.getWriteBuffer()); } diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index 8285e254473bb..690d8653aa427 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -3,9 +3,10 @@ #include "envoy/event/file_event.h" #include "common/event/dispatcher_impl.h" -#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "common/network/peer_buffer.h" +#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" + #include "test/mocks/common.h" #include "test/test_common/environment.h" #include "test/test_common/test_runtime.h" From aefff6a825341cde7b74b1f6ab660f7851a6abcf Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 19:41:02 +0000 Subject: [PATCH 49/88] moving peer buffer to extension Signed-off-by: Yuchen Dai --- source/common/event/BUILD | 1 - source/common/event/file_event_impl.h | 2 +- source/common/network/BUILD | 10 ---------- source/common/network/io_socket_error_impl.h | 2 +- source/extensions/io_socket/buffered_io_socket/BUILD | 12 +++++++++++- .../buffered_io_socket_handle_impl.h | 12 ++++++------ .../io_socket/buffered_io_socket}/peer_buffer.h | 8 ++++++-- .../buffered_io_socket/user_space_file_event_impl.cc | 5 +++-- .../buffered_io_socket/user_space_file_event_impl.h | 7 ++++--- test/common/network/BUILD | 4 ++-- test/extensions/io_socket/buffered_io_socket/BUILD | 2 +- .../buffered_io_socket_handle_impl_test.cc | 4 ++-- .../user_space_file_event_impl_test.cc | 4 ++-- 13 files changed, 39 insertions(+), 34 deletions(-) rename source/{common/network => extensions/io_socket/buffered_io_socket}/peer_buffer.h (91%) diff --git a/source/common/event/BUILD b/source/common/event/BUILD index e931c2985ba83..5e538bc52cf67 100644 --- a/source/common/event/BUILD +++ b/source/common/event/BUILD @@ -81,7 +81,6 @@ envoy_cc_library( "//source/common/common:minimal_logger_lib", "//source/common/common:thread_lib", "//source/common/signal:fatal_error_handler_lib", - "//source/common/network:peer_buffer_lib", ] + select({ "//bazel:disable_signal_trace": [], "//conditions:default": [ diff --git a/source/common/event/file_event_impl.h b/source/common/event/file_event_impl.h index cb55214831832..cc3e505d788bb 100644 --- a/source/common/event/file_event_impl.h +++ b/source/common/event/file_event_impl.h @@ -42,4 +42,4 @@ class FileEventImpl : public FileEvent, ImplBase { const bool activate_fd_events_next_event_loop_; }; } // namespace Event -} // namespace Envoy \ No newline at end of file +} // namespace Envoy diff --git a/source/common/network/BUILD b/source/common/network/BUILD index d9a6e7717671d..9840662f797a4 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -471,13 +471,3 @@ envoy_cc_library( "//source/common/common:macros", ], ) - -envoy_cc_library( - name = "peer_buffer_lib", - hdrs = ["peer_buffer.h"], - deps = [ - "//source/common/buffer:buffer_lib", - "//source/common/buffer:watermark_buffer_lib", - "//source/common/common:empty_string", - ], -) diff --git a/source/common/network/io_socket_error_impl.h b/source/common/network/io_socket_error_impl.h index e101ee4ee4998..50d08b55f26a0 100644 --- a/source/common/network/io_socket_error_impl.h +++ b/source/common/network/io_socket_error_impl.h @@ -1,7 +1,6 @@ #pragma once #include "envoy/api/io_error.h" -#include "envoy/api/os_sys_calls_common.h" #include "common/common/assert.h" @@ -33,5 +32,6 @@ class IoSocketError : public Api::IoError { private: int errno_; }; + } // namespace Network } // namespace Envoy diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index 5046e7a2f10c9..60c746e0c5f81 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -8,6 +8,16 @@ licenses(["notice"]) # Apache 2 envoy_extension_package() +envoy_cc_library( + name = "peer_buffer_lib", + hdrs = ["peer_buffer.h"], + deps = [ + "//source/common/buffer:buffer_lib", + "//source/common/buffer:watermark_buffer_lib", + "//source/common/common:empty_string", + ], +) + envoy_cc_library( name = "buffered_io_socket_handle_lib", srcs = [ @@ -19,8 +29,8 @@ envoy_cc_library( "user_space_file_event_impl.h", ], deps = [ + ":peer_buffer_lib", "//source/common/event:dispatcher_includes", "//source/common/network:default_socket_interface_lib", - "//source/common/network:peer_buffer_lib", ], ) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index 2dea13134fc3e..cbb9363fdc315 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -11,8 +11,8 @@ #include "common/buffer/watermark_buffer.h" #include "common/common/logger.h" #include "common/network/io_socket_error_impl.h" -#include "common/network/peer_buffer.h" +#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" #include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" namespace Envoy { @@ -30,7 +30,7 @@ namespace BufferedIoSocket { * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ class BufferedIoSocketHandleImpl final : public Network::IoHandle, - public Network::ReadWritable, + public ReadWritable, protected Logger::Loggable { public: BufferedIoSocketHandleImpl(); @@ -78,7 +78,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } - // Network::WritablePeer + // WritablePeer void setWriteEnd() override { read_end_stream_ = true; } bool isWriteEndSet() override { return read_end_stream_; } void maybeSetNewData() override { @@ -103,14 +103,14 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } - // Network::ReadWritable + // ReadWritable bool isPeerShutDownWrite() const override { return read_end_stream_; } bool isReadable() const override { return isPeerShutDownWrite() || pending_received_data_.length() > 0; } // Set the peer which will populate the owned pending_received_data. - void setWritablePeer(Network::WritablePeer* writable_peer) { + void setWritablePeer(WritablePeer* writable_peer) { // Swapping writable peer is undefined behavior. ASSERT(!writable_peer_); ASSERT(!write_shutdown_); @@ -136,7 +136,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, Buffer::WatermarkBuffer pending_received_data_; // Destination of the write(). The value remains non-null until the peer is closed. - Network::WritablePeer* writable_peer_{nullptr}; + WritablePeer* writable_peer_{nullptr}; // The flag whether the peer is valid. Any write attempt must check this flag. bool write_shutdown_{false}; diff --git a/source/common/network/peer_buffer.h b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h similarity index 91% rename from source/common/network/peer_buffer.h rename to source/extensions/io_socket/buffered_io_socket/peer_buffer.h index f42592daee939..aa54a0974876b 100644 --- a/source/common/network/peer_buffer.h +++ b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h @@ -4,7 +4,9 @@ #include "envoy/common/pure.h" namespace Envoy { -namespace Network { +namespace Extensions { +namespace IoSocket { +namespace BufferedIoSocket { /** * The interface for the writer. @@ -71,5 +73,7 @@ class ReadWritable : public WritablePeer { */ virtual bool isReadable() const PURE; }; -} // namespace Network +} // namespace BufferedIoSocket +} // namespace IoSocket +} // namespace Extensions } // namespace Envoy diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index 03b08ed489f1a..f9353dce44e88 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -3,7 +3,8 @@ #include #include "common/common/assert.h" -#include "common/network/peer_buffer.h" + +#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" namespace Envoy { namespace Extensions { @@ -11,7 +12,7 @@ namespace IoSocket { namespace BufferedIoSocket { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - uint32_t events, Network::ReadWritable& io_source) + uint32_t events, ReadWritable& io_source) : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { auto ephemeral_events = event_listener_.getAndClearEphemeralEvents(); ENVOY_LOG(trace, "User space event {} invokes callbacks on events = {}", diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h index 0ad34ca1ff949..0830c466dca39 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h @@ -6,7 +6,8 @@ #include "common/event/dispatcher_impl.h" #include "common/event/event_impl_base.h" -#include "common/network/peer_buffer.h" + +#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" namespace Envoy { @@ -40,7 +41,7 @@ class EventListenerImpl { class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::Loggable { public: UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, - Network::ReadWritable& io_source); + ReadWritable& io_source); ~UserSpaceFileEventImpl() override = default; @@ -61,7 +62,7 @@ class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::Loggable cb_; - Network::ReadWritable& io_source_; + ReadWritable& io_source_; }; } // namespace BufferedIoSocket } // namespace IoSocket diff --git a/test/common/network/BUILD b/test/common/network/BUILD index e92b72c35af09..b37ad410fe06b 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -75,7 +75,7 @@ envoy_cc_test( name = "connection_impl_test", srcs = ["connection_impl_test.cc"], deps = [ - "//source/common/buffer:buffer_lib", + ":buffer_lib", "//source/common/common:empty_string", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", @@ -107,7 +107,7 @@ envoy_cc_test( "//include/envoy/event:dispatcher_interface", "//include/envoy/network:address_interface", "//include/envoy/network:dns_interface", - "//source/common/buffer:buffer_lib", + ":buffer_lib", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", "//source/common/network:address_lib", diff --git a/test/extensions/io_socket/buffered_io_socket/BUILD b/test/extensions/io_socket/buffered_io_socket/BUILD index 55b7b5d1e2df7..82b16c32c7d01 100644 --- a/test/extensions/io_socket/buffered_io_socket/BUILD +++ b/test/extensions/io_socket/buffered_io_socket/BUILD @@ -38,8 +38,8 @@ envoy_cc_test( "//include/envoy/event:file_event_interface", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", - "//source/common/network:peer_buffer_lib", "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", + "//source/extensions/io_socket/buffered_io_socket:peer_buffer_lib", "//test/mocks:common_lib", "//test/test_common:environment_lib", "//test/test_common:test_runtime_lib", diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 7a738911d7c97..31dbbfdd304c3 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -177,7 +177,7 @@ TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { TEST_F(BufferedIoSocketHandleTest, FlowControl) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - Network::WritablePeer* handle_as_peer = io_handle_.get(); + WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_peer_->isWritable()); @@ -309,7 +309,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - Network::WritablePeer* handle_as_peer = io_handle_.get(); + WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_peer_->isWritable()); diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index 690d8653aa427..002f899c25074 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -3,8 +3,8 @@ #include "envoy/event/file_event.h" #include "common/event/dispatcher_impl.h" -#include "common/network/peer_buffer.h" +#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" #include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" #include "test/mocks/common.h" @@ -30,7 +30,7 @@ class MockReadyCb { MOCK_METHOD(void, called, (uint32_t)); }; -class MockReadWritable : public Network::ReadWritable { +class MockReadWritable : public ReadWritable { public: MOCK_METHOD(void, setWriteEnd, ()); MOCK_METHOD(bool, isWriteEndSet, ()); From 47cf2a8ac243249703cc1e4d32aa9095bef52c4c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 2 Nov 2020 19:43:26 +0000 Subject: [PATCH 50/88] save file Signed-off-by: Yuchen Dai --- test/common/network/BUILD | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/common/network/BUILD b/test/common/network/BUILD index b37ad410fe06b..e92b72c35af09 100644 --- a/test/common/network/BUILD +++ b/test/common/network/BUILD @@ -75,7 +75,7 @@ envoy_cc_test( name = "connection_impl_test", srcs = ["connection_impl_test.cc"], deps = [ - ":buffer_lib", + "//source/common/buffer:buffer_lib", "//source/common/common:empty_string", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", @@ -107,7 +107,7 @@ envoy_cc_test( "//include/envoy/event:dispatcher_interface", "//include/envoy/network:address_interface", "//include/envoy/network:dns_interface", - ":buffer_lib", + "//source/common/buffer:buffer_lib", "//source/common/event:dispatcher_includes", "//source/common/event:dispatcher_lib", "//source/common/network:address_lib", From 6244c65a1db24ff7a485db5a61971a75757c1437 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 3 Nov 2020 00:13:25 +0000 Subject: [PATCH 51/88] clangtidy wellknown names Signed-off-by: Yuchen Dai --- source/extensions/io_socket/well_known_names.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/extensions/io_socket/well_known_names.h b/source/extensions/io_socket/well_known_names.h index 86ab21d36be5a..e912d00ad3881 100644 --- a/source/extensions/io_socket/well_known_names.h +++ b/source/extensions/io_socket/well_known_names.h @@ -27,7 +27,7 @@ class IoSocketShortNameValues { const std::string BufferedIoSocket = "buffered_io_socket"; }; -using IoSocketShortNameValues = ConstSingleton; +using IoSocketShortNames = ConstSingleton; } // namespace IoSocket } // namespace Extensions From a58a7120438b81a8170e66b6b70a85919eb88414 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 3 Nov 2020 05:42:18 +0000 Subject: [PATCH 52/88] dup counter Signed-off-by: Yuchen Dai --- .../common/upstream/cluster_manager_impl.cc | 5 +++++ test/integration/ads_integration.cc | 4 ++-- test/integration/ads_integration.h | 2 +- test/integration/ads_integration_test.cc | 22 +++++++++++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index edb4c5b070d04..ae46754b5bb88 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -67,6 +67,11 @@ void ClusterManagerInitHelper::addCluster(Cluster& cluster) { cluster.initialize(initialize_cb); } else { ASSERT(cluster.initializePhase() == Cluster::InitializePhase::Secondary); + secondary_init_clusters_.remove_if( + [name_to_remove = cluster.info()->name()](Cluster* cluster_iter) { + return cluster_iter->info()->name() == name_to_remove; + }); + secondary_init_clusters_.push_back(&cluster); if (started_secondary_initialize_) { // This can happen if we get a second CDS update that adds new clusters after we have diff --git a/test/integration/ads_integration.cc b/test/integration/ads_integration.cc index 7d81b1de0a1b4..ffbd4b90225f0 100644 --- a/test/integration/ads_integration.cc +++ b/test/integration/ads_integration.cc @@ -34,8 +34,8 @@ AdsIntegrationTest::AdsIntegrationTest(const envoy::config::core::v3::ApiVersion void AdsIntegrationTest::TearDown() { cleanUpXdsConnection(); } -envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name) { - return ConfigHelper::buildCluster(name, "ROUND_ROBIN", api_version_); +envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, const std::string& lb_policy) { + return ConfigHelper::buildCluster(name, lb_policy, api_version_); } envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildTlsCluster(const std::string& name) { diff --git a/test/integration/ads_integration.h b/test/integration/ads_integration.h index 0da99aea566a1..d84afd8d5dbf4 100644 --- a/test/integration/ads_integration.h +++ b/test/integration/ads_integration.h @@ -22,7 +22,7 @@ class AdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public Ht void TearDown() override; - envoy::config::cluster::v3::Cluster buildCluster(const std::string& name); + envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, const std::string& lb_policy = "ROUND_ROBIN"); envoy::config::cluster::v3::Cluster buildTlsCluster(const std::string& name); diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 01aae9dc9f733..3b5b7303be99a 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -1152,6 +1152,28 @@ TEST_P(AdsClusterV3Test, BasicClusterInitialWarming) { test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); } +TEST_P(AdsClusterV3Test, BasicClusterResendWarming) { + initialize(); + const auto cds_type_url = Config::getTypeUrl( + envoy::config::core::v3::ApiVersion::V3); + const auto eds_type_url = Config::getTypeUrl( + envoy::config::core::v3::ApiVersion::V3); + + EXPECT_TRUE(compareDiscoveryRequest(cds_type_url, "", {}, {}, {}, true)); + sendDiscoveryResponse( + cds_type_url, {buildCluster("cluster_0")}, {buildCluster("cluster_0")}, {}, "1", false); + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); + sendDiscoveryResponse( + cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, {}, "2", false); + EXPECT_TRUE(compareDiscoveryRequest(eds_type_url, "", {"cluster_0"}, {"cluster_0"}, {})); + sendDiscoveryResponse( + eds_type_url, {buildClusterLoadAssignment("cluster_0")}, + {buildClusterLoadAssignment("cluster_0")}, {}, "1", false); + + test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0); + test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); +} + // Verify CDS is paused during cluster warming. TEST_P(AdsClusterV3Test, CdsPausedDuringWarming) { initialize(); From 1269e1e8e4bd54f01c201718a5205a8ebb663904 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 5 Nov 2020 10:23:12 +0000 Subject: [PATCH 53/88] extension and LT Signed-off-by: Yuchen Dai --- source/extensions/io_socket/BUILD | 13 +------------ .../extensions/io_socket/buffered_io_socket/BUILD | 10 +++++++--- .../buffered_io_socket_handle_impl.cc | 2 +- .../buffered_io_socket_handle_impl.h | 2 +- 4 files changed, 10 insertions(+), 17 deletions(-) diff --git a/source/extensions/io_socket/BUILD b/source/extensions/io_socket/BUILD index 40a5e79b39d3b..21a78bd7d8c59 100644 --- a/source/extensions/io_socket/BUILD +++ b/source/extensions/io_socket/BUILD @@ -1,19 +1,8 @@ load( "//bazel:envoy_build_system.bzl", - "envoy_cc_library", "envoy_extension_package", ) licenses(["notice"]) # Apache 2 -envoy_extension_package() - -envoy_cc_library( - name = "well_known_names", - hdrs = ["well_known_names.h"], - # well known names files are public as long as they exist. - visibility = ["//visibility:public"], - deps = [ - "//source/common/singleton:const_singleton", - ], -) +envoy_extension_package() \ No newline at end of file diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index 60c746e0c5f81..a2dad3494947b 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -1,6 +1,6 @@ load( "//bazel:envoy_build_system.bzl", - "envoy_cc_library", + "envoy_cc_extension", "envoy_extension_package", ) @@ -8,9 +8,11 @@ licenses(["notice"]) # Apache 2 envoy_extension_package() -envoy_cc_library( +envoy_cc_extension( name = "peer_buffer_lib", hdrs = ["peer_buffer.h"], + security_posture = "unknown", + status = "alpha", deps = [ "//source/common/buffer:buffer_lib", "//source/common/buffer:watermark_buffer_lib", @@ -18,7 +20,7 @@ envoy_cc_library( ], ) -envoy_cc_library( +envoy_cc_extension( name = "buffered_io_socket_handle_lib", srcs = [ "buffered_io_socket_handle_impl.cc", @@ -28,6 +30,8 @@ envoy_cc_library( "buffered_io_socket_handle_impl.h", "user_space_file_event_impl.h", ], + security_posture = "unknown", + status = "alpha", deps = [ ":peer_buffer_lib", "//source/common/event:dispatcher_includes", diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index 5cf5bad161bcf..c8d63fb198366 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -269,7 +269,7 @@ void BufferedIoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatch uint32_t events) { ASSERT(user_file_event_ == nullptr, "Attempting to initialize two `file_event_` for the same " "file descriptor. This is not allowed."); - ASSERT(trigger == Event::FileTriggerType::Edge, "Only support edge type."); + ASSERT(trigger != Event::FileTriggerType::Level, "Native level trigger is not supported yet."); user_file_event_ = std::make_unique(dispatcher, cb, events, *this); } diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index cbb9363fdc315..c3730a3bcc73b 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -22,7 +22,7 @@ namespace BufferedIoSocket { /** * Network::IoHandle implementation which provides a buffer as data source. It is designed to used * by Network::ConnectionImpl. Some known limitations include - * 1. It doesn't not include a file descriptor. Do not use "fdDoNotUse". + * 1. It doesn't include a file descriptor. Do not use "fdDoNotUse". * 2. It doesn't support socket options. Wrap this in ConnectionSocket and implement the socket * getter/setter options. * 3. It doesn't support UDP interface. From c7ffacc6d04d55c91652b072a5e1a174d5a8f44e Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 5 Nov 2020 17:19:10 +0000 Subject: [PATCH 54/88] add staging Signed-off-by: Yuchen Dai --- source/extensions/io_socket/BUILD | 2 +- .../extensions/io_socket/well_known_names.h | 34 ------------------- test/integration/ads_integration.cc | 3 +- test/integration/ads_integration.h | 3 +- test/integration/ads_integration_test.cc | 3 +- 5 files changed, 7 insertions(+), 38 deletions(-) delete mode 100644 source/extensions/io_socket/well_known_names.h diff --git a/source/extensions/io_socket/BUILD b/source/extensions/io_socket/BUILD index 21a78bd7d8c59..90e061ad8da39 100644 --- a/source/extensions/io_socket/BUILD +++ b/source/extensions/io_socket/BUILD @@ -5,4 +5,4 @@ load( licenses(["notice"]) # Apache 2 -envoy_extension_package() \ No newline at end of file +envoy_extension_package() diff --git a/source/extensions/io_socket/well_known_names.h b/source/extensions/io_socket/well_known_names.h deleted file mode 100644 index e912d00ad3881..0000000000000 --- a/source/extensions/io_socket/well_known_names.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include - -#include "common/singleton/const_singleton.h" - -namespace Envoy { -namespace Extensions { -namespace IoSocket { - -/** - * Well-known io socket names. - * NOTE: New io sockets should use the well known name: envoy.io_socket.name. - */ -class IoSocketNameValues { -public: - const std::string BufferedIoSocket = "envoy.io_socket.buffered_io_socket"; -}; - -using IoSocketNames = ConstSingleton; - -/** - * Well-known io socket names. - */ -class IoSocketShortNameValues { -public: - const std::string BufferedIoSocket = "buffered_io_socket"; -}; - -using IoSocketShortNames = ConstSingleton; - -} // namespace IoSocket -} // namespace Extensions -} // namespace Envoy diff --git a/test/integration/ads_integration.cc b/test/integration/ads_integration.cc index ffbd4b90225f0..6a0db9004244f 100644 --- a/test/integration/ads_integration.cc +++ b/test/integration/ads_integration.cc @@ -34,7 +34,8 @@ AdsIntegrationTest::AdsIntegrationTest(const envoy::config::core::v3::ApiVersion void AdsIntegrationTest::TearDown() { cleanUpXdsConnection(); } -envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, const std::string& lb_policy) { +envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, + const std::string& lb_policy) { return ConfigHelper::buildCluster(name, lb_policy, api_version_); } diff --git a/test/integration/ads_integration.h b/test/integration/ads_integration.h index d84afd8d5dbf4..8c9a8e0ab3e6c 100644 --- a/test/integration/ads_integration.h +++ b/test/integration/ads_integration.h @@ -22,7 +22,8 @@ class AdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public Ht void TearDown() override; - envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, const std::string& lb_policy = "ROUND_ROBIN"); + envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, + const std::string& lb_policy = "ROUND_ROBIN"); envoy::config::cluster::v3::Cluster buildTlsCluster(const std::string& name); diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 3b5b7303be99a..3b45663df5a15 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -1164,7 +1164,8 @@ TEST_P(AdsClusterV3Test, BasicClusterResendWarming) { cds_type_url, {buildCluster("cluster_0")}, {buildCluster("cluster_0")}, {}, "1", false); test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); sendDiscoveryResponse( - cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, {}, "2", false); + cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, + {}, "2", false); EXPECT_TRUE(compareDiscoveryRequest(eds_type_url, "", {"cluster_0"}, {"cluster_0"}, {})); sendDiscoveryResponse( eds_type_url, {buildClusterLoadAssignment("cluster_0")}, From f2633f452fee86437e4142aaa5625df0e9713ee7 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 5 Nov 2020 17:51:43 +0000 Subject: [PATCH 55/88] revert Signed-off-by: Yuchen Dai --- test/integration/ads_integration.cc | 3 +-- test/integration/ads_integration.h | 3 +-- test/integration/ads_integration_test.cc | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/test/integration/ads_integration.cc b/test/integration/ads_integration.cc index 6a0db9004244f..ffbd4b90225f0 100644 --- a/test/integration/ads_integration.cc +++ b/test/integration/ads_integration.cc @@ -34,8 +34,7 @@ AdsIntegrationTest::AdsIntegrationTest(const envoy::config::core::v3::ApiVersion void AdsIntegrationTest::TearDown() { cleanUpXdsConnection(); } -envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, - const std::string& lb_policy) { +envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, const std::string& lb_policy) { return ConfigHelper::buildCluster(name, lb_policy, api_version_); } diff --git a/test/integration/ads_integration.h b/test/integration/ads_integration.h index 8c9a8e0ab3e6c..d84afd8d5dbf4 100644 --- a/test/integration/ads_integration.h +++ b/test/integration/ads_integration.h @@ -22,8 +22,7 @@ class AdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public Ht void TearDown() override; - envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, - const std::string& lb_policy = "ROUND_ROBIN"); + envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, const std::string& lb_policy = "ROUND_ROBIN"); envoy::config::cluster::v3::Cluster buildTlsCluster(const std::string& name); diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 3b45663df5a15..3b5b7303be99a 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -1164,8 +1164,7 @@ TEST_P(AdsClusterV3Test, BasicClusterResendWarming) { cds_type_url, {buildCluster("cluster_0")}, {buildCluster("cluster_0")}, {}, "1", false); test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); sendDiscoveryResponse( - cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, - {}, "2", false); + cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, {}, "2", false); EXPECT_TRUE(compareDiscoveryRequest(eds_type_url, "", {"cluster_0"}, {"cluster_0"}, {})); sendDiscoveryResponse( eds_type_url, {buildClusterLoadAssignment("cluster_0")}, From 7c81f1883d37c85e37335b2fa004c85fc17772fe Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 5 Nov 2020 17:54:45 +0000 Subject: [PATCH 56/88] revert cont Signed-off-by: Yuchen Dai --- source/common/network/BUILD | 1 - .../common/upstream/cluster_manager_impl.cc | 5 ----- test/integration/ads_integration.cc | 4 ++-- test/integration/ads_integration.h | 2 +- test/integration/ads_integration_test.cc | 22 ------------------- 5 files changed, 3 insertions(+), 31 deletions(-) diff --git a/source/common/network/BUILD b/source/common/network/BUILD index bf41cdb70df6e..969e49f206732 100644 --- a/source/common/network/BUILD +++ b/source/common/network/BUILD @@ -167,7 +167,6 @@ envoy_cc_library( hdrs = ["io_socket_error_impl.h"], deps = [ "//include/envoy/api:io_error_interface", - "//include/envoy/api:os_sys_calls_interface", "//source/common/common:assert_lib", "//source/common/common:utility_lib", ], diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index 982bad8efd76e..5a2fb1328c368 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -67,11 +67,6 @@ void ClusterManagerInitHelper::addCluster(Cluster& cluster) { cluster.initialize(initialize_cb); } else { ASSERT(cluster.initializePhase() == Cluster::InitializePhase::Secondary); - secondary_init_clusters_.remove_if( - [name_to_remove = cluster.info()->name()](Cluster* cluster_iter) { - return cluster_iter->info()->name() == name_to_remove; - }); - secondary_init_clusters_.push_back(&cluster); if (started_secondary_initialize_) { // This can happen if we get a second CDS update that adds new clusters after we have diff --git a/test/integration/ads_integration.cc b/test/integration/ads_integration.cc index ffbd4b90225f0..7d81b1de0a1b4 100644 --- a/test/integration/ads_integration.cc +++ b/test/integration/ads_integration.cc @@ -34,8 +34,8 @@ AdsIntegrationTest::AdsIntegrationTest(const envoy::config::core::v3::ApiVersion void AdsIntegrationTest::TearDown() { cleanUpXdsConnection(); } -envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name, const std::string& lb_policy) { - return ConfigHelper::buildCluster(name, lb_policy, api_version_); +envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildCluster(const std::string& name) { + return ConfigHelper::buildCluster(name, "ROUND_ROBIN", api_version_); } envoy::config::cluster::v3::Cluster AdsIntegrationTest::buildTlsCluster(const std::string& name) { diff --git a/test/integration/ads_integration.h b/test/integration/ads_integration.h index d84afd8d5dbf4..0da99aea566a1 100644 --- a/test/integration/ads_integration.h +++ b/test/integration/ads_integration.h @@ -22,7 +22,7 @@ class AdsIntegrationTest : public Grpc::DeltaSotwIntegrationParamTest, public Ht void TearDown() override; - envoy::config::cluster::v3::Cluster buildCluster(const std::string& name, const std::string& lb_policy = "ROUND_ROBIN"); + envoy::config::cluster::v3::Cluster buildCluster(const std::string& name); envoy::config::cluster::v3::Cluster buildTlsCluster(const std::string& name); diff --git a/test/integration/ads_integration_test.cc b/test/integration/ads_integration_test.cc index 3b5b7303be99a..01aae9dc9f733 100644 --- a/test/integration/ads_integration_test.cc +++ b/test/integration/ads_integration_test.cc @@ -1152,28 +1152,6 @@ TEST_P(AdsClusterV3Test, BasicClusterInitialWarming) { test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); } -TEST_P(AdsClusterV3Test, BasicClusterResendWarming) { - initialize(); - const auto cds_type_url = Config::getTypeUrl( - envoy::config::core::v3::ApiVersion::V3); - const auto eds_type_url = Config::getTypeUrl( - envoy::config::core::v3::ApiVersion::V3); - - EXPECT_TRUE(compareDiscoveryRequest(cds_type_url, "", {}, {}, {}, true)); - sendDiscoveryResponse( - cds_type_url, {buildCluster("cluster_0")}, {buildCluster("cluster_0")}, {}, "1", false); - test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 1); - sendDiscoveryResponse( - cds_type_url, {buildCluster("cluster_0", "MAGLEV")}, {buildCluster("cluster_0", "MAGLEV")}, {}, "2", false); - EXPECT_TRUE(compareDiscoveryRequest(eds_type_url, "", {"cluster_0"}, {"cluster_0"}, {})); - sendDiscoveryResponse( - eds_type_url, {buildClusterLoadAssignment("cluster_0")}, - {buildClusterLoadAssignment("cluster_0")}, {}, "1", false); - - test_server_->waitForGaugeEq("cluster_manager.warming_clusters", 0); - test_server_->waitForGaugeGe("cluster_manager.active_clusters", 2); -} - // Verify CDS is paused during cluster warming. TEST_P(AdsClusterV3Test, CdsPausedDuringWarming) { initialize(); From 9e1744a71bb83b6c6d4c0cafd696c5f411dd3e9d Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Sat, 14 Nov 2020 07:31:14 +0000 Subject: [PATCH 57/88] destroy cluster info on main thread Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl.cc | 52 ++++++++---- .../buffered_io_socket_handle_impl.h | 14 ++-- .../buffered_io_socket/peer_buffer.h | 12 +-- .../user_space_file_event_impl.cc | 17 ++-- .../user_space_file_event_impl.h | 13 +-- ...red_io_socket_handle_impl_platform_test.cc | 28 ++++--- .../buffered_io_socket_handle_impl_test.cc | 84 ++++++++++--------- .../user_space_file_event_impl_test.cc | 4 +- 8 files changed, 117 insertions(+), 107 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index c8d63fb198366..b5b193c6f6389 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -19,7 +19,7 @@ namespace Extensions { namespace IoSocket { namespace BufferedIoSocket { namespace { -Api::SysCallIntResult makeInvalidSyscall() { +Api::SysCallIntResult makeInvalidSyscallResult() { return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP}; } } // namespace @@ -27,15 +27,13 @@ Api::SysCallIntResult makeInvalidSyscall() { BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() : pending_received_data_( [this]() -> void { - over_high_watermark_ = false; if (writable_peer_) { ENVOY_LOG(debug, "Socket {} switches to low watermark. Notify {}.", static_cast(this), static_cast(writable_peer_)); - writable_peer_->onPeerBufferWritable(); + writable_peer_->onPeerBufferLowWatermark(); } }, - [this]() -> void { - over_high_watermark_ = true; + []() -> void { // Low to high is checked by peer after peer writes data. }, []() -> void {}) {} @@ -54,7 +52,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { static_cast(writable_peer_)); // Notify the peer we won't write more data. shutdown(WRITE). writable_peer_->setWriteEnd(); - writable_peer_->maybeSetNewData(); + writable_peer_->setNewDataAvailable(); // Notify the peer that we no longer accept data. shutdown(RD). writable_peer_->onPeerDestroy(); writable_peer_ = nullptr; @@ -91,12 +89,13 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, auto bytes_to_read_in_this_slice = std::min(std::min(pending_received_data_.length(), max_length) - bytes_offset, uint64_t(slices[i].len_)); - pending_received_data_.copyOut(bytes_offset, bytes_to_read_in_this_slice, slices[i].mem_); + // Copy and drain, so pending_received_data_ always copy from offset 0. + pending_received_data_.copyOut(0, bytes_to_read_in_this_slice, slices[i].mem_); + pending_received_data_.drain(bytes_to_read_in_this_slice); bytes_offset += bytes_to_read_in_this_slice; } auto bytes_read = bytes_offset; ASSERT(bytes_read <= max_length); - pending_received_data_.drain(bytes_read); ENVOY_LOG(trace, "socket {} readv {} bytes", static_cast(this), bytes_read); return {bytes_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } @@ -123,6 +122,17 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, uint64_t num_slice) { + // Empty input is allowed even though the peer is shutdown. + bool is_input_empty = true; + for (uint64_t i = 0; i < num_slice; i++) { + if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { + is_input_empty = false; + break; + } + } + if (is_input_empty) { + return Api::ioCallUint64ResultNoError(); + }; if (!isOpen()) { return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; @@ -134,7 +144,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic } // Error: write after close. if (writable_peer_->isWriteEndSet()) { - // TODO(lambdai): EPIPE or ENOTCONN + // TODO(lambdai): `EPIPE` or `ENOTCONN`. return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; } @@ -151,12 +161,16 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic bytes_written += slices[i].len_; } } - writable_peer_->maybeSetNewData(); + writable_peer_->setNewDataAvailable(); ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), bytes_written); return {bytes_written, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buffer) { + // Empty input is allowed even though the peer is shutdown. + if (buffer.length() == 0) { + return Api::ioCallUint64ResultNoError(); + } if (!isOpen()) { return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; @@ -168,7 +182,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff } // Error: write after close. if (writable_peer_->isWriteEndSet()) { - // TODO(lambdai): EPIPE or ENOTCONN + // TODO(lambdai): `EPIPE` or `ENOTCONN`. return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; } @@ -179,7 +193,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff } uint64_t total_bytes_to_write = buffer.length(); writable_peer_->getWriteBuffer()->move(buffer); - writable_peer_->maybeSetNewData(); + writable_peer_->setNewDataAvailable(); ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), total_bytes_to_write); return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } @@ -227,10 +241,10 @@ bool BufferedIoSocketHandleImpl::supportsMmsg() const { return false; } bool BufferedIoSocketHandleImpl::supportsUdpGro() const { return false; } Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Network::Address::InstanceConstSharedPtr) { - return makeInvalidSyscall(); + return makeInvalidSyscallResult(); } -Api::SysCallIntResult BufferedIoSocketHandleImpl::listen(int) { return makeInvalidSyscall(); } +Api::SysCallIntResult BufferedIoSocketHandleImpl::listen(int) { return makeInvalidSyscallResult(); } Network::IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; @@ -244,14 +258,16 @@ BufferedIoSocketHandleImpl::connect(Network::Address::InstanceConstSharedPtr) { } Api::SysCallIntResult BufferedIoSocketHandleImpl::setOption(int, int, const void*, socklen_t) { - return makeInvalidSyscall(); + return makeInvalidSyscallResult(); } Api::SysCallIntResult BufferedIoSocketHandleImpl::getOption(int, int, void*, socklen_t*) { - return makeInvalidSyscall(); + return makeInvalidSyscallResult(); } -Api::SysCallIntResult BufferedIoSocketHandleImpl::setBlocking(bool) { return makeInvalidSyscall(); } +Api::SysCallIntResult BufferedIoSocketHandleImpl::setBlocking(bool) { + return makeInvalidSyscallResult(); +} absl::optional BufferedIoSocketHandleImpl::domain() { return absl::nullopt; } @@ -305,7 +321,7 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { ASSERT(writable_peer_); // Notify the peer we won't write more data. writable_peer_->setWriteEnd(); - writable_peer_->maybeSetNewData(); + writable_peer_->setNewDataAvailable(); write_shutdown_ = true; } return {0, 0}; diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index c3730a3bcc73b..bf0929c3d1786 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -38,7 +38,10 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, ~BufferedIoSocketHandleImpl() override; // Network::IoHandle - os_fd_t fdDoNotUse() const override { return INVALID_SOCKET; } + os_fd_t fdDoNotUse() const override { + ASSERT(false, "not supported"); + return INVALID_SOCKET; + } Api::IoCallUint64Result close() override; bool isOpen() const override; Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, @@ -81,7 +84,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, // WritablePeer void setWriteEnd() override { read_end_stream_ = true; } bool isWriteEndSet() override { return read_end_stream_; } - void maybeSetNewData() override { + void setNewDataAvailable() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); if (user_file_event_) { user_file_event_->activate(Event::FileReadyType::Read); @@ -91,12 +94,12 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, writable_peer_ = nullptr; write_shutdown_ = true; } - void onPeerBufferWritable() override { + void onPeerBufferLowWatermark() override { if (user_file_event_) { user_file_event_->activate(Event::FileReadyType::Write); } } - bool isWritable() const override { return !over_high_watermark_; } + bool isWritable() const override { return !pending_received_data_.highWatermarkTriggered(); } bool isPeerWritable() const override { return writable_peer_ != nullptr && !writable_peer_->isWriteEndSet() && writable_peer_->isWritable(); @@ -140,9 +143,6 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, // The flag whether the peer is valid. Any write attempt must check this flag. bool write_shutdown_{false}; - - // The watermark state of pending_received_data_. - bool over_high_watermark_{false}; }; } // namespace BufferedIoSocket } // namespace IoSocket diff --git a/source/extensions/io_socket/buffered_io_socket/peer_buffer.h b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h index aa54a0974876b..ba0c7bfea505b 100644 --- a/source/extensions/io_socket/buffered_io_socket/peer_buffer.h +++ b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h @@ -30,10 +30,10 @@ class WritablePeer { virtual void onPeerDestroy() PURE; /** - * Notify that consumable data arrives. The consumable data can be either data to read, or the end + * Notify that consumable data arrived. The consumable data can be either data to read, or the end * of stream event. */ - virtual void maybeSetNewData() PURE; + virtual void setNewDataAvailable() PURE; /** * @return the buffer to be written. @@ -41,7 +41,7 @@ class WritablePeer { virtual Buffer::Instance* getWriteBuffer() PURE; /** - * @return false more data is acceptable. + * @return true if more data is acceptable at the destination buffer. */ virtual bool isWritable() const PURE; @@ -53,11 +53,11 @@ class WritablePeer { /** * Raised by the peer when the peer switch from high water mark to low. */ - virtual void onPeerBufferWritable() PURE; + virtual void onPeerBufferLowWatermark() PURE; }; /** - * The interface as the union of ReadableSource and WritablePeer. + * The interface for the peer as a writer and supplied read status query. */ class ReadWritable : public WritablePeer { public: @@ -69,7 +69,7 @@ class ReadWritable : public WritablePeer { virtual bool isPeerShutDownWrite() const PURE; /** - * @return true if the pending receive buffer is not full. + * @return true if the pending receive buffer is not empty or read_end is set. */ virtual bool isReadable() const PURE; }; diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index f9353dce44e88..cef1f5c0b7603 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -13,25 +13,22 @@ namespace BufferedIoSocket { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, ReadWritable& io_source) - : schedulable_(dispatcher.createSchedulableCallback([this]() { cb_(); })), cb_([this, cb]() { + : schedulable_(dispatcher.createSchedulableCallback([this, cb]() { auto ephemeral_events = event_listener_.getAndClearEphemeralEvents(); ENVOY_LOG(trace, "User space event {} invokes callbacks on events = {}", static_cast(this), ephemeral_events); cb(ephemeral_events); - }), + })), io_source_(io_source) { setEnabled(events); } -void EventListenerImpl::onEventEnabled(uint32_t) { +void EventListenerImpl::clearEphemeralEvents(uint32_t) { // Clear ephemeral events to align with FileEventImpl::setEnable(). ephemeral_events_ = 0; } void EventListenerImpl::onEventActivated(uint32_t activated_events) { - // Normally event owner should not activate any event which is disabled. Known exceptions includes - // ConsumerWantsToRead() == true. - // TODO(lambdai): Stricter check. ephemeral_events_ |= activated_events; } @@ -47,7 +44,7 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { // Only supported event types are set. ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | Event::FileReadyType::Closed)) == events); - event_listener_.onEventEnabled(events); + event_listener_.clearEphemeralEvents(events); bool was_enabled = schedulable_->enabled(); // Recalculate activated events. uint32_t events_to_notify = 0; @@ -62,8 +59,10 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { } else { schedulable_->cancel(); } - ENVOY_LOG(trace, "User space file event {} set events {}. Will {} reschedule.", - static_cast(this), events, was_enabled ? "not " : ""); + ENVOY_LOG( + trace, + "User space file event {} set enabled events {} and events {} is active. Will {} reschedule.", + static_cast(this), events, was_enabled ? "not " : ""); } } // namespace BufferedIoSocket } // namespace IoSocket diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h index 0830c466dca39..7da130cb46fcd 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h @@ -15,8 +15,6 @@ namespace Extensions { namespace IoSocket { namespace BufferedIoSocket { -class BufferedIoSocketHandleImpl; - // Return the enabled events except EV_CLOSED. This implementation is generally good since only // epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner // must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify @@ -26,7 +24,7 @@ class EventListenerImpl { public: ~EventListenerImpl() = default; - void onEventEnabled(uint32_t enabled_events); + void clearEphemeralEvents(uint32_t enabled_events); void onEventActivated(uint32_t activated_events); uint32_t getAndClearEphemeralEvents() { return std::exchange(ephemeral_events_, 0); } @@ -43,14 +41,10 @@ class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::Loggable cb_; - + // Supplies readable and writable status. ReadWritable& io_source_; }; } // namespace BufferedIoSocket diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc index 3fee0d4b13784..9488d7b2b770c 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc @@ -25,31 +25,33 @@ class MockFileEventCallback { class BufferedIoSocketHandlePlatformTest : public testing::Test { public: BufferedIoSocketHandlePlatformTest() { - io_handle_ = std::make_unique(); - io_handle_peer_ = std::make_unique(); - io_handle_->setWritablePeer(io_handle_peer_.get()); - io_handle_peer_->setWritablePeer(io_handle_.get()); + first_io_handle_ = std::make_unique(); + second_io_handle_ = std::make_unique(); + first_io_handle_->setWritablePeer(second_io_handle_.get()); + second_io_handle_->setWritablePeer(first_io_handle_.get()); } ~BufferedIoSocketHandlePlatformTest() override { - if (io_handle_->isOpen()) { - io_handle_->close(); + if (first_io_handle_->isOpen()) { + first_io_handle_->close(); } - if (io_handle_peer_->isOpen()) { - io_handle_peer_->close(); + if (second_io_handle_->isOpen()) { + second_io_handle_->close(); } } - std::unique_ptr io_handle_; - std::unique_ptr io_handle_peer_; + std::unique_ptr first_io_handle_; + std::unique_ptr second_io_handle_; NiceMock dispatcher_; MockFileEventCallback cb_; }; TEST_F(BufferedIoSocketHandlePlatformTest, TestCreatePlatformDefaultTriggerTypeFailOnWindows) { - auto scheduable_cb = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()).Times(0); - io_handle_->initializeFileEvent( + // scheduable_cb will be destroyed by IoHandle. + auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*scheduable_cb, enabled()); + EXPECT_CALL(*scheduable_cb, cancel()); + first_io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); } diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 31dbbfdd304c3..3b56e9d3f0699 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -1,3 +1,4 @@ +#include "common/common/fancy_logger.h" #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" @@ -20,11 +21,12 @@ namespace IoSocket { namespace BufferedIoSocket { namespace { -MATCHER(IsInvalidateAddress, "") { +MATCHER(IsInvalidAddress, "") { return arg.err_->getErrorCode() == Api::IoError::IoErrorCode::NoSupport; } MATCHER(IsNotSupportedResult, "") { return arg.errno_ == SOCKET_ERROR_NOT_SUP; } + class MockFileEventCallback { public: MOCK_METHOD(void, called, (uint32_t arg)); @@ -61,38 +63,10 @@ class BufferedIoSocketHandleTest : public testing::Test { absl::FixedArray buf_; }; -TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { - io_handle_->close(); - Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; - result = io_handle_->recv(buf_.data(), buf_.size(), 0); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - - Buffer::OwnedImpl buf("0123456789"); - - result = io_handle_->read(buf, 10); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - - Buffer::RawSlice slice; - buf.reserve(1024, &slice, 1); - result = io_handle_->readv(1024, &slice, 1); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - - result = io_handle_->write(buf); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - - result = io_handle_->writev(&slice, 1); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); -} - // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); - // EAGAIN. + // `EAGAIN`. EXPECT_FALSE(result.ok()); EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); io_handle_->setWriteEnd(); @@ -400,6 +374,36 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { io_handle_->resetFileEvents(); } +TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { + io_handle_->close(); + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + Buffer::OwnedImpl buf("0123456789"); + + result = io_handle_->read(buf, 10); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + Buffer::RawSlice slice; + auto r = buf.reserve(1024, &slice, 1); + FANCY_LOG(debug,"r length= ", r); + FANCY_LOG(debug, "lambdai: slice.len = {}", slice.len_); + result = io_handle_->readv(1024, &slice, 1); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + result = io_handle_->write(buf); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + + FANCY_LOG(debug, "lambdai: slice.len = {}", slice.len_); + result = io_handle_->writev(&slice, 1); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); +} + // Test that a readable event is raised when peer shutdown write. Also confirm read will return // EAGAIN. TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { @@ -465,7 +469,6 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { // Test write return error code. Ignoring the side effect of event scheduling. TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { Buffer::OwnedImpl buf("0123456789"); - Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; { // Populate write destination with massive data so as to not writable. @@ -473,7 +476,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { internal_buffer.setWatermarks(1024); internal_buffer.add(std::string(2048, ' ')); - result = io_handle_->write(buf); + auto result = io_handle_->write(buf); ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); EXPECT_EQ(10, buf.length()); } @@ -481,7 +484,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { { // Write after shutdown. io_handle_->shutdown(ENVOY_SHUT_WR); - result = io_handle_->write(buf); + auto result = io_handle_->write(buf); ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); EXPECT_EQ(10, buf.length()); } @@ -489,7 +492,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { { io_handle_peer_->close(); EXPECT_TRUE(io_handle_->isOpen()); - result = io_handle_->write(buf); + auto result = io_handle_->write(buf); ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); } } @@ -498,21 +501,20 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { TEST_F(BufferedIoSocketHandleTest, TestWritevErrorCode) { std::string buf(10, 'a'); Buffer::RawSlice slice{static_cast(buf.data()), 10}; - Api::IoCallUint64Result result{0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; { // Populate write destination with massive data so as to not writable. auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); internal_buffer.setWatermarks(1024); internal_buffer.add(std::string(2048, ' ')); - result = io_handle_->writev(&slice, 1); + auto result = io_handle_->writev(&slice, 1); ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); } { // Writev after shutdown. io_handle_->shutdown(ENVOY_SHUT_WR); - result = io_handle_->writev(&slice, 1); + auto result = io_handle_->writev(&slice, 1); ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); } @@ -520,7 +522,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevErrorCode) { // Close the peer. io_handle_peer_->close(); EXPECT_TRUE(io_handle_->isOpen()); - result = io_handle_->writev(&slice, 1); + auto result = io_handle_->writev(&slice, 1); ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); } } @@ -777,18 +779,18 @@ TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSetBlocking) { TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSendmsg) { EXPECT_THAT(io_handle_->sendmsg(&slice_, 0, 0, nullptr, Network::Address::EnvoyInternalInstance("listener_id")), - IsInvalidateAddress()); + IsInvalidAddress()); } TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmsg) { Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); - EXPECT_THAT(io_handle_->recvmsg(&slice_, 0, 0, output_is_ignored), IsInvalidateAddress()); + EXPECT_THAT(io_handle_->recvmsg(&slice_, 0, 0, output_is_ignored), IsInvalidAddress()); } TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmmsg) { RawSliceArrays slices_is_ignored(1, absl::FixedArray({slice_})); Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); - EXPECT_THAT(io_handle_->recvmmsg(slices_is_ignored, 0, output_is_ignored), IsInvalidateAddress()); + EXPECT_THAT(io_handle_->recvmmsg(slices_is_ignored, 0, output_is_ignored), IsInvalidAddress()); } TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnBind) { diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index 002f899c25074..1b849824c7a47 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -35,11 +35,11 @@ class MockReadWritable : public ReadWritable { MOCK_METHOD(void, setWriteEnd, ()); MOCK_METHOD(bool, isWriteEndSet, ()); MOCK_METHOD(void, onPeerDestroy, ()); - MOCK_METHOD(void, maybeSetNewData, ()); + MOCK_METHOD(void, setNewDataAvailable, ()); MOCK_METHOD(Buffer::Instance*, getWriteBuffer, ()); MOCK_METHOD(bool, isWritable, (), (const)); MOCK_METHOD(bool, isPeerWritable, (), (const)); - MOCK_METHOD(void, onPeerBufferWritable, ()); + MOCK_METHOD(void, onPeerBufferLowWatermark, ()); MOCK_METHOD(bool, isPeerShutDownWrite, (), (const)); MOCK_METHOD(bool, isReadable, (), (const)); }; From 7c419d1773afe68f99f7118ab6ec91be5cbcbbf5 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 16 Nov 2020 22:31:19 +0000 Subject: [PATCH 58/88] close test Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 84 +++++++++++++------ 1 file changed, 58 insertions(+), 26 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 3b56e9d3f0699..d341e254c209f 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -1,4 +1,5 @@ #include "common/common/fancy_logger.h" +#include "envoy/buffer/buffer.h" #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" @@ -27,6 +28,14 @@ MATCHER(IsInvalidAddress, "") { MATCHER(IsNotSupportedResult, "") { return arg.errno_ == SOCKET_ERROR_NOT_SUP; } +ABSL_MUST_USE_RESULT std::pair allocateOneSlice(uint64_t size) { + auto owned_slice = Buffer::OwnedSlice::create(size); + Buffer::RawSlice slice = owned_slice->reserve(size); + EXPECT_NE(nullptr, slice.mem_); + EXPECT_EQ(size, slice.len_); + return {std::move(owned_slice), slice}; +} + class MockFileEventCallback { public: MOCK_METHOD(void, called, (uint32_t arg)); @@ -374,34 +383,57 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { io_handle_->resetFileEvents(); } -TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { +// Consistent with other IoHandle: allow write empty data when handle is closed. +TEST_F(BufferedIoSocketHandleTest, TestNoErrorWriteZeroDataToClosedIoHandle) { io_handle_->close(); - auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - - Buffer::OwnedImpl buf("0123456789"); - - result = io_handle_->read(buf, 10); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - - Buffer::RawSlice slice; - auto r = buf.reserve(1024, &slice, 1); - FANCY_LOG(debug,"r length= ", r); - FANCY_LOG(debug, "lambdai: slice.len = {}", slice.len_); - result = io_handle_->readv(1024, &slice, 1); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - - result = io_handle_->write(buf); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + { + Buffer::OwnedImpl buf; + auto result = io_handle_->write(buf); + ASSERT_EQ(0, result.rc_); + ASSERT(result.ok()); + } + { + Buffer::RawSlice slice{nullptr, 0}; + auto result = io_handle_->writev(&slice, 1); + ASSERT_EQ(0, result.rc_); + ASSERT(result.ok()); + } +} - FANCY_LOG(debug, "lambdai: slice.len = {}", slice.len_); - result = io_handle_->writev(&slice, 1); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); +TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { + io_handle_->close(); + { + auto [guard, slice] = allocateOneSlice(1024); + auto result = io_handle_->recv(slice.mem_, slice.len_, 0); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + } + { + Buffer::OwnedImpl buf; + auto result = io_handle_->read(buf, 10); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + } + { + auto [guard, slice] = allocateOneSlice(1024); + auto result = io_handle_->readv(1024, &slice, 1); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + } + { + Buffer::OwnedImpl buf("0123456789"); + auto result = io_handle_->write(buf); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + } + { + Buffer::OwnedImpl buf("0123456789"); + auto slices = buf.getRawSlices(); + ASSERT(!slices.empty()); + auto result = io_handle_->writev(slices.data(), slices.size()); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + } } // Test that a readable event is raised when peer shutdown write. Also confirm read will return From 1993defc4f3844b7305182498905401a1aed4c00 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 17 Nov 2020 01:54:48 +0000 Subject: [PATCH 59/88] rewrite recv Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 117 ++++++++++++------ 1 file changed, 82 insertions(+), 35 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index d341e254c209f..eb8e80da4a1dd 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -52,12 +52,6 @@ class BufferedIoSocketHandleTest : public testing::Test { ~BufferedIoSocketHandleTest() override = default; - void expectAgain() { - auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); - EXPECT_FALSE(result.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); - } - Buffer::WatermarkBuffer& getWatermarkBufferHelper(BufferedIoSocketHandleImpl& io_handle) { return dynamic_cast(*io_handle.getWriteBuffer()); } @@ -74,13 +68,88 @@ class BufferedIoSocketHandleTest : public testing::Test { // Test recv side effects. TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { - auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); - // `EAGAIN`. - EXPECT_FALSE(result.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); - io_handle_->setWriteEnd(); - result = io_handle_->recv(buf_.data(), buf_.size(), 0); - EXPECT_TRUE(result.ok()); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); + internal_buffer.add("0123456789"); + { + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + ASSERT_EQ(10, result.rc_); + ASSERT_EQ("0123456789", absl::string_view(buf_.data(), result.rc_)); + } + { + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + // `EAGAIN`. + EXPECT_FALSE(result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); + } + { + io_handle_->setWriteEnd(); + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_TRUE(result.ok()); + } +} + +// Test recv side effects. +TEST_F(BufferedIoSocketHandleTest, TestRecvPeek) { + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); + internal_buffer.add("0123456789"); + { + ::memset(buf_.data(), 1, buf_.size()); + auto result = io_handle_->recv(buf_.data(), 5, MSG_PEEK); + ASSERT_EQ(5, result.rc_); + ASSERT_EQ("01234", absl::string_view(buf_.data(), result.rc_)); + // The data beyond the boundary is untouched. + ASSERT_EQ(std::string(buf_.size() - 5, 1), absl::string_view(buf_.data() + 5, buf_.size() - 5)); + } + { + auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + ASSERT_EQ(10, result.rc_); + ASSERT_EQ("0123456789", absl::string_view(buf_.data(), result.rc_)); + } + { + // Drain the pending buffer. + auto recv_result = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_TRUE(recv_result.ok()); + EXPECT_EQ(10, recv_result.rc_); + ASSERT_EQ("0123456789", absl::string_view(buf_.data(), recv_result.rc_)); + auto peek_result = io_handle_->recv(buf_.data(), buf_.size(), 0); + // `EAGAIN`. + EXPECT_FALSE(peek_result.ok()); + EXPECT_EQ(Api::IoError::IoErrorCode::Again, peek_result.err_->getErrorCode()); + } + { + // Peek upon shutdown. + io_handle_->setWriteEnd(); + auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + EXPECT_EQ(0, result.rc_); + ASSERT(result.ok()); + } +} + +TEST_F(BufferedIoSocketHandleTest, TestRecvPeekWhenPendingDataButShutdown) { + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); + internal_buffer.add("0123456789"); + auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); + ASSERT_EQ(10, result.rc_); + ASSERT_EQ("0123456789", absl::string_view(buf_.data(), result.rc_)); +} + +TEST_F(BufferedIoSocketHandleTest, TestMultipleRecvDrain) { + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); + internal_buffer.add("abcd"); + { + auto result = io_handle_->recv(buf_.data(), 1, 0); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(1, result.rc_); + EXPECT_EQ("a", absl::string_view(buf_.data(), 1)); + } + { + auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(3, result.rc_); + + EXPECT_EQ("bcd", absl::string_view(buf_.data(), 3)); + EXPECT_EQ(0, internal_buffer.length()); + } } // Test read side effects. @@ -136,28 +205,6 @@ TEST_F(BufferedIoSocketHandleTest, TestBasicReadv) { EXPECT_EQ(0, result.rc_); } -// Test recv side effects. -TEST_F(BufferedIoSocketHandleTest, TestBasicPeek) { - auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); - // EAGAIN. - EXPECT_FALSE(result.ok()); - EXPECT_EQ(Api::IoError::IoErrorCode::Again, result.err_->getErrorCode()); - io_handle_->setWriteEnd(); - result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); - EXPECT_TRUE(result.ok()); -} - -TEST_F(BufferedIoSocketHandleTest, TestRecvDrain) { - auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - internal_buffer.add("abcd"); - auto result = io_handle_->recv(buf_.data(), buf_.size(), 0); - EXPECT_TRUE(result.ok()); - EXPECT_EQ(4, result.rc_); - EXPECT_EQ(absl::string_view(buf_.data(), 4), "abcd"); - EXPECT_EQ(0, internal_buffer.length()); - expectAgain(); -} - TEST_F(BufferedIoSocketHandleTest, FlowControl) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); WritablePeer* handle_as_peer = io_handle_.get(); From bfb6911cdef51aac51d35e6e87a14a9703fd842f Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 17 Nov 2020 04:46:04 +0000 Subject: [PATCH 60/88] flow control test Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index eb8e80da4a1dd..dddb4c087b0f9 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -207,22 +207,26 @@ TEST_F(BufferedIoSocketHandleTest, TestBasicReadv) { TEST_F(BufferedIoSocketHandleTest, FlowControl) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - WritablePeer* handle_as_peer = io_handle_.get(); + // TODO(lambdai): Make it an IoHandle method. internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); - EXPECT_TRUE(io_handle_peer_->isWritable()); + EXPECT_TRUE(io_handle_->isWritable()); + + // Populate the data for io_handle_. + Buffer::OwnedImpl buffer(std::string(256, 'a')); + io_handle_peer_->write(buffer); - std::string big_chunk(256, 'a'); - internal_buffer.add(big_chunk); EXPECT_TRUE(io_handle_->isReadable()); - EXPECT_FALSE(handle_as_peer->isWritable()); + EXPECT_FALSE(io_handle_->isWritable()); bool writable_flipped = false; // During the repeated recv, the writable flag must switch to true. while (internal_buffer.length() > 0) { SCOPED_TRACE(internal_buffer.length()); + FANCY_LOG(debug, "internal buffer length = {}", internal_buffer.length()); EXPECT_TRUE(io_handle_->isReadable()); - bool writable = handle_as_peer->isWritable(); + bool writable = io_handle_->isWritable(); + FANCY_LOG(debug, "internal buffer length = {}, writable = {}", internal_buffer.length(), writable); if (writable) { writable_flipped = true; } else { @@ -237,7 +241,7 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { // Finally the buffer is empty. EXPECT_FALSE(io_handle_->isReadable()); - EXPECT_TRUE(handle_as_peer->isWritable()); + EXPECT_TRUE(io_handle_->isWritable()); } TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { From 92cebbf4c7c459ead3982f62ecac802978c8ab59 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 17 Nov 2020 09:21:55 +0000 Subject: [PATCH 61/88] Events test Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 106 ++++++++++-------- 1 file changed, 62 insertions(+), 44 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index dddb4c087b0f9..51f4ef92ca7fb 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -226,7 +226,8 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { FANCY_LOG(debug, "internal buffer length = {}", internal_buffer.length()); EXPECT_TRUE(io_handle_->isReadable()); bool writable = io_handle_->isWritable(); - FANCY_LOG(debug, "internal buffer length = {}, writable = {}", internal_buffer.length(), writable); + FANCY_LOG(debug, "internal buffer length = {}, writable = {}", internal_buffer.length(), + writable); if (writable) { writable_flipped = true; } else { @@ -245,60 +246,67 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { } TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { - scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*scheduable_cb, enabled()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); - EXPECT_CALL(cb_, called(_)); - scheduable_cb_->invokeCallback(); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); + scheduable_cb->invokeCallback(); io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { - scheduable_cb_ = new NiceMock(&dispatcher_); - + auto scheduable_cb = new NiceMock(&dispatcher_); // No data is available to read. Will not schedule read. { SCOPED_TRACE("enable read but no readable."); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(0); + EXPECT_CALL(*scheduable_cb, enabled()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()).Times(0); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read); + testing::Mock::VerifyAndClearExpectations(scheduable_cb); } { SCOPED_TRACE("enable readwrite but only writable."); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + EXPECT_CALL(*scheduable_cb, enabled()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); io_handle_->enableFileEvents(Event::FileReadyType::Read | Event::FileReadyType::Write); - ASSERT_TRUE(scheduable_cb_->enabled()); + ASSERT_TRUE(scheduable_cb->enabled_); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); - scheduable_cb_->invokeCallback(); - ASSERT_FALSE(scheduable_cb_->enabled()); + scheduable_cb->invokeCallback(); + ASSERT_FALSE(scheduable_cb->enabled_); + testing::Mock::VerifyAndClearExpectations(scheduable_cb); } { SCOPED_TRACE("enable write and writable."); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + EXPECT_CALL(*scheduable_cb, enabled()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); io_handle_->enableFileEvents(Event::FileReadyType::Write); - ASSERT_TRUE(scheduable_cb_->enabled()); + ASSERT_TRUE(scheduable_cb->enabled_); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); - scheduable_cb_->invokeCallback(); - ASSERT_FALSE(scheduable_cb_->enabled()); - // Close io_handle_ first to prevent events originated from peer close. - io_handle_->close(); - io_handle_peer_->close(); + scheduable_cb->invokeCallback(); + ASSERT_FALSE(scheduable_cb->enabled_); + testing::Mock::VerifyAndClearExpectations(scheduable_cb); } + // Close io_handle_ first to prevent events originated from peer close. + io_handle_->close(); + io_handle_peer_->close(); } TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { - scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*scheduable_cb, enabled()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); - scheduable_cb_->invokeCallback(); + scheduable_cb->invokeCallback(); // Neither read nor write triggers self readiness. EXPECT_CALL(cb_, called(_)).Times(0); @@ -310,40 +318,42 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { EXPECT_TRUE(result.ok()); EXPECT_EQ(1, result.rc_); - ASSERT_FALSE(scheduable_cb_->enabled()); + ASSERT_FALSE(scheduable_cb->enabled_); io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { - scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*scheduable_cb, enabled()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Write); - ASSERT_TRUE(scheduable_cb_->enabled()); + ASSERT_TRUE(scheduable_cb->enabled_); // The write event is cleared and the read event is not ready. + EXPECT_CALL(*scheduable_cb, enabled()); + EXPECT_CALL(*scheduable_cb, cancel()); io_handle_->enableFileEvents(Event::FileReadyType::Read); + testing::Mock::VerifyAndClearExpectations(scheduable_cb); - ASSERT_FALSE(scheduable_cb_->enabled()); + ASSERT_FALSE(scheduable_cb->enabled_); io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { - scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*scheduable_cb, enabled()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Write); - ASSERT_TRUE(scheduable_cb_->enabled()); - - EXPECT_CALL(cb_, called(_)).Times(0); + ASSERT_TRUE(scheduable_cb->enabled_); io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - WritablePeer* handle_as_peer = io_handle_.get(); internal_buffer.setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_peer_->isWritable()); @@ -351,29 +361,37 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { std::string big_chunk(256, 'a'); internal_buffer.add(big_chunk); EXPECT_TRUE(io_handle_->isReadable()); - EXPECT_FALSE(handle_as_peer->isWritable()); + EXPECT_FALSE(io_handle_->isWritable()); - scheduable_cb_ = new NiceMock(&dispatcher_); + auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*scheduable_cb, enabled()); + // No event is available. + EXPECT_CALL(*scheduable_cb, cancel()); io_handle_peer_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); // Neither readable nor writable. - ASSERT_FALSE(scheduable_cb_->enabled()); + ASSERT_FALSE(scheduable_cb->enabled_); { + SCOPED_TRACE("drain very few data."); auto result = io_handle_->recv(buf_.data(), 1, 0); - EXPECT_FALSE(handle_as_peer->isWritable()); + EXPECT_FALSE(io_handle_->isWritable()); } { - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); + SCOPED_TRACE("drain to low watermark."); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()).Times(1); auto result = io_handle_->recv(buf_.data(), 232, 0); - EXPECT_TRUE(handle_as_peer->isWritable()); - EXPECT_CALL(cb_, called(_)); - scheduable_cb_->invokeCallback(); + EXPECT_TRUE(io_handle_->isWritable()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); + scheduable_cb->invokeCallback(); + } + { + SCOPED_TRACE("clean up."); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()).Times(1); + // Important: close before peer. + io_handle_->close(); } - - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(1); - io_handle_->close(); } TEST_F(BufferedIoSocketHandleTest, TestClose) { From c4b1276e2e0175784a685d246d5907b17e38b666 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 17 Nov 2020 10:24:34 +0000 Subject: [PATCH 62/88] move close Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 106 +++++++++--------- 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 51f4ef92ca7fb..b0fd4b2e68227 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -245,6 +245,59 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { EXPECT_TRUE(io_handle_->isWritable()); } +// Consistent with other IoHandle: allow write empty data when handle is closed. +TEST_F(BufferedIoSocketHandleTest, TestNoErrorWriteZeroDataToClosedIoHandle) { + io_handle_->close(); + { + Buffer::OwnedImpl buf; + auto result = io_handle_->write(buf); + ASSERT_EQ(0, result.rc_); + ASSERT(result.ok()); + } + { + Buffer::RawSlice slice{nullptr, 0}; + auto result = io_handle_->writev(&slice, 1); + ASSERT_EQ(0, result.rc_); + ASSERT(result.ok()); + } +} + +TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { + io_handle_->close(); + { + auto [guard, slice] = allocateOneSlice(1024); + auto result = io_handle_->recv(slice.mem_, slice.len_, 0); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + } + { + Buffer::OwnedImpl buf; + auto result = io_handle_->read(buf, 10); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + } + { + auto [guard, slice] = allocateOneSlice(1024); + auto result = io_handle_->readv(1024, &slice, 1); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + } + { + Buffer::OwnedImpl buf("0123456789"); + auto result = io_handle_->write(buf); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + } + { + Buffer::OwnedImpl buf("0123456789"); + auto slices = buf.getRawSlices(); + ASSERT(!slices.empty()); + auto result = io_handle_->writev(slices.data(), slices.size()); + ASSERT(!result.ok()); + ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); + } +} + TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); EXPECT_CALL(*scheduable_cb, enabled()); @@ -452,59 +505,6 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { io_handle_->resetFileEvents(); } -// Consistent with other IoHandle: allow write empty data when handle is closed. -TEST_F(BufferedIoSocketHandleTest, TestNoErrorWriteZeroDataToClosedIoHandle) { - io_handle_->close(); - { - Buffer::OwnedImpl buf; - auto result = io_handle_->write(buf); - ASSERT_EQ(0, result.rc_); - ASSERT(result.ok()); - } - { - Buffer::RawSlice slice{nullptr, 0}; - auto result = io_handle_->writev(&slice, 1); - ASSERT_EQ(0, result.rc_); - ASSERT(result.ok()); - } -} - -TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { - io_handle_->close(); - { - auto [guard, slice] = allocateOneSlice(1024); - auto result = io_handle_->recv(slice.mem_, slice.len_, 0); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - } - { - Buffer::OwnedImpl buf; - auto result = io_handle_->read(buf, 10); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - } - { - auto [guard, slice] = allocateOneSlice(1024); - auto result = io_handle_->readv(1024, &slice, 1); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - } - { - Buffer::OwnedImpl buf("0123456789"); - auto result = io_handle_->write(buf); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - } - { - Buffer::OwnedImpl buf("0123456789"); - auto slices = buf.getRawSlices(); - ASSERT(!slices.empty()); - auto result = io_handle_->writev(slices.data(), slices.size()); - ASSERT(!result.ok()); - ASSERT_EQ(Api::IoError::IoErrorCode::UnknownError, result.err_->getErrorCode()); - } -} - // Test that a readable event is raised when peer shutdown write. Also confirm read will return // EAGAIN. TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { From 9484dc864ad4463b57dab025d324e24f46b73326 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 17 Nov 2020 10:24:47 +0000 Subject: [PATCH 63/88] shutdown test Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index b0fd4b2e68227..98363ac4d3108 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -775,24 +775,29 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { auto& peer_internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); peer_internal_buffer.setWatermarks(128); - std::string big_chunk(256, 'a'); - peer_internal_buffer.add(big_chunk); + // std::string big_chunk(256, 'a'); + // peer_internal_buffer.add(big_chunk); + Buffer::OwnedImpl buf(std::string(256, 'a')); + io_handle_->write(buf); EXPECT_FALSE(io_handle_peer_->isWritable()); io_handle_peer_->shutdown(ENVOY_SHUT_WR); - ENVOY_LOG_MISC(debug, "after {} shutdown write", static_cast(io_handle_peer_.get())); + FANCY_LOG(debug, "after {} shutdown write", static_cast(io_handle_peer_.get())); - scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*scheduable_cb, enabled()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( - dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::FileTriggerType::Edge, + dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read); - scheduable_cb_->invokeCallback(); - EXPECT_FALSE(scheduable_cb_->enabled()); + EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); + scheduable_cb->invokeCallback(); + EXPECT_FALSE(scheduable_cb->enabled_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); - peer_internal_buffer.drain(peer_internal_buffer.length()); - EXPECT_TRUE(scheduable_cb_->enabled()); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + auto result = io_handle_peer_->recv(buf_.data(), buf_.size(), 0); + EXPECT_EQ(256, result.rc_); + EXPECT_TRUE(scheduable_cb->enabled_); io_handle_->close(); } From ecb54c85419a0d6c43331ac9083a4d9b277cd130 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 17 Nov 2020 10:40:44 +0000 Subject: [PATCH 64/88] move writev Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 206 +++++++++--------- 1 file changed, 103 insertions(+), 103 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 98363ac4d3108..4c5f74ec09bd3 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -298,6 +298,103 @@ TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { } } +TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { + EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); + EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); +} + +TEST_F(BufferedIoSocketHandleTest, TestShutDownOptionsNotSupported) { + ASSERT_DEBUG_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RD), ""); + ASSERT_DEBUG_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RDWR), ""); +} + +TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { + Buffer::OwnedImpl buf("0123456789"); + auto result = io_handle_peer_->write(buf); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(10, result.rc_); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); + EXPECT_EQ("0123456789", internal_buffer.toString()); + EXPECT_EQ(0, buf.length()); +} + +// Test write return error code. Ignoring the side effect of event scheduling. +TEST_F(BufferedIoSocketHandleTest, TestWriteAgain) { + Buffer::OwnedImpl buf("0123456789"); + + // Populate write destination with massive data so as to not writable. + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); + internal_buffer.setWatermarks(1024); + internal_buffer.add(std::string(2048, ' ')); + + auto result = io_handle_->write(buf); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); + EXPECT_EQ(10, buf.length()); +} + +TEST_F(BufferedIoSocketHandleTest, TestWriteErrorAfterShutdown) { + Buffer::OwnedImpl buf("0123456789"); + // Write after shutdown. + io_handle_->shutdown(ENVOY_SHUT_WR); + auto result = io_handle_->write(buf); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); + EXPECT_EQ(10, buf.length()); +} + +TEST_F(BufferedIoSocketHandleTest, TestWriteErrorAfterClose) { + Buffer::OwnedImpl buf("0123456789"); + io_handle_peer_->close(); + EXPECT_TRUE(io_handle_->isOpen()); + auto result = io_handle_->write(buf); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); +} + +// Test writev return error code. Ignoring the side effect of event scheduling. +TEST_F(BufferedIoSocketHandleTest, TestWritevAgain) { + auto [guard, slice] = allocateOneSlice(128); + // Populate write destination with massive data so as to not writable. + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); + internal_buffer.setWatermarks(128); + internal_buffer.add(std::string(256, ' ')); + auto result = io_handle_->writev(&slice, 1); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); +} + +TEST_F(BufferedIoSocketHandleTest, TestWritevErrorAfterShutdown) { + auto [guard, slice] = allocateOneSlice(128); + // Writev after shutdown. + io_handle_->shutdown(ENVOY_SHUT_WR); + auto result = io_handle_->writev(&slice, 1); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); +} + +TEST_F(BufferedIoSocketHandleTest, TestWritevErrorAfterClose) { + auto [guard, slice] = allocateOneSlice(1024); + // Close the peer. + io_handle_peer_->close(); + EXPECT_TRUE(io_handle_->isOpen()); + auto result = io_handle_->writev(&slice, 1); + ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); +} + +TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { + std::string raw_data("0123456789"); + absl::InlinedVector slices{ + // Contains 1 byte. + Buffer::RawSlice{static_cast(raw_data.data()), 1}, + // Contains 0 byte. + Buffer::RawSlice{nullptr, 1}, + // Contains 0 byte. + Buffer::RawSlice{raw_data.data() + 1, 0}, + // Contains 2 byte. + Buffer::RawSlice{raw_data.data() + 1, 2}, + }; + io_handle_peer_->writev(slices.data(), slices.size()); + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); + EXPECT_EQ(3, internal_buffer.length()); + EXPECT_EQ("012", internal_buffer.toString()); +} + TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); EXPECT_CALL(*scheduable_cb, enabled()); @@ -361,12 +458,14 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); scheduable_cb->invokeCallback(); - // Neither read nor write triggers self readiness. - EXPECT_CALL(cb_, called(_)).Times(0); + Buffer::OwnedImpl buf("abcd"); + EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + io_handle_peer_->write(buf); + + EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); + scheduable_cb->invokeCallback(); // Drain 1 bytes. - auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - internal_buffer.add("abcd"); auto result = io_handle_->recv(buf_.data(), 1, 0); EXPECT_TRUE(result.ok()); EXPECT_EQ(1, result.rc_); @@ -547,105 +646,6 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { io_handle_->resetFileEvents(); } -TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { - EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); - EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); -} - -TEST_F(BufferedIoSocketHandleTest, TestShutDownOptionsNotSupported) { - ASSERT_DEBUG_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RD), ""); - ASSERT_DEBUG_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RDWR), ""); -} - -TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { - Buffer::OwnedImpl buf("0123456789"); - auto result = io_handle_peer_->write(buf); - EXPECT_TRUE(result.ok()); - EXPECT_EQ(10, result.rc_); - auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - EXPECT_EQ("0123456789", internal_buffer.toString()); - EXPECT_EQ(0, buf.length()); -} - -// Test write return error code. Ignoring the side effect of event scheduling. -TEST_F(BufferedIoSocketHandleTest, TestWriteErrorCode) { - Buffer::OwnedImpl buf("0123456789"); - - { - // Populate write destination with massive data so as to not writable. - auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); - internal_buffer.setWatermarks(1024); - internal_buffer.add(std::string(2048, ' ')); - - auto result = io_handle_->write(buf); - ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); - EXPECT_EQ(10, buf.length()); - } - - { - // Write after shutdown. - io_handle_->shutdown(ENVOY_SHUT_WR); - auto result = io_handle_->write(buf); - ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); - EXPECT_EQ(10, buf.length()); - } - - { - io_handle_peer_->close(); - EXPECT_TRUE(io_handle_->isOpen()); - auto result = io_handle_->write(buf); - ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); - } -} - -// Test writev return error code. Ignoring the side effect of event scheduling. -TEST_F(BufferedIoSocketHandleTest, TestWritevErrorCode) { - std::string buf(10, 'a'); - Buffer::RawSlice slice{static_cast(buf.data()), 10}; - - { - // Populate write destination with massive data so as to not writable. - auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); - internal_buffer.setWatermarks(1024); - internal_buffer.add(std::string(2048, ' ')); - auto result = io_handle_->writev(&slice, 1); - ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); - } - - { - // Writev after shutdown. - io_handle_->shutdown(ENVOY_SHUT_WR); - auto result = io_handle_->writev(&slice, 1); - ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); - } - - { - // Close the peer. - io_handle_peer_->close(); - EXPECT_TRUE(io_handle_->isOpen()); - auto result = io_handle_->writev(&slice, 1); - ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); - } -} - -TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { - std::string raw_data("0123456789"); - absl::InlinedVector slices{ - // Contains 1 byte. - Buffer::RawSlice{static_cast(raw_data.data()), 1}, - // Contains 0 byte. - Buffer::RawSlice{nullptr, 1}, - // Contains 0 byte. - Buffer::RawSlice{raw_data.data() + 1, 0}, - // Contains 2 byte. - Buffer::RawSlice{raw_data.data() + 1, 2}, - }; - io_handle_peer_->writev(slices.data(), slices.size()); - auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - EXPECT_EQ(3, internal_buffer.length()); - EXPECT_EQ("012", internal_buffer.toString()); -} - TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { std::string accumulator; scheduable_cb_ = new NiceMock(&dispatcher_); From 968e09e2d5f1a8cfced4ab6d0d6576d9dd89f75d Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 17 Nov 2020 11:16:42 +0000 Subject: [PATCH 65/88] user space event test Signed-off-by: Yuchen Dai --- .../buffered_io_socket/peer_buffer.h | 2 +- .../buffered_io_socket_handle_impl_test.cc | 2 +- .../user_space_file_event_impl_test.cc | 63 ++++++++----------- 3 files changed, 28 insertions(+), 39 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/peer_buffer.h b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h index ba0c7bfea505b..44ffd43f0a702 100644 --- a/source/extensions/io_socket/buffered_io_socket/peer_buffer.h +++ b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h @@ -69,7 +69,7 @@ class ReadWritable : public WritablePeer { virtual bool isPeerShutDownWrite() const PURE; /** - * @return true if the pending receive buffer is not empty or read_end is set. + * @return true if the pending receive buffer is not empty or read_end is set. */ virtual bool isReadable() const PURE; }; diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 4c5f74ec09bd3..7f85815b7208d 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -1,8 +1,8 @@ -#include "common/common/fancy_logger.h" #include "envoy/buffer/buffer.h" #include "envoy/event/file_event.h" #include "common/buffer/buffer_impl.h" +#include "common/common/fancy_logger.h" #include "common/network/address_impl.h" #include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index 1b849824c7a47..6ad259756c8fb 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -43,6 +43,7 @@ class MockReadWritable : public ReadWritable { MOCK_METHOD(bool, isPeerShutDownWrite, (), (const)); MOCK_METHOD(bool, isReadable, (), (const)); }; + class UserSpaceFileEventImplTest : public testing::Test { public: UserSpaceFileEventImplTest() @@ -83,6 +84,13 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } + { + SCOPED_TRACE("merge events"); + user_file_event_->activate(Event::FileReadyType::Read); + user_file_event_->activate(Event::FileReadyType::Write); + EXPECT_CALL(ready_cb_, called(event_rw)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } } TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { @@ -105,43 +113,19 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { } TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents) { - { - auto current_event = Event::FileReadyType::Read; - SCOPED_TRACE(absl::StrCat("current event:", current_event)); - EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(true)).RetiresOnSaturation(); - EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(false)).RetiresOnSaturation(); - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - // user_file_event_->activate(e); - EXPECT_CALL(ready_cb_, called(current_event)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - user_file_event_.reset(); - } - - { - auto current_event = Event::FileReadyType::Write; - SCOPED_TRACE(absl::StrCat("current event:", current_event)); - EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(false)).RetiresOnSaturation(); - EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(true)).RetiresOnSaturation(); - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - // user_file_event_->activate(e); - EXPECT_CALL(ready_cb_, called(current_event)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - user_file_event_.reset(); - } - - { - auto current_event = event_rw; + for (const auto current_event : {Event::FileReadyType::Read, Event::FileReadyType::Write, + Event::FileReadyType::Read | Event::FileReadyType::Write}) { SCOPED_TRACE(absl::StrCat("current event:", current_event)); - EXPECT_CALL(io_source_, isReadable()).WillOnce(Return(true)).RetiresOnSaturation(); - EXPECT_CALL(io_source_, isPeerWritable()).WillOnce(Return(true)).RetiresOnSaturation(); - user_file_event_ = std::make_unique( + EXPECT_CALL(io_source_, isReadable()) + .WillOnce(Return((current_event & Event::FileReadyType::Read) != 0)) + .RetiresOnSaturation(); + EXPECT_CALL(io_source_, isPeerWritable()) + .WillOnce(Return((current_event & Event::FileReadyType::Write) != 0)) + .RetiresOnSaturation(); + auto user_file_event = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - // user_file_event_->activate(e); EXPECT_CALL(ready_cb_, called(current_event)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - user_file_event_.reset(); } } @@ -196,14 +180,21 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } + // Ensure both events are pending so that any enabled event will be immediately delivered. + setWritable(); + setReadable(); { - setWritable(); - setReadable(); user_file_event_->activate(Event::FileReadyType::Read); user_file_event_->setEnabled(Event::FileReadyType::Write); EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } + { + user_file_event_->activate(Event::FileReadyType::Write); + user_file_event_->setEnabled(Event::FileReadyType::Read); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)).Times(1); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } { EXPECT_CALL(ready_cb_, called(_)).Times(0); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); @@ -220,8 +211,6 @@ TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyAct dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { - setWritable(); - setReadable(); user_file_event_->activate(Event::FileReadyType::Closed); // Activate could deliver Closed event bit. EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)).Times(1); From 04ae3ac78a6791c26b3f3b64650bc9eaef9acd55 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 17 Nov 2020 11:26:27 +0000 Subject: [PATCH 66/88] typo Signed-off-by: Yuchen Dai --- ...red_io_socket_handle_impl_platform_test.cc | 8 +- .../buffered_io_socket_handle_impl_test.cc | 182 +++++++++--------- 2 files changed, 95 insertions(+), 95 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc index 9488d7b2b770c..3e282726587e7 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc @@ -47,10 +47,10 @@ class BufferedIoSocketHandlePlatformTest : public testing::Test { }; TEST_F(BufferedIoSocketHandlePlatformTest, TestCreatePlatformDefaultTriggerTypeFailOnWindows) { - // scheduable_cb will be destroyed by IoHandle. - auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); - EXPECT_CALL(*scheduable_cb, enabled()); - EXPECT_CALL(*scheduable_cb, cancel()); + // schedulable_cb will be destroyed by IoHandle. + auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, cancel()); first_io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::PlatformDefaultTriggerType, Event::FileReadyType::Read); diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 7f85815b7208d..7f21f86c55b12 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -59,7 +59,7 @@ class BufferedIoSocketHandleTest : public testing::Test { NiceMock dispatcher_; // Owned by BufferedIoSocketHandle. - NiceMock* scheduable_cb_; + NiceMock* schedulable_cb_; MockFileEventCallback cb_; std::unique_ptr io_handle_; std::unique_ptr io_handle_peer_; @@ -396,51 +396,51 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { } TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { - auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); - EXPECT_CALL(*scheduable_cb, enabled()); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); - scheduable_cb->invokeCallback(); + schedulable_cb->invokeCallback(); io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { - auto scheduable_cb = new NiceMock(&dispatcher_); + auto schedulable_cb = new NiceMock(&dispatcher_); // No data is available to read. Will not schedule read. { SCOPED_TRACE("enable read but no readable."); - EXPECT_CALL(*scheduable_cb, enabled()); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()).Times(0); + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()).Times(0); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read); - testing::Mock::VerifyAndClearExpectations(scheduable_cb); + testing::Mock::VerifyAndClearExpectations(schedulable_cb); } { SCOPED_TRACE("enable readwrite but only writable."); - EXPECT_CALL(*scheduable_cb, enabled()); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); io_handle_->enableFileEvents(Event::FileReadyType::Read | Event::FileReadyType::Write); - ASSERT_TRUE(scheduable_cb->enabled_); + ASSERT_TRUE(schedulable_cb->enabled_); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); - scheduable_cb->invokeCallback(); - ASSERT_FALSE(scheduable_cb->enabled_); - testing::Mock::VerifyAndClearExpectations(scheduable_cb); + schedulable_cb->invokeCallback(); + ASSERT_FALSE(schedulable_cb->enabled_); + testing::Mock::VerifyAndClearExpectations(schedulable_cb); } { SCOPED_TRACE("enable write and writable."); - EXPECT_CALL(*scheduable_cb, enabled()); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); io_handle_->enableFileEvents(Event::FileReadyType::Write); - ASSERT_TRUE(scheduable_cb->enabled_); + ASSERT_TRUE(schedulable_cb->enabled_); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); - scheduable_cb->invokeCallback(); - ASSERT_FALSE(scheduable_cb->enabled_); - testing::Mock::VerifyAndClearExpectations(scheduable_cb); + schedulable_cb->invokeCallback(); + ASSERT_FALSE(schedulable_cb->enabled_); + testing::Mock::VerifyAndClearExpectations(schedulable_cb); } // Close io_handle_ first to prevent events originated from peer close. io_handle_->close(); @@ -448,59 +448,59 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { } TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { - auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); - EXPECT_CALL(*scheduable_cb, enabled()); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); - scheduable_cb->invokeCallback(); + schedulable_cb->invokeCallback(); Buffer::OwnedImpl buf("abcd"); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); io_handle_peer_->write(buf); EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); - scheduable_cb->invokeCallback(); + schedulable_cb->invokeCallback(); // Drain 1 bytes. auto result = io_handle_->recv(buf_.data(), 1, 0); EXPECT_TRUE(result.ok()); EXPECT_EQ(1, result.rc_); - ASSERT_FALSE(scheduable_cb->enabled_); + ASSERT_FALSE(schedulable_cb->enabled_); io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { - auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); - EXPECT_CALL(*scheduable_cb, enabled()); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Write); - ASSERT_TRUE(scheduable_cb->enabled_); + ASSERT_TRUE(schedulable_cb->enabled_); // The write event is cleared and the read event is not ready. - EXPECT_CALL(*scheduable_cb, enabled()); - EXPECT_CALL(*scheduable_cb, cancel()); + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, cancel()); io_handle_->enableFileEvents(Event::FileReadyType::Read); - testing::Mock::VerifyAndClearExpectations(scheduable_cb); + testing::Mock::VerifyAndClearExpectations(schedulable_cb); - ASSERT_FALSE(scheduable_cb->enabled_); + ASSERT_FALSE(schedulable_cb->enabled_); io_handle_->resetFileEvents(); } TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { - auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); - EXPECT_CALL(*scheduable_cb, enabled()); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Write); - ASSERT_TRUE(scheduable_cb->enabled_); + ASSERT_TRUE(schedulable_cb->enabled_); io_handle_->resetFileEvents(); } @@ -515,15 +515,15 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { EXPECT_TRUE(io_handle_->isReadable()); EXPECT_FALSE(io_handle_->isWritable()); - auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); - EXPECT_CALL(*scheduable_cb, enabled()); + auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*schedulable_cb, enabled()); // No event is available. - EXPECT_CALL(*scheduable_cb, cancel()); + EXPECT_CALL(*schedulable_cb, cancel()); io_handle_peer_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); // Neither readable nor writable. - ASSERT_FALSE(scheduable_cb->enabled_); + ASSERT_FALSE(schedulable_cb->enabled_); { SCOPED_TRACE("drain very few data."); @@ -532,15 +532,15 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { } { SCOPED_TRACE("drain to low watermark."); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()).Times(1); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()).Times(1); auto result = io_handle_->recv(buf_.data(), 232, 0); EXPECT_TRUE(io_handle_->isWritable()); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); - scheduable_cb->invokeCallback(); + schedulable_cb->invokeCallback(); } { SCOPED_TRACE("clean up."); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()).Times(1); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()).Times(1); // Important: close before peer. io_handle_->close(); } @@ -550,8 +550,8 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); std::string accumulator; - scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + schedulable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); bool should_close = false; io_handle_->initializeFileEvent( dispatcher_, @@ -586,19 +586,19 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { } }, Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); - scheduable_cb_->invokeCallback(); + schedulable_cb_->invokeCallback(); // Not closed yet. ASSERT_FALSE(should_close); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); io_handle_peer_->close(); - ASSERT_TRUE(scheduable_cb_->enabled()); - scheduable_cb_->invokeCallback(); + ASSERT_TRUE(schedulable_cb_->enabled()); + schedulable_cb_->invokeCallback(); ASSERT_TRUE(should_close); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()).Times(0); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()).Times(0); io_handle_->close(); EXPECT_EQ(4, accumulator.size()); io_handle_->resetFileEvents(); @@ -611,8 +611,8 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { internal_buffer.add("abcd"); std::string accumulator; - scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + schedulable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); bool should_close = false; io_handle_->initializeFileEvent( dispatcher_, @@ -630,16 +630,16 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { } }, Event::FileTriggerType::Edge, Event::FileReadyType::Read); - scheduable_cb_->invokeCallback(); + schedulable_cb_->invokeCallback(); // Not closed yet. ASSERT_FALSE(should_close); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); io_handle_peer_->shutdown(ENVOY_SHUT_WR); - ASSERT_TRUE(scheduable_cb_->enabled()); - scheduable_cb_->invokeCallback(); + ASSERT_TRUE(schedulable_cb_->enabled()); + schedulable_cb_->invokeCallback(); ASSERT_FALSE(should_close); EXPECT_EQ(4, accumulator.size()); io_handle_->close(); @@ -648,8 +648,8 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { std::string accumulator; - scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + schedulable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); bool should_close = false; io_handle_->initializeFileEvent( dispatcher_, @@ -670,16 +670,16 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { } }, Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); - scheduable_cb_->invokeCallback(); - EXPECT_FALSE(scheduable_cb_->enabled()); + schedulable_cb_->invokeCallback(); + EXPECT_FALSE(schedulable_cb_->enabled()); Buffer::OwnedImpl data_to_write("0123456789"); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); io_handle_peer_->write(data_to_write); EXPECT_EQ(0, data_to_write.length()); - EXPECT_TRUE(scheduable_cb_->enabled()); - scheduable_cb_->invokeCallback(); + EXPECT_TRUE(schedulable_cb_->enabled()); + schedulable_cb_->invokeCallback(); EXPECT_EQ("0123456789", accumulator); EXPECT_FALSE(should_close); @@ -688,8 +688,8 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { std::string accumulator; - scheduable_cb_ = new NiceMock(&dispatcher_); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + schedulable_cb_ = new NiceMock(&dispatcher_); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); bool should_close = false; io_handle_->initializeFileEvent( dispatcher_, @@ -710,16 +710,16 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { } }, Event::FileTriggerType::Edge, Event::FileReadyType::Read | Event::FileReadyType::Write); - scheduable_cb_->invokeCallback(); - EXPECT_FALSE(scheduable_cb_->enabled()); + schedulable_cb_->invokeCallback(); + EXPECT_FALSE(schedulable_cb_->enabled()); std::string raw_data("0123456789"); Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); io_handle_peer_->writev(&slice, 1); - EXPECT_TRUE(scheduable_cb_->enabled()); - scheduable_cb_->invokeCallback(); + EXPECT_TRUE(schedulable_cb_->enabled()); + schedulable_cb_->invokeCallback(); EXPECT_EQ("0123456789", accumulator); EXPECT_FALSE(should_close); @@ -730,7 +730,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { io_handle_peer_->shutdown(ENVOY_SHUT_WR); ENVOY_LOG_MISC(debug, "after {} shutdown write ", static_cast(io_handle_peer_.get())); std::string accumulator; - scheduable_cb_ = new NiceMock(&dispatcher_); + schedulable_cb_ = new NiceMock(&dispatcher_); bool should_close = false; io_handle_peer_->initializeFileEvent( dispatcher_, @@ -756,18 +756,18 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { }, Event::FileTriggerType::Edge, Event::FileReadyType::Read); - EXPECT_FALSE(scheduable_cb_->enabled()); + EXPECT_FALSE(schedulable_cb_->enabled()); std::string raw_data("0123456789"); Buffer::RawSlice slice{static_cast(raw_data.data()), raw_data.size()}; - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); io_handle_->writev(&slice, 1); - EXPECT_TRUE(scheduable_cb_->enabled()); + EXPECT_TRUE(schedulable_cb_->enabled()); - scheduable_cb_->invokeCallback(); - EXPECT_FALSE(scheduable_cb_->enabled()); + schedulable_cb_->invokeCallback(); + EXPECT_FALSE(schedulable_cb_->enabled()); EXPECT_EQ(raw_data, accumulator); - EXPECT_CALL(*scheduable_cb_, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); io_handle_->close(); io_handle_->resetFileEvents(); } @@ -784,20 +784,20 @@ TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { io_handle_peer_->shutdown(ENVOY_SHUT_WR); FANCY_LOG(debug, "after {} shutdown write", static_cast(io_handle_peer_.get())); - auto scheduable_cb = new Event::MockSchedulableCallback(&dispatcher_); - EXPECT_CALL(*scheduable_cb, enabled()); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); io_handle_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read); EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); - scheduable_cb->invokeCallback(); - EXPECT_FALSE(scheduable_cb->enabled_); + schedulable_cb->invokeCallback(); + EXPECT_FALSE(schedulable_cb->enabled_); - EXPECT_CALL(*scheduable_cb, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); auto result = io_handle_peer_->recv(buf_.data(), buf_.size(), 0); EXPECT_EQ(256, result.rc_); - EXPECT_TRUE(scheduable_cb->enabled_); + EXPECT_TRUE(schedulable_cb->enabled_); io_handle_->close(); } @@ -821,13 +821,13 @@ TEST_F(BufferedIoSocketHandleTest, TestConnect) { } TEST_F(BufferedIoSocketHandleTest, TestActivateEvent) { - scheduable_cb_ = new NiceMock(&dispatcher_); + schedulable_cb_ = new NiceMock(&dispatcher_); io_handle_->initializeFileEvent( dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::FileTriggerType::Edge, Event::FileReadyType::Read); - EXPECT_FALSE(scheduable_cb_->enabled()); + EXPECT_FALSE(schedulable_cb_->enabled()); io_handle_->activateFileEvents(Event::FileReadyType::Read); - ASSERT_TRUE(scheduable_cb_->enabled()); + ASSERT_TRUE(schedulable_cb_->enabled()); } TEST_F(BufferedIoSocketHandleTest, TestDeathOnActivatingDestroyedEvents) { From dfc457dde6149026d5f066a11cfc08fe563a761e Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 18 Nov 2020 19:47:28 +0000 Subject: [PATCH 67/88] watermark func, inlineNewDataAvailable, split userspace event file Signed-off-by: Yuchen Dai --- .../io_socket/buffered_io_socket/BUILD | 18 +++++++++++-- .../buffered_io_socket_handle_impl.cc | 16 ++--------- .../buffered_io_socket_handle_impl.h | 17 +++++++++++- .../buffered_io_socket_handle_impl_test.cc | 27 +++++++++---------- 4 files changed, 47 insertions(+), 31 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index a2dad3494947b..5d933c67bb6d9 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -20,20 +20,34 @@ envoy_cc_extension( ], ) +envoy_cc_extension( + name = "users_space_file_event_lib", + srcs = [ + "user_space_file_event_impl.cc", + ], + hdrs = [ + "user_space_file_event_impl.h", + ], + security_posture = "unknown", + status = "alpha", + deps = [ + ":peer_buffer_lib", + "//source/common/event:dispatcher_includes", + ], +) envoy_cc_extension( name = "buffered_io_socket_handle_lib", srcs = [ "buffered_io_socket_handle_impl.cc", - "user_space_file_event_impl.cc", ], hdrs = [ "buffered_io_socket_handle_impl.h", - "user_space_file_event_impl.h", ], security_posture = "unknown", status = "alpha", deps = [ ":peer_buffer_lib", + ":users_space_file_event_lib", "//source/common/event:dispatcher_includes", "//source/common/network:default_socket_interface_lib", ], diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index b5b193c6f6389..9ec70104de06c 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -25,18 +25,8 @@ Api::SysCallIntResult makeInvalidSyscallResult() { } // namespace BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() - : pending_received_data_( - [this]() -> void { - if (writable_peer_) { - ENVOY_LOG(debug, "Socket {} switches to low watermark. Notify {}.", - static_cast(this), static_cast(writable_peer_)); - writable_peer_->onPeerBufferLowWatermark(); - } - }, - []() -> void { - // Low to high is checked by peer after peer writes data. - }, - []() -> void {}) {} + : pending_received_data_([&]() -> void { this->onBelowLowWatermark(); }, + [&]() -> void { this->onAboveHighWatermark(); }, []() -> void {}) {} BufferedIoSocketHandleImpl::~BufferedIoSocketHandleImpl() { if (!closed_) { @@ -52,7 +42,6 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { static_cast(writable_peer_)); // Notify the peer we won't write more data. shutdown(WRITE). writable_peer_->setWriteEnd(); - writable_peer_->setNewDataAvailable(); // Notify the peer that we no longer accept data. shutdown(RD). writable_peer_->onPeerDestroy(); writable_peer_ = nullptr; @@ -321,7 +310,6 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { ASSERT(writable_peer_); // Notify the peer we won't write more data. writable_peer_->setWriteEnd(); - writable_peer_->setNewDataAvailable(); write_shutdown_ = true; } return {0, 0}; diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index bf0929c3d1786..532cd0221a041 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -81,8 +81,23 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, Api::SysCallIntResult shutdown(int how) override; absl::optional lastRoundTripTime() override { return absl::nullopt; } + void setWatermarks(uint32_t watermark) { pending_received_data_.setWatermarks(watermark); } + void onBelowLowWatermark() { + if (writable_peer_) { + ENVOY_LOG(debug, "Socket {} switches to low watermark. Notify {}.", static_cast(this), + static_cast(writable_peer_)); + writable_peer_->onPeerBufferLowWatermark(); + } + } + void onAboveHighWatermark() { + // Low to high is checked by peer after peer writes data. + } + // WritablePeer - void setWriteEnd() override { read_end_stream_ = true; } + void setWriteEnd() override { + read_end_stream_ = true; + setNewDataAvailable(); + } bool isWriteEndSet() override { return read_end_stream_; } void setNewDataAvailable() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 7f21f86c55b12..1cd530e417987 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -161,6 +161,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { io_handle_->setWriteEnd(); result = io_handle_->read(buf, 10); EXPECT_TRUE(result.ok()); + EXPECT_EQ(0, result.rc_); } // Test read side effects. @@ -206,9 +207,7 @@ TEST_F(BufferedIoSocketHandleTest, TestBasicReadv) { } TEST_F(BufferedIoSocketHandleTest, FlowControl) { - auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - // TODO(lambdai): Make it an IoHandle method. - internal_buffer.setWatermarks(128); + io_handle_->setWatermarks(128); EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_->isWritable()); @@ -221,6 +220,7 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { bool writable_flipped = false; // During the repeated recv, the writable flag must switch to true. + auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); while (internal_buffer.length() > 0) { SCOPED_TRACE(internal_buffer.length()); FANCY_LOG(debug, "internal buffer length = {}", internal_buffer.length()); @@ -320,13 +320,13 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { // Test write return error code. Ignoring the side effect of event scheduling. TEST_F(BufferedIoSocketHandleTest, TestWriteAgain) { - Buffer::OwnedImpl buf("0123456789"); - // Populate write destination with massive data so as to not writable. - auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); - internal_buffer.setWatermarks(1024); - internal_buffer.add(std::string(2048, ' ')); + io_handle_peer_->setWatermarks(128); + Buffer::OwnedImpl pending_data(std::string(256, 'a')); + io_handle_->write(pending_data); + EXPECT_FALSE(!io_handle_peer_->isWritable()); + Buffer::OwnedImpl buf("0123456789"); auto result = io_handle_->write(buf); ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); EXPECT_EQ(10, buf.length()); @@ -353,8 +353,8 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorAfterClose) { TEST_F(BufferedIoSocketHandleTest, TestWritevAgain) { auto [guard, slice] = allocateOneSlice(128); // Populate write destination with massive data so as to not writable. + io_handle_peer_->setWatermarks(128); auto& internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); - internal_buffer.setWatermarks(128); internal_buffer.add(std::string(256, ' ')); auto result = io_handle_->writev(&slice, 1); ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); @@ -505,8 +505,9 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { } TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { + io_handle_->setWatermarks(128); auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); - internal_buffer.setWatermarks(128); + EXPECT_FALSE(io_handle_->isReadable()); EXPECT_TRUE(io_handle_peer_->isWritable()); @@ -773,10 +774,8 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { } TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { - auto& peer_internal_buffer = getWatermarkBufferHelper(*io_handle_peer_); - peer_internal_buffer.setWatermarks(128); - // std::string big_chunk(256, 'a'); - // peer_internal_buffer.add(big_chunk); + io_handle_peer_->setWatermarks(128); + Buffer::OwnedImpl buf(std::string(256, 'a')); io_handle_->write(buf); EXPECT_FALSE(io_handle_peer_->isWritable()); From 042f44d1f4de51eb0031e387f375360ac1b55a11 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 18 Nov 2020 21:04:31 +0000 Subject: [PATCH 68/88] more events test Signed-off-by: Yuchen Dai --- .../io_socket/buffered_io_socket/BUILD | 1 + .../buffered_io_socket_handle_impl_test.cc | 2 +- .../user_space_file_event_impl_test.cc | 50 ++++++++++++++++++- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index 5d933c67bb6d9..3ad6f8eecd4fb 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -35,6 +35,7 @@ envoy_cc_extension( "//source/common/event:dispatcher_includes", ], ) + envoy_cc_extension( name = "buffered_io_socket_handle_lib", srcs = [ diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 1cd530e417987..f18edea17e435 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -324,7 +324,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteAgain) { io_handle_peer_->setWatermarks(128); Buffer::OwnedImpl pending_data(std::string(256, 'a')); io_handle_->write(pending_data); - EXPECT_FALSE(!io_handle_peer_->isWritable()); + EXPECT_FALSE(io_handle_peer_->isWritable()); Buffer::OwnedImpl buf("0123456789"); auto result = io_handle_->write(buf); diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index 6ad259756c8fb..168dcea9a9526 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -51,6 +51,7 @@ class UserSpaceFileEventImplTest : public testing::Test { void setWritable() { EXPECT_CALL(io_source_, isPeerWritable()).WillRepeatedly(Return(true)); } void setReadable() { EXPECT_CALL(io_source_, isReadable()).WillRepeatedly(Return(true)); } + void clearWriteReable() { testing::Mock::VerifyAndClearExpectations(&io_source_); } protected: NiceMock io_source_; @@ -61,10 +62,37 @@ class UserSpaceFileEventImplTest : public testing::Test { }; TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { + for (const auto current_event : {Event::FileReadyType::Read, Event::FileReadyType::Write, + Event::FileReadyType::Read | Event::FileReadyType::Write}) { + SCOPED_TRACE(absl::StrCat("current event:", current_event)); + clearWriteReable(); + if (current_event | Event::FileReadyType::Read) { + setReadable(); + } + if (current_event | Event::FileReadyType::Write) { + setWritable(); + } + MockReadyCb ready_cb; + auto user_file_event = std::make_unique( + *dispatcher_, [&ready_cb](uint32_t arg) { ready_cb.called(arg); }, current_event, + io_source_); + EXPECT_CALL(ready_cb, called(current_event)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + testing::Mock::VerifyAndClearExpectations(&ready_cb); + } +} + +TEST_F(UserSpaceFileEventImplTest, TestReadEventNotDeliveredAfterDisabledRead) { setWritable(); + setReadable(); user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)); + // The above should deliver both Read and Write during the poll. It is not tested here but in + // other test case. + + // Now disable Read. + user_file_event_->setEnabled(Event::FileReadyType::Write); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } @@ -183,6 +211,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { // Ensure both events are pending so that any enabled event will be immediately delivered. setWritable(); setReadable(); + // The enabled event are delivered but not the other. { user_file_event_->activate(Event::FileReadyType::Read); user_file_event_->setEnabled(Event::FileReadyType::Write); @@ -195,6 +224,24 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)).Times(1); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } + // No event is delivered since it's either user disabled or io_handle doesn't provide pending + // data. + { + clearWriteReable(); + setReadable(); + user_file_event_->activate(Event::FileReadyType::Read); + user_file_event_->setEnabled(Event::FileReadyType::Write); + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + clearWriteReable(); + setWritable(); + user_file_event_->activate(Event::FileReadyType::Write); + user_file_event_->setEnabled(Event::FileReadyType::Read); + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } { EXPECT_CALL(ready_cb_, called(_)).Times(0); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); @@ -221,7 +268,6 @@ TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyAct dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } } - } // namespace } // namespace BufferedIoSocket } // namespace IoSocket From c5e7aba521ed61f0746c8dd303e92af938a280ef Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Thu, 19 Nov 2020 17:27:14 +0000 Subject: [PATCH 69/88] lint Signed-off-by: Yuchen Dai --- .../buffered_io_socket/buffered_io_socket_handle_impl_test.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index f18edea17e435..b21016bcb181d 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -13,7 +13,6 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -using testing::_; using testing::NiceMock; namespace Envoy { From d2aa295a8ba96581d86cde14111ad66c518fa4fd Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 21 Dec 2020 01:12:29 -0800 Subject: [PATCH 70/88] move test to cc_extension_test Signed-off-by: Yuchen Dai --- source/extensions/extensions_build_config.bzl | 5 +++++ .../buffered_io_socket_handle_impl.cc | 2 ++ test/extensions/io_socket/buffered_io_socket/BUILD | 14 ++++++++++---- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index 52f127950c640..4fc8faab63e8d 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -229,6 +229,11 @@ EXTENSIONS = { "envoy.wasm.runtime.v8": "//source/extensions/wasm_runtime/v8:config", "envoy.wasm.runtime.wavm": "//source/extensions/wasm_runtime/wavm:config", "envoy.wasm.runtime.wasmtime": "//source/extensions/wasm_runtime/wasmtime:config", + + # + # IO socket + # + "envoy.io_socket.user_space_socket": "//source/extentions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", } # These can be changed to ["//visibility:public"], for downstream builds which diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index 9ec70104de06c..b378f58c15c9e 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -261,10 +261,12 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::setBlocking(bool) { absl::optional BufferedIoSocketHandleImpl::domain() { return absl::nullopt; } Network::Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { + // TODO(lambdai): Rewrite when caller accept error as the return value. throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); } Network::Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { + // TODO(lambdai): Rewrite when caller accept error as the return value. throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); } diff --git a/test/extensions/io_socket/buffered_io_socket/BUILD b/test/extensions/io_socket/buffered_io_socket/BUILD index 82b16c32c7d01..3484da468fe4c 100644 --- a/test/extensions/io_socket/buffered_io_socket/BUILD +++ b/test/extensions/io_socket/buffered_io_socket/BUILD @@ -1,16 +1,20 @@ load( "//bazel:envoy_build_system.bzl", - "envoy_cc_test", "envoy_package", ) +load( + "//test/extensions:extensions_build_system.bzl", + "envoy_extension_cc_test", +) licenses(["notice"]) # Apache 2 envoy_package() -envoy_cc_test( +envoy_extension_cc_test( name = "buffered_io_socket_handle_impl_test", srcs = ["buffered_io_socket_handle_impl_test.cc"], + extension_name = "envoy.io_socket.user_space_socket", deps = [ "//source/common/common:utility_lib", "//source/common/network:address_lib", @@ -19,9 +23,10 @@ envoy_cc_test( ], ) -envoy_cc_test( +envoy_extension_cc_test( name = "buffered_io_socket_handle_impl_platform_test", srcs = ["buffered_io_socket_handle_impl_platform_test.cc"], + extension_name = "envoy.io_socket.user_space_socket", tags = ["fails_on_windows"], deps = [ "//source/common/common:utility_lib", @@ -31,9 +36,10 @@ envoy_cc_test( ], ) -envoy_cc_test( +envoy_extension_cc_test( name = "user_space_file_event_impl_test", srcs = ["user_space_file_event_impl_test.cc"], + extension_name = "envoy.io_socket.user_space_socket", deps = [ "//include/envoy/event:file_event_interface", "//source/common/event:dispatcher_includes", From faf8dc5a1ea7e18977dc6cfaa92366227e1a7cb6 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 21 Dec 2020 01:23:24 -0800 Subject: [PATCH 71/88] typo and remove Test prefix at test case name Signed-off-by: Yuchen Dai --- .../user_space_file_event_impl.cc | 4 +- .../user_space_file_event_impl.h | 2 +- ...red_io_socket_handle_impl_platform_test.cc | 2 +- .../buffered_io_socket_handle_impl_test.cc | 100 +++++++++--------- .../user_space_file_event_impl_test.cc | 26 ++--- 5 files changed, 66 insertions(+), 68 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index cef1f5c0b7603..a782310d5e5cc 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -23,7 +23,7 @@ UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Ev setEnabled(events); } -void EventListenerImpl::clearEphemeralEvents(uint32_t) { +void EventListenerImpl::clearEphemeralEvents() { // Clear ephemeral events to align with FileEventImpl::setEnable(). ephemeral_events_ = 0; } @@ -44,7 +44,7 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { // Only supported event types are set. ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | Event::FileReadyType::Closed)) == events); - event_listener_.clearEphemeralEvents(events); + event_listener_.clearEphemeralEvents(); bool was_enabled = schedulable_->enabled(); // Recalculate activated events. uint32_t events_to_notify = 0; diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h index 95314301f69ac..741f8becdfe68 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h @@ -24,7 +24,7 @@ class EventListenerImpl { public: ~EventListenerImpl() = default; - void clearEphemeralEvents(uint32_t enabled_events); + void clearEphemeralEvents(); void onEventActivated(uint32_t activated_events); uint32_t getAndClearEphemeralEvents() { return std::exchange(ephemeral_events_, 0); } diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc index 3e282726587e7..051151d99e073 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc @@ -46,7 +46,7 @@ class BufferedIoSocketHandlePlatformTest : public testing::Test { MockFileEventCallback cb_; }; -TEST_F(BufferedIoSocketHandlePlatformTest, TestCreatePlatformDefaultTriggerTypeFailOnWindows) { +TEST_F(BufferedIoSocketHandlePlatformTest, CreatePlatformDefaultTriggerTypeFailOnWindows) { // schedulable_cb will be destroyed by IoHandle. auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); EXPECT_CALL(*schedulable_cb, enabled()); diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 4a8be29745230..bfbe574ffa82a 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -66,7 +66,7 @@ class BufferedIoSocketHandleTest : public testing::Test { }; // Test recv side effects. -TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { +TEST_F(BufferedIoSocketHandleTest, BasicRecv) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("0123456789"); { @@ -88,7 +88,7 @@ TEST_F(BufferedIoSocketHandleTest, TestBasicRecv) { } // Test recv side effects. -TEST_F(BufferedIoSocketHandleTest, TestRecvPeek) { +TEST_F(BufferedIoSocketHandleTest, RecvPeek) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("0123456789"); { @@ -124,7 +124,7 @@ TEST_F(BufferedIoSocketHandleTest, TestRecvPeek) { } } -TEST_F(BufferedIoSocketHandleTest, TestRecvPeekWhenPendingDataButShutdown) { +TEST_F(BufferedIoSocketHandleTest, RecvPeekWhenPendingDataButShutdown) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("0123456789"); auto result = io_handle_->recv(buf_.data(), buf_.size(), MSG_PEEK); @@ -132,7 +132,7 @@ TEST_F(BufferedIoSocketHandleTest, TestRecvPeekWhenPendingDataButShutdown) { ASSERT_EQ("0123456789", absl::string_view(buf_.data(), result.rc_)); } -TEST_F(BufferedIoSocketHandleTest, TestMultipleRecvDrain) { +TEST_F(BufferedIoSocketHandleTest, MultipleRecvDrain) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); { @@ -152,7 +152,7 @@ TEST_F(BufferedIoSocketHandleTest, TestMultipleRecvDrain) { } // Test read side effects. -TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { +TEST_F(BufferedIoSocketHandleTest, ReadEmpty) { Buffer::OwnedImpl buf; auto result = io_handle_->read(buf, 10); EXPECT_FALSE(result.ok()); @@ -164,7 +164,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadEmpty) { } // Test read side effects. -TEST_F(BufferedIoSocketHandleTest, TestReadContent) { +TEST_F(BufferedIoSocketHandleTest, ReadContent) { Buffer::OwnedImpl buf; auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcdefg"); @@ -181,7 +181,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadContent) { } // Test readv behavior. -TEST_F(BufferedIoSocketHandleTest, TestBasicReadv) { +TEST_F(BufferedIoSocketHandleTest, BasicReadv) { Buffer::OwnedImpl buf_to_write("abc"); io_handle_peer_->write(buf_to_write); @@ -245,7 +245,7 @@ TEST_F(BufferedIoSocketHandleTest, FlowControl) { } // Consistent with other IoHandle: allow write empty data when handle is closed. -TEST_F(BufferedIoSocketHandleTest, TestNoErrorWriteZeroDataToClosedIoHandle) { +TEST_F(BufferedIoSocketHandleTest, NoErrorWriteZeroDataToClosedIoHandle) { io_handle_->close(); { Buffer::OwnedImpl buf; @@ -261,7 +261,7 @@ TEST_F(BufferedIoSocketHandleTest, TestNoErrorWriteZeroDataToClosedIoHandle) { } } -TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { +TEST_F(BufferedIoSocketHandleTest, ErrorOnClosedIoHandle) { io_handle_->close(); { auto [guard, slice] = allocateOneSlice(1024); @@ -297,17 +297,17 @@ TEST_F(BufferedIoSocketHandleTest, TestErrorOnClosedIoHandle) { } } -TEST_F(BufferedIoSocketHandleTest, TestRepeatedShutdownWR) { +TEST_F(BufferedIoSocketHandleTest, RepeatedShutdownWR) { EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); EXPECT_EQ(io_handle_peer_->shutdown(ENVOY_SHUT_WR).rc_, 0); } -TEST_F(BufferedIoSocketHandleTest, TestShutDownOptionsNotSupported) { +TEST_F(BufferedIoSocketHandleTest, ShutDownOptionsNotSupported) { ASSERT_DEBUG_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RD), ""); ASSERT_DEBUG_DEATH(io_handle_peer_->shutdown(ENVOY_SHUT_RDWR), ""); } -TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { +TEST_F(BufferedIoSocketHandleTest, WriteByMove) { Buffer::OwnedImpl buf("0123456789"); auto result = io_handle_peer_->write(buf); EXPECT_TRUE(result.ok()); @@ -318,7 +318,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteByMove) { } // Test write return error code. Ignoring the side effect of event scheduling. -TEST_F(BufferedIoSocketHandleTest, TestWriteAgain) { +TEST_F(BufferedIoSocketHandleTest, WriteAgain) { // Populate write destination with massive data so as to not writable. io_handle_peer_->setWatermarks(128); Buffer::OwnedImpl pending_data(std::string(256, 'a')); @@ -331,7 +331,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteAgain) { EXPECT_EQ(10, buf.length()); } -TEST_F(BufferedIoSocketHandleTest, TestWriteErrorAfterShutdown) { +TEST_F(BufferedIoSocketHandleTest, WriteErrorAfterShutdown) { Buffer::OwnedImpl buf("0123456789"); // Write after shutdown. io_handle_->shutdown(ENVOY_SHUT_WR); @@ -340,7 +340,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorAfterShutdown) { EXPECT_EQ(10, buf.length()); } -TEST_F(BufferedIoSocketHandleTest, TestWriteErrorAfterClose) { +TEST_F(BufferedIoSocketHandleTest, WriteErrorAfterClose) { Buffer::OwnedImpl buf("0123456789"); io_handle_peer_->close(); EXPECT_TRUE(io_handle_->isOpen()); @@ -349,7 +349,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteErrorAfterClose) { } // Test writev return error code. Ignoring the side effect of event scheduling. -TEST_F(BufferedIoSocketHandleTest, TestWritevAgain) { +TEST_F(BufferedIoSocketHandleTest, WritevAgain) { auto [guard, slice] = allocateOneSlice(128); // Populate write destination with massive data so as to not writable. io_handle_peer_->setWatermarks(128); @@ -359,7 +359,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevAgain) { ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); } -TEST_F(BufferedIoSocketHandleTest, TestWritevErrorAfterShutdown) { +TEST_F(BufferedIoSocketHandleTest, WritevErrorAfterShutdown) { auto [guard, slice] = allocateOneSlice(128); // Writev after shutdown. io_handle_->shutdown(ENVOY_SHUT_WR); @@ -367,7 +367,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevErrorAfterShutdown) { ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); } -TEST_F(BufferedIoSocketHandleTest, TestWritevErrorAfterClose) { +TEST_F(BufferedIoSocketHandleTest, WritevErrorAfterClose) { auto [guard, slice] = allocateOneSlice(1024); // Close the peer. io_handle_peer_->close(); @@ -376,7 +376,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevErrorAfterClose) { ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::UnknownError); } -TEST_F(BufferedIoSocketHandleTest, TestWritevToPeer) { +TEST_F(BufferedIoSocketHandleTest, WritevToPeer) { std::string raw_data("0123456789"); absl::InlinedVector slices{ // Contains 1 byte. @@ -407,7 +407,7 @@ TEST_F(BufferedIoSocketHandleTest, EventScheduleBasic) { io_handle_->resetFileEvents(); } -TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { +TEST_F(BufferedIoSocketHandleTest, SetEnabledTriggerEventSchedule) { auto schedulable_cb = new NiceMock(&dispatcher_); // No data is available to read. Will not schedule read. { @@ -446,7 +446,7 @@ TEST_F(BufferedIoSocketHandleTest, TestSetEnabledTriggerEventSchedule) { io_handle_peer_->close(); } -TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { +TEST_F(BufferedIoSocketHandleTest, ReadAndWriteAreEdgeTriggered) { auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); EXPECT_CALL(*schedulable_cb, enabled()); EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); @@ -473,7 +473,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAndWriteAreEdgeTriggered) { io_handle_->resetFileEvents(); } -TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { +TEST_F(BufferedIoSocketHandleTest, SetDisabledBlockEventSchedule) { auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); EXPECT_CALL(*schedulable_cb, enabled()); EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); @@ -492,7 +492,7 @@ TEST_F(BufferedIoSocketHandleTest, TestSetDisabledBlockEventSchedule) { io_handle_->resetFileEvents(); } -TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { +TEST_F(BufferedIoSocketHandleTest, EventResetClearCallback) { auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); EXPECT_CALL(*schedulable_cb, enabled()); EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); @@ -503,7 +503,7 @@ TEST_F(BufferedIoSocketHandleTest, TestEventResetClearCallback) { io_handle_->resetFileEvents(); } -TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { +TEST_F(BufferedIoSocketHandleTest, DrainToLowWaterMarkTriggerReadEvent) { io_handle_->setWatermarks(128); auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); @@ -546,7 +546,7 @@ TEST_F(BufferedIoSocketHandleTest, TestDrainToLowWaterMarkTriggerReadEvent) { } } -TEST_F(BufferedIoSocketHandleTest, TestClose) { +TEST_F(BufferedIoSocketHandleTest, Close) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); std::string accumulator; @@ -606,7 +606,7 @@ TEST_F(BufferedIoSocketHandleTest, TestClose) { // Test that a readable event is raised when peer shutdown write. Also confirm read will return // EAGAIN. -TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { +TEST_F(BufferedIoSocketHandleTest, ShutDownRaiseEvent) { auto& internal_buffer = getWatermarkBufferHelper(*io_handle_); internal_buffer.add("abcd"); @@ -646,7 +646,7 @@ TEST_F(BufferedIoSocketHandleTest, TestShutDownRaiseEvent) { io_handle_->resetFileEvents(); } -TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { +TEST_F(BufferedIoSocketHandleTest, WriteScheduleWritableEvent) { std::string accumulator; schedulable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); @@ -686,7 +686,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWriteScheduleWritableEvent) { io_handle_->close(); } -TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { +TEST_F(BufferedIoSocketHandleTest, WritevScheduleWritableEvent) { std::string accumulator; schedulable_cb_ = new NiceMock(&dispatcher_); EXPECT_CALL(*schedulable_cb_, scheduleCallbackNextIteration()); @@ -726,7 +726,7 @@ TEST_F(BufferedIoSocketHandleTest, TestWritevScheduleWritableEvent) { io_handle_->close(); } -TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { +TEST_F(BufferedIoSocketHandleTest, ReadAfterShutdownWrite) { io_handle_peer_->shutdown(ENVOY_SHUT_WR); ENVOY_LOG_MISC(debug, "after {} shutdown write ", static_cast(io_handle_peer_.get())); std::string accumulator; @@ -772,7 +772,7 @@ TEST_F(BufferedIoSocketHandleTest, TestReadAfterShutdownWrite) { io_handle_->resetFileEvents(); } -TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { +TEST_F(BufferedIoSocketHandleTest, NotififyWritableAfterShutdownWrite) { io_handle_peer_->setWatermarks(128); Buffer::OwnedImpl buf(std::string(256, 'a')); @@ -800,25 +800,23 @@ TEST_F(BufferedIoSocketHandleTest, TestNotififyWritableAfterShutdownWrite) { io_handle_->close(); } -TEST_F(BufferedIoSocketHandleTest, TestNotSupportingMmsg) { - EXPECT_FALSE(io_handle_->supportsMmsg()); -} +TEST_F(BufferedIoSocketHandleTest, NotSupportingMmsg) { EXPECT_FALSE(io_handle_->supportsMmsg()); } -TEST_F(BufferedIoSocketHandleTest, TestNotSupportsUdpGro) { +TEST_F(BufferedIoSocketHandleTest, NotSupportsUdpGro) { EXPECT_FALSE(io_handle_->supportsUdpGro()); } -TEST_F(BufferedIoSocketHandleTest, TestDomainNullOpt) { +TEST_F(BufferedIoSocketHandleTest, DomainNullOpt) { EXPECT_FALSE(io_handle_->domain().has_value()); } -TEST_F(BufferedIoSocketHandleTest, TestConnect) { +TEST_F(BufferedIoSocketHandleTest, Connect) { auto address_is_ignored = std::make_shared("listener_id"); EXPECT_EQ(0, io_handle_->connect(address_is_ignored).rc_); } -TEST_F(BufferedIoSocketHandleTest, TestActivateEvent) { +TEST_F(BufferedIoSocketHandleTest, ActivateEvent) { schedulable_cb_ = new NiceMock(&dispatcher_); io_handle_->initializeFileEvent( dispatcher_, [&, handle = io_handle_.get()](uint32_t) {}, Event::FileTriggerType::Edge, @@ -828,27 +826,27 @@ TEST_F(BufferedIoSocketHandleTest, TestActivateEvent) { ASSERT_TRUE(schedulable_cb_->enabled()); } -TEST_F(BufferedIoSocketHandleTest, TestDeathOnActivatingDestroyedEvents) { +TEST_F(BufferedIoSocketHandleTest, DeathOnActivatingDestroyedEvents) { io_handle_->resetFileEvents(); ASSERT_DEBUG_DEATH(io_handle_->activateFileEvents(Event::FileReadyType::Read), "Null user_file_event_"); } -TEST_F(BufferedIoSocketHandleTest, TestDeathOnEnablingDestroyedEvents) { +TEST_F(BufferedIoSocketHandleTest, DeathOnEnablingDestroyedEvents) { io_handle_->resetFileEvents(); ASSERT_DEBUG_DEATH(io_handle_->enableFileEvents(Event::FileReadyType::Read), "Null user_file_event_"); } -TEST_F(BufferedIoSocketHandleTest, TestNotImplementDuplicate) { +TEST_F(BufferedIoSocketHandleTest, NotImplementDuplicate) { ASSERT_DEATH(io_handle_->duplicate(), ""); } -TEST_F(BufferedIoSocketHandleTest, TestNotImplementAccept) { +TEST_F(BufferedIoSocketHandleTest, NotImplementAccept) { ASSERT_DEATH(io_handle_->accept(nullptr, nullptr), ""); } -TEST_F(BufferedIoSocketHandleTest, TestLastRoundtripTimeNullOpt) { +TEST_F(BufferedIoSocketHandleTest, LastRoundtripTimeNullOpt) { ASSERT_EQ(absl::nullopt, io_handle_->lastRoundTripTime()); } @@ -875,49 +873,49 @@ class BufferedIoSocketHandleNotImplementedTest : public testing::Test { Buffer::RawSlice slice_; }; -TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSetBlocking) { +TEST_F(BufferedIoSocketHandleNotImplementedTest, ErrorOnSetBlocking) { EXPECT_THAT(io_handle_->setBlocking(false), IsNotSupportedResult()); EXPECT_THAT(io_handle_->setBlocking(true), IsNotSupportedResult()); } -TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSendmsg) { +TEST_F(BufferedIoSocketHandleNotImplementedTest, ErrorOnSendmsg) { EXPECT_THAT(io_handle_->sendmsg(&slice_, 0, 0, nullptr, Network::Address::EnvoyInternalInstance("listener_id")), IsInvalidAddress()); } -TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmsg) { +TEST_F(BufferedIoSocketHandleNotImplementedTest, ErrorOnRecvmsg) { Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); EXPECT_THAT(io_handle_->recvmsg(&slice_, 0, 0, output_is_ignored), IsInvalidAddress()); } -TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnRecvmmsg) { +TEST_F(BufferedIoSocketHandleNotImplementedTest, ErrorOnRecvmmsg) { RawSliceArrays slices_is_ignored(1, absl::FixedArray({slice_})); Network::IoHandle::RecvMsgOutput output_is_ignored(1, nullptr); EXPECT_THAT(io_handle_->recvmmsg(slices_is_ignored, 0, output_is_ignored), IsInvalidAddress()); } -TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnBind) { +TEST_F(BufferedIoSocketHandleNotImplementedTest, ErrorOnBind) { auto address_is_ignored = std::make_shared("listener_id"); EXPECT_THAT(io_handle_->bind(address_is_ignored), IsNotSupportedResult()); } -TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnListen) { +TEST_F(BufferedIoSocketHandleNotImplementedTest, ErrorOnListen) { int back_log_is_ignored = 0; EXPECT_THAT(io_handle_->listen(back_log_is_ignored), IsNotSupportedResult()); } -TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnAddress) { +TEST_F(BufferedIoSocketHandleNotImplementedTest, ErrorOnAddress) { ASSERT_THROW(io_handle_->peerAddress(), EnvoyException); ASSERT_THROW(io_handle_->localAddress(), EnvoyException); } -TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnSetOption) { +TEST_F(BufferedIoSocketHandleNotImplementedTest, ErrorOnSetOption) { EXPECT_THAT(io_handle_->setOption(0, 0, nullptr, 0), IsNotSupportedResult()); } -TEST_F(BufferedIoSocketHandleNotImplementedTest, TestErrorOnGetOption) { +TEST_F(BufferedIoSocketHandleNotImplementedTest, ErrorOnGetOption) { EXPECT_THAT(io_handle_->getOption(0, 0, nullptr, nullptr), IsNotSupportedResult()); } } // namespace diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index 168dcea9a9526..fa446c1794c67 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -51,7 +51,7 @@ class UserSpaceFileEventImplTest : public testing::Test { void setWritable() { EXPECT_CALL(io_source_, isPeerWritable()).WillRepeatedly(Return(true)); } void setReadable() { EXPECT_CALL(io_source_, isReadable()).WillRepeatedly(Return(true)); } - void clearWriteReable() { testing::Mock::VerifyAndClearExpectations(&io_source_); } + void clearReadWrite() { testing::Mock::VerifyAndClearExpectations(&io_source_); } protected: NiceMock io_source_; @@ -61,11 +61,11 @@ class UserSpaceFileEventImplTest : public testing::Test { std::unique_ptr user_file_event_; }; -TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { +TEST_F(UserSpaceFileEventImplTest, EnabledEventsTriggeredAfterCreate) { for (const auto current_event : {Event::FileReadyType::Read, Event::FileReadyType::Write, Event::FileReadyType::Read | Event::FileReadyType::Write}) { SCOPED_TRACE(absl::StrCat("current event:", current_event)); - clearWriteReable(); + clearReadWrite(); if (current_event | Event::FileReadyType::Read) { setReadable(); } @@ -82,7 +82,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledEventsTriggeredAfterCreate) { } } -TEST_F(UserSpaceFileEventImplTest, TestReadEventNotDeliveredAfterDisabledRead) { +TEST_F(UserSpaceFileEventImplTest, ReadEventNotDeliveredAfterDisabledRead) { setWritable(); setReadable(); user_file_event_ = std::make_unique( @@ -96,7 +96,7 @@ TEST_F(UserSpaceFileEventImplTest, TestReadEventNotDeliveredAfterDisabledRead) { dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } -TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { +TEST_F(UserSpaceFileEventImplTest, RescheduleAfterTriggered) { user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { @@ -121,7 +121,7 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleAfterTriggered) { } } -TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { +TEST_F(UserSpaceFileEventImplTest, RescheduleIsDeduplicated) { user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { @@ -140,7 +140,7 @@ TEST_F(UserSpaceFileEventImplTest, TestRescheduleIsDeduplicated) { } } -TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents) { +TEST_F(UserSpaceFileEventImplTest, DefaultReturnAllEnabledReadAndWriteEvents) { for (const auto current_event : {Event::FileReadyType::Read, Event::FileReadyType::Write, Event::FileReadyType::Read | Event::FileReadyType::Write}) { SCOPED_TRACE(absl::StrCat("current event:", current_event)); @@ -157,7 +157,7 @@ TEST_F(UserSpaceFileEventImplTest, TestDefaultReturnAllEnabledReadAndWriteEvents } } -TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { +TEST_F(UserSpaceFileEventImplTest, ActivateWillSchedule) { // IO is neither readable nor writable. user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); @@ -177,7 +177,7 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateWillSchedule) { } } -TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { +TEST_F(UserSpaceFileEventImplTest, ActivateDedup) { // IO is neither readable nor writable. user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); @@ -199,7 +199,7 @@ TEST_F(UserSpaceFileEventImplTest, TestActivateDedup) { } } -TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { +TEST_F(UserSpaceFileEventImplTest, EnabledClearActivate) { // IO is neither readable nor writable. user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); @@ -227,7 +227,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { // No event is delivered since it's either user disabled or io_handle doesn't provide pending // data. { - clearWriteReable(); + clearReadWrite(); setReadable(); user_file_event_->activate(Event::FileReadyType::Read); user_file_event_->setEnabled(Event::FileReadyType::Write); @@ -235,7 +235,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { - clearWriteReable(); + clearReadWrite(); setWritable(); user_file_event_->activate(Event::FileReadyType::Write); user_file_event_->setEnabled(Event::FileReadyType::Read); @@ -248,7 +248,7 @@ TEST_F(UserSpaceFileEventImplTest, TestEnabledClearActivate) { } } -TEST_F(UserSpaceFileEventImplTest, TestEventClosedIsNotTriggeredUnlessManullyActivated) { +TEST_F(UserSpaceFileEventImplTest, EventClosedIsNotTriggeredUnlessManullyActivated) { user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileReadyType::Write | Event::FileReadyType::Closed, io_source_); From f589a4c768ba345a06d08b577b03e7c6bdb5a31b Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 21 Dec 2020 02:11:33 -0800 Subject: [PATCH 72/88] renaming and format fix Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl.cc | 6 ++--- .../buffered_io_socket_handle_impl.h | 12 +++++----- .../buffered_io_socket/peer_buffer.h | 4 ++-- .../user_space_file_event_impl.cc | 2 +- .../user_space_file_event_impl.h | 8 +++---- .../buffered_io_socket_handle_impl_test.cc | 4 ++-- .../user_space_file_event_impl_test.cc | 24 +++++++++---------- 7 files changed, 30 insertions(+), 30 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index b378f58c15c9e..c346d98e957d4 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -65,7 +65,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, Network::IoSocketError::deleteIoError)}; } if (pending_received_data_.length() == 0) { - if (read_end_stream_) { + if (receive_data_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), @@ -96,7 +96,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe Network::IoSocketError::deleteIoError)}; } if (pending_received_data_.length() == 0) { - if (read_end_stream_) { + if (receive_data_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), @@ -210,7 +210,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t le } // No data and the writer closed. if (pending_received_data_.length() == 0) { - if (read_end_stream_) { + if (receive_data_end_stream_) { return {0, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } else { return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index 532cd0221a041..590e371cb6032 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -30,7 +30,7 @@ namespace BufferedIoSocket { * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ class BufferedIoSocketHandleImpl final : public Network::IoHandle, - public ReadWritable, + public UserspaceIoHandle, protected Logger::Loggable { public: BufferedIoSocketHandleImpl(); @@ -95,10 +95,10 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, // WritablePeer void setWriteEnd() override { - read_end_stream_ = true; + receive_data_end_stream_ = true; setNewDataAvailable(); } - bool isWriteEndSet() override { return read_end_stream_; } + bool isWriteEndSet() override { return receive_data_end_stream_; } void setNewDataAvailable() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); if (user_file_event_) { @@ -121,8 +121,8 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } - // ReadWritable - bool isPeerShutDownWrite() const override { return read_end_stream_; } + // `UserspaceIoHandle` + bool isPeerShutDownWrite() const override { return receive_data_end_stream_; } bool isReadable() const override { return isPeerShutDownWrite() || pending_received_data_.length() > 0; } @@ -147,7 +147,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, // True if pending_received_data_ is not addable. Note that pending_received_data_ may have // pending data to drain. - bool read_end_stream_{false}; + bool receive_data_end_stream_{false}; // The buffer owned by this socket. This buffer is populated by the write operations of the peer // socket and drained by read operations of this socket. diff --git a/source/extensions/io_socket/buffered_io_socket/peer_buffer.h b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h index 44ffd43f0a702..d485ebfafb58f 100644 --- a/source/extensions/io_socket/buffered_io_socket/peer_buffer.h +++ b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h @@ -59,9 +59,9 @@ class WritablePeer { /** * The interface for the peer as a writer and supplied read status query. */ -class ReadWritable : public WritablePeer { +class UserspaceIoHandle : public WritablePeer { public: - ~ReadWritable() override = default; + ~UserspaceIoHandle() override = default; /** * Read the flag to indicate no further write. Used by early close detection. diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index a782310d5e5cc..31741c38cf5d9 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -12,7 +12,7 @@ namespace IoSocket { namespace BufferedIoSocket { UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - uint32_t events, ReadWritable& io_source) + uint32_t events, UserspaceIoHandle& io_source) : schedulable_(dispatcher.createSchedulableCallback([this, cb]() { auto ephemeral_events = event_listener_.getAndClearEphemeralEvents(); ENVOY_LOG(trace, "User space event {} invokes callbacks on events = {}", diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h index 741f8becdfe68..dd458faa4e590 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h @@ -39,14 +39,14 @@ class EventListenerImpl { class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::Loggable { public: UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, - ReadWritable& io_source); + UserspaceIoHandle& io_source); // Event::FileEvent void activate(uint32_t events) override; void setEnabled(uint32_t events) override; - // UserspaceFileEvent acts always as edge triggered regardless the underlying OS is level or edge - // triggered. The event owner on windows platform should not emulate edge events. + // `UserspaceFileEvent` acts always as edge triggered regardless the underlying OS is level or + // edge triggered. The event owner on windows platform should not emulate edge events. void unregisterEventIfEmulatedEdge(uint32_t) override {} void registerEventIfEmulatedEdge(uint32_t) override {} @@ -58,7 +58,7 @@ class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::Loggablerecv(buf_.data(), 232, 0); EXPECT_TRUE(io_handle_->isWritable()); EXPECT_CALL(cb_, called(Event::FileReadyType::Write)); @@ -540,7 +540,7 @@ TEST_F(BufferedIoSocketHandleTest, DrainToLowWaterMarkTriggerReadEvent) { } { SCOPED_TRACE("clean up."); - EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()).Times(1); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); // Important: close before peer. io_handle_->close(); } diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index fa446c1794c67..63f8451d8e05e 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -30,7 +30,7 @@ class MockReadyCb { MOCK_METHOD(void, called, (uint32_t)); }; -class MockReadWritable : public ReadWritable { +class MockUserspaceIoHandle : public UserspaceIoHandle { public: MOCK_METHOD(void, setWriteEnd, ()); MOCK_METHOD(bool, isWriteEndSet, ()); @@ -54,7 +54,7 @@ class UserSpaceFileEventImplTest : public testing::Test { void clearReadWrite() { testing::Mock::VerifyAndClearExpectations(&io_source_); } protected: - NiceMock io_source_; + NiceMock io_source_; MockReadyCb ready_cb_; Api::ApiPtr api_; Event::DispatcherPtr dispatcher_; @@ -66,10 +66,10 @@ TEST_F(UserSpaceFileEventImplTest, EnabledEventsTriggeredAfterCreate) { Event::FileReadyType::Read | Event::FileReadyType::Write}) { SCOPED_TRACE(absl::StrCat("current event:", current_event)); clearReadWrite(); - if (current_event | Event::FileReadyType::Read) { + if (current_event & Event::FileReadyType::Read) { setReadable(); } - if (current_event | Event::FileReadyType::Write) { + if (current_event & Event::FileReadyType::Write) { setWritable(); } MockReadyCb ready_cb; @@ -92,7 +92,7 @@ TEST_F(UserSpaceFileEventImplTest, ReadEventNotDeliveredAfterDisabledRead) { // Now disable Read. user_file_event_->setEnabled(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } @@ -129,7 +129,7 @@ TEST_F(UserSpaceFileEventImplTest, RescheduleIsDeduplicated) { user_file_event_->activate(event_rw); user_file_event_->activate(event_rw); - EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } @@ -167,12 +167,12 @@ TEST_F(UserSpaceFileEventImplTest, ActivateWillSchedule) { } { user_file_event_->activate(Event::FileReadyType::Read); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)).Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { user_file_event_->activate(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } } @@ -190,7 +190,7 @@ TEST_F(UserSpaceFileEventImplTest, ActivateDedup) { user_file_event_->activate(Event::FileReadyType::Write); user_file_event_->activate(Event::FileReadyType::Write); user_file_event_->activate(Event::FileReadyType::Read); - EXPECT_CALL(ready_cb_, called(event_rw)).Times(1); + EXPECT_CALL(ready_cb_, called(event_rw)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { @@ -215,13 +215,13 @@ TEST_F(UserSpaceFileEventImplTest, EnabledClearActivate) { { user_file_event_->activate(Event::FileReadyType::Read); user_file_event_->setEnabled(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)).Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { user_file_event_->activate(Event::FileReadyType::Write); user_file_event_->setEnabled(Event::FileReadyType::Read); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)).Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } // No event is delivered since it's either user disabled or io_handle doesn't provide pending @@ -260,7 +260,7 @@ TEST_F(UserSpaceFileEventImplTest, EventClosedIsNotTriggeredUnlessManullyActivat { user_file_event_->activate(Event::FileReadyType::Closed); // Activate could deliver Closed event bit. - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)).Times(1); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)); dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { From 5407f4b3ac2a7db119aeae70c6b0ecf2eed9c747 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 21 Dec 2020 14:18:04 -0800 Subject: [PATCH 73/88] impl partial write in userspace io socket Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl.cc | 23 ++++-- .../buffered_io_socket_handle_impl_test.cc | 80 +++++++++++++++++++ 2 files changed, 97 insertions(+), 6 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index c346d98e957d4..292ee20265ad6 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -72,7 +72,6 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, Network::IoSocketError::deleteIoError)}; } } - absl::FixedArray iov(num_slice); uint64_t bytes_offset = 0; for (uint64_t i = 0; i < num_slice && bytes_offset < max_length; i++) { auto bytes_to_read_in_this_slice = @@ -142,11 +141,13 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), Network::IoSocketError::deleteIoError)}; } + + auto* const dest_buffer = writable_peer_->getWriteBuffer(); // Write along with iteration. Buffer guarantee the fragment is always append-able. uint64_t bytes_written = 0; - for (uint64_t i = 0; i < num_slice; i++) { + for (uint64_t i = 0; i < num_slice && !dest_buffer->highWatermarkTriggered(); i++) { if (slices[i].mem_ != nullptr && slices[i].len_ != 0) { - writable_peer_->getWriteBuffer()->add(slices[i].mem_, slices[i].len_); + dest_buffer->add(slices[i].mem_, slices[i].len_); bytes_written += slices[i].len_; } } @@ -180,10 +181,20 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), Network::IoSocketError::deleteIoError)}; } - uint64_t total_bytes_to_write = buffer.length(); - writable_peer_->getWriteBuffer()->move(buffer); + uint64_t total_bytes_to_write = 0; + const uint64_t max_bytes_to_write = buffer.length(); + while (writable_peer_->isWritable()) { + const auto& front_slice = buffer.frontSlice(); + if (front_slice.len_ == 0) { + break; + } else { + writable_peer_->getWriteBuffer()->move(buffer, front_slice.len_); + total_bytes_to_write += front_slice.len_; + } + } writable_peer_->setNewDataAvailable(); - ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), total_bytes_to_write); + ENVOY_LOG(trace, "socket {} writev {} bytes of {}", static_cast(this), + total_bytes_to_write, max_bytes_to_write); return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 983487b635156..f2f0498d167d0 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -331,6 +331,43 @@ TEST_F(BufferedIoSocketHandleTest, WriteAgain) { EXPECT_EQ(10, buf.length()); } +// Test write() moves the fragments in front until the destination is over high watermark. +TEST_F(BufferedIoSocketHandleTest, PartialWrite) { + // Populate write destination with massive data so as to not writable. + io_handle_peer_->setWatermarks(128); + // Fragment contents | a | bbbb...b | ccc | + // Len per fragment | 1 | 255 | 3 | + // Watermark locates at b area |low | high... | + // Write | 1st | 2nd | + Buffer::OwnedImpl pending_data("a"); + auto long_frag = Buffer::OwnedBufferFragmentImpl::create( + std::string(255, 'b'), [](const Buffer::OwnedBufferFragmentImpl*) {}); + auto tail_frag = + Buffer::OwnedBufferFragmentImpl::create("ccc", [](const Buffer::OwnedBufferFragmentImpl*) {}); + pending_data.addBufferFragment(*long_frag); + pending_data.addBufferFragment(*tail_frag); + + // Partial write: the first two slices are moved because the second slice move reaches the high + // watermark. + auto result = io_handle_->write(pending_data); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(result.rc_, 256); + EXPECT_EQ(pending_data.length(), 3); + EXPECT_FALSE(io_handle_peer_->isWritable()); + + // Confirm that the further write return `EAGAIN`. + auto result2 = io_handle_->write(pending_data); + ASSERT_EQ(result2.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); + + // Make the peer writable again. + Buffer::OwnedImpl black_hole_buffer; + io_handle_peer_->read(black_hole_buffer, 10240); + EXPECT_TRUE(io_handle_peer_->isWritable()); + auto result3 = io_handle_->write(pending_data); + EXPECT_EQ(result3.rc_, 3); + EXPECT_EQ(0, pending_data.length()); +} + TEST_F(BufferedIoSocketHandleTest, WriteErrorAfterShutdown) { Buffer::OwnedImpl buf("0123456789"); // Write after shutdown. @@ -359,6 +396,49 @@ TEST_F(BufferedIoSocketHandleTest, WritevAgain) { ASSERT_EQ(result.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); } +// Test writev() copies the slices in front until the destination is over high watermark. +TEST_F(BufferedIoSocketHandleTest, PartialWritev) { + // Populate write destination with massive data so as to not writable. + io_handle_peer_->setWatermarks(128); + // Slices contents | a | bbbb...b | ccc | + // Len per slice | 1 | 255 | 3 | + // Watermark locates at b area |low | high... | + // Writev | 1st | 2nd | + Buffer::OwnedImpl pending_data("a"); + auto long_frag = Buffer::OwnedBufferFragmentImpl::create( + std::string(255, 'b'), [](const Buffer::OwnedBufferFragmentImpl*) {}); + auto tail_frag = + Buffer::OwnedBufferFragmentImpl::create("ccc", [](const Buffer::OwnedBufferFragmentImpl*) {}); + pending_data.addBufferFragment(*long_frag); + pending_data.addBufferFragment(*tail_frag); + + // Partial write: the first two slices are moved because the second slice move reaches the high + // watermark. + auto slices = pending_data.getRawSlices(); + EXPECT_EQ(3, slices.size()); + auto result = io_handle_->writev(slices.data(), slices.size()); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(result.rc_, 256); + pending_data.drain(result.rc_); + EXPECT_EQ(pending_data.length(), 3); + EXPECT_FALSE(io_handle_peer_->isWritable()); + + // Confirm that the further write return `EAGAIN`. + auto slices2 = pending_data.getRawSlices(); + auto result2 = io_handle_->writev(slices2.data(), slices2.size()); + ASSERT_EQ(result2.err_->getErrorCode(), Api::IoError::IoErrorCode::Again); + + // Make the peer writable again. + Buffer::OwnedImpl black_hole_buffer; + io_handle_peer_->read(black_hole_buffer, 10240); + EXPECT_TRUE(io_handle_peer_->isWritable()); + auto slices3 = pending_data.getRawSlices(); + auto result3 = io_handle_->writev(slices3.data(), slices3.size()); + EXPECT_EQ(result3.rc_, 3); + pending_data.drain(result3.rc_); + EXPECT_EQ(0, pending_data.length()); +} + TEST_F(BufferedIoSocketHandleTest, WritevErrorAfterShutdown) { auto [guard, slice] = allocateOneSlice(128); // Writev after shutdown. From cc4f7f6390b32630391d206a3b207c47975b3fde Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 21 Dec 2020 15:40:51 -0800 Subject: [PATCH 74/88] typo extension Signed-off-by: Yuchen Dai --- source/extensions/extensions_build_config.bzl | 2 +- .../buffered_io_socket_handle_impl_test.cc | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index 4fc8faab63e8d..83535fb46d874 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -233,7 +233,7 @@ EXTENSIONS = { # # IO socket # - "envoy.io_socket.user_space_socket": "//source/extentions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", + "envoy.io_socket.user_space_socket": "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", } # These can be changed to ["//visibility:public"], for downstream builds which diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index f2f0498d167d0..69b025b01b043 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -335,9 +335,9 @@ TEST_F(BufferedIoSocketHandleTest, WriteAgain) { TEST_F(BufferedIoSocketHandleTest, PartialWrite) { // Populate write destination with massive data so as to not writable. io_handle_peer_->setWatermarks(128); - // Fragment contents | a | bbbb...b | ccc | + // Fragment contents | a |`bbbb...b`|`ccc`| // Len per fragment | 1 | 255 | 3 | - // Watermark locates at b area |low | high... | + // Watermark boundary at b area | low | high | // Write | 1st | 2nd | Buffer::OwnedImpl pending_data("a"); auto long_frag = Buffer::OwnedBufferFragmentImpl::create( @@ -400,9 +400,9 @@ TEST_F(BufferedIoSocketHandleTest, WritevAgain) { TEST_F(BufferedIoSocketHandleTest, PartialWritev) { // Populate write destination with massive data so as to not writable. io_handle_peer_->setWatermarks(128); - // Slices contents | a | bbbb...b | ccc | + // Slices contents | a |`bbbb...b`|`ccc`| // Len per slice | 1 | 255 | 3 | - // Watermark locates at b area |low | high... | + // Watermark boundary at b area | low | high | // Writev | 1st | 2nd | Buffer::OwnedImpl pending_data("a"); auto long_frag = Buffer::OwnedBufferFragmentImpl::create( From d87f6b1bee2bce43bc16142e7d393b158ed16462 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 21 Dec 2020 16:51:25 -0800 Subject: [PATCH 75/88] mark io_socket extension undocumented Signed-off-by: Yuchen Dai --- source/extensions/io_socket/buffered_io_socket/BUILD | 1 + 1 file changed, 1 insertion(+) diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD index 3ad6f8eecd4fb..6f0cbc1038c35 100644 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ b/source/extensions/io_socket/buffered_io_socket/BUILD @@ -46,6 +46,7 @@ envoy_cc_extension( ], security_posture = "unknown", status = "alpha", + undocumented = True, deps = [ ":peer_buffer_lib", ":users_space_file_event_lib", From 03aa2c3ccc3b2d5b412d320f1c03229f4d3d3cc9 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 21 Dec 2020 18:28:02 -0800 Subject: [PATCH 76/88] fix OwnedBufferFragmentImpl usage in asan test Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 69b025b01b043..98656ab0b5fe7 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -341,11 +341,12 @@ TEST_F(BufferedIoSocketHandleTest, PartialWrite) { // Write | 1st | 2nd | Buffer::OwnedImpl pending_data("a"); auto long_frag = Buffer::OwnedBufferFragmentImpl::create( - std::string(255, 'b'), [](const Buffer::OwnedBufferFragmentImpl*) {}); - auto tail_frag = - Buffer::OwnedBufferFragmentImpl::create("ccc", [](const Buffer::OwnedBufferFragmentImpl*) {}); - pending_data.addBufferFragment(*long_frag); - pending_data.addBufferFragment(*tail_frag); + std::string(255, 'b'), + [](const Buffer::OwnedBufferFragmentImpl* fragment) { delete fragment; }); + auto tail_frag = Buffer::OwnedBufferFragmentImpl::create( + "ccc", [](const Buffer::OwnedBufferFragmentImpl* fragment) { delete fragment; }); + pending_data.addBufferFragment(*long_frag.release()); + pending_data.addBufferFragment(*tail_frag.release()); // Partial write: the first two slices are moved because the second slice move reaches the high // watermark. @@ -406,11 +407,12 @@ TEST_F(BufferedIoSocketHandleTest, PartialWritev) { // Writev | 1st | 2nd | Buffer::OwnedImpl pending_data("a"); auto long_frag = Buffer::OwnedBufferFragmentImpl::create( - std::string(255, 'b'), [](const Buffer::OwnedBufferFragmentImpl*) {}); - auto tail_frag = - Buffer::OwnedBufferFragmentImpl::create("ccc", [](const Buffer::OwnedBufferFragmentImpl*) {}); - pending_data.addBufferFragment(*long_frag); - pending_data.addBufferFragment(*tail_frag); + std::string(255, 'b'), + [](const Buffer::OwnedBufferFragmentImpl* fragment) { delete fragment; }); + auto tail_frag = Buffer::OwnedBufferFragmentImpl::create( + "ccc", [](const Buffer::OwnedBufferFragmentImpl* fragment) { delete fragment; }); + pending_data.addBufferFragment(*long_frag.release()); + pending_data.addBufferFragment(*tail_frag.release()); // Partial write: the first two slices are moved because the second slice move reaches the high // watermark. From 6ad181c4a63a0e0374ff5deb8b2db16f78971d87 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 22 Dec 2020 15:15:42 -0800 Subject: [PATCH 77/88] add specialized file covr and fix mac build Signed-off-by: Yuchen Dai --- .../buffered_io_socket/buffered_io_socket_handle_impl.cc | 4 ++-- test/per_file_coverage.sh | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index 292ee20265ad6..ea54ff9983ff2 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -10,7 +10,6 @@ #include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" -#include "absl/container/fixed_array.h" #include "absl/types/optional.h" namespace Envoy { @@ -228,7 +227,8 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t le Network::IoSocketError::deleteIoError)}; } } - auto max_bytes_to_read = std::min(pending_received_data_.length(), length); + // Specify uint64_t since the latter length may not have the same type. + auto max_bytes_to_read = std::min(pending_received_data_.length(), length); pending_received_data_.copyOut(0, max_bytes_to_read, buffer); if (!(flags & MSG_PEEK)) { pending_received_data_.drain(max_bytes_to_read); diff --git a/test/per_file_coverage.sh b/test/per_file_coverage.sh index d5394b4a5abb0..99e993f85e564 100755 --- a/test/per_file_coverage.sh +++ b/test/per_file_coverage.sh @@ -52,6 +52,7 @@ declare -a KNOWN_LOW_COVERAGE=( "source/extensions/filters/network/sni_dynamic_forward_proxy:90.9" "source/extensions/health_checkers:95.9" "source/extensions/health_checkers/redis:95.9" +"source/extensions/io_socket/buffered_io_socket:96.0" # Death tests don't report LCOV "source/extensions/quic_listeners:85.0" "source/extensions/quic_listeners/quiche:84.8" "source/extensions/stat_sinks/statsd:85.2" From f69ba83f1db9696e96ea255d2442a9837498fd84 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 22 Dec 2020 16:45:39 -0800 Subject: [PATCH 78/88] parent lcov annotation Signed-off-by: Yuchen Dai --- test/per_file_coverage.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/per_file_coverage.sh b/test/per_file_coverage.sh index 99e993f85e564..4e0625a1e81ee 100755 --- a/test/per_file_coverage.sh +++ b/test/per_file_coverage.sh @@ -52,6 +52,7 @@ declare -a KNOWN_LOW_COVERAGE=( "source/extensions/filters/network/sni_dynamic_forward_proxy:90.9" "source/extensions/health_checkers:95.9" "source/extensions/health_checkers/redis:95.9" +"source/extensions/io_socket:96.0" # Death tests don't report LCOV "source/extensions/io_socket/buffered_io_socket:96.0" # Death tests don't report LCOV "source/extensions/quic_listeners:85.0" "source/extensions/quic_listeners/quiche:84.8" From 6eaff67769d464bb9f92bb5ff22aab52b7813a37 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 11 Jan 2021 12:01:06 -0800 Subject: [PATCH 79/88] add ReadyType::Closed support and merge isWriteEndSet and isPeerShutDownWrite Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl.cc | 4 +-- .../buffered_io_socket_handle_impl.h | 5 ++-- .../buffered_io_socket/peer_buffer.h | 8 ++---- .../user_space_file_event_impl.cc | 3 +++ .../user_space_file_event_impl_test.cc | 27 ++++++++++++++----- 5 files changed, 29 insertions(+), 18 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index ea54ff9983ff2..c1b800e8b254d 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -130,7 +130,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic Network::IoSocketError::deleteIoError)}; } // Error: write after close. - if (writable_peer_->isWriteEndSet()) { + if (writable_peer_->isPeerShutDownWrite()) { // TODO(lambdai): `EPIPE` or `ENOTCONN`. return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; @@ -170,7 +170,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff Network::IoSocketError::deleteIoError)}; } // Error: write after close. - if (writable_peer_->isWriteEndSet()) { + if (writable_peer_->isPeerShutDownWrite()) { // TODO(lambdai): `EPIPE` or `ENOTCONN`. return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index 590e371cb6032..b4beb2a54afdf 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -98,7 +98,6 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, receive_data_end_stream_ = true; setNewDataAvailable(); } - bool isWriteEndSet() override { return receive_data_end_stream_; } void setNewDataAvailable() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); if (user_file_event_) { @@ -115,14 +114,14 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, } } bool isWritable() const override { return !pending_received_data_.highWatermarkTriggered(); } + bool isPeerShutDownWrite() const override { return receive_data_end_stream_; } bool isPeerWritable() const override { - return writable_peer_ != nullptr && !writable_peer_->isWriteEndSet() && + return writable_peer_ != nullptr && !writable_peer_->isPeerShutDownWrite() && writable_peer_->isWritable(); } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } // `UserspaceIoHandle` - bool isPeerShutDownWrite() const override { return receive_data_end_stream_; } bool isReadable() const override { return isPeerShutDownWrite() || pending_received_data_.length() > 0; } diff --git a/source/extensions/io_socket/buffered_io_socket/peer_buffer.h b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h index d485ebfafb58f..2e6630b8dab18 100644 --- a/source/extensions/io_socket/buffered_io_socket/peer_buffer.h +++ b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h @@ -19,10 +19,11 @@ class WritablePeer { * Set the flag to indicate no further write from peer. */ virtual void setWriteEnd() PURE; + /** * @return true if the peer promise no more write. */ - virtual bool isWriteEndSet() PURE; + virtual bool isPeerShutDownWrite() const PURE; /** * Raised when peer is destroyed. No further write to peer is allowed. @@ -63,11 +64,6 @@ class UserspaceIoHandle : public WritablePeer { public: ~UserspaceIoHandle() override = default; - /** - * Read the flag to indicate no further write. Used by early close detection. - */ - virtual bool isPeerShutDownWrite() const PURE; - /** * @return true if the pending receive buffer is not empty or read_end is set. */ diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index 31741c38cf5d9..c73302be25493 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -54,6 +54,9 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { if ((events & Event::FileReadyType::Write) && io_source_.isPeerWritable()) { events_to_notify |= Event::FileReadyType::Write; } + if ((events & Event::FileReadyType::Closed) && io_source_.isPeerShutDownWrite()) { + events_to_notify |= Event::FileReadyType::Closed; + } if (events_to_notify != 0) { activate(events_to_notify); } else { diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index 63f8451d8e05e..473a62ec43b53 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -33,14 +33,13 @@ class MockReadyCb { class MockUserspaceIoHandle : public UserspaceIoHandle { public: MOCK_METHOD(void, setWriteEnd, ()); - MOCK_METHOD(bool, isWriteEndSet, ()); + MOCK_METHOD(bool, isPeerShutDownWrite, (), (const)); MOCK_METHOD(void, onPeerDestroy, ()); MOCK_METHOD(void, setNewDataAvailable, ()); MOCK_METHOD(Buffer::Instance*, getWriteBuffer, ()); MOCK_METHOD(bool, isWritable, (), (const)); MOCK_METHOD(bool, isPeerWritable, (), (const)); MOCK_METHOD(void, onPeerBufferLowWatermark, ()); - MOCK_METHOD(bool, isPeerShutDownWrite, (), (const)); MOCK_METHOD(bool, isReadable, (), (const)); }; @@ -51,7 +50,10 @@ class UserSpaceFileEventImplTest : public testing::Test { void setWritable() { EXPECT_CALL(io_source_, isPeerWritable()).WillRepeatedly(Return(true)); } void setReadable() { EXPECT_CALL(io_source_, isReadable()).WillRepeatedly(Return(true)); } - void clearReadWrite() { testing::Mock::VerifyAndClearExpectations(&io_source_); } + void setWriteEnd() { + EXPECT_CALL(io_source_, isPeerShutDownWrite()).WillRepeatedly(Return(true)); + } + void clearEventExpectation() { testing::Mock::VerifyAndClearExpectations(&io_source_); } protected: NiceMock io_source_; @@ -65,7 +67,7 @@ TEST_F(UserSpaceFileEventImplTest, EnabledEventsTriggeredAfterCreate) { for (const auto current_event : {Event::FileReadyType::Read, Event::FileReadyType::Write, Event::FileReadyType::Read | Event::FileReadyType::Write}) { SCOPED_TRACE(absl::StrCat("current event:", current_event)); - clearReadWrite(); + clearEventExpectation(); if (current_event & Event::FileReadyType::Read) { setReadable(); } @@ -211,6 +213,7 @@ TEST_F(UserSpaceFileEventImplTest, EnabledClearActivate) { // Ensure both events are pending so that any enabled event will be immediately delivered. setWritable(); setReadable(); + setWriteEnd(); // The enabled event are delivered but not the other. { user_file_event_->activate(Event::FileReadyType::Read); @@ -227,7 +230,7 @@ TEST_F(UserSpaceFileEventImplTest, EnabledClearActivate) { // No event is delivered since it's either user disabled or io_handle doesn't provide pending // data. { - clearReadWrite(); + clearEventExpectation(); setReadable(); user_file_event_->activate(Event::FileReadyType::Read); user_file_event_->setEnabled(Event::FileReadyType::Write); @@ -235,7 +238,7 @@ TEST_F(UserSpaceFileEventImplTest, EnabledClearActivate) { dispatcher_->run(Event::Dispatcher::RunType::NonBlock); } { - clearReadWrite(); + clearEventExpectation(); setWritable(); user_file_event_->activate(Event::FileReadyType::Write); user_file_event_->setEnabled(Event::FileReadyType::Read); @@ -248,7 +251,17 @@ TEST_F(UserSpaceFileEventImplTest, EnabledClearActivate) { } } -TEST_F(UserSpaceFileEventImplTest, EventClosedIsNotTriggeredUnlessManullyActivated) { +TEST_F(UserSpaceFileEventImplTest, EventClosedIsTriggeredBySetWriteEnd) { + setWriteEnd(); + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, + Event::FileReadyType::Write | Event::FileReadyType::Closed, io_source_); + + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); +} + +TEST_F(UserSpaceFileEventImplTest, EventClosedIsTriggeredByManullyActivate) { user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, Event::FileReadyType::Write | Event::FileReadyType::Closed, io_source_); From 21cc67a869213d0af45f2236381b374c8aed9bc5 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 11 Jan 2021 14:58:39 -0800 Subject: [PATCH 80/88] optimization: add poll method to deliver enabled events unless explicitly activate() Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl.h | 4 +-- .../user_space_file_event_impl.cc | 16 ++++++++++++ .../user_space_file_event_impl.h | 18 +++++++++---- .../buffered_io_socket_handle_impl_test.cc | 26 ++++++++++++++----- 4 files changed, 50 insertions(+), 14 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index b4beb2a54afdf..e1ad18143b4a2 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -101,7 +101,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, void setNewDataAvailable() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); if (user_file_event_) { - user_file_event_->activate(Event::FileReadyType::Read); + user_file_event_->poll(Event::FileReadyType::Read); } } void onPeerDestroy() override { @@ -110,7 +110,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, } void onPeerBufferLowWatermark() override { if (user_file_event_) { - user_file_event_->activate(Event::FileReadyType::Write); + user_file_event_->poll(Event::FileReadyType::Write); } } bool isWritable() const override { return !pending_received_data_.highWatermarkTriggered(); } diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc index c73302be25493..ecabf8540cf23 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc @@ -32,6 +32,10 @@ void EventListenerImpl::onEventActivated(uint32_t activated_events) { ephemeral_events_ |= activated_events; } +void EventListenerImpl::setEnabledEvents(uint32_t enabled_events) { + enabled_events_ = enabled_events; +} + void UserSpaceFileEventImpl::activate(uint32_t events) { // Only supported event types are set. ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | @@ -45,6 +49,7 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | Event::FileReadyType::Closed)) == events); event_listener_.clearEphemeralEvents(); + event_listener_.setEnabledEvents(events); bool was_enabled = schedulable_->enabled(); // Recalculate activated events. uint32_t events_to_notify = 0; @@ -67,6 +72,17 @@ void UserSpaceFileEventImpl::setEnabled(uint32_t events) { "User space file event {} set enabled events {} and events {} is active. Will {} reschedule.", static_cast(this), events, was_enabled ? "not " : ""); } + +void UserSpaceFileEventImpl::poll(uint32_t events) { + ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | + Event::FileReadyType::Closed)) == events); + // filtered out disabled events. + uint32_t filter_enabled = events & event_listener_.getEnabledEvents(); + if (filter_enabled == 0) { + return; + } + activate(filter_enabled); +} } // namespace BufferedIoSocket } // namespace IoSocket } // namespace Extensions diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h index dd458faa4e590..98b3149d5de7e 100644 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h @@ -15,15 +15,17 @@ namespace Extensions { namespace IoSocket { namespace BufferedIoSocket { -// Return the enabled events except EV_CLOSED. This implementation is generally good since only -// epoll supports EV_CLOSED but the entire envoy code base supports another poller. The event owner -// must assume EV_CLOSED is never activated. Also event owner must tolerate that OS could notify -// events which are not actually triggered. -// TODO(lambdai): Add support of delivering EV_CLOSED. +// This class maintains the ephemeral events and enabled events. +// getAndClearEphemeralEvents class EventListenerImpl { public: ~EventListenerImpl() = default; + // Reset the enabled events. The caller must refresh the triggered events. + void setEnabledEvents(uint32_t enabled_events); + // Return the enabled events. + uint32_t getEnabledEvents() { return enabled_events_; } + void clearEphemeralEvents(); void onEventActivated(uint32_t activated_events); @@ -32,6 +34,8 @@ class EventListenerImpl { private: // The events set by activate() and will be cleared after the io callback. uint32_t ephemeral_events_{}; + // The events set by setEnabled(). The new value replaces the old value. + uint32_t enabled_events_{}; }; // A FileEvent implementation which is used to drive BufferedIoSocketHandle. @@ -50,6 +54,10 @@ class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::LoggableresetFileEvents(); } -TEST_F(BufferedIoSocketHandleTest, NotififyWritableAfterShutdownWrite) { +TEST_F(BufferedIoSocketHandleTest, NotifyWritableAfterShutdownWrite) { io_handle_peer_->setWatermarks(128); Buffer::OwnedImpl buf(std::string(256, 'a')); io_handle_->write(buf); EXPECT_FALSE(io_handle_peer_->isWritable()); - io_handle_peer_->shutdown(ENVOY_SHUT_WR); - FANCY_LOG(debug, "after {} shutdown write", static_cast(io_handle_peer_.get())); + io_handle_->shutdown(ENVOY_SHUT_WR); + FANCY_LOG(debug, "after {} shutdown write", static_cast(io_handle_.get())); auto schedulable_cb = new Event::MockSchedulableCallback(&dispatcher_); EXPECT_CALL(*schedulable_cb, enabled()); EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); - io_handle_->initializeFileEvent( + io_handle_peer_->initializeFileEvent( dispatcher_, [this](uint32_t events) { cb_.called(events); }, Event::FileTriggerType::Edge, Event::FileReadyType::Read); EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); schedulable_cb->invokeCallback(); EXPECT_FALSE(schedulable_cb->enabled_); - EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()).Times(0); auto result = io_handle_peer_->recv(buf_.data(), buf_.size(), 0); EXPECT_EQ(256, result.rc_); - EXPECT_TRUE(schedulable_cb->enabled_); + // Readable event is not activated due to edge trigger type. + EXPECT_FALSE(schedulable_cb->enabled_); - io_handle_->close(); + // The `end of stream` is delivered. + auto result_at_eof = io_handle_peer_->recv(buf_.data(), buf_.size(), 0); + EXPECT_EQ(0, result_at_eof.rc_); + + // Also confirm `EOS` can triggered read ready event. + EXPECT_CALL(*schedulable_cb, enabled()); + EXPECT_CALL(*schedulable_cb, scheduleCallbackNextIteration()); + io_handle_peer_->enableFileEvents(Event::FileReadyType::Read); + EXPECT_CALL(cb_, called(Event::FileReadyType::Read)); + schedulable_cb->invokeCallback(); + + io_handle_peer_->close(); } TEST_F(BufferedIoSocketHandleTest, NotSupportingMmsg) { EXPECT_FALSE(io_handle_->supportsMmsg()); } From 29c1beaa2a67229f504205d3fbd68647d7578fe1 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 13 Jan 2021 15:45:15 -0800 Subject: [PATCH 81/88] massage merge master Signed-off-by: Yuchen Dai --- CODEOWNERS | 6 ++++-- source/extensions/extensions_build_config.bzl | 11 +++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 38daeeab0ad95..6586099ea1775 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -153,6 +153,8 @@ extensions/filters/common/original_src @snowp @klarose # Core upstream code extensions/upstreams/http @alyssawilk @snowp @mattklein123 extensions/upstreams/tcp @alyssawilk @ggreenway @mattklein123 +# user space socket pair and event +/*/extensions/io_socket/buffered_io_socket @lambdai @antoniovicente # OAuth2 extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp # HTTP Local Rate Limit @@ -160,5 +162,5 @@ extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp /*/extensions/filters/common/local_ratelimit @mattklein123 @rgs1 # HTTP Kill Request /*/extensions/filters/http/kill_request @qqustc @htuch -# user space socket pair and event -/*/extensions/io_socket/buffered_io_socket @lambdai @antoniovicente +# Rate limit expression descriptor +/*/extensions/rate_limit_descriptors/expr @kyessenov @lizan diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index 83535fb46d874..61adc4f0bf8c7 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -220,6 +220,12 @@ EXTENSIONS = { # "envoy.watchdog.profile_action": "//source/extensions/watchdog/profile_action:config", + + # + # IO socket + # + + "envoy.io_socket.user_space_socket": "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", # # WebAssembly runtimes @@ -231,9 +237,10 @@ EXTENSIONS = { "envoy.wasm.runtime.wasmtime": "//source/extensions/wasm_runtime/wasmtime:config", # - # IO socket + # Rate limit descriptors # - "envoy.io_socket.user_space_socket": "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", + + "envoy.rate_limit_descriptors.expr": "//source/extensions/rate_limit_descriptors/expr:config", } # These can be changed to ["//visibility:public"], for downstream builds which From 51db809362950fad18ea559354af8c287ffccf7c Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 13 Jan 2021 23:17:17 -0800 Subject: [PATCH 82/88] add coverage by adding more Closed ready type Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl.h | 4 +- .../user_space_file_event_impl_test.cc | 41 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index e1ad18143b4a2..8bf7c0a51a8f3 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -101,7 +101,9 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, void setNewDataAvailable() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); if (user_file_event_) { - user_file_event_->poll(Event::FileReadyType::Read); + user_file_event_->poll(Event::FileReadyType::Read | + // Closed ready type is defined as `end of stream` + (receive_data_end_stream_ ? Event::FileReadyType::Closed : 0)); } } void onPeerDestroy() override { diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc index 473a62ec43b53..e45e7c205b6b6 100644 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc @@ -203,6 +203,7 @@ TEST_F(UserSpaceFileEventImplTest, ActivateDedup) { TEST_F(UserSpaceFileEventImplTest, EnabledClearActivate) { // IO is neither readable nor writable. + user_file_event_ = std::make_unique( *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); { @@ -251,6 +252,46 @@ TEST_F(UserSpaceFileEventImplTest, EnabledClearActivate) { } } +TEST_F(UserSpaceFileEventImplTest, PollTriggeredOnlyEnabledEvents) { + user_file_event_ = std::make_unique( + *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, + Event::FileReadyType::Read | Event::FileReadyType::Closed, io_source_); + { + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + // All 3 ready types are polled. However, only enabled events are triggered. + { + user_file_event_->poll(Event::FileReadyType::Read | Event::FileReadyType::Write | + Event::FileReadyType::Closed); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read | Event::FileReadyType::Closed)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + + // Below events contains Read but not Closed. The callback sees Read. + { + user_file_event_->poll(Event::FileReadyType::Read); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->poll(Event::FileReadyType::Read | Event::FileReadyType::Write); + EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + // Below ready types has no overlap with enabled. No callback is triggered. + { + user_file_event_->poll(Event::FileReadyType::Write); + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } + { + user_file_event_->poll(0); + EXPECT_CALL(ready_cb_, called(_)).Times(0); + dispatcher_->run(Event::Dispatcher::RunType::NonBlock); + } +} + TEST_F(UserSpaceFileEventImplTest, EventClosedIsTriggeredBySetWriteEnd) { setWriteEnd(); user_file_event_ = std::make_unique( From 38822f96d0b9ea9c7d4ff2f4c885344f8747da00 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Wed, 13 Jan 2021 23:21:51 -0800 Subject: [PATCH 83/88] massage CI Signed-off-by: Yuchen Dai --- CODEOWNERS | 2 -- source/extensions/extensions_build_config.bzl | 5 ----- 2 files changed, 7 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 6586099ea1775..5259f5e43cd39 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -162,5 +162,3 @@ extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp /*/extensions/filters/common/local_ratelimit @mattklein123 @rgs1 # HTTP Kill Request /*/extensions/filters/http/kill_request @qqustc @htuch -# Rate limit expression descriptor -/*/extensions/rate_limit_descriptors/expr @kyessenov @lizan diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index 61adc4f0bf8c7..d577f4f063d62 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -236,11 +236,6 @@ EXTENSIONS = { "envoy.wasm.runtime.wavm": "//source/extensions/wasm_runtime/wavm:config", "envoy.wasm.runtime.wasmtime": "//source/extensions/wasm_runtime/wasmtime:config", - # - # Rate limit descriptors - # - - "envoy.rate_limit_descriptors.expr": "//source/extensions/rate_limit_descriptors/expr:config", } # These can be changed to ["//visibility:public"], for downstream builds which From 726e3e9368c90c783549efece7dc2f5ed80bc1ba Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Mon, 1 Feb 2021 23:52:43 -0800 Subject: [PATCH 84/88] fixing build Signed-off-by: Yuchen Dai --- .../buffered_io_socket/buffered_io_socket_handle_impl.cc | 8 ++++++-- .../buffered_io_socket/buffered_io_socket_handle_impl.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc index c1b800e8b254d..b53128fcccdfa 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc @@ -88,7 +88,11 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, } Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, - uint64_t max_length) { + absl::optional max_length_opt) { + const uint64_t max_length = max_length_opt.value_or(UINT64_MAX); + if (max_length == 0) { + return Api::ioCallUint64ResultNoError(); + } if (!isOpen()) { return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; @@ -101,7 +105,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe Network::IoSocketError::deleteIoError)}; } } - // TODO(lambdai): Move at slice boundary to move to reduce the copy. + // TODO(lambdai): Move slice by slice until high watermark. uint64_t max_bytes_to_read = std::min(max_length, pending_received_data_.length()); buffer.move(pending_received_data_, max_bytes_to_read); return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h index 8bf7c0a51a8f3..4b4dbf38af663 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h @@ -46,7 +46,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, bool isOpen() const override; Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, uint64_t num_slice) override; - Api::IoCallUint64Result read(Buffer::Instance& buffer, uint64_t max_length) override; + Api::IoCallUint64Result read(Buffer::Instance& buffer, absl::optional max_length_opt) override; Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; Api::IoCallUint64Result write(Buffer::Instance& buffer) override; Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, From 4adf60c673e64cb1e5b8cc88392c256941e9b8db Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 2 Feb 2021 00:57:07 -0800 Subject: [PATCH 85/88] fix test build Signed-off-by: Yuchen Dai --- .../buffered_io_socket_handle_impl_test.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc index 24dc4fe2ae0aa..8eeaa236fe340 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc @@ -186,8 +186,8 @@ TEST_F(BufferedIoSocketHandleTest, BasicReadv) { io_handle_peer_->write(buf_to_write); Buffer::OwnedImpl buf; - Buffer::RawSlice slice; - buf.reserve(1024, &slice, 1); + buf.reserveSingleSlice(1024); + auto slice = buf.frontSlice(); auto result = io_handle_->readv(1024, &slice, 1); EXPECT_TRUE(result.ok()); @@ -738,8 +738,8 @@ TEST_F(BufferedIoSocketHandleTest, WriteScheduleWritableEvent) { [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { Buffer::OwnedImpl buf; - Buffer::RawSlice slice; - buf.reserve(1024, &slice, 1); + buf.reserveSingleSlice(1024); + auto slice = buf.frontSlice(); auto result = handle->readv(1024, &slice, 1); if (result.ok()) { accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); @@ -778,8 +778,8 @@ TEST_F(BufferedIoSocketHandleTest, WritevScheduleWritableEvent) { [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { Buffer::OwnedImpl buf; - Buffer::RawSlice slice; - buf.reserve(1024, &slice, 1); + buf.reserveSingleSlice(1024); + auto slice = buf.frontSlice(); auto result = handle->readv(1024, &slice, 1); if (result.ok()) { accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); @@ -819,8 +819,8 @@ TEST_F(BufferedIoSocketHandleTest, ReadAfterShutdownWrite) { [&should_close, handle = io_handle_peer_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { Buffer::OwnedImpl buf; - Buffer::RawSlice slice; - buf.reserve(1024, &slice, 1); + buf.reserveSingleSlice(1024); + auto slice = buf.frontSlice(); auto result = handle->readv(1024, &slice, 1); if (result.ok()) { if (result.rc_ == 0) { From 1f91272ade4a0bb323f2fc724467016ae32b283a Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 2 Feb 2021 01:42:00 -0800 Subject: [PATCH 86/88] fix build Signed-off-by: Yuchen Dai --- CODEOWNERS | 2 - source/extensions/extensions_build_config.bzl | 6 -- .../io_socket/buffered_io_socket/BUILD | 56 ------------ .../buffered_io_socket/peer_buffer.h | 75 ---------------- .../user_space_file_event_impl.cc | 89 ------------------- .../user_space_file_event_impl.h | 74 --------------- source/extensions/io_socket/user_space/BUILD | 16 ++++ .../buffered_io_socket_handle_impl.cc | 44 ++++----- .../buffered_io_socket_handle_impl.h | 36 ++++---- 9 files changed, 56 insertions(+), 342 deletions(-) delete mode 100644 source/extensions/io_socket/buffered_io_socket/BUILD delete mode 100644 source/extensions/io_socket/buffered_io_socket/peer_buffer.h delete mode 100644 source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc delete mode 100644 source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h rename source/extensions/io_socket/{buffered_io_socket => user_space}/buffered_io_socket_handle_impl.cc (92%) rename source/extensions/io_socket/{buffered_io_socket => user_space}/buffered_io_socket_handle_impl.h (88%) diff --git a/CODEOWNERS b/CODEOWNERS index c9cd125be4290..00a3e81fd1e53 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -153,8 +153,6 @@ extensions/filters/common/original_src @snowp @klarose # Core upstream code extensions/upstreams/http @alyssawilk @snowp @mattklein123 extensions/upstreams/tcp @alyssawilk @ggreenway @mattklein123 -# user space socket pair and event -/*/extensions/io_socket/buffered_io_socket @lambdai @antoniovicente # OAuth2 extensions/filters/http/oauth2 @rgs1 @derekargueta @snowp # HTTP Local Rate Limit diff --git a/source/extensions/extensions_build_config.bzl b/source/extensions/extensions_build_config.bzl index b2afdcb39bab2..1f861f0a22998 100644 --- a/source/extensions/extensions_build_config.bzl +++ b/source/extensions/extensions_build_config.bzl @@ -220,12 +220,6 @@ EXTENSIONS = { # "envoy.watchdog.profile_action": "//source/extensions/watchdog/profile_action:config", - - # - # IO socket - # - - "envoy.io_socket.user_space_socket": "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", # # WebAssembly runtimes diff --git a/source/extensions/io_socket/buffered_io_socket/BUILD b/source/extensions/io_socket/buffered_io_socket/BUILD deleted file mode 100644 index 6f0cbc1038c35..0000000000000 --- a/source/extensions/io_socket/buffered_io_socket/BUILD +++ /dev/null @@ -1,56 +0,0 @@ -load( - "//bazel:envoy_build_system.bzl", - "envoy_cc_extension", - "envoy_extension_package", -) - -licenses(["notice"]) # Apache 2 - -envoy_extension_package() - -envoy_cc_extension( - name = "peer_buffer_lib", - hdrs = ["peer_buffer.h"], - security_posture = "unknown", - status = "alpha", - deps = [ - "//source/common/buffer:buffer_lib", - "//source/common/buffer:watermark_buffer_lib", - "//source/common/common:empty_string", - ], -) - -envoy_cc_extension( - name = "users_space_file_event_lib", - srcs = [ - "user_space_file_event_impl.cc", - ], - hdrs = [ - "user_space_file_event_impl.h", - ], - security_posture = "unknown", - status = "alpha", - deps = [ - ":peer_buffer_lib", - "//source/common/event:dispatcher_includes", - ], -) - -envoy_cc_extension( - name = "buffered_io_socket_handle_lib", - srcs = [ - "buffered_io_socket_handle_impl.cc", - ], - hdrs = [ - "buffered_io_socket_handle_impl.h", - ], - security_posture = "unknown", - status = "alpha", - undocumented = True, - deps = [ - ":peer_buffer_lib", - ":users_space_file_event_lib", - "//source/common/event:dispatcher_includes", - "//source/common/network:default_socket_interface_lib", - ], -) diff --git a/source/extensions/io_socket/buffered_io_socket/peer_buffer.h b/source/extensions/io_socket/buffered_io_socket/peer_buffer.h deleted file mode 100644 index 2e6630b8dab18..0000000000000 --- a/source/extensions/io_socket/buffered_io_socket/peer_buffer.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include "envoy/buffer/buffer.h" -#include "envoy/common/pure.h" - -namespace Envoy { -namespace Extensions { -namespace IoSocket { -namespace BufferedIoSocket { - -/** - * The interface for the writer. - */ -class WritablePeer { -public: - virtual ~WritablePeer() = default; - - /** - * Set the flag to indicate no further write from peer. - */ - virtual void setWriteEnd() PURE; - - /** - * @return true if the peer promise no more write. - */ - virtual bool isPeerShutDownWrite() const PURE; - - /** - * Raised when peer is destroyed. No further write to peer is allowed. - */ - virtual void onPeerDestroy() PURE; - - /** - * Notify that consumable data arrived. The consumable data can be either data to read, or the end - * of stream event. - */ - virtual void setNewDataAvailable() PURE; - - /** - * @return the buffer to be written. - */ - virtual Buffer::Instance* getWriteBuffer() PURE; - - /** - * @return true if more data is acceptable at the destination buffer. - */ - virtual bool isWritable() const PURE; - - /** - * @return true if peer is valid and writable. - */ - virtual bool isPeerWritable() const PURE; - - /** - * Raised by the peer when the peer switch from high water mark to low. - */ - virtual void onPeerBufferLowWatermark() PURE; -}; - -/** - * The interface for the peer as a writer and supplied read status query. - */ -class UserspaceIoHandle : public WritablePeer { -public: - ~UserspaceIoHandle() override = default; - - /** - * @return true if the pending receive buffer is not empty or read_end is set. - */ - virtual bool isReadable() const PURE; -}; -} // namespace BufferedIoSocket -} // namespace IoSocket -} // namespace Extensions -} // namespace Envoy diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc deleted file mode 100644 index ecabf8540cf23..0000000000000 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.cc +++ /dev/null @@ -1,89 +0,0 @@ -#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" - -#include - -#include "common/common/assert.h" - -#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" - -namespace Envoy { -namespace Extensions { -namespace IoSocket { -namespace BufferedIoSocket { - -UserSpaceFileEventImpl::UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, - uint32_t events, UserspaceIoHandle& io_source) - : schedulable_(dispatcher.createSchedulableCallback([this, cb]() { - auto ephemeral_events = event_listener_.getAndClearEphemeralEvents(); - ENVOY_LOG(trace, "User space event {} invokes callbacks on events = {}", - static_cast(this), ephemeral_events); - cb(ephemeral_events); - })), - io_source_(io_source) { - setEnabled(events); -} - -void EventListenerImpl::clearEphemeralEvents() { - // Clear ephemeral events to align with FileEventImpl::setEnable(). - ephemeral_events_ = 0; -} - -void EventListenerImpl::onEventActivated(uint32_t activated_events) { - ephemeral_events_ |= activated_events; -} - -void EventListenerImpl::setEnabledEvents(uint32_t enabled_events) { - enabled_events_ = enabled_events; -} - -void UserSpaceFileEventImpl::activate(uint32_t events) { - // Only supported event types are set. - ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | - Event::FileReadyType::Closed)) == events); - event_listener_.onEventActivated(events); - schedulable_->scheduleCallbackNextIteration(); -} - -void UserSpaceFileEventImpl::setEnabled(uint32_t events) { - // Only supported event types are set. - ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | - Event::FileReadyType::Closed)) == events); - event_listener_.clearEphemeralEvents(); - event_listener_.setEnabledEvents(events); - bool was_enabled = schedulable_->enabled(); - // Recalculate activated events. - uint32_t events_to_notify = 0; - if ((events & Event::FileReadyType::Read) && io_source_.isReadable()) { - events_to_notify |= Event::FileReadyType::Read; - } - if ((events & Event::FileReadyType::Write) && io_source_.isPeerWritable()) { - events_to_notify |= Event::FileReadyType::Write; - } - if ((events & Event::FileReadyType::Closed) && io_source_.isPeerShutDownWrite()) { - events_to_notify |= Event::FileReadyType::Closed; - } - if (events_to_notify != 0) { - activate(events_to_notify); - } else { - schedulable_->cancel(); - } - ENVOY_LOG( - trace, - "User space file event {} set enabled events {} and events {} is active. Will {} reschedule.", - static_cast(this), events, was_enabled ? "not " : ""); -} - -void UserSpaceFileEventImpl::poll(uint32_t events) { - ASSERT((events & (Event::FileReadyType::Read | Event::FileReadyType::Write | - Event::FileReadyType::Closed)) == events); - // filtered out disabled events. - uint32_t filter_enabled = events & event_listener_.getEnabledEvents(); - if (filter_enabled == 0) { - return; - } - activate(filter_enabled); -} -} // namespace BufferedIoSocket -} // namespace IoSocket -} // namespace Extensions -} // namespace Envoy \ No newline at end of file diff --git a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h b/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h deleted file mode 100644 index 98b3149d5de7e..0000000000000 --- a/source/extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include - -#include "envoy/event/file_event.h" - -#include "common/event/dispatcher_impl.h" -#include "common/event/event_impl_base.h" - -#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" - -namespace Envoy { - -namespace Extensions { -namespace IoSocket { -namespace BufferedIoSocket { - -// This class maintains the ephemeral events and enabled events. -// getAndClearEphemeralEvents -class EventListenerImpl { -public: - ~EventListenerImpl() = default; - - // Reset the enabled events. The caller must refresh the triggered events. - void setEnabledEvents(uint32_t enabled_events); - // Return the enabled events. - uint32_t getEnabledEvents() { return enabled_events_; } - - void clearEphemeralEvents(); - void onEventActivated(uint32_t activated_events); - - uint32_t getAndClearEphemeralEvents() { return std::exchange(ephemeral_events_, 0); } - -private: - // The events set by activate() and will be cleared after the io callback. - uint32_t ephemeral_events_{}; - // The events set by setEnabled(). The new value replaces the old value. - uint32_t enabled_events_{}; -}; - -// A FileEvent implementation which is used to drive BufferedIoSocketHandle. -// Declare the class final to safely call virtual function setEnabled in constructor. -class UserSpaceFileEventImpl final : public Event::FileEvent, Logger::Loggable { -public: - UserSpaceFileEventImpl(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, uint32_t events, - UserspaceIoHandle& io_source); - - // Event::FileEvent - void activate(uint32_t events) override; - void setEnabled(uint32_t events) override; - - // `UserspaceFileEvent` acts always as edge triggered regardless the underlying OS is level or - // edge triggered. The event owner on windows platform should not emulate edge events. - void unregisterEventIfEmulatedEdge(uint32_t) override {} - void registerEventIfEmulatedEdge(uint32_t) override {} - - // Notify events. Unlike activate() method, this method activates the given events only if the - // events are enabled. - void poll(uint32_t events); - -private: - // Used to populate the event operations of enable and activate. - EventListenerImpl event_listener_; - - // The handle to registered async callback from dispatcher. - Event::SchedulableCallbackPtr schedulable_; - - // Supplies readable and writable status. - UserspaceIoHandle& io_source_; -}; -} // namespace BufferedIoSocket -} // namespace IoSocket -} // namespace Extensions -} // namespace Envoy diff --git a/source/extensions/io_socket/user_space/BUILD b/source/extensions/io_socket/user_space/BUILD index e449d227ef684..850cb86b46633 100644 --- a/source/extensions/io_socket/user_space/BUILD +++ b/source/extensions/io_socket/user_space/BUILD @@ -42,3 +42,19 @@ envoy_cc_library( "//include/envoy/event:dispatcher_interface", ], ) + +envoy_cc_library( + name = "buffered_io_socket_handle_lib", + srcs = [ + "buffered_io_socket_handle_impl.cc", + ], + hdrs = [ + "buffered_io_socket_handle_impl.h", + ], + deps = [ + ":io_handle_lib", + ":file_event_lib", + "//source/common/event:dispatcher_includes", + "//source/common/network:default_socket_interface_lib", + ], +) diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.cc similarity index 92% rename from source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc rename to source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.cc index b53128fcccdfa..b140c7ffa6589 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.cc @@ -1,4 +1,4 @@ -#include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" +#include "extensions/io_socket/user_space/buffered_io_socket_handle_impl.h" #include "envoy/buffer/buffer.h" #include "envoy/common/platform.h" @@ -8,7 +8,7 @@ #include "common/common/utility.h" #include "common/network/address_impl.h" -#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" +#include "extensions/io_socket/user_space/file_event_impl.h" #include "absl/types/optional.h" @@ -16,7 +16,7 @@ namespace Envoy { namespace Extensions { namespace IoSocket { -namespace BufferedIoSocket { +namespace UserSpace { namespace { Api::SysCallIntResult makeInvalidSyscallResult() { return Api::SysCallIntResult{-1, SOCKET_ERROR_NOT_SUP}; @@ -36,14 +36,14 @@ BufferedIoSocketHandleImpl::~BufferedIoSocketHandleImpl() { Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { ASSERT(!closed_); if (!closed_) { - if (writable_peer_) { + if (peer_handle_) { ENVOY_LOG(trace, "socket {} close before peer {} closes.", static_cast(this), - static_cast(writable_peer_)); + static_cast(peer_handle_)); // Notify the peer we won't write more data. shutdown(WRITE). - writable_peer_->setWriteEnd(); + peer_handle_->setWriteEnd(); // Notify the peer that we no longer accept data. shutdown(RD). - writable_peer_->onPeerDestroy(); - writable_peer_ = nullptr; + peer_handle_->onPeerDestroy(); + peer_handle_ = nullptr; } else { ENVOY_LOG(trace, "socket {} close after peer closed.", static_cast(this)); } @@ -129,23 +129,23 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic Network::IoSocketError::deleteIoError)}; } // Closed peer. - if (!writable_peer_) { + if (!peer_handle_) { return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; } // Error: write after close. - if (writable_peer_->isPeerShutDownWrite()) { + if (peer_handle_->isPeerShutDownWrite()) { // TODO(lambdai): `EPIPE` or `ENOTCONN`. return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; } // The peer is valid but temporary not accepts new data. Likely due to flow control. - if (!writable_peer_->isWritable()) { + if (!peer_handle_->isWritable()) { return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), Network::IoSocketError::deleteIoError)}; } - auto* const dest_buffer = writable_peer_->getWriteBuffer(); + auto* const dest_buffer = peer_handle_->getWriteBuffer(); // Write along with iteration. Buffer guarantee the fragment is always append-able. uint64_t bytes_written = 0; for (uint64_t i = 0; i < num_slice && !dest_buffer->highWatermarkTriggered(); i++) { @@ -154,7 +154,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic bytes_written += slices[i].len_; } } - writable_peer_->setNewDataAvailable(); + peer_handle_->setNewDataAvailable(); ENVOY_LOG(trace, "socket {} writev {} bytes", static_cast(this), bytes_written); return {bytes_written, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } @@ -169,33 +169,33 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff Network::IoSocketError::deleteIoError)}; } // Closed peer. - if (!writable_peer_) { + if (!peer_handle_) { return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; } // Error: write after close. - if (writable_peer_->isPeerShutDownWrite()) { + if (peer_handle_->isPeerShutDownWrite()) { // TODO(lambdai): `EPIPE` or `ENOTCONN`. return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; } // The peer is valid but temporary not accepts new data. Likely due to flow control. - if (!writable_peer_->isWritable()) { + if (!peer_handle_->isWritable()) { return {0, Api::IoErrorPtr(Network::IoSocketError::getIoSocketEagainInstance(), Network::IoSocketError::deleteIoError)}; } uint64_t total_bytes_to_write = 0; const uint64_t max_bytes_to_write = buffer.length(); - while (writable_peer_->isWritable()) { + while (peer_handle_->isWritable()) { const auto& front_slice = buffer.frontSlice(); if (front_slice.len_ == 0) { break; } else { - writable_peer_->getWriteBuffer()->move(buffer, front_slice.len_); + peer_handle_->getWriteBuffer()->move(buffer, front_slice.len_); total_bytes_to_write += front_slice.len_; } } - writable_peer_->setNewDataAvailable(); + peer_handle_->setNewDataAvailable(); ENVOY_LOG(trace, "socket {} writev {} bytes of {}", static_cast(this), total_bytes_to_write, max_bytes_to_write); return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; @@ -292,7 +292,7 @@ void BufferedIoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatch ASSERT(user_file_event_ == nullptr, "Attempting to initialize two `file_event_` for the same " "file descriptor. This is not allowed."); ASSERT(trigger != Event::FileTriggerType::Level, "Native level trigger is not supported yet."); - user_file_event_ = std::make_unique(dispatcher, cb, events, *this); + user_file_event_ = std::make_unique(dispatcher, cb, events, *this); } Network::IoHandlePtr BufferedIoSocketHandleImpl::duplicate() { @@ -324,9 +324,9 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { ASSERT(how == ENVOY_SHUT_WR); ASSERT(!closed_); if (!write_shutdown_) { - ASSERT(writable_peer_); + ASSERT(peer_handle_); // Notify the peer we won't write more data. - writable_peer_->setWriteEnd(); + peer_handle_->setWriteEnd(); write_shutdown_ = true; } return {0, 0}; diff --git a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.h similarity index 88% rename from source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h rename to source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.h index 4b4dbf38af663..da494c5d8a8b4 100644 --- a/source/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.h @@ -12,13 +12,13 @@ #include "common/common/logger.h" #include "common/network/io_socket_error_impl.h" -#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" -#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" +#include "extensions/io_socket/user_space/io_handle.h" +#include "extensions/io_socket/user_space/file_event_impl.h" namespace Envoy { namespace Extensions { namespace IoSocket { -namespace BufferedIoSocket { +namespace UserSpace { /** * Network::IoHandle implementation which provides a buffer as data source. It is designed to used * by Network::ConnectionImpl. Some known limitations include @@ -30,7 +30,7 @@ namespace BufferedIoSocket { * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ class BufferedIoSocketHandleImpl final : public Network::IoHandle, - public UserspaceIoHandle, + public UserSpace::IoHandle, protected Logger::Loggable { public: BufferedIoSocketHandleImpl(); @@ -83,17 +83,17 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, void setWatermarks(uint32_t watermark) { pending_received_data_.setWatermarks(watermark); } void onBelowLowWatermark() { - if (writable_peer_) { + if (peer_handle_) { ENVOY_LOG(debug, "Socket {} switches to low watermark. Notify {}.", static_cast(this), - static_cast(writable_peer_)); - writable_peer_->onPeerBufferLowWatermark(); + static_cast(peer_handle_)); + peer_handle_->onPeerBufferLowWatermark(); } } void onAboveHighWatermark() { // Low to high is checked by peer after peer writes data. } - // WritablePeer + // UserSpace::IoHandle void setWriteEnd() override { receive_data_end_stream_ = true; setNewDataAvailable(); @@ -101,25 +101,25 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, void setNewDataAvailable() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); if (user_file_event_) { - user_file_event_->poll(Event::FileReadyType::Read | + user_file_event_->activateIfEnabled(Event::FileReadyType::Read | // Closed ready type is defined as `end of stream` (receive_data_end_stream_ ? Event::FileReadyType::Closed : 0)); } } void onPeerDestroy() override { - writable_peer_ = nullptr; + peer_handle_ = nullptr; write_shutdown_ = true; } void onPeerBufferLowWatermark() override { if (user_file_event_) { - user_file_event_->poll(Event::FileReadyType::Write); + user_file_event_->activateIfEnabled(Event::FileReadyType::Write); } } bool isWritable() const override { return !pending_received_data_.highWatermarkTriggered(); } bool isPeerShutDownWrite() const override { return receive_data_end_stream_; } bool isPeerWritable() const override { - return writable_peer_ != nullptr && !writable_peer_->isPeerShutDownWrite() && - writable_peer_->isWritable(); + return peer_handle_ != nullptr && !peer_handle_->isPeerShutDownWrite() && + peer_handle_->isWritable(); } Buffer::Instance* getWriteBuffer() override { return &pending_received_data_; } @@ -129,11 +129,11 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, } // Set the peer which will populate the owned pending_received_data. - void setWritablePeer(WritablePeer* writable_peer) { + void setPeerHandle(UserSpace::IoHandle* writable_peer) { // Swapping writable peer is undefined behavior. - ASSERT(!writable_peer_); + ASSERT(!peer_handle_); ASSERT(!write_shutdown_); - writable_peer_ = writable_peer; + peer_handle_ = writable_peer; } private: @@ -144,7 +144,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, // The attached file event with this socket. The event is not owned by the socket in the current // Envoy model. Multiple events can be created during the life time of this IO handle but at any // moment at most 1 event is attached. - std::unique_ptr user_file_event_; + std::unique_ptr user_file_event_; // True if pending_received_data_ is not addable. Note that pending_received_data_ may have // pending data to drain. @@ -155,7 +155,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, Buffer::WatermarkBuffer pending_received_data_; // Destination of the write(). The value remains non-null until the peer is closed. - WritablePeer* writable_peer_{nullptr}; + UserSpace::IoHandle* peer_handle_{nullptr}; // The flag whether the peer is valid. Any write attempt must check this flag. bool write_shutdown_{false}; From 65b590e898a0ce49e0c5bc114d4580ede829a076 Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 2 Feb 2021 02:00:49 -0800 Subject: [PATCH 87/88] fix tests Signed-off-by: Yuchen Dai --- source/extensions/io_socket/user_space/BUILD | 8 +- ...andle_impl.cc => io_socket_handle_impl.cc} | 89 +++-- ..._handle_impl.h => io_socket_handle_impl.h} | 24 +- .../io_socket/buffered_io_socket/BUILD | 54 --- .../user_space_file_event_impl_test.cc | 329 ------------------ test/extensions/io_socket/user_space/BUILD | 25 ++ .../io_socket_handle_impl_platform_test.cc} | 18 +- .../io_socket_handle_impl_test.cc} | 48 +-- 8 files changed, 116 insertions(+), 479 deletions(-) rename source/extensions/io_socket/user_space/{buffered_io_socket_handle_impl.cc => io_socket_handle_impl.cc} (72%) rename source/extensions/io_socket/user_space/{buffered_io_socket_handle_impl.h => io_socket_handle_impl.h} (90%) delete mode 100644 test/extensions/io_socket/buffered_io_socket/BUILD delete mode 100644 test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc rename test/extensions/io_socket/{buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc => user_space/io_socket_handle_impl_platform_test.cc} (71%) rename test/extensions/io_socket/{buffered_io_socket/buffered_io_socket_handle_impl_test.cc => user_space/io_socket_handle_impl_test.cc} (96%) diff --git a/source/extensions/io_socket/user_space/BUILD b/source/extensions/io_socket/user_space/BUILD index 850cb86b46633..420943a7b005a 100644 --- a/source/extensions/io_socket/user_space/BUILD +++ b/source/extensions/io_socket/user_space/BUILD @@ -44,16 +44,16 @@ envoy_cc_library( ) envoy_cc_library( - name = "buffered_io_socket_handle_lib", + name = "io_socket_handle_lib", srcs = [ - "buffered_io_socket_handle_impl.cc", + "io_socket_handle_impl.cc", ], hdrs = [ - "buffered_io_socket_handle_impl.h", + "io_socket_handle_impl.h", ], deps = [ - ":io_handle_lib", ":file_event_lib", + ":io_handle_lib", "//source/common/event:dispatcher_includes", "//source/common/network:default_socket_interface_lib", ], diff --git a/source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.cc b/source/extensions/io_socket/user_space/io_socket_handle_impl.cc similarity index 72% rename from source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.cc rename to source/extensions/io_socket/user_space/io_socket_handle_impl.cc index b140c7ffa6589..d54bed4da9659 100644 --- a/source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.cc +++ b/source/extensions/io_socket/user_space/io_socket_handle_impl.cc @@ -1,4 +1,4 @@ -#include "extensions/io_socket/user_space/buffered_io_socket_handle_impl.h" +#include "extensions/io_socket/user_space/io_socket_handle_impl.h" #include "envoy/buffer/buffer.h" #include "envoy/common/platform.h" @@ -23,17 +23,17 @@ Api::SysCallIntResult makeInvalidSyscallResult() { } } // namespace -BufferedIoSocketHandleImpl::BufferedIoSocketHandleImpl() +IoSocketHandleImpl::IoSocketHandleImpl() : pending_received_data_([&]() -> void { this->onBelowLowWatermark(); }, [&]() -> void { this->onAboveHighWatermark(); }, []() -> void {}) {} -BufferedIoSocketHandleImpl::~BufferedIoSocketHandleImpl() { +IoSocketHandleImpl::~IoSocketHandleImpl() { if (!closed_) { close(); } } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { +Api::IoCallUint64Result IoSocketHandleImpl::close() { ASSERT(!closed_); if (!closed_) { if (peer_handle_) { @@ -52,11 +52,10 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::close() { return Api::ioCallUint64ResultNoError(); } -bool BufferedIoSocketHandleImpl::isOpen() const { return !closed_; } +bool IoSocketHandleImpl::isOpen() const { return !closed_; } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, - Buffer::RawSlice* slices, - uint64_t num_slice) { +Api::IoCallUint64Result IoSocketHandleImpl::readv(uint64_t max_length, Buffer::RawSlice* slices, + uint64_t num_slice) { if (!isOpen()) { return {0, // TODO(lambdai): Add EBADF in Network::IoSocketError and adopt it here. @@ -87,8 +86,8 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::readv(uint64_t max_length, return {bytes_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffer, - absl::optional max_length_opt) { +Api::IoCallUint64Result IoSocketHandleImpl::read(Buffer::Instance& buffer, + absl::optional max_length_opt) { const uint64_t max_length = max_length_opt.value_or(UINT64_MAX); if (max_length == 0) { return Api::ioCallUint64ResultNoError(); @@ -111,8 +110,8 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::read(Buffer::Instance& buffe return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlice* slices, - uint64_t num_slice) { +Api::IoCallUint64Result IoSocketHandleImpl::writev(const Buffer::RawSlice* slices, + uint64_t num_slice) { // Empty input is allowed even though the peer is shutdown. bool is_input_empty = true; for (uint64_t i = 0; i < num_slice; i++) { @@ -159,7 +158,7 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::writev(const Buffer::RawSlic return {bytes_written, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buffer) { +Api::IoCallUint64Result IoSocketHandleImpl::write(Buffer::Instance& buffer) { // Empty input is allowed even though the peer is shutdown. if (buffer.length() == 0) { return Api::ioCallUint64ResultNoError(); @@ -201,23 +200,22 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::write(Buffer::Instance& buff return {total_bytes_to_write, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, - const Network::Address::Ip*, - const Network::Address::Instance&) { +Api::IoCallUint64Result IoSocketHandleImpl::sendmsg(const Buffer::RawSlice*, uint64_t, int, + const Network::Address::Ip*, + const Network::Address::Instance&) { return Network::IoSocketError::ioResultSocketInvalidAddress(); } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmsg(Buffer::RawSlice*, const uint64_t, - uint32_t, RecvMsgOutput&) { +Api::IoCallUint64Result IoSocketHandleImpl::recvmsg(Buffer::RawSlice*, const uint64_t, uint32_t, + RecvMsgOutput&) { return Network::IoSocketError::ioResultSocketInvalidAddress(); } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::recvmmsg(RawSliceArrays&, uint32_t, - RecvMsgOutput&) { +Api::IoCallUint64Result IoSocketHandleImpl::recvmmsg(RawSliceArrays&, uint32_t, RecvMsgOutput&) { return Network::IoSocketError::ioResultSocketInvalidAddress(); } -Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { +Api::IoCallUint64Result IoSocketHandleImpl::recv(void* buffer, size_t length, int flags) { if (!isOpen()) { return {0, Api::IoErrorPtr(new Network::IoSocketError(SOCKET_ERROR_INVAL), Network::IoSocketError::deleteIoError)}; @@ -240,68 +238,63 @@ Api::IoCallUint64Result BufferedIoSocketHandleImpl::recv(void* buffer, size_t le return {max_bytes_to_read, Api::IoErrorPtr(nullptr, [](Api::IoError*) {})}; } -bool BufferedIoSocketHandleImpl::supportsMmsg() const { return false; } +bool IoSocketHandleImpl::supportsMmsg() const { return false; } -bool BufferedIoSocketHandleImpl::supportsUdpGro() const { return false; } +bool IoSocketHandleImpl::supportsUdpGro() const { return false; } -Api::SysCallIntResult BufferedIoSocketHandleImpl::bind(Network::Address::InstanceConstSharedPtr) { +Api::SysCallIntResult IoSocketHandleImpl::bind(Network::Address::InstanceConstSharedPtr) { return makeInvalidSyscallResult(); } -Api::SysCallIntResult BufferedIoSocketHandleImpl::listen(int) { return makeInvalidSyscallResult(); } +Api::SysCallIntResult IoSocketHandleImpl::listen(int) { return makeInvalidSyscallResult(); } -Network::IoHandlePtr BufferedIoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { +Network::IoHandlePtr IoSocketHandleImpl::accept(struct sockaddr*, socklen_t*) { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } -Api::SysCallIntResult -BufferedIoSocketHandleImpl::connect(Network::Address::InstanceConstSharedPtr) { +Api::SysCallIntResult IoSocketHandleImpl::connect(Network::Address::InstanceConstSharedPtr) { // Buffered Io handle should always be considered as connected. // Use write or read to determine if peer is closed. return {0, 0}; } -Api::SysCallIntResult BufferedIoSocketHandleImpl::setOption(int, int, const void*, socklen_t) { +Api::SysCallIntResult IoSocketHandleImpl::setOption(int, int, const void*, socklen_t) { return makeInvalidSyscallResult(); } -Api::SysCallIntResult BufferedIoSocketHandleImpl::getOption(int, int, void*, socklen_t*) { +Api::SysCallIntResult IoSocketHandleImpl::getOption(int, int, void*, socklen_t*) { return makeInvalidSyscallResult(); } -Api::SysCallIntResult BufferedIoSocketHandleImpl::setBlocking(bool) { - return makeInvalidSyscallResult(); -} +Api::SysCallIntResult IoSocketHandleImpl::setBlocking(bool) { return makeInvalidSyscallResult(); } -absl::optional BufferedIoSocketHandleImpl::domain() { return absl::nullopt; } +absl::optional IoSocketHandleImpl::domain() { return absl::nullopt; } -Network::Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::localAddress() { +Network::Address::InstanceConstSharedPtr IoSocketHandleImpl::localAddress() { // TODO(lambdai): Rewrite when caller accept error as the return value. - throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); + throw EnvoyException(fmt::format("getsockname failed for IoSocketHandleImpl")); } -Network::Address::InstanceConstSharedPtr BufferedIoSocketHandleImpl::peerAddress() { +Network::Address::InstanceConstSharedPtr IoSocketHandleImpl::peerAddress() { // TODO(lambdai): Rewrite when caller accept error as the return value. - throw EnvoyException(fmt::format("getsockname failed for BufferedIoSocketHandleImpl")); + throw EnvoyException(fmt::format("getsockname failed for IoSocketHandleImpl")); } -void BufferedIoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatcher, - Event::FileReadyCb cb, - Event::FileTriggerType trigger, - uint32_t events) { +void IoSocketHandleImpl::initializeFileEvent(Event::Dispatcher& dispatcher, Event::FileReadyCb cb, + Event::FileTriggerType trigger, uint32_t events) { ASSERT(user_file_event_ == nullptr, "Attempting to initialize two `file_event_` for the same " "file descriptor. This is not allowed."); ASSERT(trigger != Event::FileTriggerType::Level, "Native level trigger is not supported yet."); user_file_event_ = std::make_unique(dispatcher, cb, events, *this); } -Network::IoHandlePtr BufferedIoSocketHandleImpl::duplicate() { +Network::IoHandlePtr IoSocketHandleImpl::duplicate() { // duplicate() is supposed to be used on listener io handle while this implementation doesn't // support listen. NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } -void BufferedIoSocketHandleImpl::activateFileEvents(uint32_t events) { +void IoSocketHandleImpl::activateFileEvents(uint32_t events) { if (user_file_event_) { user_file_event_->activate(events); } else { @@ -309,7 +302,7 @@ void BufferedIoSocketHandleImpl::activateFileEvents(uint32_t events) { } } -void BufferedIoSocketHandleImpl::enableFileEvents(uint32_t events) { +void IoSocketHandleImpl::enableFileEvents(uint32_t events) { if (user_file_event_) { user_file_event_->setEnabled(events); } else { @@ -317,9 +310,9 @@ void BufferedIoSocketHandleImpl::enableFileEvents(uint32_t events) { } } -void BufferedIoSocketHandleImpl::resetFileEvents() { user_file_event_.reset(); } +void IoSocketHandleImpl::resetFileEvents() { user_file_event_.reset(); } -Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { +Api::SysCallIntResult IoSocketHandleImpl::shutdown(int how) { // Support only shutdown write. ASSERT(how == ENVOY_SHUT_WR); ASSERT(!closed_); @@ -331,7 +324,7 @@ Api::SysCallIntResult BufferedIoSocketHandleImpl::shutdown(int how) { } return {0, 0}; } -} // namespace BufferedIoSocket +} // namespace UserSpace } // namespace IoSocket } // namespace Extensions } // namespace Envoy \ No newline at end of file diff --git a/source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.h b/source/extensions/io_socket/user_space/io_socket_handle_impl.h similarity index 90% rename from source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.h rename to source/extensions/io_socket/user_space/io_socket_handle_impl.h index da494c5d8a8b4..8f3ff3bd6ccef 100644 --- a/source/extensions/io_socket/user_space/buffered_io_socket_handle_impl.h +++ b/source/extensions/io_socket/user_space/io_socket_handle_impl.h @@ -12,8 +12,8 @@ #include "common/common/logger.h" #include "common/network/io_socket_error_impl.h" -#include "extensions/io_socket/user_space/io_handle.h" #include "extensions/io_socket/user_space/file_event_impl.h" +#include "extensions/io_socket/user_space/io_handle.h" namespace Envoy { namespace Extensions { @@ -29,13 +29,13 @@ namespace UserSpace { * 4. The peer BufferedIoSocket must be scheduled in the same thread to avoid data race because * BufferedIoSocketHandle mutates the state of peer handle and no lock is introduced. */ -class BufferedIoSocketHandleImpl final : public Network::IoHandle, - public UserSpace::IoHandle, - protected Logger::Loggable { +class IoSocketHandleImpl final : public Network::IoHandle, + public UserSpace::IoHandle, + protected Logger::Loggable { public: - BufferedIoSocketHandleImpl(); + IoSocketHandleImpl(); - ~BufferedIoSocketHandleImpl() override; + ~IoSocketHandleImpl() override; // Network::IoHandle os_fd_t fdDoNotUse() const override { @@ -46,7 +46,8 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, bool isOpen() const override; Api::IoCallUint64Result readv(uint64_t max_length, Buffer::RawSlice* slices, uint64_t num_slice) override; - Api::IoCallUint64Result read(Buffer::Instance& buffer, absl::optional max_length_opt) override; + Api::IoCallUint64Result read(Buffer::Instance& buffer, + absl::optional max_length_opt) override; Api::IoCallUint64Result writev(const Buffer::RawSlice* slices, uint64_t num_slice) override; Api::IoCallUint64Result write(Buffer::Instance& buffer) override; Api::IoCallUint64Result sendmsg(const Buffer::RawSlice* slices, uint64_t num_slice, int flags, @@ -101,9 +102,10 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, void setNewDataAvailable() override { ENVOY_LOG(trace, "{} on socket {}", __FUNCTION__, static_cast(this)); if (user_file_event_) { - user_file_event_->activateIfEnabled(Event::FileReadyType::Read | - // Closed ready type is defined as `end of stream` - (receive_data_end_stream_ ? Event::FileReadyType::Closed : 0)); + user_file_event_->activateIfEnabled( + Event::FileReadyType::Read | + // Closed ready type is defined as `end of stream` + (receive_data_end_stream_ ? Event::FileReadyType::Closed : 0)); } } void onPeerDestroy() override { @@ -160,7 +162,7 @@ class BufferedIoSocketHandleImpl final : public Network::IoHandle, // The flag whether the peer is valid. Any write attempt must check this flag. bool write_shutdown_{false}; }; -} // namespace BufferedIoSocket +} // namespace UserSpace } // namespace IoSocket } // namespace Extensions } // namespace Envoy \ No newline at end of file diff --git a/test/extensions/io_socket/buffered_io_socket/BUILD b/test/extensions/io_socket/buffered_io_socket/BUILD deleted file mode 100644 index 3484da468fe4c..0000000000000 --- a/test/extensions/io_socket/buffered_io_socket/BUILD +++ /dev/null @@ -1,54 +0,0 @@ -load( - "//bazel:envoy_build_system.bzl", - "envoy_package", -) -load( - "//test/extensions:extensions_build_system.bzl", - "envoy_extension_cc_test", -) - -licenses(["notice"]) # Apache 2 - -envoy_package() - -envoy_extension_cc_test( - name = "buffered_io_socket_handle_impl_test", - srcs = ["buffered_io_socket_handle_impl_test.cc"], - extension_name = "envoy.io_socket.user_space_socket", - deps = [ - "//source/common/common:utility_lib", - "//source/common/network:address_lib", - "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", - "//test/mocks/event:event_mocks", - ], -) - -envoy_extension_cc_test( - name = "buffered_io_socket_handle_impl_platform_test", - srcs = ["buffered_io_socket_handle_impl_platform_test.cc"], - extension_name = "envoy.io_socket.user_space_socket", - tags = ["fails_on_windows"], - deps = [ - "//source/common/common:utility_lib", - "//source/common/network:address_lib", - "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", - "//test/mocks/event:event_mocks", - ], -) - -envoy_extension_cc_test( - name = "user_space_file_event_impl_test", - srcs = ["user_space_file_event_impl_test.cc"], - extension_name = "envoy.io_socket.user_space_socket", - deps = [ - "//include/envoy/event:file_event_interface", - "//source/common/event:dispatcher_includes", - "//source/common/event:dispatcher_lib", - "//source/extensions/io_socket/buffered_io_socket:buffered_io_socket_handle_lib", - "//source/extensions/io_socket/buffered_io_socket:peer_buffer_lib", - "//test/mocks:common_lib", - "//test/test_common:environment_lib", - "//test/test_common:test_runtime_lib", - "//test/test_common:utility_lib", - ], -) diff --git a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc b/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc deleted file mode 100644 index e45e7c205b6b6..0000000000000 --- a/test/extensions/io_socket/buffered_io_socket/user_space_file_event_impl_test.cc +++ /dev/null @@ -1,329 +0,0 @@ -#include - -#include "envoy/event/file_event.h" - -#include "common/event/dispatcher_impl.h" - -#include "extensions/io_socket/buffered_io_socket/peer_buffer.h" -#include "extensions/io_socket/buffered_io_socket/user_space_file_event_impl.h" - -#include "test/mocks/common.h" -#include "test/test_common/environment.h" -#include "test/test_common/test_runtime.h" -#include "test/test_common/utility.h" - -#include "gmock/gmock.h" -#include "gtest/gtest.h" - -namespace Envoy { -namespace Extensions { -namespace IoSocket { -namespace BufferedIoSocket { -namespace { - -using testing::NiceMock; -using testing::Return; - -constexpr auto event_rw = Event::FileReadyType::Read | Event::FileReadyType::Write; -class MockReadyCb { -public: - MOCK_METHOD(void, called, (uint32_t)); -}; - -class MockUserspaceIoHandle : public UserspaceIoHandle { -public: - MOCK_METHOD(void, setWriteEnd, ()); - MOCK_METHOD(bool, isPeerShutDownWrite, (), (const)); - MOCK_METHOD(void, onPeerDestroy, ()); - MOCK_METHOD(void, setNewDataAvailable, ()); - MOCK_METHOD(Buffer::Instance*, getWriteBuffer, ()); - MOCK_METHOD(bool, isWritable, (), (const)); - MOCK_METHOD(bool, isPeerWritable, (), (const)); - MOCK_METHOD(void, onPeerBufferLowWatermark, ()); - MOCK_METHOD(bool, isReadable, (), (const)); -}; - -class UserSpaceFileEventImplTest : public testing::Test { -public: - UserSpaceFileEventImplTest() - : api_(Api::createApiForTest()), dispatcher_(api_->allocateDispatcher("test_thread")) {} - - void setWritable() { EXPECT_CALL(io_source_, isPeerWritable()).WillRepeatedly(Return(true)); } - void setReadable() { EXPECT_CALL(io_source_, isReadable()).WillRepeatedly(Return(true)); } - void setWriteEnd() { - EXPECT_CALL(io_source_, isPeerShutDownWrite()).WillRepeatedly(Return(true)); - } - void clearEventExpectation() { testing::Mock::VerifyAndClearExpectations(&io_source_); } - -protected: - NiceMock io_source_; - MockReadyCb ready_cb_; - Api::ApiPtr api_; - Event::DispatcherPtr dispatcher_; - std::unique_ptr user_file_event_; -}; - -TEST_F(UserSpaceFileEventImplTest, EnabledEventsTriggeredAfterCreate) { - for (const auto current_event : {Event::FileReadyType::Read, Event::FileReadyType::Write, - Event::FileReadyType::Read | Event::FileReadyType::Write}) { - SCOPED_TRACE(absl::StrCat("current event:", current_event)); - clearEventExpectation(); - if (current_event & Event::FileReadyType::Read) { - setReadable(); - } - if (current_event & Event::FileReadyType::Write) { - setWritable(); - } - MockReadyCb ready_cb; - auto user_file_event = std::make_unique( - *dispatcher_, [&ready_cb](uint32_t arg) { ready_cb.called(arg); }, current_event, - io_source_); - EXPECT_CALL(ready_cb, called(current_event)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - testing::Mock::VerifyAndClearExpectations(&ready_cb); - } -} - -TEST_F(UserSpaceFileEventImplTest, ReadEventNotDeliveredAfterDisabledRead) { - setWritable(); - setReadable(); - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - // The above should deliver both Read and Write during the poll. It is not tested here but in - // other test case. - - // Now disable Read. - user_file_event_->setEnabled(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); -} - -TEST_F(UserSpaceFileEventImplTest, RescheduleAfterTriggered) { - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - { - SCOPED_TRACE("1st schedule"); - user_file_event_->activate(event_rw); - EXPECT_CALL(ready_cb_, called(event_rw)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - - { - SCOPED_TRACE("2nd schedule"); - user_file_event_->activate(event_rw); - EXPECT_CALL(ready_cb_, called(event_rw)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - SCOPED_TRACE("merge events"); - user_file_event_->activate(Event::FileReadyType::Read); - user_file_event_->activate(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(event_rw)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } -} - -TEST_F(UserSpaceFileEventImplTest, RescheduleIsDeduplicated) { - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - { - SCOPED_TRACE("1st schedule"); - user_file_event_->activate(event_rw); - - user_file_event_->activate(event_rw); - EXPECT_CALL(ready_cb_, called(event_rw)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - - { - SCOPED_TRACE("further dispatcher drive"); - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } -} - -TEST_F(UserSpaceFileEventImplTest, DefaultReturnAllEnabledReadAndWriteEvents) { - for (const auto current_event : {Event::FileReadyType::Read, Event::FileReadyType::Write, - Event::FileReadyType::Read | Event::FileReadyType::Write}) { - SCOPED_TRACE(absl::StrCat("current event:", current_event)); - EXPECT_CALL(io_source_, isReadable()) - .WillOnce(Return((current_event & Event::FileReadyType::Read) != 0)) - .RetiresOnSaturation(); - EXPECT_CALL(io_source_, isPeerWritable()) - .WillOnce(Return((current_event & Event::FileReadyType::Write) != 0)) - .RetiresOnSaturation(); - auto user_file_event = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - EXPECT_CALL(ready_cb_, called(current_event)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } -} - -TEST_F(UserSpaceFileEventImplTest, ActivateWillSchedule) { - // IO is neither readable nor writable. - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - { - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - user_file_event_->activate(Event::FileReadyType::Read); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - user_file_event_->activate(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } -} - -TEST_F(UserSpaceFileEventImplTest, ActivateDedup) { - // IO is neither readable nor writable. - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - { - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - user_file_event_->activate(Event::FileReadyType::Read); - user_file_event_->activate(Event::FileReadyType::Write); - user_file_event_->activate(Event::FileReadyType::Write); - user_file_event_->activate(Event::FileReadyType::Read); - EXPECT_CALL(ready_cb_, called(event_rw)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } -} - -TEST_F(UserSpaceFileEventImplTest, EnabledClearActivate) { - // IO is neither readable nor writable. - - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, event_rw, io_source_); - { - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - - // Ensure both events are pending so that any enabled event will be immediately delivered. - setWritable(); - setReadable(); - setWriteEnd(); - // The enabled event are delivered but not the other. - { - user_file_event_->activate(Event::FileReadyType::Read); - user_file_event_->setEnabled(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Write)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - user_file_event_->activate(Event::FileReadyType::Write); - user_file_event_->setEnabled(Event::FileReadyType::Read); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - // No event is delivered since it's either user disabled or io_handle doesn't provide pending - // data. - { - clearEventExpectation(); - setReadable(); - user_file_event_->activate(Event::FileReadyType::Read); - user_file_event_->setEnabled(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - clearEventExpectation(); - setWritable(); - user_file_event_->activate(Event::FileReadyType::Write); - user_file_event_->setEnabled(Event::FileReadyType::Read); - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } -} - -TEST_F(UserSpaceFileEventImplTest, PollTriggeredOnlyEnabledEvents) { - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, - Event::FileReadyType::Read | Event::FileReadyType::Closed, io_source_); - { - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - // All 3 ready types are polled. However, only enabled events are triggered. - { - user_file_event_->poll(Event::FileReadyType::Read | Event::FileReadyType::Write | - Event::FileReadyType::Closed); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read | Event::FileReadyType::Closed)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - - // Below events contains Read but not Closed. The callback sees Read. - { - user_file_event_->poll(Event::FileReadyType::Read); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - user_file_event_->poll(Event::FileReadyType::Read | Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Read)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - // Below ready types has no overlap with enabled. No callback is triggered. - { - user_file_event_->poll(Event::FileReadyType::Write); - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - user_file_event_->poll(0); - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } -} - -TEST_F(UserSpaceFileEventImplTest, EventClosedIsTriggeredBySetWriteEnd) { - setWriteEnd(); - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, - Event::FileReadyType::Write | Event::FileReadyType::Closed, io_source_); - - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); -} - -TEST_F(UserSpaceFileEventImplTest, EventClosedIsTriggeredByManullyActivate) { - user_file_event_ = std::make_unique( - *dispatcher_, [this](uint32_t arg) { ready_cb_.called(arg); }, - Event::FileReadyType::Write | Event::FileReadyType::Closed, io_source_); - { - // No Closed event bit if enabled by not activated. - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - user_file_event_->activate(Event::FileReadyType::Closed); - // Activate could deliver Closed event bit. - EXPECT_CALL(ready_cb_, called(Event::FileReadyType::Closed)); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } - { - EXPECT_CALL(ready_cb_, called(_)).Times(0); - dispatcher_->run(Event::Dispatcher::RunType::NonBlock); - } -} -} // namespace -} // namespace BufferedIoSocket -} // namespace IoSocket -} // namespace Extensions -} // namespace Envoy \ No newline at end of file diff --git a/test/extensions/io_socket/user_space/BUILD b/test/extensions/io_socket/user_space/BUILD index 3111862fe0107..829d9bacf9f14 100644 --- a/test/extensions/io_socket/user_space/BUILD +++ b/test/extensions/io_socket/user_space/BUILD @@ -27,3 +27,28 @@ envoy_extension_cc_test( "//test/test_common:utility_lib", ], ) + +envoy_extension_cc_test( + name = "io_socket_handle_impl_test", + srcs = ["io_socket_handle_impl_test.cc"], + extension_name = "envoy.io_socket.user_space", + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/extensions/io_socket/user_space:io_socket_handle_lib", + "//test/mocks/event:event_mocks", + ], +) + +envoy_extension_cc_test( + name = "io_socket_handle_impl_platform_test", + srcs = ["io_socket_handle_impl_platform_test.cc"], + extension_name = "envoy.io_socket.user_space", + tags = ["fails_on_windows"], + deps = [ + "//source/common/common:utility_lib", + "//source/common/network:address_lib", + "//source/extensions/io_socket/user_space:io_socket_handle_lib", + "//test/mocks/event:event_mocks", + ], +) diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc b/test/extensions/io_socket/user_space/io_socket_handle_impl_platform_test.cc similarity index 71% rename from test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc rename to test/extensions/io_socket/user_space/io_socket_handle_impl_platform_test.cc index 051151d99e073..e5b1b808bfbbf 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_platform_test.cc +++ b/test/extensions/io_socket/user_space/io_socket_handle_impl_platform_test.cc @@ -1,7 +1,7 @@ #include "envoy/common/platform.h" #include "envoy/event/file_event.h" -#include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" +#include "extensions/io_socket/user_space/io_socket_handle_impl.h" #include "test/mocks/event/mocks.h" @@ -11,7 +11,7 @@ namespace Envoy { namespace Extensions { namespace IoSocket { -namespace BufferedIoSocket { +namespace UserSpace { namespace { using testing::NiceMock; @@ -25,10 +25,10 @@ class MockFileEventCallback { class BufferedIoSocketHandlePlatformTest : public testing::Test { public: BufferedIoSocketHandlePlatformTest() { - first_io_handle_ = std::make_unique(); - second_io_handle_ = std::make_unique(); - first_io_handle_->setWritablePeer(second_io_handle_.get()); - second_io_handle_->setWritablePeer(first_io_handle_.get()); + first_io_handle_ = std::make_unique(); + second_io_handle_ = std::make_unique(); + first_io_handle_->setPeerHandle(second_io_handle_.get()); + second_io_handle_->setPeerHandle(first_io_handle_.get()); } ~BufferedIoSocketHandlePlatformTest() override { @@ -40,8 +40,8 @@ class BufferedIoSocketHandlePlatformTest : public testing::Test { } } - std::unique_ptr first_io_handle_; - std::unique_ptr second_io_handle_; + std::unique_ptr first_io_handle_; + std::unique_ptr second_io_handle_; NiceMock dispatcher_; MockFileEventCallback cb_; }; @@ -57,7 +57,7 @@ TEST_F(BufferedIoSocketHandlePlatformTest, CreatePlatformDefaultTriggerTypeFailO } } // namespace -} // namespace BufferedIoSocket +} // namespace UserSpace } // namespace IoSocket } // namespace Extensions } // namespace Envoy diff --git a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc b/test/extensions/io_socket/user_space/io_socket_handle_impl_test.cc similarity index 96% rename from test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc rename to test/extensions/io_socket/user_space/io_socket_handle_impl_test.cc index 8eeaa236fe340..12b022759421c 100644 --- a/test/extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/user_space/io_socket_handle_impl_test.cc @@ -5,7 +5,7 @@ #include "common/common/fancy_logger.h" #include "common/network/address_impl.h" -#include "extensions/io_socket/buffered_io_socket/buffered_io_socket_handle_impl.h" +#include "extensions/io_socket/user_space/io_socket_handle_impl.h" #include "test/mocks/event/mocks.h" @@ -18,7 +18,7 @@ using testing::NiceMock; namespace Envoy { namespace Extensions { namespace IoSocket { -namespace BufferedIoSocket { +namespace UserSpace { namespace { MATCHER(IsInvalidAddress, "") { @@ -43,15 +43,15 @@ class MockFileEventCallback { class BufferedIoSocketHandleTest : public testing::Test { public: BufferedIoSocketHandleTest() : buf_(1024) { - io_handle_ = std::make_unique(); - io_handle_peer_ = std::make_unique(); - io_handle_->setWritablePeer(io_handle_peer_.get()); - io_handle_peer_->setWritablePeer(io_handle_.get()); + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setPeerHandle(io_handle_peer_.get()); + io_handle_peer_->setPeerHandle(io_handle_.get()); } ~BufferedIoSocketHandleTest() override = default; - Buffer::WatermarkBuffer& getWatermarkBufferHelper(BufferedIoSocketHandleImpl& io_handle) { + Buffer::WatermarkBuffer& getWatermarkBufferHelper(IoSocketHandleImpl& io_handle) { return dynamic_cast(*io_handle.getWriteBuffer()); } @@ -60,8 +60,8 @@ class BufferedIoSocketHandleTest : public testing::Test { // Owned by BufferedIoSocketHandle. NiceMock* schedulable_cb_; MockFileEventCallback cb_; - std::unique_ptr io_handle_; - std::unique_ptr io_handle_peer_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; absl::FixedArray buf_; }; @@ -186,8 +186,8 @@ TEST_F(BufferedIoSocketHandleTest, BasicReadv) { io_handle_peer_->write(buf_to_write); Buffer::OwnedImpl buf; - buf.reserveSingleSlice(1024); - auto slice = buf.frontSlice(); + auto reservation = buf.reserveSingleSlice(1024); + auto slice = reservation.slice(); auto result = io_handle_->readv(1024, &slice, 1); EXPECT_TRUE(result.ok()); @@ -738,8 +738,8 @@ TEST_F(BufferedIoSocketHandleTest, WriteScheduleWritableEvent) { [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { Buffer::OwnedImpl buf; - buf.reserveSingleSlice(1024); - auto slice = buf.frontSlice(); + auto reservation = buf.reserveSingleSlice(1024); + auto slice = reservation.slice(); auto result = handle->readv(1024, &slice, 1); if (result.ok()) { accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); @@ -778,8 +778,8 @@ TEST_F(BufferedIoSocketHandleTest, WritevScheduleWritableEvent) { [&should_close, handle = io_handle_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { Buffer::OwnedImpl buf; - buf.reserveSingleSlice(1024); - auto slice = buf.frontSlice(); + auto reservation = buf.reserveSingleSlice(1024); + auto slice = reservation.slice(); auto result = handle->readv(1024, &slice, 1); if (result.ok()) { accumulator += absl::string_view(static_cast(slice.mem_), result.rc_); @@ -819,8 +819,8 @@ TEST_F(BufferedIoSocketHandleTest, ReadAfterShutdownWrite) { [&should_close, handle = io_handle_peer_.get(), &accumulator](uint32_t events) { if (events & Event::FileReadyType::Read) { Buffer::OwnedImpl buf; - buf.reserveSingleSlice(1024); - auto slice = buf.frontSlice(); + auto reservation = buf.reserveSingleSlice(1024); + auto slice = reservation.slice(); auto result = handle->readv(1024, &slice, 1); if (result.ok()) { if (result.rc_ == 0) { @@ -947,10 +947,10 @@ TEST_F(BufferedIoSocketHandleTest, LastRoundtripTimeNullOpt) { class BufferedIoSocketHandleNotImplementedTest : public testing::Test { public: BufferedIoSocketHandleNotImplementedTest() { - io_handle_ = std::make_unique(); - io_handle_peer_ = std::make_unique(); - io_handle_->setWritablePeer(io_handle_peer_.get()); - io_handle_peer_->setWritablePeer(io_handle_.get()); + io_handle_ = std::make_unique(); + io_handle_peer_ = std::make_unique(); + io_handle_->setPeerHandle(io_handle_peer_.get()); + io_handle_peer_->setPeerHandle(io_handle_.get()); } ~BufferedIoSocketHandleNotImplementedTest() override { @@ -962,8 +962,8 @@ class BufferedIoSocketHandleNotImplementedTest : public testing::Test { } } - std::unique_ptr io_handle_; - std::unique_ptr io_handle_peer_; + std::unique_ptr io_handle_; + std::unique_ptr io_handle_peer_; Buffer::RawSlice slice_; }; @@ -1013,7 +1013,7 @@ TEST_F(BufferedIoSocketHandleNotImplementedTest, ErrorOnGetOption) { EXPECT_THAT(io_handle_->getOption(0, 0, nullptr, nullptr), IsNotSupportedResult()); } } // namespace -} // namespace BufferedIoSocket +} // namespace UserSpace } // namespace IoSocket } // namespace Extensions } // namespace Envoy From 8087b0ded5bb81f646186ae76e62dcec57a0a19a Mon Sep 17 00:00:00 2001 From: Yuchen Dai Date: Tue, 2 Feb 2021 10:27:16 -0800 Subject: [PATCH 88/88] cover read(buf, 0) Signed-off-by: Yuchen Dai --- .../io_socket/user_space/io_socket_handle_impl_test.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/extensions/io_socket/user_space/io_socket_handle_impl_test.cc b/test/extensions/io_socket/user_space/io_socket_handle_impl_test.cc index 12b022759421c..093f12b10c5ce 100644 --- a/test/extensions/io_socket/user_space/io_socket_handle_impl_test.cc +++ b/test/extensions/io_socket/user_space/io_socket_handle_impl_test.cc @@ -163,6 +163,15 @@ TEST_F(BufferedIoSocketHandleTest, ReadEmpty) { EXPECT_EQ(0, result.rc_); } +// Read allows max_length value 0 and returns no error. +TEST_F(BufferedIoSocketHandleTest, ReadWhileProvidingNoCapacity) { + Buffer::OwnedImpl buf; + absl::optional max_length_opt{0}; + auto result = io_handle_->read(buf, max_length_opt); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(0, result.rc_); +} + // Test read side effects. TEST_F(BufferedIoSocketHandleTest, ReadContent) { Buffer::OwnedImpl buf;