diff --git a/LICENSE.txt b/LICENSE.txt index df5f5cce783..9b9954e228a 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -221,37 +221,6 @@ limitations under the License. -------------------------------------------------------------------------------- -src/plasma/thirdparty/ae: Modified / 3-Clause BSD - -Copyright (c) 2006-2010, Salvatore Sanfilippo -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of Redis nor the names of its contributors may be used - to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - --------------------------------------------------------------------------------- - src/plasma/thirdparty/dlmalloc.c: CC0 This is a version (aka dlmalloc) of malloc/free/realloc written by @@ -378,7 +347,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- -This project includes code from the Boost project +This project includes code from the Boost project and independent Asio headers Boost Software License - Version 1.0 - August 17th, 2003 diff --git a/cpp/apidoc/tutorials/plasma.md b/cpp/apidoc/tutorials/plasma.md index 40c5a10603e..21ce303f490 100644 --- a/cpp/apidoc/tutorials/plasma.md +++ b/cpp/apidoc/tutorials/plasma.md @@ -384,16 +384,14 @@ sealed in the object store. This may especially be handy when your program is collaborating with other Plasma clients, and needs to know when they make objects available. -First, you can subscribe your current Plasma client to such notifications -by getting a file descriptor: +First, you can subscribe your current Plasma client to such notifications: ```cpp // Start receiving notifications into file_descriptor. -int fd; -ARROW_CHECK_OK(client.Subscribe(&fd)); +ARROW_CHECK_OK(client.Subscribe()); ``` -Once you have the file descriptor, you can have your current Plasma client +Once you have subscribed, you can have your current Plasma client wait to receive the next object notification. Object notifications include information such as Object ID, data size, and metadata size of the next newly available object: @@ -404,7 +402,7 @@ the next newly available object: ObjectID object_id; int64_t data_size; int64_t metadata_size; -ARROW_CHECK_OK(client.GetNotification(fd, &object_id, &data_size, &metadata_size)); +ARROW_CHECK_OK(client.GetNotification(&object_id, &data_size, &metadata_size)); // Get the newly available object. ObjectBuffer object_buffer; @@ -423,14 +421,13 @@ int main(int argc, char** argv) { PlasmaClient client; ARROW_CHECK_OK(client.Connect("/tmp/plasma")); - int fd; - ARROW_CHECK_OK(client.Subscribe(&fd)); + ARROW_CHECK_OK(client.Subscribe()); ObjectID object_id; int64_t data_size; int64_t metadata_size; while (true) { - ARROW_CHECK_OK(client.GetNotification(fd, &object_id, &data_size, &metadata_size)); + ARROW_CHECK_OK(client.GetNotification(&object_id, &data_size, &metadata_size)); std::cout << "Received object notification for object_id = " << object_id.hex() << ", with data_size = " << data_size diff --git a/cpp/src/plasma/CMakeLists.txt b/cpp/src/plasma/CMakeLists.txt index 4687ce9e65c..48356184784 100644 --- a/cpp/src/plasma/CMakeLists.txt +++ b/cpp/src/plasma/CMakeLists.txt @@ -65,22 +65,29 @@ add_custom_command( set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") +# Set compiling options for asio headers. +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-conversion -Wno-documentation") + +set(PLASMA_IO_SRCS + fling.cc + io/basic_connection.cc + io/connection.cc + protocol.cc) + set(PLASMA_SRCS client.cc common.cc - fling.cc - io.cc malloc.cc plasma.cc - protocol.cc) + protocol.cc + ${PLASMA_IO_SRCS}) set(PLASMA_STORE_SRCS dlmalloc.cc - events.cc eviction_policy.cc plasma_allocator.cc - store.cc - thirdparty/ae/ae.c) + ${PLASMA_IO_SRCS} + store.cc) set(PLASMA_LINK_LIBS arrow_shared) set(PLASMA_STATIC_LINK_LIBS arrow_static) @@ -141,12 +148,14 @@ list(APPEND PLASMA_EXTERNAL_STORE_SOURCES "external_store.cc" "hash_table_store. # We use static libraries for the plasma_store_server executable so that it can # be copied around and used in different locations. add_executable(plasma_store_server ${PLASMA_EXTERNAL_STORE_SOURCES} ${PLASMA_STORE_SRCS}) + if(ARROW_BUILD_STATIC) target_link_libraries(plasma_store_server plasma_static ${PLASMA_STATIC_LINK_LIBS}) else() # Fallback to shared libs in the case that static libraries are not build. target_link_libraries(plasma_store_server plasma_shared ${PLASMA_LINK_LIBS}) endif() + add_dependencies(plasma plasma_store_server) if(ARROW_RPATH_ORIGIN) @@ -174,11 +183,7 @@ elseif(APPLE) endif() endif() -install(FILES common.h - compat.h - client.h - events.h - test-util.h +install(FILES common.h compat.h client.h test-util.h DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/plasma") # Plasma store diff --git a/cpp/src/plasma/client.cc b/cpp/src/plasma/client.cc index a6cdf7f17ca..6015583d4dd 100644 --- a/cpp/src/plasma/client.cc +++ b/cpp/src/plasma/client.cc @@ -23,34 +23,22 @@ #include #endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include // PROT_READ, PROT_WRITE, MAP_SHARED, MAP_FAILED #include #include #include #include #include +#include #include #include "arrow/buffer.h" +#include "arrow/util/logging.h" #include "arrow/util/thread-pool.h" #include "plasma/common.h" -#include "plasma/fling.h" -#include "plasma/io.h" #include "plasma/malloc.h" -#include "plasma/plasma.h" #include "plasma/protocol.h" #ifdef PLASMA_CUDA @@ -68,12 +56,11 @@ using arrow::cuda::CudaDeviceManager; #define XXH64_DEFAULT_SEED 0 -namespace fb = plasma::flatbuf; - namespace plasma { -using fb::MessageType; -using fb::PlasmaError; +using flatbuf::MessageType; +using flatbuf::PlasmaError; +using io::ServerConnection; using arrow::MutableBuffer; @@ -196,6 +183,11 @@ class ClientMmapTableEntry { ARROW_DISALLOW_COPY_AND_ASSIGN(ClientMmapTableEntry); }; +Status PlasmaReceive(const std::shared_ptr& client, + MessageType message_type, std::vector* buffer) { + return client->ReadMessage(static_cast(message_type), buffer); +} + class PlasmaClient::Impl : public std::enable_shared_from_this { public: Impl(); @@ -203,9 +195,7 @@ class PlasmaClient::Impl : public std::enable_shared_from_this* data, int device_num = 0); @@ -235,13 +225,16 @@ class PlasmaClient::Impl : public std::enable_shared_from_thisGetNativeHandle(); + } Status Disconnect(); @@ -255,8 +248,9 @@ class PlasmaClient::Impl : public std::enable_shared_from_this store_conn_; + std::shared_ptr notification_conn_; + /// The name of the socket we are connecting to. + std::string store_socket_name_; /// Table of dlmalloc buffer files that have been memory mapped so far. This /// is a hash table mapping a file descriptor to a struct containing the /// address of the corresponding memory-mapped file. @@ -349,15 +348,14 @@ bool PlasmaClient::Impl::IsInUse(const ObjectID& object_id) { return (elem != objects_in_use_.end()); } -int PlasmaClient::Impl::GetStoreFd(int store_fd) { +Status PlasmaClient::Impl::GetStoreFd(int store_fd, int* fd) { auto entry = mmap_table_.find(store_fd); if (entry == mmap_table_.end()) { - int fd = recv_fd(store_conn_); - ARROW_CHECK(fd >= 0) << "recv not successful"; - return fd; + RETURN_NOT_OK(store_conn_->RecvFd(fd)); } else { - return entry->second->fd(); + *fd = entry->second->fd(); } + return Status::OK(); } void PlasmaClient::Impl::IncrementObjectCount(const ObjectID& object_id, @@ -405,7 +403,8 @@ Status PlasmaClient::Impl::Create(const ObjectID& object_id, int64_t data_size, // If the CreateReply included an error, then the store will not send a file // descriptor. if (device_num == 0) { - int fd = GetStoreFd(store_fd); + int fd; + RETURN_NOT_OK(GetStoreFd(store_fd, &fd)); ARROW_CHECK(object.data_size == data_size); ARROW_CHECK(object.metadata_size == metadata_size); // The metadata should come right after the data. @@ -495,8 +494,10 @@ Status PlasmaClient::Impl::GetBuffers( // This client created the object but hasn't sealed it. If we call Get // with no timeout, we will deadlock, because this client won't be able to // call Seal. - ARROW_CHECK(timeout_ms != -1) - << "Plasma client called get on an unsealed object that it created"; + if (timeout_ms == -1) { + return Status::Invalid( + "Plasma client called get on an unsealed object that it created"); + } ARROW_LOG(WARNING) << "Attempting to get an object that this client created but hasn't sealed."; all_present = false; @@ -551,7 +552,8 @@ Status PlasmaClient::Impl::GetBuffers( // in the subsequent loop based on just the store file descriptor and without // having to know the relevant file descriptor received from recv_fd. for (size_t i = 0; i < store_fds.size(); i++) { - int fd = GetStoreFd(store_fds[i]); + int fd; + RETURN_NOT_OK(GetStoreFd(store_fds[i], &fd)); LookupOrMmap(fd, store_fds[i], mmap_sizes[i]); } @@ -653,7 +655,12 @@ Status PlasmaClient::Impl::Release(const ObjectID& object_id) { return Status::OK(); } auto object_entry = objects_in_use_.find(object_id); - ARROW_CHECK(object_entry != objects_in_use_.end()); + if (object_entry == objects_in_use_.end()) { + return Status::Invalid("Trying to release a non-existing object."); + } + auto& entry = *object_entry->second; + entry.count -= 1; + ARROW_CHECK(entry.count >= 0) << "Got negative ref count."; #ifdef PLASMA_CUDA if (object_entry->second->object.device_num != 0) { @@ -667,10 +674,8 @@ Status PlasmaClient::Impl::Release(const ObjectID& object_id) { } #endif - object_entry->second->count -= 1; - ARROW_CHECK(object_entry->second->count >= 0); // Check if the client is no longer using this object. - if (object_entry->second->count == 0) { + if (entry.count == 0) { // Tell the store that the client no longer needs the object. RETURN_NOT_OK(MarkObjectUnused(object_id)); RETURN_NOT_OK(SendReleaseRequest(store_conn_, object_id)); @@ -815,15 +820,21 @@ Status PlasmaClient::Impl::Seal(const ObjectID& object_id) { Status PlasmaClient::Impl::Abort(const ObjectID& object_id) { std::lock_guard guard(client_mutex_); auto object_entry = objects_in_use_.find(object_id); - ARROW_CHECK(object_entry != objects_in_use_.end()) - << "Plasma client called abort on an object without a reference to it"; - ARROW_CHECK(!object_entry->second->is_sealed) - << "Plasma client called abort on a sealed object"; + if (object_entry == objects_in_use_.end()) { + return Status::Invalid( + "Plasma client called abort on an object without a reference to it"); + } + + auto& entry = *object_entry->second; + + if (entry.is_sealed) { + return Status::Invalid("Plasma client called abort on a sealed object"); + } // Make sure that the Plasma client only has one reference to the object. If // it has more, then the client needs to release the buffer before calling // abort. - if (object_entry->second->count > 1) { + if (entry.count > 1) { return Status::Invalid("Plasma client cannot have a reference to the buffer."); } @@ -841,13 +852,12 @@ Status PlasmaClient::Impl::Abort(const ObjectID& object_id) { // Send the abort request. RETURN_NOT_OK(SendAbortRequest(store_conn_, object_id)); // Decrease the reference count to zero, then remove the object. - object_entry->second->count--; + entry.count--; RETURN_NOT_OK(MarkObjectUnused(object_id)); std::vector buffer; ObjectID id; - MessageType type; - RETURN_NOT_OK(ReadMessage(store_conn_, &type, &buffer)); + RETURN_NOT_OK(PlasmaReceive(store_conn_, MessageType::PlasmaAbortReply, &buffer)); return ReadAbortReply(buffer.data(), buffer.size(), &id); } @@ -883,8 +893,7 @@ Status PlasmaClient::Impl::Evict(int64_t num_bytes, int64_t& num_bytes_evicted) RETURN_NOT_OK(SendEvictRequest(store_conn_, num_bytes)); // Wait for a response with the number of bytes actually evicted. std::vector buffer; - MessageType type; - RETURN_NOT_OK(ReadMessage(store_conn_, &type, &buffer)); + RETURN_NOT_OK(PlasmaReceive(store_conn_, MessageType::PlasmaEvictReply, &buffer)); return ReadEvictReply(buffer.data(), buffer.size(), num_bytes_evicted); } @@ -905,35 +914,30 @@ Status PlasmaClient::Impl::Hash(const ObjectID& object_id, uint8_t* digest) { return Status::OK(); } -Status PlasmaClient::Impl::Subscribe(int* fd) { - std::lock_guard guard(client_mutex_); - - int sock[2]; - // Create a non-blocking socket pair. This will only be used to send - // notifications from the Plasma store to the client. - socketpair(AF_UNIX, SOCK_STREAM, 0, sock); - // Make the socket non-blocking. - int flags = fcntl(sock[1], F_GETFL, 0); - ARROW_CHECK(fcntl(sock[1], F_SETFL, flags | O_NONBLOCK) == 0); +Status PlasmaClient::Impl::Subscribe() { + if (store_socket_name_.empty()) { + ARROW_LOG(FATAL) << "Please connect to the store before subscribing messages."; + } + io::PlasmaStream stream(io_context_); + RETURN_NOT_OK(io::CreateLocalStream(store_socket_name_, &stream)); + auto conn = ServerConnection::Create(std::move(stream)); + notification_conn_ = std::move(conn); // Tell the Plasma store about the subscription. - RETURN_NOT_OK(SendSubscribeRequest(store_conn_)); - // Send the file descriptor that the Plasma store should use to push - // notifications about sealed objects to this client. - ARROW_CHECK(send_fd(store_conn_, sock[1]) >= 0); - close(sock[1]); - // Return the file descriptor that the client should use to read notifications - // about sealed objects. - *fd = sock[0]; - return Status::OK(); + return SendSubscribeRequest(notification_conn_); } +// TODO(suquark): Move it to protocol.cc Status PlasmaClient::Impl::DecodeNotification(const uint8_t* buffer, ObjectID* object_id, int64_t* data_size, int64_t* metadata_size) { std::lock_guard guard(client_mutex_); - auto object_info = flatbuffers::GetRoot(buffer); - ARROW_CHECK(object_info->object_id()->size() == sizeof(ObjectID)); + auto object_info = flatbuffers::GetRoot(buffer); + if (object_info->object_id()->size() != sizeof(ObjectID)) { + return Status::Invalid( + "The size of ObjectID in the message is different from the size " + "of ObjectID in Plasma. The message could have been corrupt."); + } memcpy(object_id, object_info->object_id()->data(), sizeof(ObjectID)); if (object_info->is_deletion()) { *data_size = -1; @@ -945,30 +949,29 @@ Status PlasmaClient::Impl::DecodeNotification(const uint8_t* buffer, ObjectID* o return Status::OK(); } -Status PlasmaClient::Impl::GetNotification(int fd, ObjectID* object_id, - int64_t* data_size, int64_t* metadata_size) { +Status PlasmaClient::Impl::GetNotification(ObjectID* object_id, int64_t* data_size, + int64_t* metadata_size) { std::lock_guard guard(client_mutex_); - - auto notification = ReadMessageAsync(fd); - if (notification == NULL) { + std::unique_ptr notification; + if (!notification_conn_) { + ARROW_LOG(ERROR) << "Get notification without subscription."; + return Status::ExecutionError("Get notification without subscription."); + } + auto status = notification_conn_->ReadNotificationMessage(notification); + if (!status.ok()) { return Status::IOError("Failed to read object notification from Plasma socket"); } return DecodeNotification(notification.get(), object_id, data_size, metadata_size); } -Status PlasmaClient::Impl::Connect(const std::string& store_socket_name, - const std::string& manager_socket_name, - int release_delay, int num_retries) { +Status PlasmaClient::Impl::Connect(const std::string& store_socket_name) { std::lock_guard guard(client_mutex_); + store_socket_name_ = store_socket_name; + io::PlasmaStream stream(io_context_); + RETURN_NOT_OK(io::CreateLocalStream(store_socket_name_, &stream)); + auto conn = ServerConnection::Create(std::move(stream)); + store_conn_ = std::move(conn); - RETURN_NOT_OK(ConnectIpcSocketRetry(store_socket_name, num_retries, -1, &store_conn_)); - if (manager_socket_name != "") { - return Status::NotImplemented("plasma manager is no longer supported"); - } - if (release_delay != 0) { - ARROW_LOG(WARNING) << "The release_delay parameter in PlasmaClient::Connect " - << "is deprecated"; - } // Send a ConnectRequest to the store to get its memory capacity. RETURN_NOT_OK(SendConnectRequest(store_conn_)); std::vector buffer; @@ -986,9 +989,14 @@ Status PlasmaClient::Impl::Disconnect() { // Close the connections to Plasma. The Plasma store will release the objects // that were in use by us when handling the SIGPIPE. - close(store_conn_); - store_conn_ = -1; - return Status::OK(); + if (notification_conn_) { + auto status = notification_conn_->Disconnect(); + if (!status.ok()) { + ARROW_LOG(ERROR) << "Failed to disconnect notification client " + << "(" << status << ")"; + } + } + return store_conn_->Disconnect(); } // ---------------------------------------------------------------------- @@ -1001,8 +1009,19 @@ PlasmaClient::~PlasmaClient() {} Status PlasmaClient::Connect(const std::string& store_socket_name, const std::string& manager_socket_name, int release_delay, int num_retries) { - return impl_->Connect(store_socket_name, manager_socket_name, release_delay, - num_retries); + // Keep "manager_socket_name" & "release_delay" for compatibility. + if (manager_socket_name != "") { + return Status::NotImplemented("plasma manager is no longer supported"); + } + if (release_delay != 0) { + ARROW_LOG(WARNING) << "The release_delay parameter in PlasmaClient::Connect " + << "is deprecated"; + } + if (num_retries != -1) { + ARROW_LOG(WARNING) << "The num_retries parameter in PlasmaClient::Connect " + << "is deprecated"; + } + return impl_->Connect(store_socket_name); } Status PlasmaClient::Create(const ObjectID& object_id, int64_t data_size, @@ -1056,11 +1075,11 @@ Status PlasmaClient::Hash(const ObjectID& object_id, uint8_t* digest) { return impl_->Hash(object_id, digest); } -Status PlasmaClient::Subscribe(int* fd) { return impl_->Subscribe(fd); } +Status PlasmaClient::Subscribe() { return impl_->Subscribe(); } -Status PlasmaClient::GetNotification(int fd, ObjectID* object_id, int64_t* data_size, +Status PlasmaClient::GetNotification(ObjectID* object_id, int64_t* data_size, int64_t* metadata_size) { - return impl_->GetNotification(fd, object_id, data_size, metadata_size); + return impl_->GetNotification(object_id, data_size, metadata_size); } Status PlasmaClient::DecodeNotification(const uint8_t* buffer, ObjectID* object_id, @@ -1068,6 +1087,10 @@ Status PlasmaClient::DecodeNotification(const uint8_t* buffer, ObjectID* object_ return impl_->DecodeNotification(buffer, object_id, data_size, metadata_size); } +int PlasmaClient::GetNativeNotificationHandle() { + return impl_->GetNativeNotificationHandle(); +} + Status PlasmaClient::Disconnect() { return impl_->Disconnect(); } bool PlasmaClient::IsInUse(const ObjectID& object_id) { diff --git a/cpp/src/plasma/client.h b/cpp/src/plasma/client.h index facfd37ca78..f35ada95b6c 100644 --- a/cpp/src/plasma/client.h +++ b/cpp/src/plasma/client.h @@ -59,7 +59,8 @@ class ARROW_EXPORT PlasmaClient { /// Note that plasma manager is no longer supported, this function /// will return failure if this is not "". /// \param release_delay Deprecated (not used). - /// \param num_retries number of attempts to connect to IPC socket, default 50 + /// \param num_retries number of attempts to connect to IPC socket, + /// default 50. Deprecated (not used). /// \return The return status. Status Connect(const std::string& store_socket_name, const std::string& manager_socket_name = "", int release_delay = 0, @@ -225,21 +226,19 @@ class ARROW_EXPORT PlasmaClient { /// Whenever an object is sealed, a message will be written to the client /// socket that is returned by this method. /// - /// \param fd Out parameter for the file descriptor the client should use to - /// read notifications - /// from the object store about sealed objects. /// \return The return status. - Status Subscribe(int* fd); + Status Subscribe(); + + /// Return the native handle of the notification client. + int GetNativeNotificationHandle(); /// Receive next object notification for this client if Subscribe has been called. /// - /// \param fd The file descriptor we are reading the notification from. /// \param object_id Out parameter, the object_id of the object that was sealed. /// \param data_size Out parameter, the data size of the object that was sealed. /// \param metadata_size Out parameter, the metadata size of the object that was sealed. /// \return The return status. - Status GetNotification(int fd, ObjectID* object_id, int64_t* data_size, - int64_t* metadata_size); + Status GetNotification(ObjectID* object_id, int64_t* data_size, int64_t* metadata_size); Status DecodeNotification(const uint8_t* buffer, ObjectID* object_id, int64_t* data_size, int64_t* metadata_size); diff --git a/cpp/src/plasma/common.cc b/cpp/src/plasma/common.cc index bbcd2c9c3f1..cc16eb94b78 100644 --- a/cpp/src/plasma/common.cc +++ b/cpp/src/plasma/common.cc @@ -22,9 +22,7 @@ #include "arrow/util/ubsan.h" -#include "plasma/plasma_generated.h" - -namespace fb = plasma::flatbuf; +#include "arrow/util/ubsan.h" namespace plasma { diff --git a/cpp/src/plasma/dlmalloc.cc b/cpp/src/plasma/dlmalloc.cc index 463e967e036..6acbf46e705 100644 --- a/cpp/src/plasma/dlmalloc.cc +++ b/cpp/src/plasma/dlmalloc.cc @@ -29,6 +29,8 @@ #include #include +#include "arrow/util/logging.h" + #include "plasma/common.h" #include "plasma/plasma.h" diff --git a/cpp/src/plasma/events.cc b/cpp/src/plasma/events.cc deleted file mode 100644 index 28ff1267545..00000000000 --- a/cpp/src/plasma/events.cc +++ /dev/null @@ -1,107 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#include "plasma/events.h" - -#include - -#include - -extern "C" { -#include "plasma/thirdparty/ae/ae.h" -} - -namespace plasma { - -// Verify that the constants defined in events.h are defined correctly. -static_assert(kEventLoopTimerDone == AE_NOMORE, "constant defined incorrectly"); -static_assert(kEventLoopOk == AE_OK, "constant defined incorrectly"); -static_assert(kEventLoopRead == AE_READABLE, "constant defined incorrectly"); -static_assert(kEventLoopWrite == AE_WRITABLE, "constant defined incorrectly"); - -void EventLoop::FileEventCallback(aeEventLoop* loop, int fd, void* context, int events) { - FileCallback* callback = reinterpret_cast(context); - (*callback)(events); -} - -int EventLoop::TimerEventCallback(aeEventLoop* loop, TimerID timer_id, void* context) { - TimerCallback* callback = reinterpret_cast(context); - return (*callback)(timer_id); -} - -constexpr int kInitialEventLoopSize = 1024; - -EventLoop::EventLoop() { loop_ = aeCreateEventLoop(kInitialEventLoopSize); } - -bool EventLoop::AddFileEvent(int fd, int events, const FileCallback& callback) { - if (file_callbacks_.find(fd) != file_callbacks_.end()) { - return false; - } - auto data = std::unique_ptr(new FileCallback(callback)); - void* context = reinterpret_cast(data.get()); - // Try to add the file descriptor. - int err = aeCreateFileEvent(loop_, fd, events, EventLoop::FileEventCallback, context); - // If it cannot be added, increase the size of the event loop. - if (err == AE_ERR && errno == ERANGE) { - err = aeResizeSetSize(loop_, 3 * aeGetSetSize(loop_) / 2); - if (err != AE_OK) { - return false; - } - err = aeCreateFileEvent(loop_, fd, events, EventLoop::FileEventCallback, context); - } - // In any case, test if there were errors. - if (err == AE_OK) { - file_callbacks_.emplace(fd, std::move(data)); - return true; - } - return false; -} - -void EventLoop::RemoveFileEvent(int fd) { - aeDeleteFileEvent(loop_, fd, AE_READABLE | AE_WRITABLE); - file_callbacks_.erase(fd); -} - -void EventLoop::Start() { aeMain(loop_); } - -void EventLoop::Stop() { aeStop(loop_); } - -void EventLoop::Shutdown() { - if (loop_ != nullptr) { - aeDeleteEventLoop(loop_); - loop_ = nullptr; - } -} - -EventLoop::~EventLoop() { Shutdown(); } - -int64_t EventLoop::AddTimer(int64_t timeout, const TimerCallback& callback) { - auto data = std::unique_ptr(new TimerCallback(callback)); - void* context = reinterpret_cast(data.get()); - int64_t timer_id = - aeCreateTimeEvent(loop_, timeout, EventLoop::TimerEventCallback, context, NULL); - timer_callbacks_.emplace(timer_id, std::move(data)); - return timer_id; -} - -int EventLoop::RemoveTimer(int64_t timer_id) { - int err = aeDeleteTimeEvent(loop_, timer_id); - timer_callbacks_.erase(timer_id); - return err; -} - -} // namespace plasma diff --git a/cpp/src/plasma/events.h b/cpp/src/plasma/events.h deleted file mode 100644 index 765be9c01fb..00000000000 --- a/cpp/src/plasma/events.h +++ /dev/null @@ -1,111 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#ifndef PLASMA_EVENTS -#define PLASMA_EVENTS - -#include -#include -#include - -struct aeEventLoop; - -namespace plasma { - -// The constants below are defined using hardcoded values taken from ae.h so -// that ae.h does not need to be included in this file. - -/// Constant specifying that the timer is done and it will be removed. -constexpr int kEventLoopTimerDone = -1; // AE_NOMORE - -/// A successful status. -constexpr int kEventLoopOk = 0; // AE_OK - -/// Read event on the file descriptor. -constexpr int kEventLoopRead = 1; // AE_READABLE - -/// Write event on the file descriptor. -constexpr int kEventLoopWrite = 2; // AE_WRITABLE - -typedef long long TimerID; // NOLINT - -class EventLoop { - public: - // Signature of the handler that will be called when there is a new event - // on the file descriptor that this handler has been registered for. - // - // The arguments are the event flags (read or write). - using FileCallback = std::function; - - // This handler will be called when a timer times out. The timer id is - // passed as an argument. The return is the number of milliseconds the timer - // shall be reset to or kEventLoopTimerDone if the timer shall not be - // triggered again. - using TimerCallback = std::function; - - EventLoop(); - - ~EventLoop(); - - /// Add a new file event handler to the event loop. - /// - /// \param fd The file descriptor we are listening to. - /// \param events The flags for events we are listening to (read or write). - /// \param callback The callback that will be called when the event happens. - /// \return Returns true if the event handler was added successfully. - bool AddFileEvent(int fd, int events, const FileCallback& callback); - - /// Remove a file event handler from the event loop. - /// - /// \param fd The file descriptor of the event handler. - void RemoveFileEvent(int fd); - - /// Register a handler that will be called after a time slice of - /// "timeout" milliseconds. - /// - /// \param timeout The timeout in milliseconds. - /// \param callback The callback for the timeout. - /// \return The ID of the newly created timer. - int64_t AddTimer(int64_t timeout, const TimerCallback& callback); - - /// Remove a timer handler from the event loop. - /// - /// \param timer_id The ID of the timer that is to be removed. - /// \return The ae.c error code. TODO(pcm): needs to be standardized - int RemoveTimer(int64_t timer_id); - - /// \brief Run the event loop. - void Start(); - - /// \brief Stop the event loop - void Stop(); - - void Shutdown(); - - private: - static void FileEventCallback(aeEventLoop* loop, int fd, void* context, int events); - - static int TimerEventCallback(aeEventLoop* loop, TimerID timer_id, void* context); - - aeEventLoop* loop_; - std::unordered_map> file_callbacks_; - std::unordered_map> timer_callbacks_; -}; - -} // namespace plasma - -#endif // PLASMA_EVENTS diff --git a/cpp/src/plasma/eviction_policy.cc b/cpp/src/plasma/eviction_policy.cc index da5df5a36dd..c4fe9c9fea7 100644 --- a/cpp/src/plasma/eviction_policy.cc +++ b/cpp/src/plasma/eviction_policy.cc @@ -16,6 +16,7 @@ // under the License. #include "plasma/eviction_policy.h" +#include "arrow/util/logging.h" #include "plasma/plasma_allocator.h" #include diff --git a/cpp/src/plasma/eviction_policy.h b/cpp/src/plasma/eviction_policy.h index 68342ae102f..2f04be7898d 100644 --- a/cpp/src/plasma/eviction_policy.h +++ b/cpp/src/plasma/eviction_policy.h @@ -60,7 +60,7 @@ class EvictionPolicy { public: /// Construct an eviction policy. /// - /// @param store_info Information about the Plasma store that is exposed + /// \param store_info Information about the Plasma store that is exposed /// to the eviction policy. explicit EvictionPolicy(PlasmaStoreInfo* store_info); @@ -69,7 +69,7 @@ class EvictionPolicy { /// store calls begin_object_access, we can remove the object from the LRU /// cache. /// - /// @param object_id The object ID of the object that was created. + /// \param object_id The object ID of the object that was created. void ObjectCreated(const ObjectID& object_id); /// This method will be called when the Plasma store needs more space, perhaps @@ -77,11 +77,11 @@ class EvictionPolicy { /// policy will assume that the objects chosen to be evicted will in fact be /// evicted from the Plasma store by the caller. /// - /// @param size The size in bytes of the new object, including both data and + /// \param size The size in bytes of the new object, including both data and /// metadata. - /// @param objects_to_evict The object IDs that were chosen for eviction will + /// \param objects_to_evict The object IDs that were chosen for eviction will /// be stored into this vector. - /// @return True if enough space can be freed and false otherwise. + /// \return True if enough space can be freed and false otherwise. bool RequireSpace(int64_t size, std::vector* objects_to_evict); /// This method will be called whenever an unused object in the Plasma store @@ -89,8 +89,8 @@ class EvictionPolicy { /// assume that the objects chosen to be evicted will in fact be evicted from /// the Plasma store by the caller. /// - /// @param object_id The ID of the object that is now being used. - /// @param objects_to_evict The object IDs that were chosen for eviction will + /// \param object_id The ID of the object that is now being used. + /// \param objects_to_evict The object IDs that were chosen for eviction will /// be stored into this vector. void BeginObjectAccess(const ObjectID& object_id, std::vector* objects_to_evict); @@ -100,8 +100,8 @@ class EvictionPolicy { /// eviction policy will assume that the objects chosen to be evicted will in /// fact be evicted from the Plasma store by the caller. /// - /// @param object_id The ID of the object that is no longer being used. - /// @param objects_to_evict The object IDs that were chosen for eviction will + /// \param object_id The ID of the object that is no longer being used. + /// \param objects_to_evict The object IDs that were chosen for eviction will /// be stored into this vector. void EndObjectAccess(const ObjectID& object_id, std::vector* objects_to_evict); @@ -113,16 +113,16 @@ class EvictionPolicy { /// @note This method is not part of the API. It is exposed in the header file /// only for testing. /// - /// @param num_bytes_required The number of bytes of space to try to free up. - /// @param objects_to_evict The object IDs that were chosen for eviction will + /// \param num_bytes_required The number of bytes of space to try to free up. + /// \param objects_to_evict The object IDs that were chosen for eviction will /// be stored into this vector. - /// @return The total number of bytes of space chosen to be evicted. + /// \return The total number of bytes of space chosen to be evicted. int64_t ChooseObjectsToEvict(int64_t num_bytes_required, std::vector* objects_to_evict); /// This method will be called when an object is going to be removed /// - /// @param object_id The ID of the object that is now being used. + /// \param object_id The ID of the object that is now being used. void RemoveObject(const ObjectID& object_id); private: diff --git a/cpp/src/plasma/fling.h b/cpp/src/plasma/fling.h index 78ac9d17f26..f05803db690 100644 --- a/cpp/src/plasma/fling.h +++ b/cpp/src/plasma/fling.h @@ -40,13 +40,13 @@ void init_msg(struct msghdr* msg, struct iovec* iov, char* buf, size_t buf_len); // Send a file descriptor over a unix domain socket. // -// @param conn Unix domain socket to send the file descriptor over. -// @param fd File descriptor to send over. -// @return Status code which is < 0 on failure. +// \param conn Unix domain socket to send the file descriptor over. +// \param fd File descriptor to send over. +// \return Status code which is < 0 on failure. int send_fd(int conn, int fd); // Receive a file descriptor over a unix domain socket. // -// @param conn Unix domain socket to receive the file descriptor from. -// @return File descriptor or a value < 0 on failure. +// \param conn Unix domain socket to receive the file descriptor from. +// \return File descriptor or a value < 0 on failure. int recv_fd(int conn); diff --git a/cpp/src/plasma/io.cc b/cpp/src/plasma/io.cc deleted file mode 100644 index ba5f2551919..00000000000 --- a/cpp/src/plasma/io.cc +++ /dev/null @@ -1,241 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#include "plasma/io.h" - -#include -#include -#include - -#include "arrow/status.h" -#include "arrow/util/logging.h" - -#include "plasma/common.h" -#include "plasma/plasma_generated.h" - -using arrow::Status; - -/// Number of times we try connecting to a socket. -constexpr int64_t kNumConnectAttempts = 20; -/// Time to wait between connection attempts to a socket. -constexpr int64_t kConnectTimeoutMs = 400; - -namespace plasma { - -using flatbuf::MessageType; - -Status WriteBytes(int fd, uint8_t* cursor, size_t length) { - ssize_t nbytes = 0; - size_t bytesleft = length; - size_t offset = 0; - while (bytesleft > 0) { - // While we haven't written the whole message, write to the file descriptor, - // advance the cursor, and decrease the amount left to write. - nbytes = write(fd, cursor + offset, bytesleft); - if (nbytes < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { - continue; - } - return Status::IOError(strerror(errno)); - } else if (nbytes == 0) { - return Status::IOError("Encountered unexpected EOF"); - } - ARROW_CHECK(nbytes > 0); - bytesleft -= nbytes; - offset += nbytes; - } - - return Status::OK(); -} - -Status WriteMessage(int fd, MessageType type, int64_t length, uint8_t* bytes) { - int64_t version = kPlasmaProtocolVersion; - RETURN_NOT_OK(WriteBytes(fd, reinterpret_cast(&version), sizeof(version))); - RETURN_NOT_OK(WriteBytes(fd, reinterpret_cast(&type), sizeof(type))); - RETURN_NOT_OK(WriteBytes(fd, reinterpret_cast(&length), sizeof(length))); - return WriteBytes(fd, bytes, length * sizeof(char)); -} - -Status ReadBytes(int fd, uint8_t* cursor, size_t length) { - ssize_t nbytes = 0; - // Termination condition: EOF or read 'length' bytes total. - size_t bytesleft = length; - size_t offset = 0; - while (bytesleft > 0) { - nbytes = read(fd, cursor + offset, bytesleft); - if (nbytes < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { - continue; - } - return Status::IOError(strerror(errno)); - } else if (0 == nbytes) { - return Status::IOError("Encountered unexpected EOF"); - } - ARROW_CHECK(nbytes > 0); - bytesleft -= nbytes; - offset += nbytes; - } - - return Status::OK(); -} - -Status ReadMessage(int fd, MessageType* type, std::vector* buffer) { - int64_t version; - RETURN_NOT_OK_ELSE(ReadBytes(fd, reinterpret_cast(&version), sizeof(version)), - *type = MessageType::PlasmaDisconnectClient); - ARROW_CHECK(version == kPlasmaProtocolVersion) << "version = " << version; - RETURN_NOT_OK_ELSE(ReadBytes(fd, reinterpret_cast(type), sizeof(*type)), - *type = MessageType::PlasmaDisconnectClient); - int64_t length_temp; - RETURN_NOT_OK_ELSE( - ReadBytes(fd, reinterpret_cast(&length_temp), sizeof(length_temp)), - *type = MessageType::PlasmaDisconnectClient); - // The length must be read as an int64_t, but it should be used as a size_t. - size_t length = static_cast(length_temp); - if (length > buffer->size()) { - buffer->resize(length); - } - RETURN_NOT_OK_ELSE(ReadBytes(fd, buffer->data(), length), - *type = MessageType::PlasmaDisconnectClient); - return Status::OK(); -} - -int BindIpcSock(const std::string& pathname, bool shall_listen) { - struct sockaddr_un socket_address; - int socket_fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (socket_fd < 0) { - ARROW_LOG(ERROR) << "socket() failed for pathname " << pathname; - return -1; - } - // Tell the system to allow the port to be reused. - int on = 1; - if (setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast(&on), - sizeof(on)) < 0) { - ARROW_LOG(ERROR) << "setsockopt failed for pathname " << pathname; - close(socket_fd); - return -1; - } - - unlink(pathname.c_str()); - memset(&socket_address, 0, sizeof(socket_address)); - socket_address.sun_family = AF_UNIX; - if (pathname.size() + 1 > sizeof(socket_address.sun_path)) { - ARROW_LOG(ERROR) << "Socket pathname is too long."; - close(socket_fd); - return -1; - } - strncpy(socket_address.sun_path, pathname.c_str(), pathname.size() + 1); - - if (bind(socket_fd, reinterpret_cast(&socket_address), - sizeof(socket_address)) != 0) { - ARROW_LOG(ERROR) << "Bind failed for pathname " << pathname; - close(socket_fd); - return -1; - } - if (shall_listen && listen(socket_fd, 128) == -1) { - ARROW_LOG(ERROR) << "Could not listen to socket " << pathname; - close(socket_fd); - return -1; - } - return socket_fd; -} - -Status ConnectIpcSocketRetry(const std::string& pathname, int num_retries, - int64_t timeout, int* fd) { - // Pick the default values if the user did not specify. - if (num_retries < 0) { - num_retries = kNumConnectAttempts; - } - if (timeout < 0) { - timeout = kConnectTimeoutMs; - } - *fd = ConnectIpcSock(pathname); - while (*fd < 0 && num_retries > 0) { - ARROW_LOG(ERROR) << "Connection to IPC socket failed for pathname " << pathname - << ", retrying " << num_retries << " more times"; - // Sleep for timeout milliseconds. - usleep(static_cast(timeout * 1000)); - *fd = ConnectIpcSock(pathname); - --num_retries; - } - - // If we could not connect to the socket, exit. - if (*fd == -1) { - return Status::IOError("Could not connect to socket ", pathname); - } - - return Status::OK(); -} - -int ConnectIpcSock(const std::string& pathname) { - struct sockaddr_un socket_address; - int socket_fd; - - socket_fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (socket_fd < 0) { - ARROW_LOG(ERROR) << "socket() failed for pathname " << pathname; - return -1; - } - - memset(&socket_address, 0, sizeof(socket_address)); - socket_address.sun_family = AF_UNIX; - if (pathname.size() + 1 > sizeof(socket_address.sun_path)) { - ARROW_LOG(ERROR) << "Socket pathname is too long."; - close(socket_fd); - return -1; - } - strncpy(socket_address.sun_path, pathname.c_str(), pathname.size() + 1); - - if (connect(socket_fd, reinterpret_cast(&socket_address), - sizeof(socket_address)) != 0) { - close(socket_fd); - return -1; - } - - return socket_fd; -} - -int AcceptClient(int socket_fd) { - int client_fd = accept(socket_fd, NULL, NULL); - if (client_fd < 0) { - ARROW_LOG(ERROR) << "Error reading from socket."; - return -1; - } - return client_fd; -} - -std::unique_ptr ReadMessageAsync(int sock) { - int64_t size; - Status s = ReadBytes(sock, reinterpret_cast(&size), sizeof(int64_t)); - if (!s.ok()) { - // The other side has closed the socket. - ARROW_LOG(DEBUG) << "Socket has been closed, or some other error has occurred."; - close(sock); - return NULL; - } - auto message = std::unique_ptr(new uint8_t[size]); - s = ReadBytes(sock, message.get(), size); - if (!s.ok()) { - // The other side has closed the socket. - ARROW_LOG(DEBUG) << "Socket has been closed, or some other error has occurred."; - close(sock); - return NULL; - } - return message; -} - -} // namespace plasma diff --git a/cpp/src/plasma/io.h b/cpp/src/plasma/io.h deleted file mode 100644 index 745518ab227..00000000000 --- a/cpp/src/plasma/io.h +++ /dev/null @@ -1,70 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#ifndef PLASMA_IO_H -#define PLASMA_IO_H - -#include -#include -#include -#include - -#include -#include -#include - -#include "arrow/status.h" -#include "plasma/compat.h" - -namespace plasma { - -namespace flatbuf { - -// Forward declaration outside the namespace, which is defined in plasma_generated.h. -enum class MessageType : int64_t; - -} // namespace flatbuf - -// TODO(pcm): Replace our own custom message header (message type, -// message length, plasma protocol verion) with one that is serialized -// using flatbuffers. -constexpr int64_t kPlasmaProtocolVersion = 0x0000000000000000; - -using arrow::Status; - -Status WriteBytes(int fd, uint8_t* cursor, size_t length); - -Status WriteMessage(int fd, flatbuf::MessageType type, int64_t length, uint8_t* bytes); - -Status ReadBytes(int fd, uint8_t* cursor, size_t length); - -Status ReadMessage(int fd, flatbuf::MessageType* type, std::vector* buffer); - -int BindIpcSock(const std::string& pathname, bool shall_listen); - -int ConnectIpcSock(const std::string& pathname); - -Status ConnectIpcSocketRetry(const std::string& pathname, int num_retries, - int64_t timeout, int* fd); - -int AcceptClient(int socket_fd); - -std::unique_ptr ReadMessageAsync(int sock); - -} // namespace plasma - -#endif // PLASMA_IO_H diff --git a/cpp/src/plasma/io/basic_connection.cc b/cpp/src/plasma/io/basic_connection.cc new file mode 100644 index 00000000000..7325855ac52 --- /dev/null +++ b/cpp/src/plasma/io/basic_connection.cc @@ -0,0 +1,256 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "plasma/io/basic_connection.h" +#include "arrow/util/logging.h" + +#include +#include +#include +#include + +namespace plasma { +namespace io { + +/// Connect a Unix local domain socket. +/// +/// \param socket The socket to connect. +/// \param socket_name The name/path of the socket. +/// \return Status. +error_code UnixDomainSocketConnect(asio::local::stream_protocol::socket& socket, + const std::string& socket_name) { + asio::local::stream_protocol::endpoint endpoint(socket_name); + error_code ec; + socket.connect(endpoint, ec); + if (ec) { + // Close the socket if the connect failed. + error_code close_error; + socket.close(close_error); + } + return ec; +} + +Status CreateLocalStream(const std::string& name, PlasmaStream* result) { + // TODO(suquark): May be use "kNumConnectAttempts" and "kConnectTimeoutMs"? + constexpr int num_retries = 50; + constexpr int timeout_ms = 100; + if (name.empty()) { + return Status::Invalid("Cannot connect to empty socket name"); + } +#ifndef _WIN32 + for (int i = 0; i < num_retries; i++) { + error_code ec = UnixDomainSocketConnect(*result, name); + if (!ec) { + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(timeout_ms)); + if (i > 0) { + ARROW_LOG(ERROR) << "Retrying to connect to socket for pathname " << name + << " (num_attempts = " << i << ", num_retries = " << num_retries + << ")"; + } + } + return Status::OK(); +#else +// For windows: https://stackoverflow.com/questions/1236460/c-using-windows-named-pipes +#error "Windows has not been supported." +#endif +} + +PlasmaAcceptor CreateLocalAcceptor(asio::io_context& io_context, + const std::string& name) { +#ifndef _WIN32 + return PlasmaAcceptor(io_context, asio::local::stream_protocol::endpoint(name)); +#else +// For windows: https://stackoverflow.com/questions/1236460/c-using-windows-named-pipes +#error "Windows has not been supported." +#endif +} + +template +Connection::Connection(T&& stream) + : stream_(std::move(stream)), + async_write_in_flight_(false), + async_write_max_messages_(1), + async_write_queue_() {} + +template +Connection::~Connection() { + // If there are any pending messages, invoke their callbacks with an IOError status. + for (const auto& write_buffer : async_write_queue_) { + write_buffer->Handle( + error_code(static_cast(boost::system::errc::io_error), boost::system::system_category())); + } +} + +template +error_code Connection::ReadBuffer(const asio::mutable_buffer& buffer) { + error_code ec; + // Loop until all bytes are read while handling interrupts. + uint64_t bytes_remaining = asio::buffer_size(buffer); + uint64_t position = 0; + while (bytes_remaining != 0) { + size_t bytes_read = + stream_.read_some(asio::buffer(buffer + position, bytes_remaining), ec); + position += bytes_read; + bytes_remaining -= bytes_read; + if (ec.value() == EINTR) { + continue; + } else if (ec) { + return ec; + } + } + return error_code(); +} + +template +error_code Connection::ReadBuffer( + const std::vector& buffer) { + // Loop until all bytes are read while handling interrupts. + for (const auto& b : buffer) { + auto ec = ReadBuffer(b); + if (ec) return ec; + } + return error_code(); +} + +/// Write a buffer to this connection. +/// +/// \param buffer The buffer. +template +error_code Connection::WriteBuffer(const asio::const_buffer& buffer) { + error_code error; + // Loop until all bytes are written while handling interrupts. + // When profiling with pprof, unhandled interrupts were being sent by the profiler to + // the raylet process, which was causing synchronous reads and writes to fail. + uint64_t bytes_remaining = asio::buffer_size(buffer); + uint64_t position = 0; + while (bytes_remaining != 0) { + size_t bytes_written = + stream_.write_some(asio::buffer(buffer + position, bytes_remaining), error); + position += bytes_written; + bytes_remaining -= bytes_written; + if (error.value() == EINTR) { + continue; + } else if (error) { + return error; + } + } + return error_code(); +} + +template +error_code Connection::WriteBuffer( + const std::vector& buffer) { + error_code error; + // Loop until all bytes are written while handling interrupts. + // When profiling with pprof, unhandled interrupts were being sent by the profiler to + // the raylet process, which was causing synchronous reads and writes to fail. + for (const auto& b : buffer) { + error = WriteBuffer(b); + if (error) { + return error; + } + } + return error_code(); +} + +template +void Connection::WriteBufferAsync(std::unique_ptr write_buffer) { + async_writes_ += 1; + auto size = async_write_queue_.size(); + auto size_is_power_of_two = (size & (size - 1)) == 0; + if (size > 1000 && size_is_power_of_two) { + ARROW_LOG(WARNING) << "Connection has " << size << " buffered async writes"; + } + async_write_queue_.push_back(std::move(write_buffer)); + if (!async_write_in_flight_) { + DoAsyncWrites(); + } +} + +// Shuts down socket for this connection. +template +void Connection::Close() { + error_code ec; + stream_.close(ec); +} + +template +std::string Connection::DebugString() const { + std::stringstream result; + result << "\n- bytes read: " << bytes_read_; + result << "\n- bytes written: " << bytes_written_; + result << "\n- num async writes: " << async_writes_; + result << "\n- num sync writes: " << sync_writes_; + result << "\n- writing: " << async_write_in_flight_; + result << "\n- pending async messages: " << async_write_queue_.size(); + return result.str(); +} + +template +void Connection::DoAsyncWrites() { + // Make sure we were not writing to the socket. + ARROW_CHECK(!async_write_in_flight_); + async_write_in_flight_ = true; + + // Do an async write of everything currently in the queue to the socket. + std::vector message_buffers; + int num_messages = 0; + for (const auto& write_buffer : async_write_queue_) { + write_buffer->ToBuffers(message_buffers); + num_messages++; + if (num_messages >= async_write_max_messages_) { + break; + } + } + + // Ensure lambda holds a reference to this. + auto this_ptr = this->shared_from_this(); + asio::async_write(stream_, message_buffers, + [this, this_ptr, num_messages](const error_code& ec, + size_t bytes_transferred) { + bytes_written_ += bytes_transferred; + bool close_connection = false; + // Call the handlers for the written messages. + for (int i = 0; i < num_messages; i++) { + auto write_buffer = std::move(async_write_queue_.front()); + auto return_code = write_buffer->Handle(ec); + if (return_code != AsyncWriteCallbackCode::OK) { + close_connection = true; + } + async_write_queue_.pop_front(); // release object + } + // We finished writing, so mark that we're no longer doing an + // async write. + async_write_in_flight_ = false; + if (close_connection) { + Close(); + return; + } + // If there is more to write, try to write the rest. + if (!async_write_queue_.empty()) { + DoAsyncWrites(); + } + }); +} + +// We have to fill the template of all possible types. +template class Connection; + +} // namespace io +} // namespace plasma diff --git a/cpp/src/plasma/io/basic_connection.h b/cpp/src/plasma/io/basic_connection.h new file mode 100644 index 00000000000..0bda2eacfc2 --- /dev/null +++ b/cpp/src/plasma/io/basic_connection.h @@ -0,0 +1,152 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#ifndef PLASMA_IO_BASIC_CONNECTION_H +#define PLASMA_IO_BASIC_CONNECTION_H + +#ifndef ASIO_STANDALONE +#define ASIO_STANDALONE +#endif + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "arrow/status.h" + +namespace asio = boost::asio; + +using error_code = boost::system::error_code; +using arrow::Status; + +namespace plasma { +namespace io { + +enum class AsyncWriteCallbackCode { + OK, + DISCONNECT, + UNKNOWN_ERROR, +}; + +using AsyncWriteCallback = std::function; +// TODO(suquark): Change it according to the platform. +using PlasmaStream = asio::basic_stream_socket; +using PlasmaAcceptor = asio::local::stream_protocol::acceptor; + +/// Create a local acceptor depends on the platform. +PlasmaAcceptor CreateLocalAcceptor(asio::io_context& io_context, const std::string& name); + +/// Create a local stream depends on the platform. +Status CreateLocalStream(const std::string& name, PlasmaStream* result); + +/// A message that is queued for writing asynchronously. +struct AsyncWriteBuffer { + virtual void ToBuffers(std::vector& message_buffers) = 0; + virtual ~AsyncWriteBuffer() {} + inline AsyncWriteCallbackCode Handle(const error_code& ec) { return handler_(ec); } + + protected: + AsyncWriteCallback handler_; +}; + +template +class Connection : public std::enable_shared_from_this> { + public: + explicit Connection(T&& stream); + + ~Connection(); + + /// Read a buffer from this connection. + /// + /// \param buffer The output buffer. + error_code ReadBuffer(const asio::mutable_buffer& buffer); + + /// Read buffers from this connection. + /// + /// \param buffer The output vector of buffers. + error_code ReadBuffer(const std::vector& buffer); + + /// Write a buffer to this connection. + /// + /// \param buffer The buffer. + error_code WriteBuffer(const asio::const_buffer& buffer); + + /// Write buffers to this connection. + /// + /// \param buffer The vector of buffers. + error_code WriteBuffer(const std::vector& buffer); + + /// Write buffers to this connection async. + /// + /// \param write_buffer The buffer to write async. + void WriteBufferAsync(std::unique_ptr write_buffer); + + /// Whether the stream is open. + inline bool IsOpen() { return stream_.is_open(); } + + /// Shuts down the stream for this connection. + void Close(); + + /// Get the native handle from the stream. + inline int GetNativeHandle() { return stream_.native_handle(); } + + /// Get the debug string. + std::string DebugString() const; + + protected: + /// The stream that supports most asio protocols (read, read_some, write, + /// write_some, async_read, async_write, async_read_some, async_write_some). + T stream_; + + /// Whether we are in the middle of an async write. + bool async_write_in_flight_; + + /// Max number of messages to write out at once. + const int async_write_max_messages_; + + /// List of pending messages to write. + std::deque> async_write_queue_; + + /// Count of sync messages sent total. + int64_t sync_writes_ = 0; + + /// Count of async messages sent total. + int64_t async_writes_ = 0; + + /// Count of bytes sent total. + int64_t bytes_written_ = 0; + + /// Count of bytes read total. + int64_t bytes_read_ = 0; + + private: + /// Asynchronously flushes the write queue. While async writes are running, the flag + /// async_write_in_flight_ will be set. This should only be called when no async writes + /// are currently in flight. + void DoAsyncWrites(); +}; + +} // namespace io +} // namespace plasma + +#endif // PLASMA_IO_BASIC_CONNECTION_H diff --git a/cpp/src/plasma/io/connection.cc b/cpp/src/plasma/io/connection.cc new file mode 100644 index 00000000000..97300a7a777 --- /dev/null +++ b/cpp/src/plasma/io/connection.cc @@ -0,0 +1,343 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "plasma/io/connection.h" + +#include +#include +#include + +#include "arrow/util/logging.h" +#include "plasma/fling.h" +#include "plasma/plasma_generated.h" +#include "plasma/protocol.h" + +// TODO(pcm): Replace our own custom message header (message type, +// message length, plasma protocol verion) with one that is serialized +// using flatbuffers. +constexpr int64_t kPlasmaProtocolVersion = 0x504C41534D410000; // PLASMA\0\0 + +namespace plasma { +namespace io { + +using flatbuf::MessageType; + +Status asio_to_arrow_status(const error_code& ec) { + if (!ec) { + return Status::OK(); + } + if (ec.value() == EPIPE || ec.value() == EBADF || ec.value() == ECONNRESET) { + ARROW_LOG(WARNING) << "Received SIGPIPE, BAD FILE DESCRIPTOR, or ECONNRESET when " + "processing a message. The client on the other end may " + "have hung up."; + } + return Status::IOError("Error code = ", strerror(ec.value())); +} + +struct AsyncMessageWriteBuffer : public AsyncWriteBuffer { + AsyncMessageWriteBuffer(int64_t version, int64_t type, int64_t length, + const uint8_t* message, AsyncWriteCallback callback) + : write_version(version), write_type(type), write_length(length) { + write_message.resize(length); + write_message.assign(message, message + length); + AsyncWriteBuffer::handler_ = callback; + } + + void ToBuffers(std::vector& message_buffers) override { + message_buffers.push_back(asio::buffer(&write_version, sizeof(write_version))); + message_buffers.push_back(asio::buffer(&write_type, sizeof(write_type))); + message_buffers.push_back(asio::buffer(&write_length, sizeof(write_length))); + message_buffers.push_back(asio::buffer(write_message)); + } + + int64_t write_version; + int64_t write_type; + uint64_t write_length; + std::vector write_message; +}; + +std::shared_ptr ServerConnection::shared_from_this() { + return std::static_pointer_cast(PlasmaConnection::shared_from_this()); +} + +std::shared_ptr ServerConnection::Create(PlasmaStream&& stream) { + std::shared_ptr self(new ServerConnection(std::move(stream))); + return self; +} + +Status ServerConnection::ReadMessage(int64_t type, std::vector* message) { + int64_t read_version, read_type, read_length; + // Wait for a message header from the client. The message header includes the + // protocol version, the message type, and the length of the message. + std::vector header; + header.push_back(asio::buffer(&read_version, sizeof(read_version))); + header.push_back(asio::buffer(&read_type, sizeof(read_type))); + header.push_back(asio::buffer(&read_length, sizeof(read_length))); + + auto ec = PlasmaConnection::ReadBuffer(header); + if (ec) { + return asio_to_arrow_status(ec); + } + // If there was no error, make sure the protocol version matches. + if (read_version != kPlasmaProtocolVersion) { + return Status::IOError( + "Expected Plasma message protocol version: ", kPlasmaProtocolVersion, + ", got protocol version: ", read_version); + } + if (type != read_type) { + if (read_type == static_cast(MessageType::PlasmaDisconnectClient)) { + // Disconnected by client. + return Status::IOError("The other side disconnected."); + } + return Status::IOError("Connection corrupted. Expected message type: ", type, + "; got message type: ", read_type, + ". Check logs or dmesg for previous errors."); + } + // Create read buffer. + message->resize(read_length); + auto buffer = asio::buffer(*message); + // Wait for the message to be read. + return asio_to_arrow_status(PlasmaConnection::ReadBuffer(buffer)); +} + +Status ServerConnection::WriteMessage(int64_t type, int64_t length, + const uint8_t* message) { + PlasmaConnection::sync_writes_ += 1; + PlasmaConnection::bytes_written_ += length; + + std::vector message_buffers; + auto write_version = kPlasmaProtocolVersion; + message_buffers.push_back(asio::buffer(&write_version, sizeof(write_version))); + message_buffers.push_back(asio::buffer(&type, sizeof(type))); + message_buffers.push_back(asio::buffer(&length, sizeof(length))); + message_buffers.push_back(asio::buffer(message, length)); + return asio_to_arrow_status(PlasmaConnection::WriteBuffer(message_buffers)); +} + +void ServerConnection::WriteMessageAsync(int64_t type, int64_t length, + const uint8_t* message, + const AsyncWriteCallback& handler) { + auto write_buffer = std::unique_ptr(new AsyncMessageWriteBuffer( + kPlasmaProtocolVersion, type, length, message, handler)); + PlasmaConnection::WriteBufferAsync(std::move(write_buffer)); +} + +Status ServerConnection::RecvFd(int* fd) { + *fd = recv_fd(GetNativeHandle()); + if (*fd < 0) { + return Status::Invalid("Got an invalid fd."); + } + return Status::OK(); +} + +Status ServerConnection::Disconnect() { + if (!IsOpen()) { + ARROW_LOG(WARNING) << "The client is not connected. 'Disconnect()' is ignored."; + return Status::OK(); + } + // Write the disconnection message. + auto status = + WriteMessage(static_cast(MessageType::PlasmaDisconnectClient), 0, NULLPTR); + Close(); // Close the stream anyway. + return status; +} + +Status ServerConnection::ReadNotificationMessage(std::unique_ptr& message) { + int64_t size; + auto ec = ReadBuffer(asio::mutable_buffer(&size, sizeof(size))); + if (ec) { + // The other side has closed the socket. + ARROW_LOG(DEBUG) << "Socket has been closed, or some other error has occurred."; + return asio_to_arrow_status(ec); + } + message.reset(new uint8_t[size]); + ec = ReadBuffer(asio::mutable_buffer(message.get(), size)); + if (ec) { + // The other side has closed the socket. + ARROW_LOG(DEBUG) << "Socket has been closed, or some other error has occurred."; + return asio_to_arrow_status(ec); + } + return Status::OK(); +} + +ServerConnection::ServerConnection(PlasmaStream&& stream) + : PlasmaConnection(std::move(stream)) {} + +std::shared_ptr ClientConnection::Create( + PlasmaStream&& stream, MessageHandler& message_handler) { + return std::shared_ptr( + new ClientConnection(std::move(stream), message_handler)); +} + +ClientConnection::ClientConnection(PlasmaStream&& stream, MessageHandler& message_handler) + : ServerConnection(std::move(stream)), message_handler_(message_handler) {} + +std::shared_ptr ClientConnection::shared_from_this() { + return std::static_pointer_cast(ServerConnection::shared_from_this()); +} + +void ClientConnection::ProcessMessages() { + // Wait for a message header from the client. The message header includes the + // protocol version, the message type, and the length of the message. + std::vector header{ + asio::buffer(&read_version_, sizeof(read_version_)), + asio::buffer(&read_type_, sizeof(read_type_)), + asio::buffer(&read_length_, sizeof(read_length_))}; + + asio::async_read(ServerConnection::stream_, header, + std::bind(&ClientConnection::ProcessMessageHeader, shared_from_this(), + std::placeholders::_1)); // Ignore byte_transferred +} + +void ClientConnection::ProcessMessageHeader(const error_code& ec) { + auto status = asio_to_arrow_status(ec); + if (!status.ok()) { + // If there was an error, disconnect the client. + ProcessError(status); + return; + } + + // If there was no error, make sure the protocol version matches. + if (read_version_ != kPlasmaProtocolVersion) { + status = Status::IOError( + "Expected Plasma message protocol version: ", kPlasmaProtocolVersion, + ", got protocol version: ", read_version_); + ProcessError(status); + return; + } + // Resize the message buffer to match the received length. + read_message_.resize(read_length_); + ServerConnection::bytes_read_ += read_length_; + // Wait for the message to be read. + asio::async_read(ServerConnection::stream_, asio::buffer(read_message_), + std::bind(&ClientConnection::ProcessMessageBody, shared_from_this(), + std::placeholders::_1)); +} + +void ClientConnection::ProcessMessageBody(const error_code& ec) { + auto status = asio_to_arrow_status(ec); + if (!status.ok()) { + // If there was an error, disconnect the client. + ProcessError(status); + return; + } + + ProcessMessage(read_type_, read_length_, read_message_.data()); +} + +void ClientConnection::ProcessError(const Status& status) { + ARROW_LOG(ERROR) << "Failed when processing message. Disconnecting the client. (" + << status << ")"; + // If there was an error, disconnect the client. + PlasmaConnection::Close(); +} + +void ClientConnection::ProcessMessage(int64_t type, int64_t length, const uint8_t* data) { + message_handler_(shared_from_this(), type, length, data); +} + +struct AsyncObjectNotificationWriteBuffer : public AsyncWriteBuffer { + ~AsyncObjectNotificationWriteBuffer() override {} + + static std::unique_ptr MakeDeletion( + const ObjectID& object_id) { + auto message = new std::vector(); + SerializeObjectDeletionNotification(object_id, message); + return std::unique_ptr( + new AsyncObjectNotificationWriteBuffer(message)); + } + + static std::unique_ptr MakeReady( + const ObjectID& object_id, const ObjectTableEntry& entry) { + auto message = new std::vector(); + SerializeObjectSealedNotification(object_id, entry, message); + return std::unique_ptr( + new AsyncObjectNotificationWriteBuffer(message)); + } + + void ToBuffers(std::vector& message_buffers) override { + message_buffers.push_back(asio::buffer(&size, sizeof(size))); + message_buffers.push_back(asio::buffer(*notification_msg)); + } + + std::unique_ptr> notification_msg; + int64_t size; + + protected: + explicit AsyncObjectNotificationWriteBuffer(std::vector* message) { + // Serialize the object. + notification_msg.reset(message); + size = message->size(); + AsyncWriteBuffer::handler_ = + [](const error_code& status) -> AsyncWriteCallbackCode { + auto errno_ = status.value(); + if (!errno_) { + return AsyncWriteCallbackCode::OK; + } + if (errno_ == EAGAIN || errno_ == EWOULDBLOCK || errno_ == EINTR) { + ARROW_LOG(DEBUG) << "The socket's send buffer is full, so we are caching this " + "notification and will send it later."; + ARROW_LOG(WARNING) << "Blocked unexpectly when sending message async."; + return AsyncWriteCallbackCode::OK; + } else { + ARROW_LOG(WARNING) << "Failed to send notification to client."; + if (errno_ == EPIPE) { + return AsyncWriteCallbackCode::DISCONNECT; + } + return AsyncWriteCallbackCode::UNKNOWN_ERROR; + } + }; + } +}; + +Status ClientConnection::SendFd(int fd) { + // Only send the file descriptor if it hasn't been sent (see analogous + // logic in GetStoreFd in client.cc). + if (used_fds.find(fd) == used_fds.end()) { + auto ec = send_fd(GetNativeHandle(), fd); + if (ec <= 0) { + if (ec == 0) { + return Status::IOError("Encountered unexpected EOF"); + } else { + return Status::IOError("Unknown I/O Error"); + } + } + used_fds.insert(fd); // Succeed, record the fd. + } + return Status::OK(); +} + +void ClientConnection::SendObjectDeletionAsync(const ObjectID& object_id) { + auto raw_ptr = AsyncObjectNotificationWriteBuffer::MakeDeletion(object_id).release(); + auto write_buffer = + std::unique_ptr(static_cast(raw_ptr)); + // Attempt to send a notification about this object ID. + WriteBufferAsync(std::move(write_buffer)); +} + +void ClientConnection::SendObjectReadyAsync(const ObjectID& object_id, + const ObjectTableEntry& entry) { + auto raw_ptr = + AsyncObjectNotificationWriteBuffer::MakeReady(object_id, entry).release(); + auto write_buffer = + std::unique_ptr(static_cast(raw_ptr)); + // Attempt to send a notification about this object ID. + WriteBufferAsync(std::move(write_buffer)); +} + +} // namespace io +} // namespace plasma diff --git a/cpp/src/plasma/io/connection.h b/cpp/src/plasma/io/connection.h new file mode 100644 index 00000000000..1bf232558d0 --- /dev/null +++ b/cpp/src/plasma/io/connection.h @@ -0,0 +1,181 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#ifndef PLASMA_IO_CONNECTION_H +#define PLASMA_IO_CONNECTION_H + +#include +#include +#include +#include +#include +#include +#include + +#include "arrow/status.h" +#include "plasma/common.h" +#include "plasma/io/basic_connection.h" + +namespace plasma { +namespace io { + +using arrow::Status; + +using PlasmaConnection = Connection; + +Status asio_to_arrow_status(const error_code& ec); + +/// A generic type representing a client connection to a server. This typename +/// can be used to write messages synchronously to the server. +class ServerConnection : public PlasmaConnection { + public: + std::shared_ptr shared_from_this(); + + /// Allocate a new server connection. + /// + /// \param stream A reference to the server stream. + /// \return std::shared_ptr. + static std::shared_ptr Create(PlasmaStream&& stream); + + /// Write a message to the client. + /// + /// \param type The message type (e.g., a flatbuffer enum). + /// \param length The size in bytes of the message. + /// \param message A pointer to the message buffer. + /// \return Status. + Status WriteMessage(int64_t type, int64_t length, const uint8_t* message); + + /// Read a message from the client. + /// + /// \param type The message type (e.g., a flatbuffer enum). + /// \param message A pointer to the message vector. + /// \return Status. + Status ReadMessage(int64_t type, std::vector* message); + + /// Write a message to the client asynchronously. + /// + /// \param type The message type (e.g., a flatbuffer enum). + /// \param length The size in bytes of the message. + /// \param message A pointer to the message buffer. + /// \param handler A callback to run on write completion. + void WriteMessageAsync(int64_t type, int64_t length, const uint8_t* message, + const AsyncWriteCallback& handler); + + Status RecvFd(int* fd); + + Status Disconnect(); + + Status ReadNotificationMessage(std::unique_ptr& message); + + protected: + /// A private constructor for a server connection. + explicit ServerConnection(PlasmaStream&& stream); +}; + +class ClientConnection; +using MessageHandler = std::function, int64_t type, + int64_t length, const uint8_t*)>; + +/// A generic type representing a client connection on a server. In addition to +/// writing messages to the client, like in ServerConnection, this typename can +/// also be used to process messages asynchronously from client. +class ClientConnection : public ServerConnection { + public: + /// Allocate a new node client connection. + /// + /// \param stream The client stream. + /// \param message_handler A reference to the message handler. + /// \return std::shared_ptr. + static std::shared_ptr Create(PlasmaStream&& stream, + MessageHandler& message_handler); + + std::shared_ptr shared_from_this(); + + /// Listen for and process messages from the client connection. Once a + /// message has been fully received, the client manager's + /// ProcessClientMessage handler will be called. + void ProcessMessages(); + + Status SendFd(int fd); + + inline bool ObjectIDExists(const ObjectID& object_id) { + return object_ids.find(object_id) != object_ids.end(); + } + + inline void RemoveObjectID(const ObjectID& object_id) { object_ids.erase(object_id); } + + inline int RemoveObjectIDIfExists(const ObjectID& object_id) { + auto it = object_ids.find(object_id); + if (it != object_ids.end()) { + object_ids.erase(it); + // Return 1 to indicate that the client was removed. + return 1; + } else { + // Return 0 to indicate that the client was not removed. + return 0; + } + } + + /// Send notifications about sealed objects to the subscribers. This is called + /// in SealObject. + void SendObjectReadyAsync(const ObjectID& object_id, const ObjectTableEntry& entry); + + /// Send notifications about evicted objects to the subscribers. + void SendObjectDeletionAsync(const ObjectID& object_id); + + /// Object ids that are used by this client. + std::unordered_set object_ids; + /// File descriptors that are used by this client. + std::unordered_set used_fds; + + private: + /// Process the message header from the client. + /// \param ec The returned error code. + void ProcessMessageHeader(const error_code& ec); + + /// Process the message body from the client. + /// \param ec The returned error code. + void ProcessMessageBody(const error_code& ec); + + /// Process the message from the client. + /// \param type The type of the message. + /// \param length The length of the message. + /// \param data The data buffer of the message. + void ProcessMessage(int64_t type, int64_t length, const uint8_t* data); + + /// Process an error from reading the message from the client. + /// \param status The status code. + void ProcessError(const Status& status); + + /// A private constructor for a node client connection. + ClientConnection(PlasmaStream&& stream, MessageHandler& message_handler); + + /// The handler for a message from the client. + MessageHandler message_handler_; + + int64_t read_version_; + int64_t read_type_; + uint64_t read_length_; + + /// Buffers for the current message being read from the client. + std::vector read_message_; +}; + +} // namespace io +} // namespace plasma + +#endif // PLASMA_IO_CONNECTION_H diff --git a/cpp/src/plasma/malloc.cc b/cpp/src/plasma/malloc.cc index bb027a6cb90..14217894f38 100644 --- a/cpp/src/plasma/malloc.cc +++ b/cpp/src/plasma/malloc.cc @@ -29,6 +29,7 @@ #include #include +#include "arrow/util/logging.h" #include "plasma/common.h" #include "plasma/plasma.h" diff --git a/cpp/src/plasma/malloc.h b/cpp/src/plasma/malloc.h index a081190b3ef..92d6537e948 100644 --- a/cpp/src/plasma/malloc.h +++ b/cpp/src/plasma/malloc.h @@ -35,8 +35,8 @@ void GetMallocMapinfo(void* addr, int* fd, int64_t* map_length, ptrdiff_t* offse /// Get the mmap size corresponding to a specific file descriptor. /// -/// @param fd The file descriptor to look up. -/// @return The size of the corresponding memory-mapped file. +/// \param fd The file descriptor to look up. +/// \return The size of the corresponding memory-mapped file. int64_t GetMmapSize(int fd); struct MmapRecord { diff --git a/cpp/src/plasma/plasma.cc b/cpp/src/plasma/plasma.cc index d0ef4f8d317..538422d3b49 100644 --- a/cpp/src/plasma/plasma.cc +++ b/cpp/src/plasma/plasma.cc @@ -16,16 +16,7 @@ // under the License. #include "plasma/plasma.h" - -#include -#include -#include - #include "plasma/common.h" -#include "plasma/common_generated.h" -#include "plasma/protocol.h" - -namespace fb = plasma::flatbuf; namespace plasma { @@ -33,42 +24,6 @@ ObjectTableEntry::ObjectTableEntry() : pointer(nullptr), ref_count(0) {} ObjectTableEntry::~ObjectTableEntry() { pointer = nullptr; } -int WarnIfSigpipe(int status, int client_sock) { - if (status >= 0) { - return 0; - } - if (errno == EPIPE || errno == EBADF || errno == ECONNRESET) { - ARROW_LOG(WARNING) << "Received SIGPIPE, BAD FILE DESCRIPTOR, or ECONNRESET when " - "sending a message to client on fd " - << client_sock - << ". The client on the other end may " - "have hung up."; - return errno; - } - ARROW_LOG(FATAL) << "Failed to write message to client on fd " << client_sock << "."; - return -1; // This is never reached. -} - -/** - * This will create a new ObjectInfo buffer. The first sizeof(int64_t) bytes - * of this buffer are the length of the remaining message and the - * remaining message is a serialized version of the object info. - * - * @param object_info The object info to be serialized - * @return The object info buffer. It is the caller's responsibility to free - * this buffer with "delete" after it has been used. - */ -std::unique_ptr CreateObjectInfoBuffer(fb::ObjectInfoT* object_info) { - flatbuffers::FlatBufferBuilder fbb; - auto message = fb::CreateObjectInfo(fbb, object_info); - fbb.Finish(message); - auto notification = - std::unique_ptr(new uint8_t[sizeof(int64_t) + fbb.GetSize()]); - *(reinterpret_cast(notification.get())) = fbb.GetSize(); - memcpy(notification.get() + sizeof(int64_t), fbb.GetBufferPointer(), fbb.GetSize()); - return notification; -} - ObjectTableEntry* GetObjectTableEntry(PlasmaStoreInfo* store_info, const ObjectID& object_id) { auto it = store_info->objects.find(object_id); diff --git a/cpp/src/plasma/plasma.h b/cpp/src/plasma/plasma.h index 0948e6de8e9..92386cc83bb 100644 --- a/cpp/src/plasma/plasma.h +++ b/cpp/src/plasma/plasma.h @@ -18,15 +18,6 @@ #ifndef PLASMA_PLASMA_H #define PLASMA_PLASMA_H -#include -#include -#include -#include -#include -#include -#include -#include // pid_t - #include #include #include @@ -35,8 +26,6 @@ #include "plasma/compat.h" #include "arrow/status.h" -#include "arrow/util/logging.h" -#include "arrow/util/macros.h" #include "plasma/common.h" #ifdef PLASMA_CUDA @@ -45,32 +34,9 @@ using arrow::cuda::CudaIpcMemHandle; namespace plasma { -namespace flatbuf { -struct ObjectInfoT; -} // namespace flatbuf - -#define HANDLE_SIGPIPE(s, fd_) \ - do { \ - Status _s = (s); \ - if (!_s.ok()) { \ - if (errno == EPIPE || errno == EBADF || errno == ECONNRESET) { \ - ARROW_LOG(WARNING) \ - << "Received SIGPIPE, BAD FILE DESCRIPTOR, or ECONNRESET when " \ - "sending a message to client on fd " \ - << fd_ \ - << ". " \ - "The client on the other end may have hung up."; \ - } else { \ - return _s; \ - } \ - } \ - } while (0); - /// Allocation granularity used in plasma for object allocation. constexpr int64_t kBlockSize = 64; -struct Client; - // TODO(pcm): Replace this by the flatbuffers message PlasmaObjectSpec. struct PlasmaObject { #ifdef PLASMA_CUDA @@ -126,31 +92,13 @@ struct PlasmaStoreInfo { /// Get an entry from the object table and return NULL if the object_id /// is not present. /// -/// @param store_info The PlasmaStoreInfo that contains the object table. -/// @param object_id The object_id of the entry we are looking for. -/// @return The entry associated with the object_id or NULL if the object_id +/// \param store_info The PlasmaStoreInfo that contains the object table. +/// \param object_id The object_id of the entry we are looking for. +/// \return The entry associated with the object_id or NULL if the object_id /// is not present. ObjectTableEntry* GetObjectTableEntry(PlasmaStoreInfo* store_info, const ObjectID& object_id); -/// Print a warning if the status is less than zero. This should be used to check -/// the success of messages sent to plasma clients. We print a warning instead of -/// failing because the plasma clients are allowed to die. This is used to handle -/// situations where the store writes to a client file descriptor, and the client -/// may already have disconnected. If we have processed the disconnection and -/// closed the file descriptor, we should get a BAD FILE DESCRIPTOR error. If we -/// have not, then we should get a SIGPIPE. If we write to a TCP socket that -/// isn't connected yet, then we should get an ECONNRESET. -/// -/// @param status The status to check. If it is less less than zero, we will -/// print a warning. -/// @param client_sock The client socket. This is just used to print some extra -/// information. -/// @return The errno set. -int WarnIfSigpipe(int status, int client_sock); - -std::unique_ptr CreateObjectInfoBuffer(flatbuf::ObjectInfoT* object_info); - } // namespace plasma #endif // PLASMA_PLASMA_H diff --git a/cpp/src/plasma/protocol.cc b/cpp/src/plasma/protocol.cc index c22d77d6019..9fe340b9e41 100644 --- a/cpp/src/plasma/protocol.cc +++ b/cpp/src/plasma/protocol.cc @@ -19,11 +19,12 @@ #include +#include "arrow/util/logging.h" #include "flatbuffers/flatbuffers.h" #include "plasma/plasma_generated.h" #include "plasma/common.h" -#include "plasma/io.h" +#include "plasma/io/connection.h" #ifdef PLASMA_CUDA #include "arrow/gpu/cuda_api.h" @@ -53,15 +54,6 @@ ToFlatbuffer(flatbuffers::FlatBufferBuilder* fbb, const ObjectID* object_ids, return fbb->CreateVector(arrow::util::MakeNonNull(results.data()), results.size()); } -Status PlasmaReceive(int sock, MessageType message_type, std::vector* buffer) { - MessageType type; - RETURN_NOT_OK(ReadMessage(sock, &type, buffer)); - ARROW_CHECK(type == message_type) - << "type = " << static_cast(type) - << ", message_type = " << static_cast(message_type); - return Status::OK(); -} - // Helper function to create a vector of elements from Data (Request/Reply struct). // The Getter function is used to extract one element from Data. template @@ -74,13 +66,6 @@ void ToVector(const Data& request, std::vector* out, const Getter& getter) { } } -template -Status PlasmaSend(int sock, MessageType message_type, flatbuffers::FlatBufferBuilder* fbb, - const Message& message) { - fbb->Finish(message); - return WriteMessage(sock, message_type, fbb->GetSize(), fbb->GetBufferPointer()); -} - Status PlasmaErrorStatus(fb::PlasmaError plasma_error) { switch (plasma_error) { case fb::PlasmaError::OK: @@ -100,17 +85,39 @@ Status PlasmaErrorStatus(fb::PlasmaError plasma_error) { return Status::OK(); } +Status PlasmaSend(const std::shared_ptr& client, + MessageType message_type, flatbuffers::FlatBufferBuilder* fbb) { + if (fbb) { + return client->WriteMessage(static_cast(message_type), fbb->GetSize(), + fbb->GetBufferPointer()); + } else { + return client->WriteMessage(static_cast(message_type), 0, NULLPTR); + } +} + +Status PlasmaSend(const std::shared_ptr& client, + MessageType message_type, flatbuffers::FlatBufferBuilder* fbb) { + if (fbb) { + return client->WriteMessage(static_cast(message_type), fbb->GetSize(), + fbb->GetBufferPointer()); + } else { + return client->WriteMessage(static_cast(message_type), 0, NULLPTR); + } +} + // Create messages. -Status SendCreateRequest(int sock, ObjectID object_id, int64_t data_size, - int64_t metadata_size, int device_num) { +Status SendCreateRequest(const std::shared_ptr& client, + ObjectID object_id, int64_t data_size, int64_t metadata_size, + int device_num) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaCreateRequest(fbb, fbb.CreateString(object_id.binary()), data_size, metadata_size, device_num); - return PlasmaSend(sock, MessageType::PlasmaCreateRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaCreateRequest, &fbb); } -Status ReadCreateRequest(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadCreateRequest(const uint8_t* data, size_t size, ObjectID* object_id, int64_t* data_size, int64_t* metadata_size, int* device_num) { DCHECK(data); auto message = flatbuffers::GetRoot(data); @@ -122,8 +129,9 @@ Status ReadCreateRequest(uint8_t* data, size_t size, ObjectID* object_id, return Status::OK(); } -Status SendCreateReply(int sock, ObjectID object_id, PlasmaObject* object, - PlasmaError error_code, int64_t mmap_size) { +Status SendCreateReply(const std::shared_ptr& client, + ObjectID object_id, PlasmaObject* object, PlasmaError error_code, + int64_t mmap_size) { flatbuffers::FlatBufferBuilder fbb; PlasmaObjectSpec plasma_object(object->store_fd, object->data_offset, object->data_size, object->metadata_offset, object->metadata_size, @@ -152,10 +160,11 @@ Status SendCreateReply(int sock, ObjectID object_id, PlasmaObject* object, #endif } auto message = crb.Finish(); - return PlasmaSend(sock, MessageType::PlasmaCreateReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaCreateReply, &fbb); } -Status ReadCreateReply(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadCreateReply(const uint8_t* data, size_t size, ObjectID* object_id, PlasmaObject* object, int* store_fd, int64_t* mmap_size) { DCHECK(data); auto message = flatbuffers::GetRoot(data); @@ -180,18 +189,19 @@ Status ReadCreateReply(uint8_t* data, size_t size, ObjectID* object_id, return PlasmaErrorStatus(message->error()); } -Status SendCreateAndSealRequest(int sock, const ObjectID& object_id, - const std::string& data, const std::string& metadata, - unsigned char* digest) { +Status SendCreateAndSealRequest(const std::shared_ptr& client, + const ObjectID& object_id, const std::string& data, + const std::string& metadata, unsigned char* digest) { flatbuffers::FlatBufferBuilder fbb; auto digest_string = fbb.CreateString(reinterpret_cast(digest), kDigestSize); auto message = fb::CreatePlasmaCreateAndSealRequest( fbb, fbb.CreateString(object_id.binary()), fbb.CreateString(data), fbb.CreateString(metadata), digest_string); - return PlasmaSend(sock, MessageType::PlasmaCreateAndSealRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaCreateAndSealRequest, &fbb); } -Status ReadCreateAndSealRequest(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadCreateAndSealRequest(const uint8_t* data, size_t size, ObjectID* object_id, std::string* object_data, std::string* metadata, unsigned char* digest) { DCHECK(data); @@ -206,26 +216,30 @@ Status ReadCreateAndSealRequest(uint8_t* data, size_t size, ObjectID* object_id, return Status::OK(); } -Status SendCreateAndSealReply(int sock, PlasmaError error) { +Status SendCreateAndSealReply(const std::shared_ptr& client, + PlasmaError error) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaCreateAndSealReply(fbb, static_cast(error)); - return PlasmaSend(sock, MessageType::PlasmaCreateAndSealReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaCreateAndSealReply, &fbb); } -Status ReadCreateAndSealReply(uint8_t* data, size_t size) { +Status ReadCreateAndSealReply(const uint8_t* data, size_t size) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); return PlasmaErrorStatus(message->error()); } -Status SendAbortRequest(int sock, ObjectID object_id) { +Status SendAbortRequest(const std::shared_ptr& client, + ObjectID object_id) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaAbortRequest(fbb, fbb.CreateString(object_id.binary())); - return PlasmaSend(sock, MessageType::PlasmaAbortRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaAbortRequest, &fbb); } -Status ReadAbortRequest(uint8_t* data, size_t size, ObjectID* object_id) { +Status ReadAbortRequest(const uint8_t* data, size_t size, ObjectID* object_id) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -233,13 +247,15 @@ Status ReadAbortRequest(uint8_t* data, size_t size, ObjectID* object_id) { return Status::OK(); } -Status SendAbortReply(int sock, ObjectID object_id) { +Status SendAbortReply(const std::shared_ptr& client, + ObjectID object_id) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaAbortReply(fbb, fbb.CreateString(object_id.binary())); - return PlasmaSend(sock, MessageType::PlasmaAbortReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaAbortReply, &fbb); } -Status ReadAbortReply(uint8_t* data, size_t size, ObjectID* object_id) { +Status ReadAbortReply(const uint8_t* data, size_t size, ObjectID* object_id) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -249,15 +265,17 @@ Status ReadAbortReply(uint8_t* data, size_t size, ObjectID* object_id) { // Seal messages. -Status SendSealRequest(int sock, ObjectID object_id, unsigned char* digest) { +Status SendSealRequest(const std::shared_ptr& client, + ObjectID object_id, unsigned char* digest) { flatbuffers::FlatBufferBuilder fbb; auto digest_string = fbb.CreateString(reinterpret_cast(digest), kDigestSize); auto message = fb::CreatePlasmaSealRequest(fbb, fbb.CreateString(object_id.binary()), digest_string); - return PlasmaSend(sock, MessageType::PlasmaSealRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaSealRequest, &fbb); } -Status ReadSealRequest(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadSealRequest(const uint8_t* data, size_t size, ObjectID* object_id, unsigned char* digest) { DCHECK(data); auto message = flatbuffers::GetRoot(data); @@ -268,14 +286,16 @@ Status ReadSealRequest(uint8_t* data, size_t size, ObjectID* object_id, return Status::OK(); } -Status SendSealReply(int sock, ObjectID object_id, PlasmaError error) { +Status SendSealReply(const std::shared_ptr& client, ObjectID object_id, + PlasmaError error) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaSealReply(fbb, fbb.CreateString(object_id.binary()), error); - return PlasmaSend(sock, MessageType::PlasmaSealReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaSealReply, &fbb); } -Status ReadSealReply(uint8_t* data, size_t size, ObjectID* object_id) { +Status ReadSealReply(const uint8_t* data, size_t size, ObjectID* object_id) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -285,14 +305,16 @@ Status ReadSealReply(uint8_t* data, size_t size, ObjectID* object_id) { // Release messages. -Status SendReleaseRequest(int sock, ObjectID object_id) { +Status SendReleaseRequest(const std::shared_ptr& client, + ObjectID object_id) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaReleaseRequest(fbb, fbb.CreateString(object_id.binary())); - return PlasmaSend(sock, MessageType::PlasmaReleaseRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaReleaseRequest, &fbb); } -Status ReadReleaseRequest(uint8_t* data, size_t size, ObjectID* object_id) { +Status ReadReleaseRequest(const uint8_t* data, size_t size, ObjectID* object_id) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -300,14 +322,16 @@ Status ReadReleaseRequest(uint8_t* data, size_t size, ObjectID* object_id) { return Status::OK(); } -Status SendReleaseReply(int sock, ObjectID object_id, PlasmaError error) { +Status SendReleaseReply(const std::shared_ptr& client, + ObjectID object_id, PlasmaError error) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaReleaseReply(fbb, fbb.CreateString(object_id.binary()), error); - return PlasmaSend(sock, MessageType::PlasmaReleaseReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaReleaseReply, &fbb); } -Status ReadReleaseReply(uint8_t* data, size_t size, ObjectID* object_id) { +Status ReadReleaseReply(const uint8_t* data, size_t size, ObjectID* object_id) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -317,15 +341,18 @@ Status ReadReleaseReply(uint8_t* data, size_t size, ObjectID* object_id) { // Delete objects messages. -Status SendDeleteRequest(int sock, const std::vector& object_ids) { +Status SendDeleteRequest(const std::shared_ptr& client, + const std::vector& object_ids) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaDeleteRequest( fbb, static_cast(object_ids.size()), ToFlatbuffer(&fbb, &object_ids[0], object_ids.size())); - return PlasmaSend(sock, MessageType::PlasmaDeleteRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaDeleteRequest, &fbb); } -Status ReadDeleteRequest(uint8_t* data, size_t size, std::vector* object_ids) { +Status ReadDeleteRequest(const uint8_t* data, size_t size, + std::vector* object_ids) { using fb::PlasmaDeleteRequest; DCHECK(data); @@ -338,7 +365,8 @@ Status ReadDeleteRequest(uint8_t* data, size_t size, std::vector* obje return Status::OK(); } -Status SendDeleteReply(int sock, const std::vector& object_ids, +Status SendDeleteReply(const std::shared_ptr& client, + const std::vector& object_ids, const std::vector& errors) { DCHECK(object_ids.size() == errors.size()); flatbuffers::FlatBufferBuilder fbb; @@ -348,10 +376,12 @@ Status SendDeleteReply(int sock, const std::vector& object_ids, fbb.CreateVector( arrow::util::MakeNonNull(reinterpret_cast(errors.data())), object_ids.size())); - return PlasmaSend(sock, MessageType::PlasmaDeleteReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaDeleteReply, &fbb); } -Status ReadDeleteReply(uint8_t* data, size_t size, std::vector* object_ids, +Status ReadDeleteReply(const uint8_t* data, size_t size, + std::vector* object_ids, std::vector* errors) { using fb::PlasmaDeleteReply; @@ -371,14 +401,16 @@ Status ReadDeleteReply(uint8_t* data, size_t size, std::vector* object // Contains messages. -Status SendContainsRequest(int sock, ObjectID object_id) { +Status SendContainsRequest(const std::shared_ptr& client, + ObjectID object_id) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaContainsRequest(fbb, fbb.CreateString(object_id.binary())); - return PlasmaSend(sock, MessageType::PlasmaContainsRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaContainsRequest, &fbb); } -Status ReadContainsRequest(uint8_t* data, size_t size, ObjectID* object_id) { +Status ReadContainsRequest(const uint8_t* data, size_t size, ObjectID* object_id) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -386,14 +418,16 @@ Status ReadContainsRequest(uint8_t* data, size_t size, ObjectID* object_id) { return Status::OK(); } -Status SendContainsReply(int sock, ObjectID object_id, bool has_object) { +Status SendContainsReply(const std::shared_ptr& client, + ObjectID object_id, bool has_object) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaContainsReply(fbb, fbb.CreateString(object_id.binary()), has_object); - return PlasmaSend(sock, MessageType::PlasmaContainsReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaContainsReply, &fbb); } -Status ReadContainsReply(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadContainsReply(const uint8_t* data, size_t size, ObjectID* object_id, bool* has_object) { DCHECK(data); auto message = flatbuffers::GetRoot(data); @@ -405,15 +439,17 @@ Status ReadContainsReply(uint8_t* data, size_t size, ObjectID* object_id, // List messages. -Status SendListRequest(int sock) { +Status SendListRequest(const std::shared_ptr& client) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaListRequest(fbb); - return PlasmaSend(sock, MessageType::PlasmaListRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaListRequest, &fbb); } -Status ReadListRequest(uint8_t* data, size_t size) { return Status::OK(); } +Status ReadListRequest(const uint8_t* data, size_t size) { return Status::OK(); } -Status SendListReply(int sock, const ObjectTable& objects) { +Status SendListReply(const std::shared_ptr& client, + const ObjectTable& objects) { flatbuffers::FlatBufferBuilder fbb; std::vector> object_infos; for (auto const& entry : objects) { @@ -430,10 +466,11 @@ Status SendListReply(int sock, const ObjectTable& objects) { auto message = fb::CreatePlasmaListReply( fbb, fbb.CreateVector(arrow::util::MakeNonNull(object_infos.data()), object_infos.size())); - return PlasmaSend(sock, MessageType::PlasmaListReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaListReply, &fbb); } -Status ReadListReply(uint8_t* data, size_t size, ObjectTable* objects) { +Status ReadListReply(const uint8_t* data, size_t size, ObjectTable* objects) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -454,21 +491,24 @@ Status ReadListReply(uint8_t* data, size_t size, ObjectTable* objects) { // Connect messages. -Status SendConnectRequest(int sock) { +Status SendConnectRequest(const std::shared_ptr& client) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaConnectRequest(fbb); - return PlasmaSend(sock, MessageType::PlasmaConnectRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaConnectRequest, &fbb); } -Status ReadConnectRequest(uint8_t* data) { return Status::OK(); } +Status ReadConnectRequest(const uint8_t* data) { return Status::OK(); } -Status SendConnectReply(int sock, int64_t memory_capacity) { +Status SendConnectReply(const std::shared_ptr& client, + int64_t memory_capacity) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaConnectReply(fbb, memory_capacity); - return PlasmaSend(sock, MessageType::PlasmaConnectReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaConnectReply, &fbb); } -Status ReadConnectReply(uint8_t* data, size_t size, int64_t* memory_capacity) { +Status ReadConnectReply(const uint8_t* data, size_t size, int64_t* memory_capacity) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -478,13 +518,15 @@ Status ReadConnectReply(uint8_t* data, size_t size, int64_t* memory_capacity) { // Evict messages. -Status SendEvictRequest(int sock, int64_t num_bytes) { +Status SendEvictRequest(const std::shared_ptr& client, + int64_t num_bytes) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaEvictRequest(fbb, num_bytes); - return PlasmaSend(sock, MessageType::PlasmaEvictRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaEvictRequest, &fbb); } -Status ReadEvictRequest(uint8_t* data, size_t size, int64_t* num_bytes) { +Status ReadEvictRequest(const uint8_t* data, size_t size, int64_t* num_bytes) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -492,13 +534,15 @@ Status ReadEvictRequest(uint8_t* data, size_t size, int64_t* num_bytes) { return Status::OK(); } -Status SendEvictReply(int sock, int64_t num_bytes) { +Status SendEvictReply(const std::shared_ptr& client, + int64_t num_bytes) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaEvictReply(fbb, num_bytes); - return PlasmaSend(sock, MessageType::PlasmaEvictReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaEvictReply, &fbb); } -Status ReadEvictReply(uint8_t* data, size_t size, int64_t& num_bytes) { +Status ReadEvictReply(const uint8_t* data, size_t size, int64_t& num_bytes) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -508,15 +552,17 @@ Status ReadEvictReply(uint8_t* data, size_t size, int64_t& num_bytes) { // Get messages. -Status SendGetRequest(int sock, const ObjectID* object_ids, int64_t num_objects, +Status SendGetRequest(const std::shared_ptr& client, + const ObjectID* object_ids, int64_t num_objects, int64_t timeout_ms) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaGetRequest( fbb, ToFlatbuffer(&fbb, object_ids, num_objects), timeout_ms); - return PlasmaSend(sock, MessageType::PlasmaGetRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaGetRequest, &fbb); } -Status ReadGetRequest(uint8_t* data, size_t size, std::vector& object_ids, +Status ReadGetRequest(const uint8_t* data, size_t size, std::vector& object_ids, int64_t* timeout_ms) { DCHECK(data); auto message = flatbuffers::GetRoot(data); @@ -529,7 +575,8 @@ Status ReadGetRequest(uint8_t* data, size_t size, std::vector& object_ return Status::OK(); } -Status SendGetReply(int sock, ObjectID object_ids[], +Status SendGetReply(const std::shared_ptr& client, + ObjectID object_ids[], std::unordered_map& plasma_objects, int64_t num_objects, const std::vector& store_fds, const std::vector& mmap_sizes) { @@ -557,10 +604,11 @@ Status SendGetReply(int sock, ObjectID object_ids[], fbb.CreateVector(arrow::util::MakeNonNull(store_fds.data()), store_fds.size()), fbb.CreateVector(arrow::util::MakeNonNull(mmap_sizes.data()), mmap_sizes.size()), fbb.CreateVector(arrow::util::MakeNonNull(handles.data()), handles.size())); - return PlasmaSend(sock, MessageType::PlasmaGetReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaGetReply, &fbb); } -Status ReadGetReply(uint8_t* data, size_t size, ObjectID object_ids[], +Status ReadGetReply(const uint8_t* data, size_t size, ObjectID object_ids[], PlasmaObject plasma_objects[], int64_t num_objects, std::vector& store_fds, std::vector& mmap_sizes) { DCHECK(data); @@ -597,26 +645,20 @@ Status ReadGetReply(uint8_t* data, size_t size, ObjectID object_ids[], return Status::OK(); } -// Subscribe messages. - -Status SendSubscribeRequest(int sock) { - flatbuffers::FlatBufferBuilder fbb; - auto message = fb::CreatePlasmaSubscribeRequest(fbb); - return PlasmaSend(sock, MessageType::PlasmaSubscribeRequest, &fbb, message); -} - // Data messages. -Status SendDataRequest(int sock, ObjectID object_id, const char* address, int port) { +Status SendDataRequest(const std::shared_ptr& client, + ObjectID object_id, const char* address, int port) { flatbuffers::FlatBufferBuilder fbb; auto addr = fbb.CreateString(address, strlen(address)); auto message = fb::CreatePlasmaDataRequest(fbb, fbb.CreateString(object_id.binary()), addr, port); - return PlasmaSend(sock, MessageType::PlasmaDataRequest, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaDataRequest, &fbb); } -Status ReadDataRequest(uint8_t* data, size_t size, ObjectID* object_id, char** address, - int* port) { +Status ReadDataRequest(const uint8_t* data, size_t size, ObjectID* object_id, + char** address, int* port) { DCHECK(data); auto message = flatbuffers::GetRoot(data); DCHECK(VerifyFlatbuffer(message, data, size)); @@ -627,15 +669,16 @@ Status ReadDataRequest(uint8_t* data, size_t size, ObjectID* object_id, char** a return Status::OK(); } -Status SendDataReply(int sock, ObjectID object_id, int64_t object_size, - int64_t metadata_size) { +Status SendDataReply(const std::shared_ptr& client, ObjectID object_id, + int64_t object_size, int64_t metadata_size) { flatbuffers::FlatBufferBuilder fbb; auto message = fb::CreatePlasmaDataReply(fbb, fbb.CreateString(object_id.binary()), object_size, metadata_size); - return PlasmaSend(sock, MessageType::PlasmaDataReply, &fbb, message); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaDataReply, &fbb); } -Status ReadDataReply(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadDataReply(const uint8_t* data, size_t size, ObjectID* object_id, int64_t* object_size, int64_t* metadata_size) { DCHECK(data); auto message = flatbuffers::GetRoot(data); @@ -646,4 +689,39 @@ Status ReadDataReply(uint8_t* data, size_t size, ObjectID* object_id, return Status::OK(); } +Status SendSubscribeRequest(const std::shared_ptr& client) { + // Subscribe messages. + flatbuffers::FlatBufferBuilder fbb; + auto message = fb::CreatePlasmaSubscribeRequest(fbb); + fbb.Finish(message); + return PlasmaSend(client, MessageType::PlasmaSubscribeRequest, &fbb); +} + +void SerializeObjectDeletionNotification(const ObjectID& object_id, + std::vector* serialized) { + flatbuf::ObjectInfoT info; + info.object_id = object_id.binary(); + info.is_deletion = true; + flatbuffers::FlatBufferBuilder fbb; + auto message = fb::CreateObjectInfo(fbb, &info); + fbb.Finish(message); + serialized->resize(fbb.GetSize()); + serialized->assign(fbb.GetBufferPointer(), fbb.GetBufferPointer() + fbb.GetSize()); +} + +void SerializeObjectSealedNotification(const ObjectID& object_id, + const ObjectTableEntry& entry, + std::vector* serialized) { + flatbuf::ObjectInfoT info; + info.object_id = object_id.binary(); + info.data_size = entry.data_size; + info.metadata_size = entry.metadata_size; + info.digest = std::string(reinterpret_cast(&entry.digest[0]), kDigestSize); + flatbuffers::FlatBufferBuilder fbb; + auto message = fb::CreateObjectInfo(fbb, &info); + fbb.Finish(message); + serialized->resize(fbb.GetSize()); + serialized->assign(fbb.GetBufferPointer(), fbb.GetBufferPointer() + fbb.GetSize()); +} + } // namespace plasma diff --git a/cpp/src/plasma/protocol.h b/cpp/src/plasma/protocol.h index 0362bd47797..e9abb1935a0 100644 --- a/cpp/src/plasma/protocol.h +++ b/cpp/src/plasma/protocol.h @@ -24,168 +24,192 @@ #include #include "arrow/status.h" +#include "plasma/io/connection.h" #include "plasma/plasma.h" #include "plasma/plasma_generated.h" namespace plasma { using arrow::Status; - -using flatbuf::MessageType; using flatbuf::PlasmaError; +using io::ClientConnection; +using io::ServerConnection; template -bool VerifyFlatbuffer(T* object, uint8_t* data, size_t size) { +bool VerifyFlatbuffer(T* object, const uint8_t* data, size_t size) { flatbuffers::Verifier verifier(data, size); return object->Verify(verifier); } -/* Plasma receive message. */ - -Status PlasmaReceive(int sock, MessageType message_type, std::vector* buffer); - /* Plasma Create message functions. */ -Status SendCreateRequest(int sock, ObjectID object_id, int64_t data_size, - int64_t metadata_size, int device_num); +Status SendCreateRequest(const std::shared_ptr& client, + ObjectID object_id, int64_t data_size, int64_t metadata_size, + int device_num); -Status ReadCreateRequest(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadCreateRequest(const uint8_t* data, size_t size, ObjectID* object_id, int64_t* data_size, int64_t* metadata_size, int* device_num); -Status SendCreateReply(int sock, ObjectID object_id, PlasmaObject* object, - PlasmaError error, int64_t mmap_size); +Status SendCreateReply(const std::shared_ptr& client, + ObjectID object_id, PlasmaObject* object, PlasmaError error, + int64_t mmap_size); -Status ReadCreateReply(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadCreateReply(const uint8_t* data, size_t size, ObjectID* object_id, PlasmaObject* object, int* store_fd, int64_t* mmap_size); -Status SendCreateAndSealRequest(int sock, const ObjectID& object_id, - const std::string& data, const std::string& metadata, - unsigned char* digest); +Status SendCreateAndSealRequest(const std::shared_ptr& client, + const ObjectID& object_id, const std::string& data, + const std::string& metadata, unsigned char* digest); -Status ReadCreateAndSealRequest(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadCreateAndSealRequest(const uint8_t* data, size_t size, ObjectID* object_id, std::string* object_data, std::string* metadata, unsigned char* digest); -Status SendCreateAndSealReply(int sock, PlasmaError error); +Status SendCreateAndSealReply(const std::shared_ptr& client, + PlasmaError error); -Status ReadCreateAndSealReply(uint8_t* data, size_t size); +Status ReadCreateAndSealReply(const uint8_t* data, size_t size); -Status SendAbortRequest(int sock, ObjectID object_id); +Status SendAbortRequest(const std::shared_ptr& client, + ObjectID object_id); -Status ReadAbortRequest(uint8_t* data, size_t size, ObjectID* object_id); +Status ReadAbortRequest(const uint8_t* data, size_t size, ObjectID* object_id); -Status SendAbortReply(int sock, ObjectID object_id); +Status SendAbortReply(const std::shared_ptr& client, + ObjectID object_id); -Status ReadAbortReply(uint8_t* data, size_t size, ObjectID* object_id); +Status ReadAbortReply(const uint8_t* data, size_t size, ObjectID* object_id); /* Plasma Seal message functions. */ -Status SendSealRequest(int sock, ObjectID object_id, unsigned char* digest); +Status SendSealRequest(const std::shared_ptr& client, + ObjectID object_id, unsigned char* digest); -Status ReadSealRequest(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadSealRequest(const uint8_t* data, size_t size, ObjectID* object_id, unsigned char* digest); -Status SendSealReply(int sock, ObjectID object_id, PlasmaError error); +Status SendSealReply(const std::shared_ptr& client, ObjectID object_id, + PlasmaError error); -Status ReadSealReply(uint8_t* data, size_t size, ObjectID* object_id); +Status ReadSealReply(const uint8_t* data, size_t size, ObjectID* object_id); /* Plasma Get message functions. */ -Status SendGetRequest(int sock, const ObjectID* object_ids, int64_t num_objects, +Status SendGetRequest(const std::shared_ptr& client, + const ObjectID* object_ids, int64_t num_objects, int64_t timeout_ms); -Status ReadGetRequest(uint8_t* data, size_t size, std::vector& object_ids, +Status ReadGetRequest(const uint8_t* data, size_t size, std::vector& object_ids, int64_t* timeout_ms); -Status SendGetReply(int sock, ObjectID object_ids[], +Status SendGetReply(const std::shared_ptr& client, + ObjectID object_ids[], std::unordered_map& plasma_objects, int64_t num_objects, const std::vector& store_fds, const std::vector& mmap_sizes); -Status ReadGetReply(uint8_t* data, size_t size, ObjectID object_ids[], +Status ReadGetReply(const uint8_t* data, size_t size, ObjectID object_ids[], PlasmaObject plasma_objects[], int64_t num_objects, std::vector& store_fds, std::vector& mmap_sizes); /* Plasma Release message functions. */ -Status SendReleaseRequest(int sock, ObjectID object_id); +Status SendReleaseRequest(const std::shared_ptr& client, + ObjectID object_id); -Status ReadReleaseRequest(uint8_t* data, size_t size, ObjectID* object_id); +Status ReadReleaseRequest(const uint8_t* data, size_t size, ObjectID* object_id); -Status SendReleaseReply(int sock, ObjectID object_id, PlasmaError error); +Status SendReleaseReply(const std::shared_ptr& client, + ObjectID object_id, PlasmaError error); -Status ReadReleaseReply(uint8_t* data, size_t size, ObjectID* object_id); +Status ReadReleaseReply(const uint8_t* data, size_t size, ObjectID* object_id); /* Plasma Delete objects message functions. */ -Status SendDeleteRequest(int sock, const std::vector& object_ids); +Status SendDeleteRequest(const std::shared_ptr& client, + const std::vector& object_ids); -Status ReadDeleteRequest(uint8_t* data, size_t size, std::vector* object_ids); +Status ReadDeleteRequest(const uint8_t* data, size_t size, + std::vector* object_ids); -Status SendDeleteReply(int sock, const std::vector& object_ids, +Status SendDeleteReply(const std::shared_ptr& client, + const std::vector& object_ids, const std::vector& errors); -Status ReadDeleteReply(uint8_t* data, size_t size, std::vector* object_ids, +Status ReadDeleteReply(const uint8_t* data, size_t size, + std::vector* object_ids, std::vector* errors); /* Plasma Constains message functions. */ -Status SendContainsRequest(int sock, ObjectID object_id); +Status SendContainsRequest(const std::shared_ptr& client, + ObjectID object_id); -Status ReadContainsRequest(uint8_t* data, size_t size, ObjectID* object_id); +Status ReadContainsRequest(const uint8_t* data, size_t size, ObjectID* object_id); -Status SendContainsReply(int sock, ObjectID object_id, bool has_object); +Status SendContainsReply(const std::shared_ptr& client, + ObjectID object_id, bool has_object); -Status ReadContainsReply(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadContainsReply(const uint8_t* data, size_t size, ObjectID* object_id, bool* has_object); /* Plasma List message functions. */ -Status SendListRequest(int sock); +Status SendListRequest(const std::shared_ptr& client); -Status ReadListRequest(uint8_t* data, size_t size); +Status ReadListRequest(const uint8_t* data, size_t size); -Status SendListReply(int sock, const ObjectTable& objects); +Status SendListReply(const std::shared_ptr& client, + const ObjectTable& objects); -Status ReadListReply(uint8_t* data, size_t size, ObjectTable* objects); +Status ReadListReply(const uint8_t* data, size_t size, ObjectTable* objects); /* Plasma Connect message functions. */ -Status SendConnectRequest(int sock); +Status SendConnectRequest(const std::shared_ptr& client); -Status ReadConnectRequest(uint8_t* data, size_t size); +Status ReadConnectRequest(const uint8_t* data, size_t size); -Status SendConnectReply(int sock, int64_t memory_capacity); +Status SendConnectReply(const std::shared_ptr& client, + int64_t memory_capacity); -Status ReadConnectReply(uint8_t* data, size_t size, int64_t* memory_capacity); +Status ReadConnectReply(const uint8_t* data, size_t size, int64_t* memory_capacity); /* Plasma Evict message functions (no reply so far). */ -Status SendEvictRequest(int sock, int64_t num_bytes); - -Status ReadEvictRequest(uint8_t* data, size_t size, int64_t* num_bytes); +Status SendEvictRequest(const std::shared_ptr& client, + int64_t num_bytes); -Status SendEvictReply(int sock, int64_t num_bytes); +Status ReadEvictRequest(const uint8_t* data, size_t size, int64_t* num_bytes); -Status ReadEvictReply(uint8_t* data, size_t size, int64_t& num_bytes); +Status SendEvictReply(const std::shared_ptr& client, int64_t num_bytes); -/* Plasma Subscribe message functions. */ - -Status SendSubscribeRequest(int sock); +Status ReadEvictReply(const uint8_t* data, size_t size, int64_t& num_bytes); /* Data messages. */ -Status SendDataRequest(int sock, ObjectID object_id, const char* address, int port); +Status SendDataRequest(const std::shared_ptr& client, + ObjectID object_id, const char* address, int port); -Status ReadDataRequest(uint8_t* data, size_t size, ObjectID* object_id, char** address, - int* port); +Status ReadDataRequest(const uint8_t* data, size_t size, ObjectID* object_id, + char** address, int* port); -Status SendDataReply(int sock, ObjectID object_id, int64_t object_size, - int64_t metadata_size); +Status SendDataReply(const std::shared_ptr& client, ObjectID object_id, + int64_t object_size, int64_t metadata_size); -Status ReadDataReply(uint8_t* data, size_t size, ObjectID* object_id, +Status ReadDataReply(const uint8_t* data, size_t size, ObjectID* object_id, int64_t* object_size, int64_t* metadata_size); +/* Plasma notification message functions. */ + +Status SendSubscribeRequest(const std::shared_ptr& client); + +void SerializeObjectDeletionNotification(const ObjectID& object_id, + std::vector* serialized); + +void SerializeObjectSealedNotification(const ObjectID& object_id, + const ObjectTableEntry& entry, + std::vector* serialized); } // namespace plasma #endif /* PLASMA_PROTOCOL */ diff --git a/cpp/src/plasma/store.cc b/cpp/src/plasma/store.cc index c574d094a98..34964fec79a 100644 --- a/cpp/src/plasma/store.cc +++ b/cpp/src/plasma/store.cc @@ -28,23 +28,16 @@ #include "plasma/store.h" -#include -#include #include -#include #include #include #include -#include -#include -#include +#include +#ifdef __linux__ #include -#include -#include -#include - +#endif +#include #include -#include #include #include #include @@ -53,13 +46,11 @@ #include #include "arrow/status.h" - +#include "arrow/util/logging.h" #include "plasma/common.h" -#include "plasma/common_generated.h" -#include "plasma/fling.h" -#include "plasma/io.h" #include "plasma/malloc.h" #include "plasma/plasma_allocator.h" +#include "plasma/plasma_generated.h" #include "plasma/protocol.h" #ifdef PLASMA_CUDA @@ -73,19 +64,68 @@ using arrow::cuda::CudaDeviceManager; using arrow::util::ArrowLog; using arrow::util::ArrowLogLevel; -namespace fb = plasma::flatbuf; - namespace plasma { +using flatbuf::MessageType; + void SetMallocGranularity(int value); struct GetRequest { - GetRequest(Client* client, const std::vector& object_ids); + GetRequest(asio::io_context& io_context, + const std::shared_ptr& client, + const std::vector& object_ids) + : client(client), + object_ids(object_ids.begin(), object_ids.end()), + objects(object_ids.size()), + num_satisfied(0), + timer_(io_context) { + std::unordered_set unique_ids(object_ids.begin(), object_ids.end()); + num_objects_to_wait_for = unique_ids.size(); + } + + void ReturnFromGet() { + // Figure out how many file descriptors we need to send. + std::unordered_set fds_to_send; + std::vector store_fds; + std::vector mmap_sizes; + for (const auto& object_id : object_ids) { + PlasmaObject& object = objects[object_id]; + int fd = object.store_fd; + if (object.data_size != -1 && fds_to_send.count(fd) == 0 && fd != -1) { + fds_to_send.insert(fd); + store_fds.push_back(fd); + mmap_sizes.push_back(GetMmapSize(fd)); + } + } + + // Send the get reply to the client. + Status s = SendGetReply(client, &object_ids[0], objects, object_ids.size(), store_fds, + mmap_sizes); + // If we successfully sent the get reply message to the client, then also send + // the file descriptors. + if (s.ok()) { + // Send all of the file descriptors for the present objects. + for (int store_fd : store_fds) { + auto status = client->SendFd(store_fd); + if (!status.ok()) { + // TODO(suquark): Should we close the client here? + ARROW_LOG(ERROR) << "Failed to send a mmap fd to client"; + } + } + } + } + + void AsyncWait(int64_t timeout_ms, + std::function on_timeout) { + // Set an expiry time relative to now. + timer_.expires_from_now(std::chrono::milliseconds(timeout_ms)); + timer_.async_wait(on_timeout); + } + + void CancelTimer() { timer_.cancel(); } + /// The client that called get. - Client* client; - /// The ID of the timer that will time out and cause this wait to return to - /// the client if it hasn't already returned. - int64_t timer; + std::shared_ptr client; /// The object IDs involved in this request. This is used in the reply. std::vector object_ids; /// The object information for the objects in this request. This is used in @@ -96,29 +136,29 @@ struct GetRequest { /// The number of object requests in this wait request that are already /// satisfied. int64_t num_satisfied; -}; -GetRequest::GetRequest(Client* client, const std::vector& object_ids) - : client(client), - timer(-1), - object_ids(object_ids.begin(), object_ids.end()), - objects(object_ids.size()), - num_satisfied(0) { - std::unordered_set unique_ids(object_ids.begin(), object_ids.end()); - num_objects_to_wait_for = unique_ids.size(); -} - -Client::Client(int fd) : fd(fd), notification_fd(-1) {} + private: + /// The timer that will time out and cause this wait to return to + /// the client if it hasn't already returned. + asio::steady_timer timer_; +}; -PlasmaStore::PlasmaStore(EventLoop* loop, std::string directory, bool hugepages_enabled, - const std::string& socket_name, +PlasmaStore::PlasmaStore(asio::io_context& io_context, std::string directory, + bool hugepages_enabled, const std::string& stream_name, std::shared_ptr external_store) - : loop_(loop), eviction_policy_(&store_info_), external_store_(external_store) { + : eviction_policy_(&store_info_), + external_store_(external_store), + io_context_(io_context), + stream_name_(stream_name), + acceptor_(io::CreateLocalAcceptor(io_context, stream_name)), + stream_(io_context) { store_info_.directory = directory; store_info_.hugepages_enabled = hugepages_enabled; #ifdef PLASMA_CUDA DCHECK_OK(CudaDeviceManager::GetInstance(&manager_)); #endif + // Start listening for clients. + DoAccept(); } // TODO(pcm): Get rid of this destructor by using RAII to clean up data. @@ -129,22 +169,12 @@ const PlasmaStoreInfo* PlasmaStore::GetPlasmaStoreInfo() { return &store_info_; // If this client is not already using the object, add the client to the // object's list of clients, otherwise do nothing. void PlasmaStore::AddToClientObjectIds(const ObjectID& object_id, ObjectTableEntry* entry, - Client* client) { + const std::shared_ptr& client) { // Check if this client is already using the object. - if (client->object_ids.find(object_id) != client->object_ids.end()) { + if (client->ObjectIDExists(object_id)) { return; } - // If there are no other clients using this object, notify the eviction policy - // that the object is being used. - if (entry->ref_count == 0) { - // Tell the eviction policy that this object is being used. - std::vector objects_to_evict; - eviction_policy_.BeginObjectAccess(object_id, &objects_to_evict); - EvictObjects(objects_to_evict); - } - // Increase reference count. - entry->ref_count++; - + IncreaseObjectRefCount(object_id, entry); // Add object id to the list of object ids that this client is using. client->object_ids.insert(object_id); } @@ -206,7 +236,8 @@ Status PlasmaStore::FreeCudaMemory(int device_num, int64_t size, uint8_t* pointe // Create a new object buffer in the hash table. PlasmaError PlasmaStore::CreateObject(const ObjectID& object_id, int64_t data_size, int64_t metadata_size, int device_num, - Client* client, PlasmaObject* result) { + const std::shared_ptr& client, + PlasmaObject* result) { ARROW_LOG(DEBUG) << "creating object " << object_id.hex(); auto entry = GetObjectTableEntry(&store_info_, object_id); @@ -311,13 +342,12 @@ void PlasmaStore::RemoveGetRequest(GetRequest* get_request) { } } // Remove the get request. - if (get_request->timer != -1) { - ARROW_CHECK(loop_->RemoveTimer(get_request->timer) == kEventLoopOk); - } + get_request->CancelTimer(); delete get_request; } -void PlasmaStore::RemoveGetRequestsForClient(Client* client) { +void PlasmaStore::RemoveGetRequestsForClient( + const std::shared_ptr& client) { std::unordered_set get_requests_to_remove; for (auto const& pair : object_get_requests_) { for (GetRequest* get_request : pair.second) { @@ -336,38 +366,7 @@ void PlasmaStore::RemoveGetRequestsForClient(Client* client) { } void PlasmaStore::ReturnFromGet(GetRequest* get_req) { - // Figure out how many file descriptors we need to send. - std::unordered_set fds_to_send; - std::vector store_fds; - std::vector mmap_sizes; - for (const auto& object_id : get_req->object_ids) { - PlasmaObject& object = get_req->objects[object_id]; - int fd = object.store_fd; - if (object.data_size != -1 && fds_to_send.count(fd) == 0 && fd != -1) { - fds_to_send.insert(fd); - store_fds.push_back(fd); - mmap_sizes.push_back(GetMmapSize(fd)); - } - } - - // Send the get reply to the client. - Status s = SendGetReply(get_req->client->fd, &get_req->object_ids[0], get_req->objects, - get_req->object_ids.size(), store_fds, mmap_sizes); - WarnIfSigpipe(s.ok() ? 0 : -1, get_req->client->fd); - // If we successfully sent the get reply message to the client, then also send - // the file descriptors. - if (s.ok()) { - // Send all of the file descriptors for the present objects. - for (int store_fd : store_fds) { - // Only send the file descriptor if it hasn't been sent (see analogous - // logic in GetStoreFd in client.cc). - if (get_req->client->used_fds.find(store_fd) == get_req->client->used_fds.end()) { - WarnIfSigpipe(send_fd(get_req->client->fd, store_fd), get_req->client->fd); - get_req->client->used_fds.insert(store_fd); - } - } - } - + get_req->ReturnFromGet(); // Remove the get request from each of the relevant object_get_requests hash // tables if it is present there. It should only be present there if the get // request timed out. @@ -418,11 +417,11 @@ void PlasmaStore::UpdateObjectGetRequests(const ObjectID& object_id) { } } -void PlasmaStore::ProcessGetRequest(Client* client, - const std::vector& object_ids, - int64_t timeout_ms) { +Status PlasmaStore::ProcessGetRequest(const std::shared_ptr& client, + const std::vector& object_ids, + int64_t timeout_ms) { // Create a get request for this object. - auto get_req = new GetRequest(client, object_ids); + auto get_req = new GetRequest(io_context_, client, object_ids); std::vector evicted_ids; std::vector evicted_entries; for (auto object_id : object_ids) { @@ -499,42 +498,14 @@ void PlasmaStore::ProcessGetRequest(Client* client, } else if (timeout_ms != -1) { // Set a timer that will cause the get request to return to the client. Note // that a timeout of -1 is used to indicate that no timer should be set. - get_req->timer = loop_->AddTimer(timeout_ms, [this, get_req](int64_t timer_id) { - ReturnFromGet(get_req); - return kEventLoopTimerDone; - }); - } -} - -int PlasmaStore::RemoveFromClientObjectIds(const ObjectID& object_id, - ObjectTableEntry* entry, Client* client) { - auto it = client->object_ids.find(object_id); - if (it != client->object_ids.end()) { - client->object_ids.erase(it); - // Decrease reference count. - entry->ref_count--; - - // If no more clients are using this object, notify the eviction policy - // that the object is no longer being used. - if (entry->ref_count == 0) { - if (deletion_cache_.count(object_id) == 0) { - // Tell the eviction policy that this object is no longer being used. - std::vector objects_to_evict; - eviction_policy_.EndObjectAccess(object_id, &objects_to_evict); - EvictObjects(objects_to_evict); - } else { - // Above code does not really delete an object. Instead, it just put an - // object to LRU cache which will be cleaned when the memory is not enough. - deletion_cache_.erase(object_id); - EvictObjects({object_id}); + get_req->AsyncWait(timeout_ms, [this, get_req](const error_code& ec) { + if (ec != asio::error::operation_aborted) { + // Timer was not cancelled, take necessary action. + ReturnFromGet(get_req); } - } - // Return 1 to indicate that the client was removed. - return 1; - } else { - // Return 0 to indicate that the client was not removed. - return 0; + }); } + return Status::OK(); } void PlasmaStore::EraseFromObjectTable(const ObjectID& object_id) { @@ -550,11 +521,13 @@ void PlasmaStore::EraseFromObjectTable(const ObjectID& object_id) { store_info_.objects.erase(object_id); } -void PlasmaStore::ReleaseObject(const ObjectID& object_id, Client* client) { +void PlasmaStore::ReleaseObject(const ObjectID& object_id, + const std::shared_ptr& client) { + // Remove the client from the object's array of clients. + ARROW_CHECK(client->RemoveObjectIDIfExists(object_id)); auto entry = GetObjectTableEntry(&store_info_, object_id); ARROW_CHECK(entry != nullptr); - // Remove the client from the object's array of clients. - ARROW_CHECK(RemoveFromClientObjectIds(object_id, entry, client) == 1); + DecreaseObjectRefCount(object_id, entry); } // Check if an object is present. @@ -580,18 +553,13 @@ void PlasmaStore::SealObject(const ObjectID& object_id, unsigned char digest[]) entry->construct_duration = std::time(nullptr) - entry->create_time; // Inform all subscribers that a new object has been sealed. - ObjectInfoT info; - info.object_id = object_id.binary(); - info.data_size = entry->data_size; - info.metadata_size = entry->metadata_size; - info.digest = std::string(reinterpret_cast(&digest[0]), kDigestSize); - PushNotification(&info); - + PushObjectReadyNotification(object_id, *entry); // Update all get requests that involve this object. UpdateObjectGetRequests(object_id); } -int PlasmaStore::AbortObject(const ObjectID& object_id, Client* client) { +int PlasmaStore::AbortObject(const ObjectID& object_id, + const std::shared_ptr& client) { auto entry = GetObjectTableEntry(&store_info_, object_id); ARROW_CHECK(entry != nullptr) << "To abort an object it must be in the object table."; ARROW_CHECK(entry->state != ObjectState::PLASMA_SEALED) @@ -636,11 +604,7 @@ PlasmaError PlasmaStore::DeleteObject(ObjectID& object_id) { eviction_policy_.RemoveObject(object_id); EraseFromObjectTable(object_id); // Inform all subscribers that the object has been deleted. - fb::ObjectInfoT notification; - notification.object_id = object_id.binary(); - notification.is_deletion = true; - PushNotification(¬ification); - + PushObjectDeletionNotification(object_id); return PlasmaError::OK; } @@ -671,10 +635,7 @@ void PlasmaStore::EvictObjects(const std::vector& object_ids) { // and send a deletion notification. EraseFromObjectTable(object_id); // Inform all subscribers that the object has been deleted. - fb::ObjectInfoT notification; - notification.object_id = object_id.binary(); - notification.is_deletion = true; - PushNotification(¬ification); + PushObjectDeletionNotification(object_id); } } @@ -688,33 +649,107 @@ void PlasmaStore::EvictObjects(const std::vector& object_ids) { } } -void PlasmaStore::ConnectClient(int listener_sock) { - int client_fd = AcceptClient(listener_sock); +void PlasmaStore::IncreaseObjectRefCount(const ObjectID& object_id, + ObjectTableEntry* entry) { + // If there are no other clients using this object, notify the eviction policy + // that the object is being used. + if (entry->ref_count == 0) { + // Tell the eviction policy that this object is being used. + std::vector objects_to_evict; + eviction_policy_.BeginObjectAccess(object_id, &objects_to_evict); + EvictObjects(objects_to_evict); + } + // Increase reference count. + entry->ref_count++; +} + +void PlasmaStore::DecreaseObjectRefCount(const ObjectID& object_id, + ObjectTableEntry* entry) { + // Decrease reference count. + entry->ref_count--; + + // If no more clients are using this object, notify the eviction policy + // that the object is no longer being used. + if (entry->ref_count == 0) { + if (deletion_cache_.count(object_id) == 0) { + // Tell the eviction policy that this object is no longer being used. + std::vector objects_to_evict; + eviction_policy_.EndObjectAccess(object_id, &objects_to_evict); + EvictObjects(objects_to_evict); + } else { + // Above code does not really delete an object. Instead, it just put an + // object to LRU cache which will be cleaned when the memory is not enough. + deletion_cache_.erase(object_id); + EvictObjects({object_id}); + } + } +} + +void PlasmaStore::PushObjectReadyNotification(const ObjectID& object_id, + const ObjectTableEntry& entry) { + for (const auto& client : notification_clients_) { + client->SendObjectReadyAsync(object_id, entry); + } +} + +void PlasmaStore::PushObjectDeletionNotification(const ObjectID& object_id) { + for (const auto& client : notification_clients_) { + client->SendObjectDeletionAsync(object_id); + } +} + +// Subscribe to notifications about sealed objects. +void PlasmaStore::SubscribeToUpdates(const std::shared_ptr& client) { + ARROW_LOG(DEBUG) << "subscribing to updates on fd " << client->GetNativeHandle(); + if (notification_clients_.count(client) > 0) { + // This client has already subscribed. Return. + return; + } - Client* client = new Client(client_fd); - connected_clients_[client_fd] = std::unique_ptr(client); + // Add this client to the notification set, which is needed for this client to receive + // notifications. + notification_clients_.insert(client); - // Add a callback to handle events on this socket. - // TODO(pcm): Check return value. - loop_->AddFileEvent(client_fd, kEventLoopRead, [this, client](int events) { - Status s = ProcessMessage(client); - if (!s.ok()) { - ARROW_LOG(FATAL) << "Failed to process file event: " << s; + // Push notifications to the new subscriber about existing sealed objects. + for (const auto& entry : store_info_.objects) { + if (entry.second->state == ObjectState::PLASMA_SEALED) { + client->SendObjectReadyAsync(entry.first, *entry.second); } - }); - ARROW_LOG(DEBUG) << "New connection with fd " << client_fd; + } +} + +void PlasmaStore::DoAccept() { + // TODO(suquark): Use shared_from_this() here ? + acceptor_.async_accept(stream_, + [this](const error_code& ec) { HandleAccept(ec); }); +} + +void PlasmaStore::HandleAccept(const error_code& error) { + if (!error) { + io::MessageHandler message_handler = [this](std::shared_ptr client, + int64_t message_type, int64_t length, + const uint8_t* message) { + Status s = ProcessClientMessage(client, message_type, length, message); + if (!s.ok()) { + ARROW_LOG(ERROR) << "[PlasmaStore] Failed to process the event" + << "(type=" << message_type << "): " << s << ", " + << "fd = " << client->GetNativeHandle(); + } + }; + // Accept a new local client and dispatch it to the store. + auto new_connection = ClientConnection::Create(std::move(stream_), message_handler); + // Insert the client before processing messages. + connected_clients_.insert(new_connection); + // Process our new connection. + new_connection->ProcessMessages(); + } + // We're ready to accept another client. + DoAccept(); } -void PlasmaStore::DisconnectClient(int client_fd) { - ARROW_CHECK(client_fd > 0); - auto it = connected_clients_.find(client_fd); - ARROW_CHECK(it != connected_clients_.end()); - loop_->RemoveFileEvent(client_fd); - // Close the socket. - close(client_fd); - ARROW_LOG(INFO) << "Disconnecting client on fd " << client_fd; +void PlasmaStore::ReleaseClientResources( + const std::shared_ptr& client) { // Release all the objects that the client was using. - auto client = it->second.get(); std::unordered_map sealed_objects; for (const auto& object_id : client->object_ids) { auto it = store_info_.objects.find(object_id); @@ -737,193 +772,86 @@ void PlasmaStore::DisconnectClient(int client_fd) { RemoveGetRequestsForClient(client); for (const auto& entry : sealed_objects) { - RemoveFromClientObjectIds(entry.first, entry.second, client); - } - - if (client->notification_fd > 0) { - // This client has subscribed for notifications. - auto notify_fd = client->notification_fd; - loop_->RemoveFileEvent(notify_fd); - // Close socket. - close(notify_fd); - // Remove notification queue for this fd from global map. - pending_notifications_.erase(notify_fd); - // Reset fd. - client->notification_fd = -1; - } - - connected_clients_.erase(it); -} - -/// Send notifications about sealed objects to the subscribers. This is called -/// in SealObject. If the socket's send buffer is full, the notification will -/// be buffered, and this will be called again when the send buffer has room. -/// Since we call erase on pending_notifications_, all iterators get -/// invalidated, which is why we return a valid iterator to the next client to -/// be used in PushNotification. -/// -/// @param it Iterator that points to the client to send the notification to. -/// @return Iterator pointing to the next client. -PlasmaStore::NotificationMap::iterator PlasmaStore::SendNotifications( - PlasmaStore::NotificationMap::iterator it) { - int client_fd = it->first; - auto& notifications = it->second.object_notifications; - - int num_processed = 0; - bool closed = false; - // Loop over the array of pending notifications and send as many of them as - // possible. - for (size_t i = 0; i < notifications.size(); ++i) { - auto& notification = notifications.at(i); - // Decode the length, which is the first bytes of the message. - int64_t size = *(reinterpret_cast(notification.get())); - - // Attempt to send a notification about this object ID. - ssize_t nbytes = send(client_fd, notification.get(), sizeof(int64_t) + size, 0); - if (nbytes >= 0) { - ARROW_CHECK(nbytes == static_cast(sizeof(int64_t)) + size); - } else if (nbytes == -1 && - (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) { - ARROW_LOG(DEBUG) << "The socket's send buffer is full, so we are caching this " - "notification and will send it later."; - // Add a callback to the event loop to send queued notifications whenever - // there is room in the socket's send buffer. Callbacks can be added - // more than once here and will be overwritten. The callback is removed - // at the end of the method. - // TODO(pcm): Introduce status codes and check in case the file descriptor - // is added twice. - loop_->AddFileEvent(client_fd, kEventLoopWrite, [this, client_fd](int events) { - SendNotifications(pending_notifications_.find(client_fd)); - }); - break; - } else { - ARROW_LOG(WARNING) << "Failed to send notification to client on fd " << client_fd; - if (errno == EPIPE) { - closed = true; - break; - } - } - num_processed += 1; - } - // Remove the sent notifications from the array. - notifications.erase(notifications.begin(), notifications.begin() + num_processed); - - // If we have sent all notifications, remove the fd from the event loop. - if (notifications.empty()) { - loop_->RemoveFileEvent(client_fd); - } - - // Stop sending notifications if the pipe was broken. - if (closed) { - close(client_fd); - return pending_notifications_.erase(it); - } else { - return ++it; + // The object ID must exist in client's record. + client->RemoveObjectID(entry.first); + DecreaseObjectRefCount(entry.first, entry.second); } } -void PlasmaStore::PushNotification(fb::ObjectInfoT* object_info) { - auto it = pending_notifications_.begin(); - while (it != pending_notifications_.end()) { - auto notification = CreateObjectInfoBuffer(object_info); - it->second.object_notifications.emplace_back(std::move(notification)); - it = SendNotifications(it); - } -} - -void PlasmaStore::PushNotification(fb::ObjectInfoT* object_info, int client_fd) { - auto it = pending_notifications_.find(client_fd); - if (it != pending_notifications_.end()) { - auto notification = CreateObjectInfoBuffer(object_info); - it->second.object_notifications.emplace_back(std::move(notification)); - SendNotifications(it); - } -} - -// Subscribe to notifications about sealed objects. -void PlasmaStore::SubscribeToUpdates(Client* client) { - ARROW_LOG(DEBUG) << "subscribing to updates on fd " << client->fd; - if (client->notification_fd > 0) { - // This client has already subscribed. Return. +void PlasmaStore::ProcessDisconnectClient( + const std::shared_ptr& client) { + if (!client->IsOpen()) { + ARROW_LOG(ERROR) << "Received disconnection request from a disconnected client."; return; } - - // TODO(rkn): The store could block here if the client doesn't send a file - // descriptor. - int fd = recv_fd(client->fd); - if (fd < 0) { - // This may mean that the client died before sending the file descriptor. - ARROW_LOG(WARNING) << "Failed to receive file descriptor from client on fd " - << client->fd << "."; + // Close the client. + ARROW_LOG(INFO) << "Disconnecting client on fd " << client->GetNativeHandle(); + client->Close(); + + // Remove the client from the connection set. + auto it = connected_clients_.find(client); + if (it == connected_clients_.end()) { + ARROW_LOG(FATAL) << "[PlasmaStore] (on DisconnectClient) Unexpected error: The " + << "client to disconnect is not in the connected clients list."; return; } - - // Add this fd to global map, which is needed for this client to receive notifications. - pending_notifications_[fd]; - client->notification_fd = fd; - - // Push notifications to the new subscriber about existing sealed objects. - for (const auto& entry : store_info_.objects) { - if (entry.second->state == ObjectState::PLASMA_SEALED) { - ObjectInfoT info; - info.object_id = entry.first.binary(); - info.data_size = entry.second->data_size; - info.metadata_size = entry.second->metadata_size; - info.digest = - std::string(reinterpret_cast(&entry.second->digest[0]), kDigestSize); - PushNotification(&info, fd); - } + connected_clients_.erase(it); + // Remove the client from the notification set. + if (notification_clients_.count(client) > 0) { + notification_clients_.erase(client); } -} -Status PlasmaStore::ProcessMessage(Client* client) { - fb::MessageType type; - Status s = ReadMessage(client->fd, &type, &input_buffer_); - ARROW_CHECK(s.ok() || s.IsIOError()); + // Release resources. + ReleaseClientResources(client); +} - uint8_t* input = input_buffer_.data(); - size_t input_size = input_buffer_.size(); +Status PlasmaStore::ProcessClientMessage(const std::shared_ptr& client, + int64_t message_type, int64_t message_size, + const uint8_t* message_data) { + auto message_type_value = static_cast(message_type); ObjectID object_id; - PlasmaObject object = {}; // Process the different types of requests. - switch (type) { - case fb::MessageType::PlasmaCreateRequest: { + switch (message_type_value) { + case MessageType::PlasmaCreateRequest: { int64_t data_size; int64_t metadata_size; int device_num; - RETURN_NOT_OK(ReadCreateRequest(input, input_size, &object_id, &data_size, + RETURN_NOT_OK(ReadCreateRequest(message_data, message_size, &object_id, &data_size, &metadata_size, &device_num)); + PlasmaObject object = {}; PlasmaError error_code = CreateObject(object_id, data_size, metadata_size, device_num, client, &object); int64_t mmap_size = 0; if (error_code == PlasmaError::OK && device_num == 0) { mmap_size = GetMmapSize(object.store_fd); } - HANDLE_SIGPIPE( - SendCreateReply(client->fd, object_id, &object, error_code, mmap_size), - client->fd); + RETURN_NOT_OK(SendCreateReply(client, object_id, &object, error_code, mmap_size)); // Only send the file descriptor if it hasn't been sent (see analogous // logic in GetStoreFd in client.cc). Similar in ReturnFromGet. - if (error_code == PlasmaError::OK && device_num == 0 && - client->used_fds.find(object.store_fd) == client->used_fds.end()) { - WarnIfSigpipe(send_fd(client->fd, object.store_fd), client->fd); - client->used_fds.insert(object.store_fd); + if (error_code == PlasmaError::OK && device_num == 0) { + auto status = client->SendFd(object.store_fd); + if (!status.ok()) { + // TODO(suquark): Should we close the client here? + ARROW_LOG(ERROR) << "[PlasmaStore] (on CreateRequest) Failed to send a mmap fd" + << " to the client."; + } } } break; - case fb::MessageType::PlasmaCreateAndSealRequest: { + case MessageType::PlasmaCreateAndSealRequest: { std::string data; std::string metadata; unsigned char digest[kDigestSize]; - RETURN_NOT_OK(ReadCreateAndSealRequest(input, input_size, &object_id, &data, - &metadata, &digest[0])); + RETURN_NOT_OK(ReadCreateAndSealRequest(message_data, message_size, &object_id, + &data, &metadata, &digest[0])); + PlasmaObject object = {}; // CreateAndSeal currently only supports device_num = 0, which corresponds // to the host. int device_num = 0; PlasmaError error_code = CreateObject(object_id, data.size(), metadata.size(), device_num, client, &object); // Reply to the client. - HANDLE_SIGPIPE(SendCreateAndSealReply(client->fd, error_code), client->fd); + RETURN_NOT_OK(SendCreateAndSealReply(client, error_code)); // If the object was successfully created, fill out the object data and seal it. if (error_code == PlasmaError::OK) { @@ -937,78 +865,78 @@ Status PlasmaStore::ProcessMessage(Client* client) { // object is not being used by any client. The client was added to the // object's array of clients in CreateObject. This is analogous to the // Release call that happens in the client's Seal method. - ARROW_CHECK(RemoveFromClientObjectIds(object_id, entry, client) == 1); + ARROW_CHECK(client->RemoveObjectIDIfExists(object_id)); + DecreaseObjectRefCount(object_id, entry); } } break; - case fb::MessageType::PlasmaAbortRequest: { - RETURN_NOT_OK(ReadAbortRequest(input, input_size, &object_id)); - ARROW_CHECK(AbortObject(object_id, client) == 1) << "To abort an object, the only " - "client currently using it " - "must be the creator."; - HANDLE_SIGPIPE(SendAbortReply(client->fd, object_id), client->fd); + case MessageType::PlasmaAbortRequest: { + RETURN_NOT_OK(ReadAbortRequest(message_data, message_size, &object_id)); + if (AbortObject(object_id, client) != 1) { + ARROW_LOG(ERROR) << "[PlasmaStore] (on AbortRequest) To abort an object, the " + << "only client currently using it must be the creator."; + } + RETURN_NOT_OK(SendAbortReply(client, object_id)); } break; - case fb::MessageType::PlasmaGetRequest: { - std::vector object_ids_to_get; + case MessageType::PlasmaGetRequest: { + std::vector object_ids; int64_t timeout_ms; - RETURN_NOT_OK(ReadGetRequest(input, input_size, object_ids_to_get, &timeout_ms)); - ProcessGetRequest(client, object_ids_to_get, timeout_ms); + RETURN_NOT_OK(ReadGetRequest(message_data, message_size, object_ids, &timeout_ms)); + RETURN_NOT_OK(ProcessGetRequest(client, object_ids, timeout_ms)); } break; - case fb::MessageType::PlasmaReleaseRequest: { - RETURN_NOT_OK(ReadReleaseRequest(input, input_size, &object_id)); + case MessageType::PlasmaReleaseRequest: { + RETURN_NOT_OK(ReadReleaseRequest(message_data, message_size, &object_id)); ReleaseObject(object_id, client); } break; - case fb::MessageType::PlasmaDeleteRequest: { + case MessageType::PlasmaDeleteRequest: { std::vector object_ids; std::vector error_codes; - RETURN_NOT_OK(ReadDeleteRequest(input, input_size, &object_ids)); + RETURN_NOT_OK(ReadDeleteRequest(message_data, message_size, &object_ids)); error_codes.reserve(object_ids.size()); for (auto& object_id : object_ids) { error_codes.push_back(DeleteObject(object_id)); } - HANDLE_SIGPIPE(SendDeleteReply(client->fd, object_ids, error_codes), client->fd); + RETURN_NOT_OK(SendDeleteReply(client, object_ids, error_codes)); } break; - case fb::MessageType::PlasmaContainsRequest: { - RETURN_NOT_OK(ReadContainsRequest(input, input_size, &object_id)); - if (ContainsObject(object_id) == ObjectStatus::OBJECT_FOUND) { - HANDLE_SIGPIPE(SendContainsReply(client->fd, object_id, 1), client->fd); - } else { - HANDLE_SIGPIPE(SendContainsReply(client->fd, object_id, 0), client->fd); - } + case MessageType::PlasmaContainsRequest: { + RETURN_NOT_OK(ReadContainsRequest(message_data, message_size, &object_id)); + auto has_object = (ContainsObject(object_id) == ObjectStatus::OBJECT_FOUND); + RETURN_NOT_OK(SendContainsReply(client, object_id, has_object)); } break; - case fb::MessageType::PlasmaListRequest: { - RETURN_NOT_OK(ReadListRequest(input, input_size)); - HANDLE_SIGPIPE(SendListReply(client->fd, store_info_.objects), client->fd); + case MessageType::PlasmaListRequest: { + RETURN_NOT_OK(ReadListRequest(message_data, message_size)); + RETURN_NOT_OK(SendListReply(client, store_info_.objects)); } break; - case fb::MessageType::PlasmaSealRequest: { + case MessageType::PlasmaSealRequest: { unsigned char digest[kDigestSize]; - RETURN_NOT_OK(ReadSealRequest(input, input_size, &object_id, &digest[0])); + RETURN_NOT_OK(ReadSealRequest(message_data, message_size, &object_id, &digest[0])); SealObject(object_id, &digest[0]); } break; - case fb::MessageType::PlasmaEvictRequest: { + case MessageType::PlasmaEvictRequest: { // This code path should only be used for testing. int64_t num_bytes; - RETURN_NOT_OK(ReadEvictRequest(input, input_size, &num_bytes)); + RETURN_NOT_OK(ReadEvictRequest(message_data, message_size, &num_bytes)); std::vector objects_to_evict; int64_t num_bytes_evicted = eviction_policy_.ChooseObjectsToEvict(num_bytes, &objects_to_evict); EvictObjects(objects_to_evict); - HANDLE_SIGPIPE(SendEvictReply(client->fd, num_bytes_evicted), client->fd); + RETURN_NOT_OK(SendEvictReply(client, num_bytes_evicted)); } break; - case fb::MessageType::PlasmaSubscribeRequest: + case MessageType::PlasmaSubscribeRequest: SubscribeToUpdates(client); break; - case fb::MessageType::PlasmaConnectRequest: { - HANDLE_SIGPIPE(SendConnectReply(client->fd, PlasmaAllocator::GetFootprintLimit()), - client->fd); + case MessageType::PlasmaConnectRequest: { + RETURN_NOT_OK(SendConnectReply(client, PlasmaAllocator::GetFootprintLimit())); } break; - case fb::MessageType::PlasmaDisconnectClient: - ARROW_LOG(DEBUG) << "Disconnecting client on fd " << client->fd; - DisconnectClient(client->fd); - break; + case MessageType::PlasmaDisconnectClient: + ARROW_LOG(DEBUG) << "Disconnecting client on fd " << client->GetNativeHandle(); + ProcessDisconnectClient(client); + return Status::OK(); // Stop listening for more messages. default: // This code should be unreachable. ARROW_CHECK(0); } + // Listen for more messages. + client->ProcessMessages(); return Status::OK(); } @@ -1016,11 +944,16 @@ class PlasmaStoreRunner { public: PlasmaStoreRunner() {} - void Start(char* socket_name, std::string directory, bool hugepages_enabled, - std::shared_ptr external_store) { + void Start(const std::string& stream_name, std::string directory, + bool hugepages_enabled, std::shared_ptr external_store) { + signal_set_.async_wait([this](std::error_code ec, int signal) { + if (signal == SIGTERM) { + ARROW_LOG(INFO) << "SIGTERM Signal received, closing Plasma Server..."; + Stop(); + } + }); // Create the event loop. - loop_.reset(new EventLoop); - store_.reset(new PlasmaStore(loop_.get(), directory, hugepages_enabled, socket_name, + store_.reset(new PlasmaStore(io_context_, directory, hugepages_enabled, stream_name, external_store)); plasma_config = store_->GetPlasmaStoreInfo(); @@ -1028,7 +961,7 @@ class PlasmaStoreRunner { // large amount of space up front. According to the documentation, // dlmalloc might need up to 128*sizeof(size_t) bytes for internal // bookkeeping. - void* pointer = plasma::PlasmaAllocator::Memalign( + void* pointer = PlasmaAllocator::Memalign( kBlockSize, PlasmaAllocator::GetFootprintLimit() - 256 * sizeof(size_t)); ARROW_CHECK(pointer != nullptr); // This will unmap the file, but the next one created will be as large @@ -1036,57 +969,33 @@ class PlasmaStoreRunner { plasma::PlasmaAllocator::Free( pointer, PlasmaAllocator::GetFootprintLimit() - 256 * sizeof(size_t)); - int socket = BindIpcSock(socket_name, true); - // TODO(pcm): Check return value. - ARROW_CHECK(socket >= 0); - - loop_->AddFileEvent(socket, kEventLoopRead, [this, socket](int events) { - this->store_->ConnectClient(socket); - }); - loop_->Start(); + io_context_.run(); } - void Stop() { loop_->Stop(); } + void Stop() { io_context_.stop(); } void Shutdown() { - loop_->Shutdown(); - loop_ = nullptr; + io_context_.stop(); store_ = nullptr; } private: - std::unique_ptr loop_; + asio::io_context io_context_; + asio::signal_set signal_set_{io_context_, SIGTERM}; + // Ignore SIGPIPE signals. If we don't do this, then when we attempt to write + // to a client that has already died, the store could die. + asio::signal_set signal_ign_{io_context_, SIGPIPE}; std::unique_ptr store_; }; static std::unique_ptr g_runner = nullptr; -void HandleSignal(int signal) { - if (signal == SIGTERM) { - ARROW_LOG(INFO) << "SIGTERM Signal received, closing Plasma Server..."; - if (g_runner != nullptr) { - g_runner->Stop(); - } - } -} - -void StartServer(char* socket_name, std::string plasma_directory, bool hugepages_enabled, - std::shared_ptr external_store) { - // Ignore SIGPIPE signals. If we don't do this, then when we attempt to write - // to a client that has already died, the store could die. - signal(SIGPIPE, SIG_IGN); - - g_runner.reset(new PlasmaStoreRunner()); - signal(SIGTERM, HandleSignal); - g_runner->Start(socket_name, plasma_directory, hugepages_enabled, external_store); -} - } // namespace plasma int main(int argc, char* argv[]) { ArrowLog::StartArrowLog(argv[0], ArrowLogLevel::ARROW_INFO); ArrowLog::InstallFailureSignalHandler(); - char* socket_name = nullptr; + char* stream_name = nullptr; // Directory where plasma memory mapped files are stored. std::string plasma_directory; std::string external_store_endpoint; @@ -1105,7 +1014,7 @@ int main(int argc, char* argv[]) { hugepages_enabled = true; break; case 's': - socket_name = optarg; + stream_name = optarg; break; case 'm': { char extra; @@ -1123,7 +1032,7 @@ int main(int argc, char* argv[]) { } } // Sanity check command line options. - if (!socket_name) { + if (!stream_name) { ARROW_LOG(FATAL) << "please specify socket for incoming connections with -s switch"; } if (system_memory == -1) { @@ -1184,8 +1093,10 @@ int main(int argc, char* argv[]) { ARROW_LOG(DEBUG) << "connecting to external store..."; ARROW_CHECK_OK(external_store->Connect(external_store_endpoint)); } - ARROW_LOG(DEBUG) << "starting server listening on " << socket_name; - plasma::StartServer(socket_name, plasma_directory, hugepages_enabled, external_store); + ARROW_LOG(DEBUG) << "starting server listening on " << stream_name; + plasma::g_runner.reset(new plasma::PlasmaStoreRunner()); + plasma::g_runner->Start(stream_name, plasma_directory, hugepages_enabled, + external_store); plasma::g_runner->Shutdown(); plasma::g_runner = nullptr; diff --git a/cpp/src/plasma/store.h b/cpp/src/plasma/store.h index 26b49f02e72..af84285a970 100644 --- a/cpp/src/plasma/store.h +++ b/cpp/src/plasma/store.h @@ -18,7 +18,6 @@ #ifndef PLASMA_STORE_H #define PLASMA_STORE_H -#include #include #include #include @@ -26,11 +25,10 @@ #include #include "plasma/common.h" -#include "plasma/events.h" #include "plasma/eviction_policy.h" #include "plasma/external_store.h" +#include "plasma/io/connection.h" #include "plasma/plasma.h" -#include "plasma/protocol.h" namespace arrow { class Status; @@ -39,46 +37,18 @@ class Status; namespace plasma { namespace flatbuf { -struct ObjectInfoT; enum class PlasmaError; } // namespace flatbuf -using flatbuf::ObjectInfoT; using flatbuf::PlasmaError; +using io::ClientConnection; struct GetRequest; -struct NotificationQueue { - /// The object notifications for clients. We notify the client about the - /// objects in the order that the objects were sealed or deleted. - std::deque> object_notifications; -}; - -/// Contains all information that is associated with a Plasma store client. -struct Client { - explicit Client(int fd); - - /// The file descriptor used to communicate with the client. - int fd; - - /// Object ids that are used by this client. - std::unordered_set object_ids; - - /// File descriptors that are used by this client. - std::unordered_set used_fds; - - /// The file descriptor used to push notifications to client. This is only valid - /// if client subscribes to plasma store. -1 indicates invalid. - int notification_fd; -}; - class PlasmaStore { public: - using NotificationMap = std::unordered_map; - - // TODO: PascalCase PlasmaStore methods. - PlasmaStore(EventLoop* loop, std::string directory, bool hugepages_enabled, - const std::string& socket_name, + PlasmaStore(asio::io_context& main_context, std::string directory, + bool hugepages_enabled, const std::string& stream_name, std::shared_ptr external_store); ~PlasmaStore(); @@ -89,17 +59,17 @@ class PlasmaStore { /// Create a new object. The client must do a call to release_object to tell /// the store when it is done with the object. /// - /// @param object_id Object ID of the object to be created. - /// @param data_size Size in bytes of the object to be created. - /// @param metadata_size Size in bytes of the object metadata. - /// @param device_num The number of the device where the object is being + /// \param object_id Object ID of the object to be created. + /// \param data_size Size in bytes of the object to be created. + /// \param metadata_size Size in bytes of the object metadata. + /// \param device_num The number of the device where the object is being /// created. /// device_num = 0 corresponds to the host, /// device_num = 1 corresponds to GPU0, /// device_num = 2 corresponds to GPU1, etc. - /// @param client The client that created the object. - /// @param result The object that has been created. - /// @return One of the following error codes: + /// \param client The client that created the object. + /// \param result The object that has been created. + /// \return One of the following error codes: /// - PlasmaError::OK, if the object was created successfully. /// - PlasmaError::ObjectExists, if an object with this ID is already /// present in the store. In this case, the client should not call @@ -108,22 +78,24 @@ class PlasmaStore { /// cannot create the object. In this case, the client should not call /// plasma_release. PlasmaError CreateObject(const ObjectID& object_id, int64_t data_size, - int64_t metadata_size, int device_num, Client* client, + int64_t metadata_size, int device_num, + const std::shared_ptr& client, PlasmaObject* result); /// Abort a created but unsealed object. If the client is not the /// creator, then the abort will fail. /// - /// @param object_id Object ID of the object to be aborted. - /// @param client The client who created the object. If this does not + /// \param object_id Object ID of the object to be aborted. + /// \param client The client who created the object. If this does not /// match the creator of the object, then the abort will fail. - /// @return 1 if the abort succeeds, else 0. - int AbortObject(const ObjectID& object_id, Client* client); + /// \return 1 if the abort succeeds, else 0. + int AbortObject(const ObjectID& object_id, + const std::shared_ptr& client); /// Delete an specific object by object_id that have been created in the hash table. /// - /// @param object_id Object ID of the object to be deleted. - /// @return One of the following error codes: + /// \param object_id Object ID of the object to be deleted. + /// \return One of the following error codes: /// - PlasmaError::OK, if the object was delete successfully. /// - PlasmaError::ObjectNonexistent, if ths object isn't existed. /// - PlasmaError::ObjectInUse, if the object is in use. @@ -131,7 +103,7 @@ class PlasmaStore { /// Evict objects returned by the eviction policy. /// - /// @param object_ids Object IDs of the objects to be evicted. + /// \param object_ids Object IDs of the objects to be evicted. void EvictObjects(const std::vector& object_ids); /// Process a get request from a client. This method assumes that we will @@ -142,79 +114,76 @@ class PlasmaStore { /// For each object, the client must do a call to release_object to tell the /// store when it is done with the object. /// - /// @param client The client making this request. - /// @param object_ids Object IDs of the objects to be gotten. - /// @param timeout_ms The timeout for the get request in milliseconds. - void ProcessGetRequest(Client* client, const std::vector& object_ids, - int64_t timeout_ms); + /// \param client The client making this request. + /// \param object_ids Object IDs of the objects to be gotten. + /// \param timeout_ms The timeout for the get request in milliseconds. + Status ProcessGetRequest(const std::shared_ptr& client, + const std::vector& object_ids, int64_t timeout_ms); /// Seal an object. The object is now immutable and can be accessed with get. /// - /// @param object_id Object ID of the object to be sealed. - /// @param digest The digest of the object. This is used to tell if two + /// \param object_id Object ID of the object to be sealed. + /// \param digest The digest of the object. This is used to tell if two /// objects with the same object ID are the same. void SealObject(const ObjectID& object_id, unsigned char digest[]); /// Check if the plasma store contains an object: /// - /// @param object_id Object ID that will be checked. - /// @return OBJECT_FOUND if the object is in the store, OBJECT_NOT_FOUND if + /// \param object_id Object ID that will be checked. + /// \return OBJECT_FOUND if the object is in the store, OBJECT_NOT_FOUND if /// not ObjectStatus ContainsObject(const ObjectID& object_id); /// Record the fact that a particular client is no longer using an object. /// - /// @param object_id The object ID of the object that is being released. - /// @param client The client making this request. - void ReleaseObject(const ObjectID& object_id, Client* client); + /// \param object_id The object ID of the object that is being released. + /// \param client The client making this request. + void ReleaseObject(const ObjectID& object_id, + const std::shared_ptr& client); /// Subscribe a file descriptor to updates about new sealed objects. /// - /// @param client The client making this request. - void SubscribeToUpdates(Client* client); - - /// Connect a new client to the PlasmaStore. - /// - /// @param listener_sock The socket that is listening to incoming connections. - void ConnectClient(int listener_sock); - - /// Disconnect a client from the PlasmaStore. - /// - /// @param client_fd The client file descriptor that is disconnected. - void DisconnectClient(int client_fd); - - NotificationMap::iterator SendNotifications(NotificationMap::iterator it); - - arrow::Status ProcessMessage(Client* client); + /// \param client The client making this request. + void SubscribeToUpdates(const std::shared_ptr& client); private: - void PushNotification(ObjectInfoT* object_notification); + // Inform all subscribers that a new object has been sealed. + void PushObjectReadyNotification(const ObjectID& object_id, + const ObjectTableEntry& entry); - void PushNotification(ObjectInfoT* object_notification, int client_fd); + // Inform all subscribers that an object has evicted. + void PushObjectDeletionNotification(const ObjectID& object_id); void AddToClientObjectIds(const ObjectID& object_id, ObjectTableEntry* entry, - Client* client); + const std::shared_ptr& client); /// Remove a GetRequest and clean up the relevant data structures. /// - /// @param get_request The GetRequest to remove. + /// \param get_request The GetRequest to remove. void RemoveGetRequest(GetRequest* get_request); /// Remove all of the GetRequests for a given client. /// - /// @param client The client whose GetRequests should be removed. - void RemoveGetRequestsForClient(Client* client); + /// \param client The client whose GetRequests should be removed. + void RemoveGetRequestsForClient(const std::shared_ptr& client); + + /// Release all resources used by the client. + /// + /// \param client The client whose resources should be released. + void ReleaseClientResources(const std::shared_ptr& client); void ReturnFromGet(GetRequest* get_req); void UpdateObjectGetRequests(const ObjectID& object_id); - int RemoveFromClientObjectIds(const ObjectID& object_id, ObjectTableEntry* entry, - Client* client); - void EraseFromObjectTable(const ObjectID& object_id); uint8_t* AllocateMemory(size_t size, int* fd, int64_t* map_size, ptrdiff_t* offset); + + void IncreaseObjectRefCount(const ObjectID& object_id, ObjectTableEntry* entry); + + void DecreaseObjectRefCount(const ObjectID& object_id, ObjectTableEntry* entry); + #ifdef PLASMA_CUDA Status AllocateCudaMemory(int device_num, int64_t size, uint8_t** out_pointer, std::shared_ptr* out_ipc_handle); @@ -222,27 +191,32 @@ class PlasmaStore { Status FreeCudaMemory(int device_num, int64_t size, uint8_t* out_pointer); #endif - /// Event loop of the plasma store. - EventLoop* loop_; + /// Accept a client connection. + void DoAccept(); + /// Handle an accepted client connection. + void HandleAccept(const error_code& error); + + Status ProcessClientMessage(const std::shared_ptr& client, + int64_t message_type, int64_t message_size, + const uint8_t* message_data); + + /// Disconnect a client from the PlasmaStore. + /// + /// \param client The client that is disconnected. + void ProcessDisconnectClient(const std::shared_ptr& client); + /// The plasma store information, including the object tables, that is exposed /// to the eviction policy. PlasmaStoreInfo store_info_; /// The state that is managed by the eviction policy. EvictionPolicy eviction_policy_; - /// Input buffer. This is allocated only once to avoid mallocs for every - /// call to process_message. - std::vector input_buffer_; /// A hash table mapping object IDs to a vector of the get requests that are /// waiting for the object to arrive. std::unordered_map> object_get_requests_; - /// The pending notifications that have not been sent to subscribers because - /// the socket send buffers were full. This is a hash table from client file - /// descriptor to an array of object_ids to send to that client. - /// TODO(pcm): Consider putting this into the Client data structure and - /// reorganize the code slightly. - NotificationMap pending_notifications_; - std::unordered_map> connected_clients_; + std::unordered_set> notification_clients_; + + std::unordered_set> connected_clients_; std::unordered_set deletion_cache_; @@ -252,6 +226,13 @@ class PlasmaStore { #ifdef PLASMA_CUDA arrow::cuda::CudaDeviceManager* manager_; #endif + asio::io_context& io_context_; + /// The name of the stream this store server listens on. + std::string stream_name_; + /// An acceptor for new clients. + io::PlasmaAcceptor acceptor_; + /// The stream to listen on for new clients. + io::PlasmaStream stream_; }; } // namespace plasma diff --git a/cpp/src/plasma/test/client_tests.cc b/cpp/src/plasma/test/client_tests.cc index deffde57976..01467f29487 100644 --- a/cpp/src/plasma/test/client_tests.cc +++ b/cpp/src/plasma/test/client_tests.cc @@ -15,14 +15,9 @@ // specific language governing permissions and limitations // under the License. -#include -#include -#include -#include -#include -#include - +#include #include +#include #include #include @@ -55,7 +50,7 @@ class TestPlasmaStore : public ::testing::Test { // stdout of the object store. Consider changing that. void SetUp() { - ARROW_CHECK_OK(TemporaryDir::Make("cli-test-", &temp_dir_)); + ASSERT_OK(TemporaryDir::Make("cli-test-", &temp_dir_)); store_socket_name_ = temp_dir_->path().ToString() + "store"; std::string plasma_directory = @@ -64,13 +59,13 @@ class TestPlasmaStore : public ::testing::Test { plasma_directory + "/plasma_store_server -m 10000000 -s " + store_socket_name_ + " 1> /dev/null 2> /dev/null & " + "echo $! > " + store_socket_name_ + ".pid"; PLASMA_CHECK_SYSTEM(system(plasma_command.c_str())); - ARROW_CHECK_OK(client_.Connect(store_socket_name_, "")); - ARROW_CHECK_OK(client2_.Connect(store_socket_name_, "")); + ASSERT_OK(client_.Connect(store_socket_name_, "")); + ASSERT_OK(client2_.Connect(store_socket_name_, "")); } virtual void TearDown() { - ARROW_CHECK_OK(client_.Disconnect()); - ARROW_CHECK_OK(client2_.Disconnect()); + ASSERT_OK(client_.Disconnect()); + ASSERT_OK(client2_.Disconnect()); // Kill plasma_store process that we started #ifdef COVERAGE_BUILD // Ask plasma_store to exit gracefully and give it time to write out @@ -89,14 +84,14 @@ class TestPlasmaStore : public ::testing::Test { const std::vector& metadata, const std::vector& data, bool release = true) { std::shared_ptr data_buffer; - ARROW_CHECK_OK(client.Create(object_id, data.size(), &metadata[0], metadata.size(), + ASSERT_OK(client.Create(object_id, data.size(), &metadata[0], metadata.size(), &data_buffer)); for (size_t i = 0; i < data.size(); i++) { data_buffer->mutable_data()[i] = data[i]; } - ARROW_CHECK_OK(client.Seal(object_id)); + ASSERT_OK(client.Seal(object_id)); if (release) { - ARROW_CHECK_OK(client.Release(object_id)); + ASSERT_OK(client.Release(object_id)); } } @@ -110,8 +105,8 @@ class TestPlasmaStore : public ::testing::Test { TEST_F(TestPlasmaStore, NewSubscriberTest) { PlasmaClient local_client, local_client2; - ARROW_CHECK_OK(local_client.Connect(store_socket_name_, "")); - ARROW_CHECK_OK(local_client2.Connect(store_socket_name_, "")); + ASSERT_OK(local_client.Connect(store_socket_name_, "")); + ASSERT_OK(local_client2.Connect(store_socket_name_, "")); ObjectID object_id = random_object_id(); @@ -121,36 +116,34 @@ TEST_F(TestPlasmaStore, NewSubscriberTest) { uint8_t metadata[] = {5}; int64_t metadata_size = sizeof(metadata); std::shared_ptr data; - ARROW_CHECK_OK( + ASSERT_OK( local_client.Create(object_id, data_size, metadata, metadata_size, &data)); - ARROW_CHECK_OK(local_client.Seal(object_id)); + ASSERT_OK(local_client.Seal(object_id)); // Test that new subscriber client2 can receive notifications about existing objects. - int fd = -1; - ARROW_CHECK_OK(local_client2.Subscribe(&fd)); - ASSERT_GT(fd, 0); + ASSERT_OK(local_client2.Subscribe()); ObjectID object_id2 = random_object_id(); int64_t data_size2 = 0; int64_t metadata_size2 = 0; - ARROW_CHECK_OK( - local_client2.GetNotification(fd, &object_id2, &data_size2, &metadata_size2)); + ASSERT_OK( + local_client2.GetNotification(&object_id2, &data_size2, &metadata_size2)); ASSERT_EQ(object_id, object_id2); ASSERT_EQ(data_size, data_size2); ASSERT_EQ(metadata_size, metadata_size2); // Delete the object. - ARROW_CHECK_OK(local_client.Release(object_id)); - ARROW_CHECK_OK(local_client.Delete(object_id)); + ASSERT_OK(local_client.Release(object_id)); + ASSERT_OK(local_client.Delete(object_id)); - ARROW_CHECK_OK( - local_client2.GetNotification(fd, &object_id2, &data_size2, &metadata_size2)); + ASSERT_OK( + local_client2.GetNotification(&object_id2, &data_size2, &metadata_size2)); ASSERT_EQ(object_id, object_id2); ASSERT_EQ(-1, data_size2); ASSERT_EQ(-1, metadata_size2); - ARROW_CHECK_OK(local_client2.Disconnect()); - ARROW_CHECK_OK(local_client.Disconnect()); + ASSERT_OK(local_client2.Disconnect()); + ASSERT_OK(local_client.Disconnect()); } TEST_F(TestPlasmaStore, SealErrorsTest) { @@ -166,7 +159,7 @@ TEST_F(TestPlasmaStore, SealErrorsTest) { // Trying to seal it again. result = client_.Seal(object_id); ASSERT_TRUE(IsPlasmaObjectAlreadySealed(result)); - ARROW_CHECK_OK(client_.Release(object_id)); + ASSERT_OK(client_.Release(object_id)); } TEST_F(TestPlasmaStore, DeleteTest) { @@ -174,7 +167,7 @@ TEST_F(TestPlasmaStore, DeleteTest) { // Test for deleting non-existance object. Status result = client_.Delete(object_id); - ARROW_CHECK_OK(result); + ASSERT_OK(result); // Test for the object being in local Plasma store. // First create object. @@ -182,20 +175,20 @@ TEST_F(TestPlasmaStore, DeleteTest) { uint8_t metadata[] = {5}; int64_t metadata_size = sizeof(metadata); std::shared_ptr data; - ARROW_CHECK_OK(client_.Create(object_id, data_size, metadata, metadata_size, &data)); - ARROW_CHECK_OK(client_.Seal(object_id)); + ASSERT_OK(client_.Create(object_id, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client_.Seal(object_id)); result = client_.Delete(object_id); - ARROW_CHECK_OK(result); + ASSERT_OK(result); bool has_object = false; - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_TRUE(has_object); - ARROW_CHECK_OK(client_.Release(object_id)); + ASSERT_OK(client_.Release(object_id)); // object_id is marked as to-be-deleted, when it is not in use, it will be deleted. - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_FALSE(has_object); - ARROW_CHECK_OK(client_.Delete(object_id)); + ASSERT_OK(client_.Delete(object_id)); } TEST_F(TestPlasmaStore, DeleteObjectsTest) { @@ -204,31 +197,31 @@ TEST_F(TestPlasmaStore, DeleteObjectsTest) { // Test for deleting non-existance object. Status result = client_.Delete(std::vector{object_id1, object_id2}); - ARROW_CHECK_OK(result); + ASSERT_OK(result); // Test for the object being in local Plasma store. // First create object. int64_t data_size = 100; uint8_t metadata[] = {5}; int64_t metadata_size = sizeof(metadata); std::shared_ptr data; - ARROW_CHECK_OK(client_.Create(object_id1, data_size, metadata, metadata_size, &data)); - ARROW_CHECK_OK(client_.Seal(object_id1)); - ARROW_CHECK_OK(client_.Create(object_id2, data_size, metadata, metadata_size, &data)); - ARROW_CHECK_OK(client_.Seal(object_id2)); + ASSERT_OK(client_.Create(object_id1, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client_.Seal(object_id1)); + ASSERT_OK(client_.Create(object_id2, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client_.Seal(object_id2)); // Release the ref count of Create function. - ARROW_CHECK_OK(client_.Release(object_id1)); - ARROW_CHECK_OK(client_.Release(object_id2)); + ASSERT_OK(client_.Release(object_id1)); + ASSERT_OK(client_.Release(object_id2)); // Increase the ref count by calling Get using client2_. std::vector object_buffers; - ARROW_CHECK_OK(client2_.Get({object_id1, object_id2}, 0, &object_buffers)); + ASSERT_OK(client2_.Get({object_id1, object_id2}, 0, &object_buffers)); // Objects are still used by client2_. result = client_.Delete(std::vector{object_id1, object_id2}); - ARROW_CHECK_OK(result); + ASSERT_OK(result); // The object is used and it should not be deleted right now. bool has_object = false; - ARROW_CHECK_OK(client_.Contains(object_id1, &has_object)); + ASSERT_OK(client_.Contains(object_id1, &has_object)); ASSERT_TRUE(has_object); - ARROW_CHECK_OK(client_.Contains(object_id2, &has_object)); + ASSERT_OK(client_.Contains(object_id2, &has_object)); ASSERT_TRUE(has_object); // Decrease the ref count by deleting the PlasmaBuffer (in ObjectBuffer). // client2_ won't send the release request immediately because the trigger @@ -236,9 +229,9 @@ TEST_F(TestPlasmaStore, DeleteObjectsTest) { object_buffers.clear(); // Delete the objects. result = client2_.Delete(std::vector{object_id1, object_id2}); - ARROW_CHECK_OK(client_.Contains(object_id1, &has_object)); + ASSERT_OK(client_.Contains(object_id1, &has_object)); ASSERT_FALSE(has_object); - ARROW_CHECK_OK(client_.Contains(object_id2, &has_object)); + ASSERT_OK(client_.Contains(object_id2, &has_object)); ASSERT_FALSE(has_object); } @@ -247,7 +240,7 @@ TEST_F(TestPlasmaStore, ContainsTest) { // Test for object non-existence. bool has_object; - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_FALSE(has_object); // Test for the object being in local Plasma store. @@ -255,8 +248,8 @@ TEST_F(TestPlasmaStore, ContainsTest) { std::vector data(100, 0); CreateObject(client_, object_id, {42}, data); std::vector object_buffers; - ARROW_CHECK_OK(client_.Get({object_id}, -1, &object_buffers)); - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Get({object_id}, -1, &object_buffers)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_TRUE(has_object); } @@ -266,7 +259,7 @@ TEST_F(TestPlasmaStore, GetTest) { ObjectID object_id = random_object_id(); // Test for object non-existence. - ARROW_CHECK_OK(client_.Get({object_id}, 0, &object_buffers)); + ASSERT_OK(client_.Get({object_id}, 0, &object_buffers)); ASSERT_EQ(object_buffers.size(), 1); ASSERT_FALSE(object_buffers[0].metadata); ASSERT_FALSE(object_buffers[0].data); @@ -279,7 +272,7 @@ TEST_F(TestPlasmaStore, GetTest) { EXPECT_FALSE(client_.IsInUse(object_id)); object_buffers.clear(); - ARROW_CHECK_OK(client_.Get({object_id}, -1, &object_buffers)); + ASSERT_OK(client_.Get({object_id}, -1, &object_buffers)); ASSERT_EQ(object_buffers.size(), 1); ASSERT_EQ(object_buffers[0].device_num, 0); AssertObjectBufferEqual(object_buffers[0], {42}, {3, 5, 6, 7, 9}); @@ -302,7 +295,7 @@ TEST_F(TestPlasmaStore, LegacyGetTest) { ObjectBuffer object_buffer; // Test for object non-existence. - ARROW_CHECK_OK(client_.Get(&object_id, 1, 0, &object_buffer)); + ASSERT_OK(client_.Get(&object_id, 1, 0, &object_buffer)); ASSERT_FALSE(object_buffer.metadata); ASSERT_FALSE(object_buffer.data); EXPECT_FALSE(client_.IsInUse(object_id)); @@ -312,12 +305,12 @@ TEST_F(TestPlasmaStore, LegacyGetTest) { CreateObject(client_, object_id, {42}, data); EXPECT_FALSE(client_.IsInUse(object_id)); - ARROW_CHECK_OK(client_.Get(&object_id, 1, -1, &object_buffer)); + ASSERT_OK(client_.Get(&object_id, 1, -1, &object_buffer)); AssertObjectBufferEqual(object_buffer, {42}, {3, 5, 6, 7, 9}); } // Object needs releasing manually EXPECT_TRUE(client_.IsInUse(object_id)); - ARROW_CHECK_OK(client_.Release(object_id)); + ASSERT_OK(client_.Release(object_id)); EXPECT_FALSE(client_.IsInUse(object_id)); } @@ -331,15 +324,15 @@ TEST_F(TestPlasmaStore, MultipleGetTest) { uint8_t metadata[] = {5}; int64_t metadata_size = sizeof(metadata); std::shared_ptr data; - ARROW_CHECK_OK(client_.Create(object_id1, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client_.Create(object_id1, data_size, metadata, metadata_size, &data)); data->mutable_data()[0] = 1; - ARROW_CHECK_OK(client_.Seal(object_id1)); + ASSERT_OK(client_.Seal(object_id1)); - ARROW_CHECK_OK(client_.Create(object_id2, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client_.Create(object_id2, data_size, metadata, metadata_size, &data)); data->mutable_data()[0] = 2; - ARROW_CHECK_OK(client_.Seal(object_id2)); + ASSERT_OK(client_.Seal(object_id2)); - ARROW_CHECK_OK(client_.Get(object_ids, -1, &object_buffers)); + ASSERT_OK(client_.Get(object_ids, -1, &object_buffers)); ASSERT_EQ(object_buffers[0].data->data()[0], 1); ASSERT_EQ(object_buffers[1].data->data()[0], 2); } @@ -349,7 +342,7 @@ TEST_F(TestPlasmaStore, AbortTest) { std::vector object_buffers; // Test for object non-existence. - ARROW_CHECK_OK(client_.Get({object_id}, 0, &object_buffers)); + ASSERT_OK(client_.Get({object_id}, 0, &object_buffers)); ASSERT_FALSE(object_buffers[0].data); // Test object abort. @@ -359,7 +352,7 @@ TEST_F(TestPlasmaStore, AbortTest) { int64_t metadata_size = sizeof(metadata); std::shared_ptr data; uint8_t* data_ptr; - ARROW_CHECK_OK(client_.Create(object_id, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client_.Create(object_id, data_size, metadata, metadata_size, &data)); data_ptr = data->mutable_data(); // Write some data. for (int64_t i = 0; i < data_size / 2; i++) { @@ -369,21 +362,21 @@ TEST_F(TestPlasmaStore, AbortTest) { Status status = client_.Abort(object_id); ASSERT_TRUE(status.IsInvalid()); // Release, then abort. - ARROW_CHECK_OK(client_.Release(object_id)); + ASSERT_OK(client_.Release(object_id)); EXPECT_TRUE(client_.IsInUse(object_id)); - ARROW_CHECK_OK(client_.Abort(object_id)); + ASSERT_OK(client_.Abort(object_id)); EXPECT_FALSE(client_.IsInUse(object_id)); // Test for object non-existence after the abort. - ARROW_CHECK_OK(client_.Get({object_id}, 0, &object_buffers)); + ASSERT_OK(client_.Get({object_id}, 0, &object_buffers)); ASSERT_FALSE(object_buffers[0].data); // Create the object successfully this time. CreateObject(client_, object_id, {42, 43}, {1, 2, 3, 4, 5}); // Test that we can get the object. - ARROW_CHECK_OK(client_.Get({object_id}, -1, &object_buffers)); + ASSERT_OK(client_.Get({object_id}, -1, &object_buffers)); AssertObjectBufferEqual(object_buffers[0], {42, 43}, {1, 2, 3, 4, 5}); } @@ -394,7 +387,7 @@ TEST_F(TestPlasmaStore, OneIdCreateRepeatedlyTest) { std::vector object_buffers; // Test for object non-existence. - ARROW_CHECK_OK(client_.Get({object_id}, 0, &object_buffers)); + ASSERT_OK(client_.Get({object_id}, 0, &object_buffers)); ASSERT_FALSE(object_buffers[0].data); int64_t data_size = 20; @@ -404,18 +397,18 @@ TEST_F(TestPlasmaStore, OneIdCreateRepeatedlyTest) { // Test the sequence: create -> release -> abort -> ... for (int64_t i = 0; i < loop_times; i++) { std::shared_ptr data; - ARROW_CHECK_OK(client_.Create(object_id, data_size, metadata, metadata_size, &data)); - ARROW_CHECK_OK(client_.Release(object_id)); - ARROW_CHECK_OK(client_.Abort(object_id)); + ASSERT_OK(client_.Create(object_id, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client_.Release(object_id)); + ASSERT_OK(client_.Abort(object_id)); } // Test the sequence: create -> seal -> release -> delete -> ... for (int64_t i = 0; i < loop_times; i++) { std::shared_ptr data; - ARROW_CHECK_OK(client_.Create(object_id, data_size, metadata, metadata_size, &data)); - ARROW_CHECK_OK(client_.Seal(object_id)); - ARROW_CHECK_OK(client_.Release(object_id)); - ARROW_CHECK_OK(client_.Delete(object_id)); + ASSERT_OK(client_.Create(object_id, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client_.Seal(object_id)); + ASSERT_OK(client_.Release(object_id)); + ASSERT_OK(client_.Delete(object_id)); } } @@ -425,7 +418,7 @@ TEST_F(TestPlasmaStore, MultipleClientTest) { // Test for object non-existence on the first client. bool has_object; - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_FALSE(has_object); // Test for the object being in local Plasma store. @@ -434,25 +427,25 @@ TEST_F(TestPlasmaStore, MultipleClientTest) { uint8_t metadata[] = {5}; int64_t metadata_size = sizeof(metadata); std::shared_ptr data; - ARROW_CHECK_OK(client2_.Create(object_id, data_size, metadata, metadata_size, &data)); - ARROW_CHECK_OK(client2_.Seal(object_id)); + ASSERT_OK(client2_.Create(object_id, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client2_.Seal(object_id)); // Test that the first client can get the object. - ARROW_CHECK_OK(client_.Get({object_id}, -1, &object_buffers)); + ASSERT_OK(client_.Get({object_id}, -1, &object_buffers)); ASSERT_TRUE(object_buffers[0].data); - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_TRUE(has_object); // Test that one client disconnecting does not interfere with the other. // First create object on the second client. object_id = random_object_id(); - ARROW_CHECK_OK(client2_.Create(object_id, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client2_.Create(object_id, data_size, metadata, metadata_size, &data)); // Disconnect the first client. - ARROW_CHECK_OK(client_.Disconnect()); + ASSERT_OK(client_.Disconnect()); // Test that the second client can seal and get the created object. - ARROW_CHECK_OK(client2_.Seal(object_id)); - ARROW_CHECK_OK(client2_.Get({object_id}, -1, &object_buffers)); + ASSERT_OK(client2_.Seal(object_id)); + ASSERT_OK(client2_.Get({object_id}, -1, &object_buffers)); ASSERT_TRUE(object_buffers[0].data); - ARROW_CHECK_OK(client2_.Contains(object_id, &has_object)); + ASSERT_OK(client2_.Contains(object_id, &has_object)); ASSERT_TRUE(has_object); } @@ -466,7 +459,7 @@ TEST_F(TestPlasmaStore, ManyObjectTest) { // Test for object non-existence on the first client. bool has_object; - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_FALSE(has_object); // Test for the object being in local Plasma store. @@ -475,29 +468,29 @@ TEST_F(TestPlasmaStore, ManyObjectTest) { uint8_t metadata[] = {5}; int64_t metadata_size = sizeof(metadata); std::shared_ptr data; - ARROW_CHECK_OK(client_.Create(object_id, data_size, metadata, metadata_size, &data)); + ASSERT_OK(client_.Create(object_id, data_size, metadata, metadata_size, &data)); if (i % 3 == 0) { // Seal one third of the objects. - ARROW_CHECK_OK(client_.Seal(object_id)); + ASSERT_OK(client_.Seal(object_id)); // Test that the first client can get the object. - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_TRUE(has_object); } else if (i % 3 == 1) { // Abort one third of the objects. - ARROW_CHECK_OK(client_.Release(object_id)); - ARROW_CHECK_OK(client_.Abort(object_id)); + ASSERT_OK(client_.Release(object_id)); + ASSERT_OK(client_.Abort(object_id)); } } // Disconnect the first client. All unsealed objects should be aborted. - ARROW_CHECK_OK(client_.Disconnect()); + ASSERT_OK(client_.Disconnect()); // Check that the second client can query the object store for the first // client's objects. int i = 0; for (auto const& object_id : object_ids) { bool has_object; - ARROW_CHECK_OK(client2_.Contains(object_id, &has_object)); + ASSERT_OK(client2_.Contains(object_id, &has_object)); if (i % 3 == 0) { // The first third should be sealed. ASSERT_TRUE(has_object); @@ -521,13 +514,13 @@ void AssertCudaRead(const std::shared_ptr& buffer, std::shared_ptr gpu_buffer; const size_t data_size = expected_data.size(); - ARROW_CHECK_OK(CudaBuffer::FromBuffer(buffer, &gpu_buffer)); + ASSERT_OK(CudaBuffer::FromBuffer(buffer, &gpu_buffer)); ASSERT_EQ(gpu_buffer->size(), data_size); CudaBufferReader reader(gpu_buffer); std::vector read_data(data_size); int64_t read_data_size; - ARROW_CHECK_OK(reader.Read(data_size, &read_data_size, read_data.data())); + ASSERT_OK(reader.Read(data_size, &read_data_size, read_data.data())); ASSERT_EQ(read_data_size, data_size); for (size_t i = 0; i < data_size; i++) { @@ -542,7 +535,7 @@ TEST_F(TestPlasmaStore, GetGPUTest) { std::vector object_buffers; // Test for object non-existence. - ARROW_CHECK_OK(client_.Get({object_id}, 0, &object_buffers)); + ASSERT_OK(client_.Get({object_id}, 0, &object_buffers)); ASSERT_EQ(object_buffers.size(), 1); ASSERT_FALSE(object_buffers[0].data); @@ -554,15 +547,15 @@ TEST_F(TestPlasmaStore, GetGPUTest) { int64_t metadata_size = sizeof(metadata); std::shared_ptr data_buffer; std::shared_ptr gpu_buffer; - ARROW_CHECK_OK( + ASSERT_OK( client_.Create(object_id, data_size, metadata, metadata_size, &data_buffer, 1)); - ARROW_CHECK_OK(CudaBuffer::FromBuffer(data_buffer, &gpu_buffer)); + ASSERT_OK(CudaBuffer::FromBuffer(data_buffer, &gpu_buffer)); CudaBufferWriter writer(gpu_buffer); - ARROW_CHECK_OK(writer.Write(data, data_size)); - ARROW_CHECK_OK(client_.Seal(object_id)); + ASSERT_OK(writer.Write(data, data_size)); + ASSERT_OK(client_.Seal(object_id)); object_buffers.clear(); - ARROW_CHECK_OK(client_.Get({object_id}, -1, &object_buffers)); + ASSERT_OK(client_.Get({object_id}, -1, &object_buffers)); ASSERT_EQ(object_buffers.size(), 1); ASSERT_EQ(object_buffers[0].device_num, 1); // Check data @@ -577,34 +570,34 @@ TEST_F(TestPlasmaStore, DeleteObjectsGPUTest) { // Test for deleting non-existance object. Status result = client_.Delete(std::vector{object_id1, object_id2}); - ARROW_CHECK_OK(result); + ASSERT_OK(result); // Test for the object being in local Plasma store. // First create object. int64_t data_size = 100; uint8_t metadata[] = {5}; int64_t metadata_size = sizeof(metadata); std::shared_ptr data; - ARROW_CHECK_OK( + ASSERT_OK( client_.Create(object_id1, data_size, metadata, metadata_size, &data, 1)); - ARROW_CHECK_OK(client_.Seal(object_id1)); - ARROW_CHECK_OK( + ASSERT_OK(client_.Seal(object_id1)); + ASSERT_OK( client_.Create(object_id2, data_size, metadata, metadata_size, &data, 1)); - ARROW_CHECK_OK(client_.Seal(object_id2)); + ASSERT_OK(client_.Seal(object_id2)); // Release the ref count of Create function. data = nullptr; - ARROW_CHECK_OK(client_.Release(object_id1)); - ARROW_CHECK_OK(client_.Release(object_id2)); + ASSERT_OK(client_.Release(object_id1)); + ASSERT_OK(client_.Release(object_id2)); // Increase the ref count by calling Get using client2_. std::vector object_buffers; - ARROW_CHECK_OK(client2_.Get({object_id1, object_id2}, 0, &object_buffers)); + ASSERT_OK(client2_.Get({object_id1, object_id2}, 0, &object_buffers)); // Objects are still used by client2_. result = client_.Delete(std::vector{object_id1, object_id2}); - ARROW_CHECK_OK(result); + ASSERT_OK(result); // The object is used and it should not be deleted right now. bool has_object = false; - ARROW_CHECK_OK(client_.Contains(object_id1, &has_object)); + ASSERT_OK(client_.Contains(object_id1, &has_object)); ASSERT_TRUE(has_object); - ARROW_CHECK_OK(client_.Contains(object_id2, &has_object)); + ASSERT_OK(client_.Contains(object_id2, &has_object)); ASSERT_TRUE(has_object); // Decrease the ref count by deleting the PlasmaBuffer (in ObjectBuffer). // client2_ won't send the release request immediately because the trigger @@ -612,9 +605,9 @@ TEST_F(TestPlasmaStore, DeleteObjectsGPUTest) { object_buffers.clear(); // Delete the objects. result = client2_.Delete(std::vector{object_id1, object_id2}); - ARROW_CHECK_OK(client_.Contains(object_id1, &has_object)); + ASSERT_OK(client_.Contains(object_id1, &has_object)); ASSERT_FALSE(has_object); - ARROW_CHECK_OK(client_.Contains(object_id2, &has_object)); + ASSERT_OK(client_.Contains(object_id2, &has_object)); ASSERT_FALSE(has_object); } @@ -631,27 +624,27 @@ TEST_F(TestPlasmaStore, RepeatlyCreateGPUTest) { ObjectID& object_id = object_ids[i]; std::shared_ptr data; - ARROW_CHECK_OK(client_.Create(object_id, data_size, 0, 0, &data, 1)); - ARROW_CHECK_OK(client_.Seal(object_id)); - ARROW_CHECK_OK(client_.Release(object_id)); + ASSERT_OK(client_.Create(object_id, data_size, 0, 0, &data, 1)); + ASSERT_OK(client_.Seal(object_id)); + ASSERT_OK(client_.Release(object_id)); } // delete and create again for (int64_t i = 0; i < loop_times; i++) { ObjectID& object_id = object_ids[i % object_num]; - ARROW_CHECK_OK(client_.Delete(object_id)); + ASSERT_OK(client_.Delete(object_id)); std::shared_ptr data; - ARROW_CHECK_OK(client_.Create(object_id, data_size, 0, 0, &data, 1)); - ARROW_CHECK_OK(client_.Seal(object_id)); + ASSERT_OK(client_.Create(object_id, data_size, 0, 0, &data, 1)); + ASSERT_OK(client_.Seal(object_id)); data = nullptr; - ARROW_CHECK_OK(client_.Release(object_id)); + ASSERT_OK(client_.Release(object_id)); } // delete all - ARROW_CHECK_OK(client_.Delete(object_ids)); + ASSERT_OK(client_.Delete(object_ids)); } TEST_F(TestPlasmaStore, MultipleClientGPUTest) { @@ -660,7 +653,7 @@ TEST_F(TestPlasmaStore, MultipleClientGPUTest) { // Test for object non-existence on the first client. bool has_object; - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_FALSE(has_object); // Test for the object being in local Plasma store. @@ -669,27 +662,27 @@ TEST_F(TestPlasmaStore, MultipleClientGPUTest) { uint8_t metadata[] = {5}; int64_t metadata_size = sizeof(metadata); std::shared_ptr data; - ARROW_CHECK_OK( + ASSERT_OK( client2_.Create(object_id, data_size, metadata, metadata_size, &data, 1)); - ARROW_CHECK_OK(client2_.Seal(object_id)); + ASSERT_OK(client2_.Seal(object_id)); // Test that the first client can get the object. - ARROW_CHECK_OK(client_.Get({object_id}, -1, &object_buffers)); - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Get({object_id}, -1, &object_buffers)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_TRUE(has_object); // Test that one client disconnecting does not interfere with the other. // First create object on the second client. object_id = random_object_id(); - ARROW_CHECK_OK( + ASSERT_OK( client2_.Create(object_id, data_size, metadata, metadata_size, &data, 1)); // Disconnect the first client. - ARROW_CHECK_OK(client_.Disconnect()); + ASSERT_OK(client_.Disconnect()); // Test that the second client can seal and get the created object. - ARROW_CHECK_OK(client2_.Seal(object_id)); + ASSERT_OK(client2_.Seal(object_id)); object_buffers.clear(); - ARROW_CHECK_OK(client2_.Contains(object_id, &has_object)); + ASSERT_OK(client2_.Contains(object_id, &has_object)); ASSERT_TRUE(has_object); - ARROW_CHECK_OK(client2_.Get({object_id}, -1, &object_buffers)); + ASSERT_OK(client2_.Get({object_id}, -1, &object_buffers)); ASSERT_EQ(object_buffers.size(), 1); ASSERT_EQ(object_buffers[0].device_num, 1); AssertCudaRead(object_buffers[0].metadata, {5}); diff --git a/cpp/src/plasma/test/external_store_tests.cc b/cpp/src/plasma/test/external_store_tests.cc index 2b7d3217352..467d11cfa1c 100644 --- a/cpp/src/plasma/test/external_store_tests.cc +++ b/cpp/src/plasma/test/external_store_tests.cc @@ -54,7 +54,7 @@ class TestPlasmaStoreWithExternal : public ::testing::Test { // TODO(pcm): At the moment, stdout of the test gets mixed up with // stdout of the object store. Consider changing that. void SetUp() override { - ARROW_CHECK_OK(TemporaryDir::Make("ext-test-", &temp_dir_)); + ASSERT_OK(TemporaryDir::Make("ext-test-", &temp_dir_)); store_socket_name_ = temp_dir_->path().ToString() + "store"; std::string plasma_directory = @@ -65,11 +65,11 @@ class TestPlasmaStoreWithExternal : public ::testing::Test { " 1> /tmp/log.stdout 2> /tmp/log.stderr & " + "echo $! > " + store_socket_name_ + ".pid"; PLASMA_CHECK_SYSTEM(system(plasma_command.c_str())); - ARROW_CHECK_OK(client_.Connect(store_socket_name_, "")); + ASSERT_OK(client_.Connect(store_socket_name_, "")); } void TearDown() override { - ARROW_CHECK_OK(client_.Disconnect()); + ASSERT_OK(client_.Disconnect()); // Kill plasma_store process that we started #ifdef COVERAGE_BUILD // Ask plasma_store to exit gracefully and give it time to write out @@ -100,14 +100,14 @@ TEST_F(TestPlasmaStoreWithExternal, EvictionTest) { // Test for object non-existence. bool has_object; - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_FALSE(has_object); // Test for the object being in local Plasma store. // Create and seal the object. - ARROW_CHECK_OK(client_.CreateAndSeal(object_id, data, metadata)); + ASSERT_OK(client_.CreateAndSeal(object_id, data, metadata)); // Test that the client can get the object. - ARROW_CHECK_OK(client_.Contains(object_id, &has_object)); + ASSERT_OK(client_.Contains(object_id, &has_object)); ASSERT_TRUE(has_object); } @@ -118,7 +118,7 @@ TEST_F(TestPlasmaStoreWithExternal, EvictionTest) { // external store on failure. This should succeed to fetch the object. // However, it may evict the next few objects. std::vector object_buffers; - ARROW_CHECK_OK(client_.Get({object_ids[i]}, -1, &object_buffers)); + ASSERT_OK(client_.Get({object_ids[i]}, -1, &object_buffers)); ASSERT_EQ(object_buffers.size(), 1); ASSERT_EQ(object_buffers[0].device_num, 0); ASSERT_TRUE(object_buffers[0].data); @@ -127,7 +127,7 @@ TEST_F(TestPlasmaStoreWithExternal, EvictionTest) { // Make sure we still cannot fetch objects that do not exist std::vector object_buffers; - ARROW_CHECK_OK(client_.Get({random_object_id()}, 100, &object_buffers)); + ASSERT_OK(client_.Get({random_object_id()}, 100, &object_buffers)); ASSERT_EQ(object_buffers.size(), 1); ASSERT_EQ(object_buffers[0].device_num, 0); ASSERT_EQ(object_buffers[0].data, nullptr); diff --git a/cpp/src/plasma/test/serialization_tests.cc b/cpp/src/plasma/test/serialization_tests.cc index f3cff428582..a8463dcb271 100644 --- a/cpp/src/plasma/test/serialization_tests.cc +++ b/cpp/src/plasma/test/serialization_tests.cc @@ -21,40 +21,56 @@ #include #include +#include #include "arrow/testing/gtest_util.h" #include "arrow/util/io-util.h" #include "plasma/common.h" -#include "plasma/io.h" -#include "plasma/plasma.h" +#include "plasma/io/connection.h" #include "plasma/protocol.h" #include "plasma/test-util.h" -namespace fb = plasma::flatbuf; - namespace plasma { -using arrow::internal::TemporaryDir; +using flatbuf::MessageType; +using io::ClientConnection; +using io::ServerConnection; -/** - * Seek to the beginning of a file and read a message from it. - * - * @param fd File descriptor of the file. - * @param message_type Message type that we expect in the file. - * - * @return Pointer to the content of the message. Needs to be freed by the - * caller. - */ -std::vector read_message_from_file(int fd, MessageType message_type) { - /* Go to the beginning of the file. */ - lseek(fd, 0, SEEK_SET); - MessageType type; - std::vector data; - Status s = ReadMessage(fd, &type, &data); - DCHECK_OK(s); - DCHECK_EQ(type, message_type); - return data; +class TestPlasmaSerialization : public ::testing::Test { + public: + void SetUp() override { + using asio::local::stream_protocol; + stream_protocol::socket parentSocket(io_context_); + stream_protocol::socket childSocket(io_context_); + // create socket pair + asio::local::connect_pair(childSocket, parentSocket); + client_ = ServerConnection::Create(std::move(childSocket)); + io::MessageHandler monk_handler = [](std::shared_ptr client, + int64_t type, int64_t length, + const uint8_t* msg) {}; + server_ = ClientConnection::Create(std::move(parentSocket), monk_handler); + } + + void TearDown() override { + client_->Close(); + server_->Close(); + } + + protected: + asio::io_context io_context_; + std::shared_ptr client_; + std::shared_ptr server_; +}; + +Status PlasmaReceive(const std::shared_ptr& client, + MessageType message_type, std::vector* buffer) { + return client->ReadMessage(static_cast(message_type), buffer); +} + +Status PlasmaReceive(const std::shared_ptr& client, + MessageType message_type, std::vector* buffer) { + return client->ReadMessage(static_cast(message_type), buffer); } PlasmaObject random_plasma_object(void) { @@ -70,36 +86,15 @@ PlasmaObject random_plasma_object(void) { return object; } -class TestPlasmaSerialization : public ::testing::Test { - public: - void SetUp() { ARROW_CHECK_OK(TemporaryDir::Make("ser-test-", &temp_dir_)); } - - // Create a temporary file. - // A fd is returned which must be closed manually. The file itself - // is deleted at the end of the test. - int CreateTemporaryFile(void) { - char path[1024]; - - std::stringstream ss; - ss << temp_dir_->path().ToString() << "fileXXXXXX"; - strncpy(path, ss.str().c_str(), sizeof(path)); - ARROW_LOG(INFO) << "file path: '" << path << "'"; - return mkstemp(path); - } - - protected: - std::unique_ptr temp_dir_; -}; - TEST_F(TestPlasmaSerialization, CreateRequest) { - int fd = CreateTemporaryFile(); ObjectID object_id1 = random_object_id(); int64_t data_size1 = 42; int64_t metadata_size1 = 11; int device_num1 = 0; - ASSERT_OK(SendCreateRequest(fd, object_id1, data_size1, metadata_size1, device_num1)); - std::vector data = - read_message_from_file(fd, MessageType::PlasmaCreateRequest); + ASSERT_OK( + SendCreateRequest(client_, object_id1, data_size1, metadata_size1, device_num1)); + std::vector data; + ASSERT_OK(PlasmaReceive(server_, MessageType::PlasmaCreateRequest, &data)); ObjectID object_id2; int64_t data_size2; int64_t metadata_size2; @@ -110,16 +105,15 @@ TEST_F(TestPlasmaSerialization, CreateRequest) { ASSERT_EQ(metadata_size1, metadata_size2); ASSERT_EQ(object_id1, object_id2); ASSERT_EQ(device_num1, device_num2); - close(fd); } TEST_F(TestPlasmaSerialization, CreateReply) { - int fd = CreateTemporaryFile(); ObjectID object_id1 = random_object_id(); PlasmaObject object1 = random_plasma_object(); int64_t mmap_size1 = 1000000; - ASSERT_OK(SendCreateReply(fd, object_id1, &object1, PlasmaError::OK, mmap_size1)); - std::vector data = read_message_from_file(fd, MessageType::PlasmaCreateReply); + ASSERT_OK(SendCreateReply(server_, object_id1, &object1, PlasmaError::OK, mmap_size1)); + std::vector data; + ASSERT_OK(PlasmaReceive(client_, MessageType::PlasmaCreateReply, &data)); ObjectID object_id2; PlasmaObject object2 = {}; int store_fd; @@ -130,44 +124,41 @@ TEST_F(TestPlasmaSerialization, CreateReply) { ASSERT_EQ(object1.store_fd, store_fd); ASSERT_EQ(mmap_size1, mmap_size2); ASSERT_EQ(memcmp(&object1, &object2, sizeof(object1)), 0); - close(fd); } TEST_F(TestPlasmaSerialization, SealRequest) { - int fd = CreateTemporaryFile(); ObjectID object_id1 = random_object_id(); unsigned char digest1[kDigestSize]; memset(&digest1[0], 7, kDigestSize); - ASSERT_OK(SendSealRequest(fd, object_id1, &digest1[0])); - std::vector data = read_message_from_file(fd, MessageType::PlasmaSealRequest); + ASSERT_OK(SendSealRequest(client_, object_id1, &digest1[0])); + std::vector data; + ASSERT_OK(PlasmaReceive(server_, MessageType::PlasmaSealRequest, &data)); ObjectID object_id2; unsigned char digest2[kDigestSize]; ASSERT_OK(ReadSealRequest(data.data(), data.size(), &object_id2, &digest2[0])); ASSERT_EQ(object_id1, object_id2); ASSERT_EQ(memcmp(&digest1[0], &digest2[0], kDigestSize), 0); - close(fd); } TEST_F(TestPlasmaSerialization, SealReply) { - int fd = CreateTemporaryFile(); ObjectID object_id1 = random_object_id(); - ASSERT_OK(SendSealReply(fd, object_id1, PlasmaError::ObjectExists)); - std::vector data = read_message_from_file(fd, MessageType::PlasmaSealReply); + ASSERT_OK(SendSealReply(server_, object_id1, PlasmaError::ObjectExists)); + std::vector data; + ASSERT_OK(PlasmaReceive(client_, MessageType::PlasmaSealReply, &data)); ObjectID object_id2; Status s = ReadSealReply(data.data(), data.size(), &object_id2); ASSERT_EQ(object_id1, object_id2); ASSERT_TRUE(IsPlasmaObjectExists(s)); - close(fd); } TEST_F(TestPlasmaSerialization, GetRequest) { - int fd = CreateTemporaryFile(); ObjectID object_ids[2]; object_ids[0] = random_object_id(); object_ids[1] = random_object_id(); int64_t timeout_ms = 1234; - ASSERT_OK(SendGetRequest(fd, object_ids, 2, timeout_ms)); - std::vector data = read_message_from_file(fd, MessageType::PlasmaGetRequest); + ASSERT_OK(SendGetRequest(client_, object_ids, 2, timeout_ms)); + std::vector data; + ASSERT_OK(PlasmaReceive(server_, MessageType::PlasmaGetRequest, &data)); std::vector object_ids_return; int64_t timeout_ms_return; ASSERT_OK( @@ -175,11 +166,9 @@ TEST_F(TestPlasmaSerialization, GetRequest) { ASSERT_EQ(object_ids[0], object_ids_return[0]); ASSERT_EQ(object_ids[1], object_ids_return[1]); ASSERT_EQ(timeout_ms, timeout_ms_return); - close(fd); } TEST_F(TestPlasmaSerialization, GetReply) { - int fd = CreateTemporaryFile(); ObjectID object_ids[2]; object_ids[0] = random_object_id(); object_ids[1] = random_object_id(); @@ -188,9 +177,10 @@ TEST_F(TestPlasmaSerialization, GetReply) { plasma_objects[object_ids[1]] = random_plasma_object(); std::vector store_fds = {1, 2, 3}; std::vector mmap_sizes = {100, 200, 300}; - ASSERT_OK(SendGetReply(fd, object_ids, plasma_objects, 2, store_fds, mmap_sizes)); + ASSERT_OK(SendGetReply(server_, object_ids, plasma_objects, 2, store_fds, mmap_sizes)); - std::vector data = read_message_from_file(fd, MessageType::PlasmaGetReply); + std::vector data; + ASSERT_OK(PlasmaReceive(client_, MessageType::PlasmaGetReply, &data)); ObjectID object_ids_return[2]; PlasmaObject plasma_objects_return[2]; std::vector store_fds_return; @@ -211,53 +201,47 @@ TEST_F(TestPlasmaSerialization, GetReply) { } ASSERT_TRUE(store_fds == store_fds_return); ASSERT_TRUE(mmap_sizes == mmap_sizes_return); - close(fd); } TEST_F(TestPlasmaSerialization, ReleaseRequest) { - int fd = CreateTemporaryFile(); ObjectID object_id1 = random_object_id(); - ASSERT_OK(SendReleaseRequest(fd, object_id1)); - std::vector data = - read_message_from_file(fd, MessageType::PlasmaReleaseRequest); + ASSERT_OK(SendReleaseRequest(client_, object_id1)); + std::vector data; + ASSERT_OK(PlasmaReceive(server_, MessageType::PlasmaReleaseRequest, &data)); ObjectID object_id2; ASSERT_OK(ReadReleaseRequest(data.data(), data.size(), &object_id2)); ASSERT_EQ(object_id1, object_id2); - close(fd); } TEST_F(TestPlasmaSerialization, ReleaseReply) { - int fd = CreateTemporaryFile(); ObjectID object_id1 = random_object_id(); - ASSERT_OK(SendReleaseReply(fd, object_id1, PlasmaError::ObjectExists)); - std::vector data = read_message_from_file(fd, MessageType::PlasmaReleaseReply); + ASSERT_OK(SendReleaseReply(server_, object_id1, PlasmaError::ObjectExists)); + std::vector data; + ASSERT_OK(PlasmaReceive(client_, MessageType::PlasmaReleaseReply, &data)); ObjectID object_id2; Status s = ReadReleaseReply(data.data(), data.size(), &object_id2); ASSERT_EQ(object_id1, object_id2); ASSERT_TRUE(IsPlasmaObjectExists(s)); - close(fd); } TEST_F(TestPlasmaSerialization, DeleteRequest) { - int fd = CreateTemporaryFile(); ObjectID object_id1 = random_object_id(); - ASSERT_OK(SendDeleteRequest(fd, std::vector{object_id1})); - std::vector data = - read_message_from_file(fd, MessageType::PlasmaDeleteRequest); + ASSERT_OK(SendDeleteRequest(client_, std::vector{object_id1})); + std::vector data; + ASSERT_OK(PlasmaReceive(server_, MessageType::PlasmaDeleteRequest, &data)); std::vector object_vec; ASSERT_OK(ReadDeleteRequest(data.data(), data.size(), &object_vec)); ASSERT_EQ(object_vec.size(), 1); ASSERT_EQ(object_id1, object_vec[0]); - close(fd); } TEST_F(TestPlasmaSerialization, DeleteReply) { - int fd = CreateTemporaryFile(); ObjectID object_id1 = random_object_id(); PlasmaError error1 = PlasmaError::ObjectExists; - ASSERT_OK(SendDeleteReply(fd, std::vector{object_id1}, + ASSERT_OK(SendDeleteReply(server_, std::vector{object_id1}, std::vector{error1})); - std::vector data = read_message_from_file(fd, MessageType::PlasmaDeleteReply); + std::vector data; + ASSERT_OK(PlasmaReceive(client_, MessageType::PlasmaDeleteReply, &data)); std::vector object_vec; std::vector error_vec; Status s = ReadDeleteReply(data.data(), data.size(), &object_vec, &error_vec); @@ -266,39 +250,36 @@ TEST_F(TestPlasmaSerialization, DeleteReply) { ASSERT_EQ(error_vec.size(), 1); ASSERT_TRUE(error_vec[0] == PlasmaError::ObjectExists); ASSERT_TRUE(s.ok()); - close(fd); } TEST_F(TestPlasmaSerialization, EvictRequest) { - int fd = CreateTemporaryFile(); int64_t num_bytes = 111; - ASSERT_OK(SendEvictRequest(fd, num_bytes)); - std::vector data = read_message_from_file(fd, MessageType::PlasmaEvictRequest); + ASSERT_OK(SendEvictRequest(client_, num_bytes)); + std::vector data; + ASSERT_OK(PlasmaReceive(server_, MessageType::PlasmaEvictRequest, &data)); int64_t num_bytes_received; ASSERT_OK(ReadEvictRequest(data.data(), data.size(), &num_bytes_received)); ASSERT_EQ(num_bytes, num_bytes_received); - close(fd); } TEST_F(TestPlasmaSerialization, EvictReply) { - int fd = CreateTemporaryFile(); int64_t num_bytes = 111; - ASSERT_OK(SendEvictReply(fd, num_bytes)); - std::vector data = read_message_from_file(fd, MessageType::PlasmaEvictReply); + ASSERT_OK(SendEvictReply(server_, num_bytes)); + std::vector data; + ASSERT_OK(PlasmaReceive(client_, MessageType::PlasmaEvictReply, &data)); int64_t num_bytes_received; ASSERT_OK(ReadEvictReply(data.data(), data.size(), num_bytes_received)); ASSERT_EQ(num_bytes, num_bytes_received); - close(fd); } TEST_F(TestPlasmaSerialization, DataRequest) { - int fd = CreateTemporaryFile(); ObjectID object_id1 = random_object_id(); const char* address1 = "address1"; int port1 = 12345; - ASSERT_OK(SendDataRequest(fd, object_id1, address1, port1)); + ASSERT_OK(SendDataRequest(client_, object_id1, address1, port1)); /* Reading message back. */ - std::vector data = read_message_from_file(fd, MessageType::PlasmaDataRequest); + std::vector data; + ASSERT_OK(PlasmaReceive(server_, MessageType::PlasmaDataRequest, &data)); ObjectID object_id2; char* address2; int port2; @@ -307,17 +288,16 @@ TEST_F(TestPlasmaSerialization, DataRequest) { ASSERT_EQ(strcmp(address1, address2), 0); ASSERT_EQ(port1, port2); free(address2); - close(fd); } TEST_F(TestPlasmaSerialization, DataReply) { - int fd = CreateTemporaryFile(); ObjectID object_id1 = random_object_id(); int64_t object_size1 = 146; int64_t metadata_size1 = 198; - ASSERT_OK(SendDataReply(fd, object_id1, object_size1, metadata_size1)); + ASSERT_OK(SendDataReply(server_, object_id1, object_size1, metadata_size1)); /* Reading message back. */ - std::vector data = read_message_from_file(fd, MessageType::PlasmaDataReply); + std::vector data; + ASSERT_OK(PlasmaReceive(client_, MessageType::PlasmaDataReply, &data)); ObjectID object_id2; int64_t object_size2; int64_t metadata_size2; diff --git a/cpp/src/plasma/thirdparty/ae/ae.c b/cpp/src/plasma/thirdparty/ae/ae.c deleted file mode 100644 index dfb72244409..00000000000 --- a/cpp/src/plasma/thirdparty/ae/ae.c +++ /dev/null @@ -1,465 +0,0 @@ -/* A simple event-driven programming library. Originally I wrote this code - * for the Jim's event-loop (Jim is a Tcl interpreter) but later translated - * it in form of a library for easy reuse. - * - * Copyright (c) 2006-2010, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "plasma/thirdparty/ae/ae.h" -#include "plasma/thirdparty/ae/zmalloc.h" -#include "plasma/thirdparty/ae/config.h" - -/* Include the best multiplexing layer supported by this system. - * The following should be ordered by performances, descending. */ -#ifdef HAVE_EVPORT -#include "plasma/thirdparty/ae/ae_evport.c" -#else - #ifdef HAVE_EPOLL - #include "plasma/thirdparty/ae/ae_epoll.c" - #else - #ifdef HAVE_KQUEUE - #include "plasma/thirdparty/ae/ae_kqueue.c" - #else - #include "plasma/thirdparty/ae/ae_select.c" - #endif - #endif -#endif - -aeEventLoop *aeCreateEventLoop(int setsize) { - aeEventLoop *eventLoop; - int i; - - if ((eventLoop = zmalloc(sizeof(*eventLoop))) == NULL) goto err; - eventLoop->events = zmalloc(sizeof(aeFileEvent)*setsize); - eventLoop->fired = zmalloc(sizeof(aeFiredEvent)*setsize); - if (eventLoop->events == NULL || eventLoop->fired == NULL) goto err; - eventLoop->setsize = setsize; - eventLoop->lastTime = time(NULL); - eventLoop->timeEventHead = NULL; - eventLoop->timeEventNextId = 0; - eventLoop->stop = 0; - eventLoop->maxfd = -1; - eventLoop->beforesleep = NULL; - if (aeApiCreate(eventLoop) == -1) goto err; - /* Events with mask == AE_NONE are not set. So let's initialize the - * vector with it. */ - for (i = 0; i < setsize; i++) - eventLoop->events[i].mask = AE_NONE; - return eventLoop; - -err: - if (eventLoop) { - zfree(eventLoop->events); - zfree(eventLoop->fired); - zfree(eventLoop); - } - return NULL; -} - -/* Return the current set size. */ -int aeGetSetSize(aeEventLoop *eventLoop) { - return eventLoop->setsize; -} - -/* Resize the maximum set size of the event loop. - * If the requested set size is smaller than the current set size, but - * there is already a file descriptor in use that is >= the requested - * set size minus one, AE_ERR is returned and the operation is not - * performed at all. - * - * Otherwise AE_OK is returned and the operation is successful. */ -int aeResizeSetSize(aeEventLoop *eventLoop, int setsize) { - int i; - - if (setsize == eventLoop->setsize) return AE_OK; - if (eventLoop->maxfd >= setsize) return AE_ERR; - if (aeApiResize(eventLoop,setsize) == -1) return AE_ERR; - - eventLoop->events = zrealloc(eventLoop->events,sizeof(aeFileEvent)*setsize); - eventLoop->fired = zrealloc(eventLoop->fired,sizeof(aeFiredEvent)*setsize); - eventLoop->setsize = setsize; - - /* Make sure that if we created new slots, they are initialized with - * an AE_NONE mask. */ - for (i = eventLoop->maxfd+1; i < setsize; i++) - eventLoop->events[i].mask = AE_NONE; - return AE_OK; -} - -void aeDeleteEventLoop(aeEventLoop *eventLoop) { - aeApiFree(eventLoop); - zfree(eventLoop->events); - zfree(eventLoop->fired); - zfree(eventLoop); -} - -void aeStop(aeEventLoop *eventLoop) { - eventLoop->stop = 1; -} - -int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, - aeFileProc *proc, void *clientData) -{ - if (fd >= eventLoop->setsize) { - errno = ERANGE; - return AE_ERR; - } - aeFileEvent *fe = &eventLoop->events[fd]; - - if (aeApiAddEvent(eventLoop, fd, mask) == -1) - return AE_ERR; - fe->mask |= mask; - if (mask & AE_READABLE) fe->rfileProc = proc; - if (mask & AE_WRITABLE) fe->wfileProc = proc; - fe->clientData = clientData; - if (fd > eventLoop->maxfd) - eventLoop->maxfd = fd; - return AE_OK; -} - -void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask) -{ - if (fd >= eventLoop->setsize) return; - aeFileEvent *fe = &eventLoop->events[fd]; - if (fe->mask == AE_NONE) return; - - aeApiDelEvent(eventLoop, fd, mask); - fe->mask = fe->mask & (~mask); - if (fd == eventLoop->maxfd && fe->mask == AE_NONE) { - /* Update the max fd */ - int j; - - for (j = eventLoop->maxfd-1; j >= 0; j--) - if (eventLoop->events[j].mask != AE_NONE) break; - eventLoop->maxfd = j; - } -} - -int aeGetFileEvents(aeEventLoop *eventLoop, int fd) { - if (fd >= eventLoop->setsize) return 0; - aeFileEvent *fe = &eventLoop->events[fd]; - - return fe->mask; -} - -static void aeGetTime(long *seconds, long *milliseconds) -{ - struct timeval tv; - - gettimeofday(&tv, NULL); - *seconds = tv.tv_sec; - *milliseconds = tv.tv_usec/1000; -} - -static void aeAddMillisecondsToNow(long long milliseconds, long *sec, long *ms) { - long cur_sec, cur_ms, when_sec, when_ms; - - aeGetTime(&cur_sec, &cur_ms); - when_sec = cur_sec + milliseconds/1000; - when_ms = cur_ms + milliseconds%1000; - if (when_ms >= 1000) { - when_sec ++; - when_ms -= 1000; - } - *sec = when_sec; - *ms = when_ms; -} - -long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, - aeTimeProc *proc, void *clientData, - aeEventFinalizerProc *finalizerProc) -{ - long long id = eventLoop->timeEventNextId++; - aeTimeEvent *te; - - te = zmalloc(sizeof(*te)); - if (te == NULL) return AE_ERR; - te->id = id; - aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); - te->timeProc = proc; - te->finalizerProc = finalizerProc; - te->clientData = clientData; - te->next = eventLoop->timeEventHead; - eventLoop->timeEventHead = te; - return id; -} - -int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id) -{ - aeTimeEvent *te = eventLoop->timeEventHead; - while(te) { - if (te->id == id) { - te->id = AE_DELETED_EVENT_ID; - return AE_OK; - } - te = te->next; - } - return AE_ERR; /* NO event with the specified ID found */ -} - -/* Search the first timer to fire. - * This operation is useful to know how many time the select can be - * put in sleep without to delay any event. - * If there are no timers NULL is returned. - * - * Note that's O(N) since time events are unsorted. - * Possible optimizations (not needed by Redis so far, but...): - * 1) Insert the event in order, so that the nearest is just the head. - * Much better but still insertion or deletion of timers is O(N). - * 2) Use a skiplist to have this operation as O(1) and insertion as O(log(N)). - */ -static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop) -{ - aeTimeEvent *te = eventLoop->timeEventHead; - aeTimeEvent *nearest = NULL; - - while(te) { - if (!nearest || te->when_sec < nearest->when_sec || - (te->when_sec == nearest->when_sec && - te->when_ms < nearest->when_ms)) - nearest = te; - te = te->next; - } - return nearest; -} - -/* Process time events */ -static int processTimeEvents(aeEventLoop *eventLoop) { - int processed = 0; - aeTimeEvent *te, *prev; - long long maxId; - time_t now = time(NULL); - - /* If the system clock is moved to the future, and then set back to the - * right value, time events may be delayed in a random way. Often this - * means that scheduled operations will not be performed soon enough. - * - * Here we try to detect system clock skews, and force all the time - * events to be processed ASAP when this happens: the idea is that - * processing events earlier is less dangerous than delaying them - * indefinitely, and practice suggests it is. */ - if (now < eventLoop->lastTime) { - te = eventLoop->timeEventHead; - while(te) { - te->when_sec = 0; - te = te->next; - } - } - eventLoop->lastTime = now; - - prev = NULL; - te = eventLoop->timeEventHead; - maxId = eventLoop->timeEventNextId-1; - while(te) { - long now_sec, now_ms; - long long id; - - /* Remove events scheduled for deletion. */ - if (te->id == AE_DELETED_EVENT_ID) { - aeTimeEvent *next = te->next; - if (prev == NULL) - eventLoop->timeEventHead = te->next; - else - prev->next = te->next; - if (te->finalizerProc) - te->finalizerProc(eventLoop, te->clientData); - zfree(te); - te = next; - continue; - } - - /* Make sure we don't process time events created by time events in - * this iteration. Note that this check is currently useless: we always - * add new timers on the head, however if we change the implementation - * detail, this check may be useful again: we keep it here for future - * defense. */ - if (te->id > maxId) { - te = te->next; - continue; - } - aeGetTime(&now_sec, &now_ms); - if (now_sec > te->when_sec || - (now_sec == te->when_sec && now_ms >= te->when_ms)) - { - int retval; - - id = te->id; - retval = te->timeProc(eventLoop, id, te->clientData); - processed++; - if (retval != AE_NOMORE) { - aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms); - } else { - te->id = AE_DELETED_EVENT_ID; - } - } - prev = te; - te = te->next; - } - return processed; -} - -/* Process every pending time event, then every pending file event - * (that may be registered by time event callbacks just processed). - * Without special flags the function sleeps until some file event - * fires, or when the next time event occurs (if any). - * - * If flags is 0, the function does nothing and returns. - * if flags has AE_ALL_EVENTS set, all the kind of events are processed. - * if flags has AE_FILE_EVENTS set, file events are processed. - * if flags has AE_TIME_EVENTS set, time events are processed. - * if flags has AE_DONT_WAIT set the function returns ASAP until all - * the events that's possible to process without to wait are processed. - * - * The function returns the number of events processed. */ -int aeProcessEvents(aeEventLoop *eventLoop, int flags) -{ - int processed = 0, numevents; - - /* Nothing to do? return ASAP */ - if (!(flags & AE_TIME_EVENTS) && !(flags & AE_FILE_EVENTS)) return 0; - - /* Note that we want call select() even if there are no - * file events to process as long as we want to process time - * events, in order to sleep until the next time event is ready - * to fire. */ - if (eventLoop->maxfd != -1 || - ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) { - int j; - aeTimeEvent *shortest = NULL; - struct timeval tv, *tvp; - - if (flags & AE_TIME_EVENTS && !(flags & AE_DONT_WAIT)) - shortest = aeSearchNearestTimer(eventLoop); - if (shortest) { - long now_sec, now_ms; - - aeGetTime(&now_sec, &now_ms); - tvp = &tv; - - /* How many milliseconds we need to wait for the next - * time event to fire? */ - long long ms = - (shortest->when_sec - now_sec)*1000 + - shortest->when_ms - now_ms; - - if (ms > 0) { - tvp->tv_sec = ms/1000; - tvp->tv_usec = (ms % 1000)*1000; - } else { - tvp->tv_sec = 0; - tvp->tv_usec = 0; - } - } else { - /* If we have to check for events but need to return - * ASAP because of AE_DONT_WAIT we need to set the timeout - * to zero */ - if (flags & AE_DONT_WAIT) { - tv.tv_sec = tv.tv_usec = 0; - tvp = &tv; - } else { - /* Otherwise we can block */ - tvp = NULL; /* wait forever */ - } - } - - numevents = aeApiPoll(eventLoop, tvp); - for (j = 0; j < numevents; j++) { - aeFileEvent *fe = &eventLoop->events[eventLoop->fired[j].fd]; - int mask = eventLoop->fired[j].mask; - int fd = eventLoop->fired[j].fd; - int rfired = 0; - - /* note the fe->mask & mask & ... code: maybe an already processed - * event removed an element that fired and we still didn't - * processed, so we check if the event is still valid. */ - if (fe->mask & mask & AE_READABLE) { - rfired = 1; - fe->rfileProc(eventLoop,fd,fe->clientData,mask); - } - if (fe->mask & mask & AE_WRITABLE) { - if (!rfired || fe->wfileProc != fe->rfileProc) - fe->wfileProc(eventLoop,fd,fe->clientData,mask); - } - processed++; - } - } - /* Check time events */ - if (flags & AE_TIME_EVENTS) - processed += processTimeEvents(eventLoop); - - return processed; /* return the number of processed file/time events */ -} - -/* Wait for milliseconds until the given file descriptor becomes - * writable/readable/exception */ -int aeWait(int fd, int mask, long long milliseconds) { - struct pollfd pfd; - int retmask = 0, retval; - - memset(&pfd, 0, sizeof(pfd)); - pfd.fd = fd; - if (mask & AE_READABLE) pfd.events |= POLLIN; - if (mask & AE_WRITABLE) pfd.events |= POLLOUT; - - if ((retval = poll(&pfd, 1, milliseconds))== 1) { - if (pfd.revents & POLLIN) retmask |= AE_READABLE; - if (pfd.revents & POLLOUT) retmask |= AE_WRITABLE; - if (pfd.revents & POLLERR) retmask |= AE_WRITABLE; - if (pfd.revents & POLLHUP) retmask |= AE_WRITABLE; - return retmask; - } else { - return retval; - } -} - -void aeMain(aeEventLoop *eventLoop) { - eventLoop->stop = 0; - while (!eventLoop->stop) { - if (eventLoop->beforesleep != NULL) - eventLoop->beforesleep(eventLoop); - aeProcessEvents(eventLoop, AE_ALL_EVENTS); - } -} - -char *aeGetApiName(void) { - return aeApiName(); -} - -void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep) { - eventLoop->beforesleep = beforesleep; -} diff --git a/cpp/src/plasma/thirdparty/ae/ae.h b/cpp/src/plasma/thirdparty/ae/ae.h deleted file mode 100644 index 827c4c9e4e5..00000000000 --- a/cpp/src/plasma/thirdparty/ae/ae.h +++ /dev/null @@ -1,123 +0,0 @@ -/* A simple event-driven programming library. Originally I wrote this code - * for the Jim's event-loop (Jim is a Tcl interpreter) but later translated - * it in form of a library for easy reuse. - * - * Copyright (c) 2006-2012, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __AE_H__ -#define __AE_H__ - -#include - -#define AE_OK 0 -#define AE_ERR -1 - -#define AE_NONE 0 -#define AE_READABLE 1 -#define AE_WRITABLE 2 - -#define AE_FILE_EVENTS 1 -#define AE_TIME_EVENTS 2 -#define AE_ALL_EVENTS (AE_FILE_EVENTS|AE_TIME_EVENTS) -#define AE_DONT_WAIT 4 - -#define AE_NOMORE -1 -#define AE_DELETED_EVENT_ID -1 - -/* Macros */ -#define AE_NOTUSED(V) ((void) V) - -struct aeEventLoop; - -/* Types and data structures */ -typedef void aeFileProc(struct aeEventLoop *eventLoop, int fd, void *clientData, int mask); -typedef int aeTimeProc(struct aeEventLoop *eventLoop, long long id, void *clientData); -typedef void aeEventFinalizerProc(struct aeEventLoop *eventLoop, void *clientData); -typedef void aeBeforeSleepProc(struct aeEventLoop *eventLoop); - -/* File event structure */ -typedef struct aeFileEvent { - int mask; /* one of AE_(READABLE|WRITABLE) */ - aeFileProc *rfileProc; - aeFileProc *wfileProc; - void *clientData; -} aeFileEvent; - -/* Time event structure */ -typedef struct aeTimeEvent { - long long id; /* time event identifier. */ - long when_sec; /* seconds */ - long when_ms; /* milliseconds */ - aeTimeProc *timeProc; - aeEventFinalizerProc *finalizerProc; - void *clientData; - struct aeTimeEvent *next; -} aeTimeEvent; - -/* A fired event */ -typedef struct aeFiredEvent { - int fd; - int mask; -} aeFiredEvent; - -/* State of an event based program */ -typedef struct aeEventLoop { - int maxfd; /* highest file descriptor currently registered */ - int setsize; /* max number of file descriptors tracked */ - long long timeEventNextId; - time_t lastTime; /* Used to detect system clock skew */ - aeFileEvent *events; /* Registered events */ - aeFiredEvent *fired; /* Fired events */ - aeTimeEvent *timeEventHead; - int stop; - void *apidata; /* This is used for polling API specific data */ - aeBeforeSleepProc *beforesleep; -} aeEventLoop; - -/* Prototypes */ -aeEventLoop *aeCreateEventLoop(int setsize); -void aeDeleteEventLoop(aeEventLoop *eventLoop); -void aeStop(aeEventLoop *eventLoop); -int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, - aeFileProc *proc, void *clientData); -void aeDeleteFileEvent(aeEventLoop *eventLoop, int fd, int mask); -int aeGetFileEvents(aeEventLoop *eventLoop, int fd); -long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds, - aeTimeProc *proc, void *clientData, - aeEventFinalizerProc *finalizerProc); -int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id); -int aeProcessEvents(aeEventLoop *eventLoop, int flags); -int aeWait(int fd, int mask, long long milliseconds); -void aeMain(aeEventLoop *eventLoop); -char *aeGetApiName(void); -void aeSetBeforeSleepProc(aeEventLoop *eventLoop, aeBeforeSleepProc *beforesleep); -int aeGetSetSize(aeEventLoop *eventLoop); -int aeResizeSetSize(aeEventLoop *eventLoop, int setsize); - -#endif diff --git a/cpp/src/plasma/thirdparty/ae/ae_epoll.c b/cpp/src/plasma/thirdparty/ae/ae_epoll.c deleted file mode 100644 index 2f70550a980..00000000000 --- a/cpp/src/plasma/thirdparty/ae/ae_epoll.c +++ /dev/null @@ -1,137 +0,0 @@ -/* Linux epoll(2) based ae.c module - * - * Copyright (c) 2009-2012, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -#include - -typedef struct aeApiState { - int epfd; - struct epoll_event *events; -} aeApiState; - -static int aeApiCreate(aeEventLoop *eventLoop) { - aeApiState *state = zmalloc(sizeof(aeApiState)); - - if (!state) return -1; - state->events = zmalloc(sizeof(struct epoll_event)*eventLoop->setsize); - if (!state->events) { - zfree(state); - return -1; - } - state->epfd = epoll_create(1024); /* 1024 is just a hint for the kernel */ - if (state->epfd == -1) { - zfree(state->events); - zfree(state); - return -1; - } - eventLoop->apidata = state; - return 0; -} - -static int aeApiResize(aeEventLoop *eventLoop, int setsize) { - aeApiState *state = eventLoop->apidata; - - state->events = zrealloc(state->events, sizeof(struct epoll_event)*setsize); - return 0; -} - -static void aeApiFree(aeEventLoop *eventLoop) { - aeApiState *state = eventLoop->apidata; - - close(state->epfd); - zfree(state->events); - zfree(state); -} - -static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { - aeApiState *state = eventLoop->apidata; - struct epoll_event ee; - memset(&ee, 0, sizeof(struct epoll_event)); // avoid valgrind warning - /* If the fd was already monitored for some event, we need a MOD - * operation. Otherwise we need an ADD operation. */ - int op = eventLoop->events[fd].mask == AE_NONE ? - EPOLL_CTL_ADD : EPOLL_CTL_MOD; - - ee.events = 0; - mask |= eventLoop->events[fd].mask; /* Merge old events */ - if (mask & AE_READABLE) ee.events |= EPOLLIN; - if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; - ee.data.fd = fd; - if (epoll_ctl(state->epfd,op,fd,&ee) == -1) return -1; - return 0; -} - -static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int delmask) { - aeApiState *state = eventLoop->apidata; - struct epoll_event ee; - memset(&ee, 0, sizeof(struct epoll_event)); // avoid valgrind warning - int mask = eventLoop->events[fd].mask & (~delmask); - - ee.events = 0; - if (mask & AE_READABLE) ee.events |= EPOLLIN; - if (mask & AE_WRITABLE) ee.events |= EPOLLOUT; - ee.data.fd = fd; - if (mask != AE_NONE) { - epoll_ctl(state->epfd,EPOLL_CTL_MOD,fd,&ee); - } else { - /* Note, Kernel < 2.6.9 requires a non null event pointer even for - * EPOLL_CTL_DEL. */ - epoll_ctl(state->epfd,EPOLL_CTL_DEL,fd,&ee); - } -} - -static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { - aeApiState *state = eventLoop->apidata; - int retval, numevents = 0; - - retval = epoll_wait(state->epfd,state->events,eventLoop->setsize, - tvp ? (tvp->tv_sec*1000 + tvp->tv_usec/1000) : -1); - if (retval > 0) { - int j; - - numevents = retval; - for (j = 0; j < numevents; j++) { - int mask = 0; - struct epoll_event *e = state->events+j; - - if (e->events & EPOLLIN) mask |= AE_READABLE; - if (e->events & EPOLLOUT) mask |= AE_WRITABLE; - if (e->events & EPOLLERR) mask |= AE_WRITABLE; - if (e->events & EPOLLHUP) mask |= AE_WRITABLE; - eventLoop->fired[j].fd = e->data.fd; - eventLoop->fired[j].mask = mask; - } - } - return numevents; -} - -static char *aeApiName(void) { - return "epoll"; -} diff --git a/cpp/src/plasma/thirdparty/ae/ae_evport.c b/cpp/src/plasma/thirdparty/ae/ae_evport.c deleted file mode 100644 index 5c317becb6f..00000000000 --- a/cpp/src/plasma/thirdparty/ae/ae_evport.c +++ /dev/null @@ -1,320 +0,0 @@ -/* ae.c module for illumos event ports. - * - * Copyright (c) 2012, Joyent, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -#include -#include -#include -#include - -#include -#include - -#include - -static int evport_debug = 0; - -/* - * This file implements the ae API using event ports, present on Solaris-based - * systems since Solaris 10. Using the event port interface, we associate file - * descriptors with the port. Each association also includes the set of poll(2) - * events that the consumer is interested in (e.g., POLLIN and POLLOUT). - * - * There's one tricky piece to this implementation: when we return events via - * aeApiPoll, the corresponding file descriptors become dissociated from the - * port. This is necessary because poll events are level-triggered, so if the - * fd didn't become dissociated, it would immediately fire another event since - * the underlying state hasn't changed yet. We must re-associate the file - * descriptor, but only after we know that our caller has actually read from it. - * The ae API does not tell us exactly when that happens, but we do know that - * it must happen by the time aeApiPoll is called again. Our solution is to - * keep track of the last fds returned by aeApiPoll and re-associate them next - * time aeApiPoll is invoked. - * - * To summarize, in this module, each fd association is EITHER (a) represented - * only via the in-kernel association OR (b) represented by pending_fds and - * pending_masks. (b) is only true for the last fds we returned from aeApiPoll, - * and only until we enter aeApiPoll again (at which point we restore the - * in-kernel association). - */ -#define MAX_EVENT_BATCHSZ 512 - -typedef struct aeApiState { - int portfd; /* event port */ - int npending; /* # of pending fds */ - int pending_fds[MAX_EVENT_BATCHSZ]; /* pending fds */ - int pending_masks[MAX_EVENT_BATCHSZ]; /* pending fds' masks */ -} aeApiState; - -static int aeApiCreate(aeEventLoop *eventLoop) { - int i; - aeApiState *state = zmalloc(sizeof(aeApiState)); - if (!state) return -1; - - state->portfd = port_create(); - if (state->portfd == -1) { - zfree(state); - return -1; - } - - state->npending = 0; - - for (i = 0; i < MAX_EVENT_BATCHSZ; i++) { - state->pending_fds[i] = -1; - state->pending_masks[i] = AE_NONE; - } - - eventLoop->apidata = state; - return 0; -} - -static int aeApiResize(aeEventLoop *eventLoop, int setsize) { - /* Nothing to resize here. */ - return 0; -} - -static void aeApiFree(aeEventLoop *eventLoop) { - aeApiState *state = eventLoop->apidata; - - close(state->portfd); - zfree(state); -} - -static int aeApiLookupPending(aeApiState *state, int fd) { - int i; - - for (i = 0; i < state->npending; i++) { - if (state->pending_fds[i] == fd) - return (i); - } - - return (-1); -} - -/* - * Helper function to invoke port_associate for the given fd and mask. - */ -static int aeApiAssociate(const char *where, int portfd, int fd, int mask) { - int events = 0; - int rv, err; - - if (mask & AE_READABLE) - events |= POLLIN; - if (mask & AE_WRITABLE) - events |= POLLOUT; - - if (evport_debug) - fprintf(stderr, "%s: port_associate(%d, 0x%x) = ", where, fd, events); - - rv = port_associate(portfd, PORT_SOURCE_FD, fd, events, - (void *)(uintptr_t)mask); - err = errno; - - if (evport_debug) - fprintf(stderr, "%d (%s)\n", rv, rv == 0 ? "no error" : strerror(err)); - - if (rv == -1) { - fprintf(stderr, "%s: port_associate: %s\n", where, strerror(err)); - - if (err == EAGAIN) - fprintf(stderr, "aeApiAssociate: event port limit exceeded."); - } - - return rv; -} - -static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { - aeApiState *state = eventLoop->apidata; - int fullmask, pfd; - - if (evport_debug) - fprintf(stderr, "aeApiAddEvent: fd %d mask 0x%x\n", fd, mask); - - /* - * Since port_associate's "events" argument replaces any existing events, we - * must be sure to include whatever events are already associated when - * we call port_associate() again. - */ - fullmask = mask | eventLoop->events[fd].mask; - pfd = aeApiLookupPending(state, fd); - - if (pfd != -1) { - /* - * This fd was recently returned from aeApiPoll. It should be safe to - * assume that the consumer has processed that poll event, but we play - * it safer by simply updating pending_mask. The fd will be - * re-associated as usual when aeApiPoll is called again. - */ - if (evport_debug) - fprintf(stderr, "aeApiAddEvent: adding to pending fd %d\n", fd); - state->pending_masks[pfd] |= fullmask; - return 0; - } - - return (aeApiAssociate("aeApiAddEvent", state->portfd, fd, fullmask)); -} - -static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) { - aeApiState *state = eventLoop->apidata; - int fullmask, pfd; - - if (evport_debug) - fprintf(stderr, "del fd %d mask 0x%x\n", fd, mask); - - pfd = aeApiLookupPending(state, fd); - - if (pfd != -1) { - if (evport_debug) - fprintf(stderr, "deleting event from pending fd %d\n", fd); - - /* - * This fd was just returned from aeApiPoll, so it's not currently - * associated with the port. All we need to do is update - * pending_mask appropriately. - */ - state->pending_masks[pfd] &= ~mask; - - if (state->pending_masks[pfd] == AE_NONE) - state->pending_fds[pfd] = -1; - - return; - } - - /* - * The fd is currently associated with the port. Like with the add case - * above, we must look at the full mask for the file descriptor before - * updating that association. We don't have a good way of knowing what the - * events are without looking into the eventLoop state directly. We rely on - * the fact that our caller has already updated the mask in the eventLoop. - */ - - fullmask = eventLoop->events[fd].mask; - if (fullmask == AE_NONE) { - /* - * We're removing *all* events, so use port_dissociate to remove the - * association completely. Failure here indicates a bug. - */ - if (evport_debug) - fprintf(stderr, "aeApiDelEvent: port_dissociate(%d)\n", fd); - - if (port_dissociate(state->portfd, PORT_SOURCE_FD, fd) != 0) { - perror("aeApiDelEvent: port_dissociate"); - abort(); /* will not return */ - } - } else if (aeApiAssociate("aeApiDelEvent", state->portfd, fd, - fullmask) != 0) { - /* - * ENOMEM is a potentially transient condition, but the kernel won't - * generally return it unless things are really bad. EAGAIN indicates - * we've reached an resource limit, for which it doesn't make sense to - * retry (counter-intuitively). All other errors indicate a bug. In any - * of these cases, the best we can do is to abort. - */ - abort(); /* will not return */ - } -} - -static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { - aeApiState *state = eventLoop->apidata; - struct timespec timeout, *tsp; - int mask, i; - uint_t nevents; - port_event_t event[MAX_EVENT_BATCHSZ]; - - /* - * If we've returned fd events before, we must re-associate them with the - * port now, before calling port_get(). See the block comment at the top of - * this file for an explanation of why. - */ - for (i = 0; i < state->npending; i++) { - if (state->pending_fds[i] == -1) - /* This fd has since been deleted. */ - continue; - - if (aeApiAssociate("aeApiPoll", state->portfd, - state->pending_fds[i], state->pending_masks[i]) != 0) { - /* See aeApiDelEvent for why this case is fatal. */ - abort(); - } - - state->pending_masks[i] = AE_NONE; - state->pending_fds[i] = -1; - } - - state->npending = 0; - - if (tvp != NULL) { - timeout.tv_sec = tvp->tv_sec; - timeout.tv_nsec = tvp->tv_usec * 1000; - tsp = &timeout; - } else { - tsp = NULL; - } - - /* - * port_getn can return with errno == ETIME having returned some events (!). - * So if we get ETIME, we check nevents, too. - */ - nevents = 1; - if (port_getn(state->portfd, event, MAX_EVENT_BATCHSZ, &nevents, - tsp) == -1 && (errno != ETIME || nevents == 0)) { - if (errno == ETIME || errno == EINTR) - return 0; - - /* Any other error indicates a bug. */ - perror("aeApiPoll: port_get"); - abort(); - } - - state->npending = nevents; - - for (i = 0; i < nevents; i++) { - mask = 0; - if (event[i].portev_events & POLLIN) - mask |= AE_READABLE; - if (event[i].portev_events & POLLOUT) - mask |= AE_WRITABLE; - - eventLoop->fired[i].fd = event[i].portev_object; - eventLoop->fired[i].mask = mask; - - if (evport_debug) - fprintf(stderr, "aeApiPoll: fd %d mask 0x%x\n", - (int)event[i].portev_object, mask); - - state->pending_fds[i] = event[i].portev_object; - state->pending_masks[i] = (uintptr_t)event[i].portev_user; - } - - return nevents; -} - -static char *aeApiName(void) { - return "evport"; -} diff --git a/cpp/src/plasma/thirdparty/ae/ae_kqueue.c b/cpp/src/plasma/thirdparty/ae/ae_kqueue.c deleted file mode 100644 index 6796f4ceb59..00000000000 --- a/cpp/src/plasma/thirdparty/ae/ae_kqueue.c +++ /dev/null @@ -1,138 +0,0 @@ -/* Kqueue(2)-based ae.c module - * - * Copyright (C) 2009 Harish Mallipeddi - harish.mallipeddi@gmail.com - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -#include -#include -#include - -typedef struct aeApiState { - int kqfd; - struct kevent *events; -} aeApiState; - -static int aeApiCreate(aeEventLoop *eventLoop) { - aeApiState *state = zmalloc(sizeof(aeApiState)); - - if (!state) return -1; - state->events = zmalloc(sizeof(struct kevent)*eventLoop->setsize); - if (!state->events) { - zfree(state); - return -1; - } - state->kqfd = kqueue(); - if (state->kqfd == -1) { - zfree(state->events); - zfree(state); - return -1; - } - eventLoop->apidata = state; - return 0; -} - -static int aeApiResize(aeEventLoop *eventLoop, int setsize) { - aeApiState *state = eventLoop->apidata; - - state->events = zrealloc(state->events, sizeof(struct kevent)*setsize); - return 0; -} - -static void aeApiFree(aeEventLoop *eventLoop) { - aeApiState *state = eventLoop->apidata; - - close(state->kqfd); - zfree(state->events); - zfree(state); -} - -static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { - aeApiState *state = eventLoop->apidata; - struct kevent ke; - - if (mask & AE_READABLE) { - EV_SET(&ke, fd, EVFILT_READ, EV_ADD, 0, 0, NULL); - if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1; - } - if (mask & AE_WRITABLE) { - EV_SET(&ke, fd, EVFILT_WRITE, EV_ADD, 0, 0, NULL); - if (kevent(state->kqfd, &ke, 1, NULL, 0, NULL) == -1) return -1; - } - return 0; -} - -static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) { - aeApiState *state = eventLoop->apidata; - struct kevent ke; - - if (mask & AE_READABLE) { - EV_SET(&ke, fd, EVFILT_READ, EV_DELETE, 0, 0, NULL); - kevent(state->kqfd, &ke, 1, NULL, 0, NULL); - } - if (mask & AE_WRITABLE) { - EV_SET(&ke, fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL); - kevent(state->kqfd, &ke, 1, NULL, 0, NULL); - } -} - -static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { - aeApiState *state = eventLoop->apidata; - int retval, numevents = 0; - - if (tvp != NULL) { - struct timespec timeout; - timeout.tv_sec = tvp->tv_sec; - timeout.tv_nsec = tvp->tv_usec * 1000; - retval = kevent(state->kqfd, NULL, 0, state->events, eventLoop->setsize, - &timeout); - } else { - retval = kevent(state->kqfd, NULL, 0, state->events, eventLoop->setsize, - NULL); - } - - if (retval > 0) { - int j; - - numevents = retval; - for(j = 0; j < numevents; j++) { - int mask = 0; - struct kevent *e = state->events+j; - - if (e->filter == EVFILT_READ) mask |= AE_READABLE; - if (e->filter == EVFILT_WRITE) mask |= AE_WRITABLE; - eventLoop->fired[j].fd = e->ident; - eventLoop->fired[j].mask = mask; - } - } - return numevents; -} - -static char *aeApiName(void) { - return "kqueue"; -} diff --git a/cpp/src/plasma/thirdparty/ae/ae_select.c b/cpp/src/plasma/thirdparty/ae/ae_select.c deleted file mode 100644 index c039a8ea312..00000000000 --- a/cpp/src/plasma/thirdparty/ae/ae_select.c +++ /dev/null @@ -1,106 +0,0 @@ -/* Select()-based ae.c module. - * - * Copyright (c) 2009-2012, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - - -#include -#include - -typedef struct aeApiState { - fd_set rfds, wfds; - /* We need to have a copy of the fd sets as it's not safe to reuse - * FD sets after select(). */ - fd_set _rfds, _wfds; -} aeApiState; - -static int aeApiCreate(aeEventLoop *eventLoop) { - aeApiState *state = zmalloc(sizeof(aeApiState)); - - if (!state) return -1; - FD_ZERO(&state->rfds); - FD_ZERO(&state->wfds); - eventLoop->apidata = state; - return 0; -} - -static int aeApiResize(aeEventLoop *eventLoop, int setsize) { - /* Just ensure we have enough room in the fd_set type. */ - if (setsize >= FD_SETSIZE) return -1; - return 0; -} - -static void aeApiFree(aeEventLoop *eventLoop) { - zfree(eventLoop->apidata); -} - -static int aeApiAddEvent(aeEventLoop *eventLoop, int fd, int mask) { - aeApiState *state = eventLoop->apidata; - - if (mask & AE_READABLE) FD_SET(fd,&state->rfds); - if (mask & AE_WRITABLE) FD_SET(fd,&state->wfds); - return 0; -} - -static void aeApiDelEvent(aeEventLoop *eventLoop, int fd, int mask) { - aeApiState *state = eventLoop->apidata; - - if (mask & AE_READABLE) FD_CLR(fd,&state->rfds); - if (mask & AE_WRITABLE) FD_CLR(fd,&state->wfds); -} - -static int aeApiPoll(aeEventLoop *eventLoop, struct timeval *tvp) { - aeApiState *state = eventLoop->apidata; - int retval, j, numevents = 0; - - memcpy(&state->_rfds,&state->rfds,sizeof(fd_set)); - memcpy(&state->_wfds,&state->wfds,sizeof(fd_set)); - - retval = select(eventLoop->maxfd+1, - &state->_rfds,&state->_wfds,NULL,tvp); - if (retval > 0) { - for (j = 0; j <= eventLoop->maxfd; j++) { - int mask = 0; - aeFileEvent *fe = &eventLoop->events[j]; - - if (fe->mask == AE_NONE) continue; - if (fe->mask & AE_READABLE && FD_ISSET(j,&state->_rfds)) - mask |= AE_READABLE; - if (fe->mask & AE_WRITABLE && FD_ISSET(j,&state->_wfds)) - mask |= AE_WRITABLE; - eventLoop->fired[numevents].fd = j; - eventLoop->fired[numevents].mask = mask; - numevents++; - } - } - return numevents; -} - -static char *aeApiName(void) { - return "select"; -} diff --git a/cpp/src/plasma/thirdparty/ae/config.h b/cpp/src/plasma/thirdparty/ae/config.h deleted file mode 100644 index 4f8e1ea1bc3..00000000000 --- a/cpp/src/plasma/thirdparty/ae/config.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2009-2012, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __CONFIG_H -#define __CONFIG_H - -#ifdef __APPLE__ -#include -#endif - -/* Test for polling API */ -#ifdef __linux__ -#define HAVE_EPOLL 1 -#endif - -#if (defined(__APPLE__) && defined(MAC_OS_X_VERSION_10_6)) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined (__NetBSD__) -#define HAVE_KQUEUE 1 -#endif - -#ifdef __sun -#include -#ifdef _DTRACE_VERSION -#define HAVE_EVPORT 1 -#endif -#endif - - -#endif diff --git a/cpp/src/plasma/thirdparty/ae/zmalloc.h b/cpp/src/plasma/thirdparty/ae/zmalloc.h deleted file mode 100644 index 6c27dd4e5c3..00000000000 --- a/cpp/src/plasma/thirdparty/ae/zmalloc.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2009-2012, Salvatore Sanfilippo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Redis nor the names of its contributors may be used - * to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _ZMALLOC_H -#define _ZMALLOC_H - -#ifndef zmalloc -#define zmalloc malloc -#endif - -#ifndef zfree -#define zfree free -#endif - -#ifndef zrealloc -#define zrealloc realloc -#endif - -#endif /* _ZMALLOC_H */ diff --git a/dev/release/rat_exclude_files.txt b/dev/release/rat_exclude_files.txt index 79a1c10483b..3783a22c3b1 100644 --- a/dev/release/rat_exclude_files.txt +++ b/dev/release/rat_exclude_files.txt @@ -22,14 +22,6 @@ cpp/cmake_modules/FindPythonLibsNew.cmake cpp/cmake_modules/SnappyCMakeLists.txt cpp/cmake_modules/SnappyConfig.h cpp/src/parquet/.parquetcppversion -cpp/src/plasma/thirdparty/ae/ae.c -cpp/src/plasma/thirdparty/ae/ae.h -cpp/src/plasma/thirdparty/ae/ae_epoll.c -cpp/src/plasma/thirdparty/ae/ae_evport.c -cpp/src/plasma/thirdparty/ae/ae_kqueue.c -cpp/src/plasma/thirdparty/ae/ae_select.c -cpp/src/plasma/thirdparty/ae/config.h -cpp/src/plasma/thirdparty/ae/zmalloc.h cpp/src/plasma/thirdparty/dlmalloc.c dev/release/rat_exclude_files.txt dev/tasks/linux-packages/debian.ubuntu-xenial/compat diff --git a/dev/release/verify-apt.sh b/dev/release/verify-apt.sh index 79b4c19056d..36fa2c0e65c 100755 --- a/dev/release/verify-apt.sh +++ b/dev/release/verify-apt.sh @@ -130,7 +130,7 @@ apt install -y -V plasma-store-server=${deb_version} if [ "${have_gandiva}" = "yes" ]; then apt install -y -V libgandiva-glib-dev=${deb_version} - apt install -y -V libgandiva-glib-doc=${deb_version} + # apt install -y -V libgandiva-glib-doc=${deb_version} fi apt install -y -V libparquet-glib-dev=${deb_version} diff --git a/python/pyarrow/_plasma.pyx b/python/pyarrow/_plasma.pyx index 7e994c3ee07..e61c2745270 100644 --- a/python/pyarrow/_plasma.pyx +++ b/python/pyarrow/_plasma.pyx @@ -125,15 +125,17 @@ cdef extern from "plasma/client.h" nogil: CStatus List(CObjectTable* objects) - CStatus Subscribe(int* fd) + CStatus Subscribe() CStatus DecodeNotification(const uint8_t* buffer, CUniqueID* object_id, int64_t* data_size, int64_t* metadata_size) - CStatus GetNotification(int fd, CUniqueID* object_id, + CStatus GetNotification(CUniqueID* object_id, int64_t* data_size, int64_t* metadata_size) + int GetNativeNotificationHandle() + CStatus Disconnect() CStatus Delete(const c_vector[CUniqueID] object_ids) @@ -296,12 +298,10 @@ cdef class PlasmaClient: cdef: shared_ptr[CPlasmaClient] client - int notification_fd c_string store_socket_name def __cinit__(self): self.client.reset(new CPlasmaClient()) - self.notification_fd = -1 self.store_socket_name = b"" cdef _get_object_buffers(self, object_ids, int64_t timeout_ms, @@ -656,14 +656,14 @@ cdef class PlasmaClient: def subscribe(self): """Subscribe to notifications about sealed objects.""" with nogil: - plasma_check_status( - self.client.get().Subscribe(&self.notification_fd)) + plasma_check_status(self.client.get().Subscribe()) def get_notification_socket(self): """ Get the notification socket. """ - return compat.get_socket_from_fd(self.notification_fd, + cdef int fd = self.client.get().GetNativeNotificationHandle() + return compat.get_socket_from_fd(fd, family=socket.AF_UNIX, type=socket.SOCK_STREAM) @@ -708,8 +708,7 @@ cdef class PlasmaClient: cdef int64_t data_size cdef int64_t metadata_size with nogil: - status = self.client.get().GetNotification(self.notification_fd, - &object_id.data, + status = self.client.get().GetNotification(&object_id.data, &data_size, &metadata_size) plasma_check_status(status)