mirror of
https://github.com/wassname/ray.git
synced 2026-07-16 11:21:10 +08:00
Make the Plasma store ready for Arrow integration (#579)
* port plasma to arrow * fixes * refactor plasma client * more modernization * fix plasma manager tests * everything compiles * fix plasma client tests * update plasma serialization tests * fix plasma manager tests * fix bug * updates * fix bug * fix tests * fix rebase * address comments * fix travis valgrind build * fix linting * fix include order again * fix linting * address comments
This commit is contained in:
committed by
Robert Nishihara
parent
609b5c1a4c
commit
b94b4a35e0
@@ -174,7 +174,8 @@ void LocalSchedulerState_free(LocalSchedulerState *state) {
|
||||
}
|
||||
|
||||
/* Disconnect from plasma. */
|
||||
plasma_disconnect(state->plasma_conn);
|
||||
ARROW_CHECK_OK(state->plasma_conn->Disconnect());
|
||||
delete state->plasma_conn;
|
||||
state->plasma_conn = NULL;
|
||||
|
||||
/* Disconnect from the database. */
|
||||
@@ -366,11 +367,18 @@ LocalSchedulerState *LocalSchedulerState_init(
|
||||
state->db = NULL;
|
||||
}
|
||||
/* Connect to Plasma. This method will retry if Plasma hasn't started yet. */
|
||||
state->plasma_conn =
|
||||
plasma_connect(plasma_store_socket_name, plasma_manager_socket_name,
|
||||
PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
state->plasma_conn = new PlasmaClient();
|
||||
if (plasma_manager_socket_name != NULL) {
|
||||
ARROW_CHECK_OK(state->plasma_conn->Connect(plasma_store_socket_name,
|
||||
plasma_manager_socket_name,
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
} else {
|
||||
ARROW_CHECK_OK(state->plasma_conn->Connect(plasma_store_socket_name, "",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
}
|
||||
/* Subscribe to notifications about sealed objects. */
|
||||
int plasma_fd = plasma_subscribe(state->plasma_conn);
|
||||
int plasma_fd;
|
||||
ARROW_CHECK_OK(state->plasma_conn->Subscribe(plasma_fd));
|
||||
/* Add the callback that processes the notification to the event loop. */
|
||||
event_loop_add_file(loop, plasma_fd, EVENT_LOOP_READ,
|
||||
process_plasma_notification, state);
|
||||
|
||||
@@ -457,7 +457,7 @@ void fetch_missing_dependency(LocalSchedulerState *state,
|
||||
/* We weren't actively fetching this object. Try the fetch once
|
||||
* immediately. */
|
||||
if (plasma_manager_is_connected(state->plasma_conn)) {
|
||||
plasma_fetch(state->plasma_conn, 1, &obj_id);
|
||||
ARROW_CHECK_OK(state->plasma_conn->Fetch(1, &obj_id));
|
||||
}
|
||||
/* Create an entry and add it to the list of active fetch requests to
|
||||
* ensure that the fetch actually happens. The entry will be moved to the
|
||||
@@ -546,7 +546,7 @@ int fetch_object_timeout_handler(event_loop *loop, timer_id id, void *context) {
|
||||
object_ids[i] = entry.second.object_id;
|
||||
i++;
|
||||
}
|
||||
plasma_fetch(state->plasma_conn, num_object_ids, object_ids);
|
||||
ARROW_CHECK_OK(state->plasma_conn->Fetch(num_object_ids, object_ids));
|
||||
for (int i = 0; i < num_object_ids; ++i) {
|
||||
reconstruct_object(state, object_ids[i]);
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ struct LocalSchedulerState {
|
||||
/** The handle to the database. */
|
||||
DBHandle *db;
|
||||
/** The Plasma client. */
|
||||
PlasmaConnection *plasma_conn;
|
||||
PlasmaClient *plasma_conn;
|
||||
/** State for the scheduling algorithm. */
|
||||
SchedulingAlgorithmState *algorithm_state;
|
||||
/** Input buffer, used for reading input in process_message to avoid
|
||||
|
||||
@@ -45,7 +45,6 @@ if(HAS_PLASMA)
|
||||
include_directories("${CMAKE_CURRENT_LIST_DIR}/../plasma")
|
||||
include_directories("${CMAKE_CURRENT_LIST_DIR}/../common")
|
||||
include_directories("${CMAKE_CURRENT_LIST_DIR}/../common/thirdparty")
|
||||
set(COMMON_EXTENSION ../common/lib/python/common_extension.cc)
|
||||
endif()
|
||||
|
||||
add_definitions(-fPIC)
|
||||
@@ -55,8 +54,7 @@ add_library(numbuf SHARED
|
||||
cpp/src/numbuf/sequence.cc
|
||||
python/src/pynumbuf/numbuf.cc
|
||||
python/src/pynumbuf/adapters/numpy.cc
|
||||
python/src/pynumbuf/adapters/python.cc
|
||||
${COMMON_EXTENSION})
|
||||
python/src/pynumbuf/adapters/python.cc)
|
||||
|
||||
|
||||
if(APPLE)
|
||||
|
||||
@@ -7,16 +7,13 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <arrow/api.h>
|
||||
#include <arrow/ipc/api.h>
|
||||
#include <arrow/ipc/writer.h>
|
||||
|
||||
#include <arrow/python/numpy_convert.h>
|
||||
|
||||
#include "adapters/python.h"
|
||||
#include "memory.h"
|
||||
|
||||
#ifdef HAS_PLASMA
|
||||
// This needs to be included before plasma_protocol. We cannot include it in
|
||||
// plasma_protocol, because that file is used both with the store and the
|
||||
// manager, the store uses it the ObjectID from plasma_common.h and the
|
||||
// manager uses it with the ObjectID from common.h.
|
||||
#include "plasma_common.h"
|
||||
|
||||
#include "plasma_client.h"
|
||||
#include "plasma_protocol.h"
|
||||
|
||||
@@ -25,11 +22,18 @@ PyObject* NumbufPlasmaOutOfMemoryError;
|
||||
PyObject* NumbufPlasmaObjectExistsError;
|
||||
}
|
||||
|
||||
#include "common_extension.h"
|
||||
#include "plasma_extension.h"
|
||||
|
||||
#endif
|
||||
|
||||
#include <arrow/api.h>
|
||||
#include <arrow/ipc/api.h>
|
||||
#include <arrow/ipc/writer.h>
|
||||
#include <arrow/python/numpy_convert.h>
|
||||
|
||||
#include "adapters/python.h"
|
||||
#include "memory.h"
|
||||
|
||||
using namespace arrow;
|
||||
using namespace numbuf;
|
||||
|
||||
@@ -253,9 +257,9 @@ static void BufferCapsule_Destructor(PyObject* capsule) {
|
||||
* is (void*) 0x1). This is neccessary because the primary pointer of the
|
||||
* capsule cannot be NULL. */
|
||||
if (PyCapsule_GetContext(context) == NULL) {
|
||||
PlasmaConnection* conn;
|
||||
CHECK(PyObjectToPlasmaConnection(context, &conn));
|
||||
plasma_release(conn, *id);
|
||||
PlasmaClient* client;
|
||||
ARROW_CHECK(PyObjectToPlasmaClient(context, &client));
|
||||
ARROW_CHECK_OK(client->Release(*id));
|
||||
}
|
||||
Py_XDECREF(context);
|
||||
delete id;
|
||||
@@ -275,10 +279,10 @@ static void BufferCapsule_Destructor(PyObject* capsule) {
|
||||
*/
|
||||
static PyObject* store_list(PyObject* self, PyObject* args) {
|
||||
ObjectID obj_id;
|
||||
PlasmaConnection* conn;
|
||||
PlasmaClient* client;
|
||||
PyObject* value;
|
||||
if (!PyArg_ParseTuple(args, "O&O&O", PyStringToUniqueID, &obj_id,
|
||||
PyObjectToPlasmaConnection, &conn, &value)) {
|
||||
PyObjectToPlasmaClient, &client, &value)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!PyList_Check(value)) { return NULL; }
|
||||
@@ -302,21 +306,20 @@ static PyObject* store_list(PyObject* self, PyObject* args) {
|
||||
* stored in the plasma data buffer. The header end offset is stored in
|
||||
* the first LENGTH_PREFIX_SIZE bytes of the data buffer. The RecordBatch
|
||||
* data is stored after that. */
|
||||
int error_code =
|
||||
plasma_create(conn, obj_id, LENGTH_PREFIX_SIZE + total_size, NULL, 0, &data);
|
||||
if (error_code == PlasmaError_ObjectExists) {
|
||||
s = client->Create(obj_id, LENGTH_PREFIX_SIZE + total_size, NULL, 0, &data);
|
||||
if (s.IsPlasmaObjectExists()) {
|
||||
PyErr_SetString(NumbufPlasmaObjectExistsError,
|
||||
"An object with this ID already exists in the plasma "
|
||||
"store.");
|
||||
return NULL;
|
||||
}
|
||||
if (error_code == PlasmaError_OutOfMemory) {
|
||||
if (s.IsPlasmaStoreFull()) {
|
||||
PyErr_SetString(NumbufPlasmaOutOfMemoryError,
|
||||
"The plasma store ran out of memory and could not create "
|
||||
"this object.");
|
||||
return NULL;
|
||||
}
|
||||
CHECK(error_code == PlasmaError_OK);
|
||||
ARROW_CHECK_OK(s);
|
||||
|
||||
auto target =
|
||||
std::make_shared<FixedBufferStream>(LENGTH_PREFIX_SIZE + data, total_size);
|
||||
@@ -324,9 +327,9 @@ static PyObject* store_list(PyObject* self, PyObject* args) {
|
||||
*((int64_t*)data) = data_size;
|
||||
|
||||
/* Do the plasma_release corresponding to the call to plasma_create. */
|
||||
plasma_release(conn, obj_id);
|
||||
ARROW_CHECK_OK(client->Release(obj_id));
|
||||
/* Seal the object. */
|
||||
plasma_seal(conn, obj_id);
|
||||
ARROW_CHECK_OK(client->Seal(obj_id));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -350,13 +353,13 @@ static PyObject* store_list(PyObject* self, PyObject* args) {
|
||||
*/
|
||||
static PyObject* retrieve_list(PyObject* self, PyObject* args) {
|
||||
PyObject* object_id_list;
|
||||
PyObject* plasma_conn;
|
||||
PyObject* plasma_client;
|
||||
long long timeout_ms;
|
||||
if (!PyArg_ParseTuple(args, "OOL", &object_id_list, &plasma_conn, &timeout_ms)) {
|
||||
if (!PyArg_ParseTuple(args, "OOL", &object_id_list, &plasma_client, &timeout_ms)) {
|
||||
return NULL;
|
||||
}
|
||||
PlasmaConnection* conn;
|
||||
if (!PyObjectToPlasmaConnection(plasma_conn, &conn)) { return NULL; }
|
||||
PlasmaClient* client;
|
||||
if (!PyObjectToPlasmaClient(plasma_client, &client)) { return NULL; }
|
||||
|
||||
Py_ssize_t num_object_ids = PyList_Size(object_id_list);
|
||||
ObjectID* object_ids = new ObjectID[num_object_ids];
|
||||
@@ -367,7 +370,7 @@ static PyObject* retrieve_list(PyObject* self, PyObject* args) {
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
plasma_get(conn, object_ids, num_object_ids, timeout_ms, object_buffers);
|
||||
ARROW_CHECK_OK(client->Get(object_ids, num_object_ids, timeout_ms, object_buffers));
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
PyObject* returns = PyList_New(num_object_ids);
|
||||
@@ -384,8 +387,8 @@ static PyObject* retrieve_list(PyObject* self, PyObject* args) {
|
||||
* buffer is in scope. This prevents memory in the object store from getting
|
||||
* released while it is still being used to back a Python object. */
|
||||
PyObject* base = PyCapsule_New(buffer_obj_id, "buffer", BufferCapsule_Destructor);
|
||||
PyCapsule_SetContext(base, plasma_conn);
|
||||
Py_XINCREF(plasma_conn);
|
||||
PyCapsule_SetContext(base, plasma_client);
|
||||
Py_XINCREF(plasma_client);
|
||||
|
||||
auto batch = std::shared_ptr<RecordBatch>();
|
||||
std::vector<std::shared_ptr<Tensor>> tensors;
|
||||
|
||||
+18
-16
@@ -43,7 +43,6 @@ include_directories("${CMAKE_CURRENT_LIST_DIR}/../")
|
||||
add_library(plasma SHARED
|
||||
plasma.cc
|
||||
plasma_extension.cc
|
||||
../common/lib/python/common_extension.cc
|
||||
plasma_protocol.cc
|
||||
plasma_client.cc
|
||||
thirdparty/xxhash.c
|
||||
@@ -52,9 +51,9 @@ add_library(plasma SHARED
|
||||
add_dependencies(plasma gen_plasma_fbs)
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(plasma "-undefined dynamic_lookup" -Wl,-force_load,${FLATBUFFERS_STATIC_LIB} common ${FLATBUFFERS_STATIC_LIB} -lpthread)
|
||||
target_link_libraries(plasma plasma_lib "-undefined dynamic_lookup" -Wl,-force_load,${FLATBUFFERS_STATIC_LIB} ${PYTHON_LIBRARIES} ${FLATBUFFERS_STATIC_LIB} -lpthread)
|
||||
else(APPLE)
|
||||
target_link_libraries(plasma -Wl,--whole-archive ${FLATBUFFERS_STATIC_LIB} -Wl,--no-whole-archive common ${FLATBUFFERS_STATIC_LIB} -lpthread)
|
||||
target_link_libraries(plasma plasma_lib -Wl,--whole-archive ${FLATBUFFERS_STATIC_LIB} -Wl,--no-whole-archive ${PYTHON_LIBRARIES} ${FLATBUFFERS_STATIC_LIB} -lpthread)
|
||||
endif(APPLE)
|
||||
|
||||
include_directories("${FLATBUFFERS_INCLUDE_DIR}")
|
||||
@@ -63,8 +62,22 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
|
||||
|
||||
set_source_files_properties(thirdparty/dlmalloc.c PROPERTIES COMPILE_FLAGS -Wno-all)
|
||||
|
||||
add_library(plasma_lib STATIC
|
||||
plasma_client.cc
|
||||
plasma.cc
|
||||
plasma_common.cc
|
||||
plasma_io.cc
|
||||
plasma_protocol.cc
|
||||
status.cc
|
||||
fling.c
|
||||
thirdparty/xxhash.c)
|
||||
|
||||
target_link_libraries(plasma_lib ${FLATBUFFERS_STATIC_LIB} -lpthread)
|
||||
add_dependencies(plasma_lib gen_plasma_fbs)
|
||||
|
||||
add_executable(plasma_store
|
||||
plasma_store.cc
|
||||
thirdparty/ae/ae.c
|
||||
plasma.cc
|
||||
plasma_events.cc
|
||||
plasma_protocol.cc
|
||||
@@ -74,18 +87,7 @@ add_executable(plasma_store
|
||||
|
||||
add_dependencies(plasma_store hiredis gen_plasma_fbs)
|
||||
|
||||
target_link_libraries(plasma_store common ${FLATBUFFERS_STATIC_LIB})
|
||||
|
||||
add_library(plasma_lib STATIC
|
||||
plasma_client.cc
|
||||
plasma.cc
|
||||
plasma_events.cc
|
||||
plasma_protocol.cc
|
||||
fling.c
|
||||
thirdparty/xxhash.c)
|
||||
|
||||
target_link_libraries(plasma_lib common ${FLATBUFFERS_STATIC_LIB} -lpthread)
|
||||
add_dependencies(plasma_lib gen_plasma_fbs)
|
||||
target_link_libraries(plasma_store plasma_lib ${FLATBUFFERS_STATIC_LIB})
|
||||
|
||||
add_dependencies(plasma protocol_fbs)
|
||||
|
||||
@@ -97,7 +99,7 @@ target_link_libraries(plasma_manager common plasma_lib ${FLATBUFFERS_STATIC_LIB}
|
||||
add_library(plasma_client SHARED plasma_client.cc)
|
||||
target_link_libraries(plasma_client ${FLATBUFFERS_STATIC_LIB})
|
||||
|
||||
target_link_libraries(plasma_client common plasma_lib ${FLATBUFFERS_STATIC_LIB})
|
||||
target_link_libraries(plasma_client plasma_lib ${FLATBUFFERS_STATIC_LIB})
|
||||
|
||||
define_test(client_tests plasma_lib)
|
||||
define_test(manager_tests plasma_lib plasma_manager.cc)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
void LRUCache::add(const ObjectID &key, int64_t size) {
|
||||
auto it = item_map_.find(key);
|
||||
CHECK(it == item_map_.end());
|
||||
ARROW_CHECK(it == item_map_.end());
|
||||
/* Note that it is important to use a list so the iterators stay valid. */
|
||||
item_list_.emplace_front(key, size);
|
||||
item_map_.emplace(key, item_list_.begin());
|
||||
@@ -10,7 +10,7 @@ void LRUCache::add(const ObjectID &key, int64_t size) {
|
||||
|
||||
void LRUCache::remove(const ObjectID &key) {
|
||||
auto it = item_map_.find(key);
|
||||
CHECK(it != item_map_.end());
|
||||
ARROW_CHECK(it != item_map_.end());
|
||||
item_list_.erase(it->second);
|
||||
item_map_.erase(it);
|
||||
}
|
||||
@@ -58,15 +58,16 @@ bool EvictionPolicy::require_space(int64_t size,
|
||||
if (required_space > 0) {
|
||||
/* Try to free up at least as much space as we need right now but ideally
|
||||
* up to 20% of the total capacity. */
|
||||
int64_t space_to_free = MAX(size, store_info_->memory_capacity / 5);
|
||||
LOG_DEBUG("not enough space to create this object, so evicting objects");
|
||||
int64_t space_to_free = std::max(size, store_info_->memory_capacity / 5);
|
||||
ARROW_LOG(DEBUG)
|
||||
<< "not enough space to create this object, so evicting objects";
|
||||
/* Choose some objects to evict, and update the return pointers. */
|
||||
num_bytes_evicted =
|
||||
choose_objects_to_evict(space_to_free, objects_to_evict);
|
||||
LOG_INFO(
|
||||
"There is not enough space to create this object, so evicting "
|
||||
"%zu objects to free up %" PRId64 " bytes.",
|
||||
objects_to_evict.size(), num_bytes_evicted);
|
||||
ARROW_LOG(INFO)
|
||||
<< "There is not enough space to create this object, so evicting "
|
||||
<< objects_to_evict.size() << " objects to free up "
|
||||
<< num_bytes_evicted << " bytes.";
|
||||
} else {
|
||||
num_bytes_evicted = 0;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <list>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "plasma_common.h"
|
||||
#include "plasma.h"
|
||||
|
||||
/* ==== The eviction policy ====
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
// 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 ARROW_UTIL_LOGGING_H
|
||||
#define ARROW_UTIL_LOGGING_H
|
||||
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
|
||||
namespace arrow {
|
||||
|
||||
// Stubbed versions of macros defined in glog/logging.h, intended for
|
||||
// environments where glog headers aren't available.
|
||||
//
|
||||
// Add more as needed.
|
||||
|
||||
// Log levels. LOG ignores them, so their values are abitrary.
|
||||
|
||||
#define ARROW_DEBUG (-1)
|
||||
#define ARROW_INFO 0
|
||||
#define ARROW_WARNING 1
|
||||
#define ARROW_ERROR 2
|
||||
#define ARROW_FATAL 3
|
||||
|
||||
#define ARROW_LOG_INTERNAL(level) ::arrow::internal::CerrLog(level)
|
||||
#define ARROW_LOG(level) ARROW_LOG_INTERNAL(ARROW_##level)
|
||||
|
||||
#define ARROW_CHECK(condition) \
|
||||
(condition) ? 0 : ::arrow::internal::FatalLog(ARROW_FATAL) \
|
||||
<< __FILE__ << __LINE__ \
|
||||
<< " Check failed: " #condition " "
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ARROW_DFATAL ARROW_WARNING
|
||||
|
||||
#define DCHECK(condition) \
|
||||
while (false) \
|
||||
::arrow::internal::NullLog()
|
||||
#define DCHECK_EQ(val1, val2) \
|
||||
while (false) \
|
||||
::arrow::internal::NullLog()
|
||||
#define DCHECK_NE(val1, val2) \
|
||||
while (false) \
|
||||
::arrow::internal::NullLog()
|
||||
#define DCHECK_LE(val1, val2) \
|
||||
while (false) \
|
||||
::arrow::internal::NullLog()
|
||||
#define DCHECK_LT(val1, val2) \
|
||||
while (false) \
|
||||
::arrow::internal::NullLog()
|
||||
#define DCHECK_GE(val1, val2) \
|
||||
while (false) \
|
||||
::arrow::internal::NullLog()
|
||||
#define DCHECK_GT(val1, val2) \
|
||||
while (false) \
|
||||
::arrow::internal::NullLog()
|
||||
|
||||
#else
|
||||
#define ARROW_DFATAL ARROW_FATAL
|
||||
|
||||
#define DCHECK(condition) ARROW_CHECK(condition)
|
||||
#define DCHECK_EQ(val1, val2) ARROW_CHECK((val1) == (val2))
|
||||
#define DCHECK_NE(val1, val2) ARROW_CHECK((val1) != (val2))
|
||||
#define DCHECK_LE(val1, val2) ARROW_CHECK((val1) <= (val2))
|
||||
#define DCHECK_LT(val1, val2) ARROW_CHECK((val1) < (val2))
|
||||
#define DCHECK_GE(val1, val2) ARROW_CHECK((val1) >= (val2))
|
||||
#define DCHECK_GT(val1, val2) ARROW_CHECK((val1) > (val2))
|
||||
|
||||
#endif // NDEBUG
|
||||
|
||||
namespace internal {
|
||||
|
||||
class NullLog {
|
||||
public:
|
||||
template <class T>
|
||||
NullLog &operator<<(const T &t) {
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
class CerrLog {
|
||||
public:
|
||||
CerrLog(int severity) // NOLINT(runtime/explicit)
|
||||
: severity_(severity),
|
||||
has_logged_(false) {}
|
||||
|
||||
virtual ~CerrLog() {
|
||||
if (has_logged_) {
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
if (severity_ == ARROW_FATAL) {
|
||||
std::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
CerrLog &operator<<(const T &t) {
|
||||
// TODO(pcm): Print this if in debug mode, but not if in valgrind
|
||||
// mode
|
||||
if (severity_ == ARROW_DEBUG) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
has_logged_ = true;
|
||||
std::cerr << t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
const int severity_;
|
||||
bool has_logged_;
|
||||
};
|
||||
|
||||
// Clang-tidy isn't smart enough to determine that DCHECK using CerrLog doesn't
|
||||
// return so we create a new class to give it a hint.
|
||||
class FatalLog : public CerrLog {
|
||||
public:
|
||||
explicit FatalLog(int /* severity */) // NOLINT
|
||||
: CerrLog(ARROW_FATAL){} // NOLINT
|
||||
|
||||
[[noreturn]] ~FatalLog() {
|
||||
if (has_logged_) {
|
||||
std::cerr << std::endl;
|
||||
}
|
||||
std::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace arrow
|
||||
|
||||
#endif // ARROW_UTIL_LOGGING_H
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "plasma_common.h"
|
||||
#include "plasma.h"
|
||||
|
||||
#include "io.h"
|
||||
@@ -12,14 +13,15 @@ int warn_if_sigpipe(int status, int client_sock) {
|
||||
return 0;
|
||||
}
|
||||
if (errno == EPIPE || errno == EBADF || errno == ECONNRESET) {
|
||||
LOG_WARN(
|
||||
"Received SIGPIPE, BAD FILE DESCRIPTOR, or ECONNRESET when "
|
||||
"sending a message to client on fd %d. The client on the other end may "
|
||||
"have hung up.",
|
||||
client_sock);
|
||||
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;
|
||||
}
|
||||
LOG_FATAL("Failed to write message to client on fd %d.", client_sock);
|
||||
ARROW_LOG(FATAL) << "Failed to write message to client on fd " << client_sock
|
||||
<< ".";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+26
-2
@@ -9,17 +9,41 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h> /* pid_t */
|
||||
|
||||
extern "C" {
|
||||
#include "sha256.h"
|
||||
}
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "common.h"
|
||||
#include "format/common_generated.h"
|
||||
#include "logging.h"
|
||||
#include "status.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#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. */
|
||||
#define BLOCK_SIZE 64
|
||||
|
||||
// Size of object hash digests.
|
||||
constexpr int64_t kDigestSize = SHA256_BLOCK_SIZE;
|
||||
|
||||
struct Client;
|
||||
|
||||
/**
|
||||
@@ -113,7 +137,7 @@ struct ObjectTableEntry {
|
||||
/** The state of the object, e.g., whether it is open or sealed. */
|
||||
object_state state;
|
||||
/** The digest of the object. Used to see if two objects are the same. */
|
||||
unsigned char digest[DIGEST_SIZE];
|
||||
unsigned char digest[kDigestSize];
|
||||
};
|
||||
|
||||
/** The plasma store information that is exposed to the eviction policy. */
|
||||
|
||||
+334
-415
@@ -1,4 +1,4 @@
|
||||
/* PLASMA CLIENT: Client library for using the plasma store and manager */
|
||||
// PLASMA CLIENT: Client library for using the plasma store and manager
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Win32_Interop/win32_types.h>
|
||||
@@ -16,18 +16,13 @@
|
||||
#include <sys/un.h>
|
||||
#include <strings.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/time.h>
|
||||
#include <netdb.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "io.h"
|
||||
#include "plasma_common.h"
|
||||
#include "plasma.h"
|
||||
#include "plasma_io.h"
|
||||
#include "plasma_protocol.h"
|
||||
#include "plasma_client.h"
|
||||
|
||||
/* C++ includes */
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
|
||||
@@ -41,89 +36,39 @@ extern "C" {
|
||||
#define XXH64_DEFAULT_SEED 0
|
||||
}
|
||||
|
||||
#define THREADPOOL_SIZE 8
|
||||
#define BYTES_IN_MB (1 << 20)
|
||||
static std::vector<std::thread> threadpool_(THREADPOOL_SIZE);
|
||||
// Number of threads used for memcopy and hash computations.
|
||||
constexpr int64_t kThreadPoolSize = 8;
|
||||
constexpr int64_t kBytesInMB = 1 << 20;
|
||||
static std::vector<std::thread> threadpool_(kThreadPoolSize);
|
||||
|
||||
struct ClientMmapTableEntry {
|
||||
/** Key that uniquely identifies the memory mapped file. In practice, we
|
||||
* take the numerical value of the file descriptor in the object store. */
|
||||
int key;
|
||||
/** The result of mmap for this file descriptor. */
|
||||
/// The result of mmap for this file descriptor.
|
||||
uint8_t *pointer;
|
||||
/** The length of the memory-mapped file. */
|
||||
/// The length of the memory-mapped file.
|
||||
size_t length;
|
||||
/** The number of objects in this memory-mapped file that are currently being
|
||||
* used by the client. When this count reaches zeros, we unmap the file. */
|
||||
/// The number of objects in this memory-mapped file that are currently being
|
||||
/// used by the client. When this count reaches zeros, we unmap the file.
|
||||
int count;
|
||||
};
|
||||
|
||||
struct ObjectInUseEntry {
|
||||
/** The ID of the object. This is used as the key in the hash table. */
|
||||
ObjectID object_id;
|
||||
/** A count of the number of times this client has called plasma_create or
|
||||
* plasma_get on this object ID minus the number of calls to plasma_release.
|
||||
* When this count reaches zero, we remove the entry from the objects_in_use
|
||||
* and decrement a count in the relevant ClientMmapTableEntry. */
|
||||
/// A count of the number of times this client has called PlasmaClient::Create
|
||||
/// or
|
||||
/// PlasmaClient::Get on this object ID minus the number of calls to
|
||||
/// PlasmaClient::Release.
|
||||
/// When this count reaches zero, we remove the entry from the ObjectsInUse
|
||||
/// and decrement a count in the relevant ClientMmapTableEntry.
|
||||
int count;
|
||||
/** Cached information to read the object. */
|
||||
/// Cached information to read the object.
|
||||
PlasmaObject object;
|
||||
/** A flag representing whether the object has been sealed. */
|
||||
/// A flag representing whether the object has been sealed.
|
||||
bool is_sealed;
|
||||
};
|
||||
|
||||
/** Configuration options for the plasma client. */
|
||||
typedef struct {
|
||||
/** Number of release calls we wait until the object is actually released.
|
||||
* This allows us to avoid invalidating the cpu cache on workers if objects
|
||||
* are reused accross tasks. */
|
||||
int release_delay;
|
||||
} plasma_client_config;
|
||||
|
||||
/** Information about a connection between a Plasma Client and Plasma Store.
|
||||
* This is used to avoid mapping the same files into memory multiple times. */
|
||||
struct PlasmaConnection {
|
||||
/** File descriptor of the Unix domain socket that connects to the store. */
|
||||
int store_conn;
|
||||
/** File descriptor of the Unix domain socket that connects to the manager. */
|
||||
int manager_conn;
|
||||
/** File descriptor of the Unix domain socket on which client receives event
|
||||
* notifications for the objects it subscribes for when these objects are
|
||||
* sealed either locally or remotely. */
|
||||
int manager_conn_subscribe;
|
||||
/** Buffer that holds memory for serializing plasma protocol messages. */
|
||||
protocol_builder *builder;
|
||||
/** 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. */
|
||||
std::unordered_map<int, ClientMmapTableEntry *> mmap_table;
|
||||
/** A hash table of the object IDs that are currently being used by this
|
||||
* client. */
|
||||
std::unordered_map<ObjectID, ObjectInUseEntry *, UniqueIDHasher>
|
||||
objects_in_use;
|
||||
/** Object IDs of the last few release calls. This is a deque and
|
||||
* is used to delay releasing objects to see if they can be reused by
|
||||
* subsequent tasks so we do not unneccessarily invalidate cpu caches.
|
||||
* TODO(pcm): replace this with a proper lru cache using the size of the L3
|
||||
* cache. */
|
||||
std::deque<ObjectID> release_history;
|
||||
/** The number of bytes in the combined objects that are held in the release
|
||||
* history doubly-linked list. If this is too large then the client starts
|
||||
* releasing objects. */
|
||||
int64_t in_use_object_bytes;
|
||||
/** Configuration options for the plasma client. */
|
||||
plasma_client_config config;
|
||||
/** The amount of memory available to the Plasma store. The client needs this
|
||||
* information to make sure that it does not delay in releasing so much
|
||||
* memory that the store is unable to evict enough objects to free up space.
|
||||
*/
|
||||
int64_t store_capacity;
|
||||
};
|
||||
|
||||
/* If the file descriptor fd has been mmapped in this client process before,
|
||||
* return the pointer that was returned by mmap, otherwise mmap it and store the
|
||||
* pointer in a hash table. */
|
||||
uint8_t *lookup_or_mmap(PlasmaConnection *conn,
|
||||
// If the file descriptor fd has been mmapped in this client process before,
|
||||
// return the pointer that was returned by mmap, otherwise mmap it and store the
|
||||
// pointer in a hash table.
|
||||
uint8_t *lookup_or_mmap(PlasmaClient *conn,
|
||||
int fd,
|
||||
int store_fd_val,
|
||||
int64_t map_size) {
|
||||
@@ -135,11 +80,10 @@ uint8_t *lookup_or_mmap(PlasmaConnection *conn,
|
||||
uint8_t *result = (uint8_t *) mmap(NULL, map_size, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd, 0);
|
||||
if (result == MAP_FAILED) {
|
||||
LOG_FATAL("mmap failed");
|
||||
ARROW_LOG(FATAL) << "mmap failed";
|
||||
}
|
||||
close(fd);
|
||||
ClientMmapTableEntry *entry = new ClientMmapTableEntry();
|
||||
entry->key = store_fd_val;
|
||||
entry->pointer = result;
|
||||
entry->length = map_size;
|
||||
entry->count = 0;
|
||||
@@ -148,285 +92,277 @@ uint8_t *lookup_or_mmap(PlasmaConnection *conn,
|
||||
}
|
||||
}
|
||||
|
||||
/* Get a pointer to a file that we know has been memory mapped in this client
|
||||
* process before. */
|
||||
uint8_t *lookup_mmapped_file(PlasmaConnection *conn, int store_fd_val) {
|
||||
// Get a pointer to a file that we know has been memory mapped in this client
|
||||
// process before.
|
||||
uint8_t *lookup_mmapped_file(PlasmaClient *conn, int store_fd_val) {
|
||||
auto entry = conn->mmap_table.find(store_fd_val);
|
||||
CHECK(entry != conn->mmap_table.end());
|
||||
ARROW_CHECK(entry != conn->mmap_table.end());
|
||||
return entry->second->pointer;
|
||||
}
|
||||
|
||||
void increment_object_count(PlasmaConnection *conn,
|
||||
void increment_object_count(PlasmaClient *conn,
|
||||
ObjectID object_id,
|
||||
PlasmaObject *object,
|
||||
bool is_sealed) {
|
||||
/* Increment the count of the object to track the fact that it is being used.
|
||||
* The corresponding decrement should happen in plasma_release. */
|
||||
// Increment the count of the object to track the fact that it is being used.
|
||||
// The corresponding decrement should happen in PlasmaClient::Release.
|
||||
auto elem = conn->objects_in_use.find(object_id);
|
||||
ObjectInUseEntry *object_entry;
|
||||
if (elem == conn->objects_in_use.end()) {
|
||||
/* Add this object ID to the hash table of object IDs in use. The
|
||||
* corresponding call to free happens in plasma_release. */
|
||||
// Add this object ID to the hash table of object IDs in use. The
|
||||
// corresponding call to free happens in PlasmaClient::Release.
|
||||
object_entry = new ObjectInUseEntry();
|
||||
object_entry->object_id = object_id;
|
||||
object_entry->object = *object;
|
||||
object_entry->count = 0;
|
||||
object_entry->is_sealed = is_sealed;
|
||||
conn->objects_in_use[object_id] = object_entry;
|
||||
/* Increment the count of the number of objects in the memory-mapped file
|
||||
* that are being used. The corresponding decrement should happen in
|
||||
* plasma_release. */
|
||||
// Increment the count of the number of objects in the memory-mapped file
|
||||
// that are being used. The corresponding decrement should happen in
|
||||
// PlasmaClient::Release.
|
||||
auto entry = conn->mmap_table.find(object->handle.store_fd);
|
||||
CHECK(entry != conn->mmap_table.end());
|
||||
CHECK(entry->second->count >= 0);
|
||||
/* Update the in_use_object_bytes. */
|
||||
ARROW_CHECK(entry != conn->mmap_table.end());
|
||||
ARROW_CHECK(entry->second->count >= 0);
|
||||
// Update the in_use_object_bytes.
|
||||
conn->in_use_object_bytes +=
|
||||
(object_entry->object.data_size + object_entry->object.metadata_size);
|
||||
entry->second->count += 1;
|
||||
} else {
|
||||
object_entry = elem->second;
|
||||
CHECK(object_entry->count > 0);
|
||||
ARROW_CHECK(object_entry->count > 0);
|
||||
}
|
||||
/* Increment the count of the number of instances of this object that are
|
||||
* being used by this client. The corresponding decrement should happen in
|
||||
* plasma_release. */
|
||||
// Increment the count of the number of instances of this object that are
|
||||
// being used by this client. The corresponding decrement should happen in
|
||||
// PlasmaClient::Release.
|
||||
object_entry->count += 1;
|
||||
}
|
||||
|
||||
int plasma_create(PlasmaConnection *conn,
|
||||
ObjectID obj_id,
|
||||
int64_t data_size,
|
||||
uint8_t *metadata,
|
||||
int64_t metadata_size,
|
||||
uint8_t **data) {
|
||||
LOG_DEBUG("called plasma_create on conn %d with size %" PRId64
|
||||
" and metadata size %" PRId64,
|
||||
conn->store_conn, data_size, metadata_size);
|
||||
CHECK(plasma_send_CreateRequest(conn->store_conn, conn->builder, obj_id,
|
||||
data_size, metadata_size) >= 0);
|
||||
uint8_t *reply_data =
|
||||
plasma_receive(conn->store_conn, MessageType_PlasmaCreateReply);
|
||||
int error;
|
||||
Status PlasmaClient::Create(ObjectID object_id,
|
||||
int64_t data_size,
|
||||
uint8_t *metadata,
|
||||
int64_t metadata_size,
|
||||
uint8_t **data) {
|
||||
ARROW_LOG(DEBUG) << "called plasma_create on conn " << store_conn
|
||||
<< " with size " << data_size << " and metadata size "
|
||||
<< metadata_size;
|
||||
RETURN_NOT_OK(
|
||||
SendCreateRequest(store_conn, object_id, data_size, metadata_size));
|
||||
std::vector<uint8_t> buffer;
|
||||
RETURN_NOT_OK(
|
||||
PlasmaReceive(store_conn, MessageType_PlasmaCreateReply, buffer));
|
||||
ObjectID id;
|
||||
PlasmaObject object;
|
||||
plasma_read_CreateReply(reply_data, &id, &object, &error);
|
||||
free(reply_data);
|
||||
if (error != PlasmaError_OK) {
|
||||
LOG_DEBUG("returned from plasma_create with error %d", error);
|
||||
CHECK(error == PlasmaError_OutOfMemory ||
|
||||
error == PlasmaError_ObjectExists);
|
||||
return error;
|
||||
}
|
||||
/* If the CreateReply included an error, then the store will not send a file
|
||||
* descriptor. */
|
||||
int fd = recv_fd(conn->store_conn);
|
||||
CHECKM(fd >= 0, "recv not successful");
|
||||
CHECK(object.data_size == data_size);
|
||||
CHECK(object.metadata_size == metadata_size);
|
||||
/* The metadata should come right after the data. */
|
||||
CHECK(object.metadata_offset == object.data_offset + data_size);
|
||||
*data = lookup_or_mmap(conn, fd, object.handle.store_fd,
|
||||
RETURN_NOT_OK(ReadCreateReply(buffer.data(), &id, &object));
|
||||
// If the CreateReply included an error, then the store will not send a file
|
||||
// descriptor.
|
||||
int fd = recv_fd(store_conn);
|
||||
ARROW_CHECK(fd >= 0) << "recv not successful";
|
||||
ARROW_CHECK(object.data_size == data_size);
|
||||
ARROW_CHECK(object.metadata_size == metadata_size);
|
||||
// The metadata should come right after the data.
|
||||
ARROW_CHECK(object.metadata_offset == object.data_offset + data_size);
|
||||
*data = lookup_or_mmap(this, fd, object.handle.store_fd,
|
||||
object.handle.mmap_size) +
|
||||
object.data_offset;
|
||||
/* If plasma_create is being called from a transfer, then we will not copy the
|
||||
* metadata here. The metadata will be written along with the data streamed
|
||||
* from the transfer. */
|
||||
// If plasma_create is being called from a transfer, then we will not copy the
|
||||
// metadata here. The metadata will be written along with the data streamed
|
||||
// from the transfer.
|
||||
if (metadata != NULL) {
|
||||
/* Copy the metadata to the buffer. */
|
||||
// Copy the metadata to the buffer.
|
||||
memcpy(*data + object.data_size, metadata, metadata_size);
|
||||
}
|
||||
/* Increment the count of the number of instances of this object that this
|
||||
* client is using. A call to plasma_release is required to decrement this
|
||||
* count. Cache the reference to the object. */
|
||||
increment_object_count(conn, obj_id, &object, false);
|
||||
/* We increment the count a second time (and the corresponding decrement will
|
||||
* happen in a plasma_release call in plasma_seal) so even if the buffer
|
||||
* returned by plasma_create goes out of scope, the object does not get
|
||||
* released before the call to plasma_seal happens. */
|
||||
increment_object_count(conn, obj_id, &object, false);
|
||||
return PlasmaError_OK;
|
||||
// Increment the count of the number of instances of this object that this
|
||||
// client is using. A call to PlasmaClient::Release is required to decrement
|
||||
// this
|
||||
// count. Cache the reference to the object.
|
||||
increment_object_count(this, object_id, &object, false);
|
||||
// We increment the count a second time (and the corresponding decrement will
|
||||
// happen in a PlasmaClient::Release call in plasma_seal) so even if the
|
||||
// buffer
|
||||
// returned by PlasmaClient::Dreate goes out of scope, the object does not get
|
||||
// released before the call to PlasmaClient::Seal happens.
|
||||
increment_object_count(this, object_id, &object, false);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void plasma_get(PlasmaConnection *conn,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects,
|
||||
int64_t timeout_ms,
|
||||
ObjectBuffer object_buffers[]) {
|
||||
/* Fill out the info for the objects that are already in use locally. */
|
||||
Status PlasmaClient::Get(ObjectID object_ids[],
|
||||
int64_t num_objects,
|
||||
int64_t timeout_ms,
|
||||
ObjectBuffer object_buffers[]) {
|
||||
// Fill out the info for the objects that are already in use locally.
|
||||
bool all_present = true;
|
||||
for (int i = 0; i < num_objects; ++i) {
|
||||
auto object_entry = conn->objects_in_use.find(object_ids[i]);
|
||||
if (object_entry == conn->objects_in_use.end()) {
|
||||
/* This object is not currently in use by this client, so we need to send
|
||||
* a request to the store. */
|
||||
auto object_entry = objects_in_use.find(object_ids[i]);
|
||||
if (object_entry == objects_in_use.end()) {
|
||||
// This object is not currently in use by this client, so we need to send
|
||||
// a request to the store.
|
||||
all_present = false;
|
||||
/* Make a note to ourselves that the object is not present. */
|
||||
// Make a note to ourselves that the object is not present.
|
||||
object_buffers[i].data_size = -1;
|
||||
} else {
|
||||
/* NOTE: If the object is still unsealed, we will deadlock, since we must
|
||||
* have been the one who created it. */
|
||||
CHECKM(object_entry->second->is_sealed,
|
||||
"Plasma client called get on an unsealed object that it created");
|
||||
// NOTE: If the object is still unsealed, we will deadlock, since we must
|
||||
// have been the one who created it.
|
||||
ARROW_CHECK(object_entry->second->is_sealed)
|
||||
<< "Plasma client called get on an unsealed object that it created";
|
||||
PlasmaObject *object = &object_entry->second->object;
|
||||
object_buffers[i].data =
|
||||
lookup_mmapped_file(conn, object->handle.store_fd);
|
||||
lookup_mmapped_file(this, object->handle.store_fd);
|
||||
object_buffers[i].data = object_buffers[i].data + object->data_offset;
|
||||
object_buffers[i].data_size = object->data_size;
|
||||
object_buffers[i].metadata = object_buffers[i].data + object->data_size;
|
||||
object_buffers[i].metadata_size = object->metadata_size;
|
||||
/* Increment the count of the number of instances of this object that this
|
||||
* client is using. A call to plasma_release is required to decrement this
|
||||
* count. Cache the reference to the object. */
|
||||
increment_object_count(conn, object_ids[i], object, true);
|
||||
// Increment the count of the number of instances of this object that this
|
||||
// client is using. A call to PlasmaClient::Release is required to
|
||||
// decrement this
|
||||
// count. Cache the reference to the object.
|
||||
increment_object_count(this, object_ids[i], object, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (all_present) {
|
||||
return;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* If we get here, then the objects aren't all currently in use by this
|
||||
* client, so we need to send a request to the plasma store. */
|
||||
CHECK(plasma_send_GetRequest(conn->store_conn, conn->builder, object_ids,
|
||||
num_objects, timeout_ms) >= 0);
|
||||
uint8_t *reply_data =
|
||||
plasma_receive(conn->store_conn, MessageType_PlasmaGetReply);
|
||||
ObjectID *received_obj_ids =
|
||||
(ObjectID *) malloc(num_objects * sizeof(ObjectID));
|
||||
PlasmaObject *object_data =
|
||||
(PlasmaObject *) malloc(num_objects * sizeof(PlasmaObject));
|
||||
// If we get here, then the objects aren't all currently in use by this
|
||||
// client, so we need to send a request to the plasma store.
|
||||
RETURN_NOT_OK(
|
||||
SendGetRequest(store_conn, object_ids, num_objects, timeout_ms));
|
||||
std::vector<uint8_t> buffer;
|
||||
RETURN_NOT_OK(PlasmaReceive(store_conn, MessageType_PlasmaGetReply, buffer));
|
||||
std::vector<ObjectID> received_object_ids(num_objects);
|
||||
std::vector<PlasmaObject> object_data(num_objects);
|
||||
PlasmaObject *object;
|
||||
plasma_read_GetReply(reply_data, received_obj_ids, object_data, num_objects);
|
||||
free(reply_data);
|
||||
RETURN_NOT_OK(ReadGetReply(buffer.data(), received_object_ids.data(),
|
||||
object_data.data(), num_objects));
|
||||
|
||||
for (int i = 0; i < num_objects; ++i) {
|
||||
DCHECK(ObjectID_equal(received_obj_ids[i], object_ids[i]));
|
||||
DCHECK(received_object_ids[i] == object_ids[i]);
|
||||
object = &object_data[i];
|
||||
if (object_buffers[i].data_size != -1) {
|
||||
/* If the object was already in use by the client, then the store should
|
||||
* have returned it. */
|
||||
// If the object was already in use by the client, then the store should
|
||||
// have returned it.
|
||||
DCHECK(object->data_size != -1);
|
||||
/* We won't use this file descriptor, but the store sent us one, so we
|
||||
* need to receive it and then close it right away so we don't leak file
|
||||
* descriptors. */
|
||||
int fd = recv_fd(conn->store_conn);
|
||||
// We won't use this file descriptor, but the store sent us one, so we
|
||||
// need to receive it and then close it right away so we don't leak file
|
||||
// descriptors.
|
||||
int fd = recv_fd(store_conn);
|
||||
close(fd);
|
||||
CHECK(fd >= 0);
|
||||
/* We've already filled out the information for this object, so we can
|
||||
* just continue. */
|
||||
ARROW_CHECK(fd >= 0);
|
||||
// We've already filled out the information for this object, so we can
|
||||
// just continue.
|
||||
continue;
|
||||
}
|
||||
/* If we are here, the object was not currently in use, so we need to
|
||||
* process the reply from the object store. */
|
||||
// If we are here, the object was not currently in use, so we need to
|
||||
// process the reply from the object store.
|
||||
if (object->data_size != -1) {
|
||||
/* The object was retrieved. The user will be responsible for releasing
|
||||
* this object. */
|
||||
int fd = recv_fd(conn->store_conn);
|
||||
CHECK(fd >= 0);
|
||||
object_buffers[i].data = lookup_or_mmap(conn, fd, object->handle.store_fd,
|
||||
// The object was retrieved. The user will be responsible for releasing
|
||||
// this object.
|
||||
int fd = recv_fd(store_conn);
|
||||
ARROW_CHECK(fd >= 0);
|
||||
object_buffers[i].data = lookup_or_mmap(this, fd, object->handle.store_fd,
|
||||
object->handle.mmap_size);
|
||||
/* Finish filling out the return values. */
|
||||
// Finish filling out the return values.
|
||||
object_buffers[i].data = object_buffers[i].data + object->data_offset;
|
||||
object_buffers[i].data_size = object->data_size;
|
||||
object_buffers[i].metadata = object_buffers[i].data + object->data_size;
|
||||
object_buffers[i].metadata_size = object->metadata_size;
|
||||
/* Increment the count of the number of instances of this object that this
|
||||
* client is using. A call to plasma_release is required to decrement this
|
||||
* count. Cache the reference to the object. */
|
||||
increment_object_count(conn, received_obj_ids[i], object, true);
|
||||
// Increment the count of the number of instances of this object that this
|
||||
// client is using. A call to PlasmaClient::Release is required to
|
||||
// decrement this
|
||||
// count. Cache the reference to the object.
|
||||
increment_object_count(this, received_object_ids[i], object, true);
|
||||
} else {
|
||||
/* The object was not retrieved. Make sure we already put a -1 here to
|
||||
* indicate that the object was not retrieved. The caller is not
|
||||
* responsible for releasing this object. */
|
||||
// The object was not retrieved. Make sure we already put a -1 here to
|
||||
// indicate that the object was not retrieved. The caller is not
|
||||
// responsible for releasing this object.
|
||||
DCHECK(object_buffers[i].data_size == -1);
|
||||
object_buffers[i].data_size = -1;
|
||||
}
|
||||
}
|
||||
free(object_data);
|
||||
free(received_obj_ids);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a helper method for implementing plasma_release. We maintain a buffer
|
||||
* of release calls and only perform them once the buffer becomes full (as
|
||||
* judged by the aggregate sizes of the objects). There may be multiple release
|
||||
* calls for the same object ID in the buffer. In this case, the first release
|
||||
* calls will not do anything. The client will only send a message to the store
|
||||
* releasing the object when the client is truly done with the object.
|
||||
*
|
||||
* @param conn The plasma connection.
|
||||
* @param object_id The object ID to attempt to release.
|
||||
*/
|
||||
void plasma_perform_release(PlasmaConnection *conn, ObjectID object_id) {
|
||||
/* Decrement the count of the number of instances of this object that are
|
||||
* being used by this client. The corresponding increment should have happened
|
||||
* in plasma_get. */
|
||||
auto object_entry = conn->objects_in_use.find(object_id);
|
||||
CHECK(object_entry != conn->objects_in_use.end());
|
||||
/// This is a helper method for implementing plasma_release. We maintain a
|
||||
/// buffer
|
||||
/// of release calls and only perform them once the buffer becomes full (as
|
||||
/// judged by the aggregate sizes of the objects). There may be multiple release
|
||||
/// calls for the same object ID in the buffer. In this case, the first release
|
||||
/// calls will not do anything. The client will only send a message to the store
|
||||
/// releasing the object when the client is truly done with the object.
|
||||
///
|
||||
/// @param conn The plasma connection.
|
||||
/// @param object_id The object ID to attempt to release.
|
||||
Status PlasmaClient::PerformRelease(ObjectID object_id) {
|
||||
// Decrement the count of the number of instances of this object that are
|
||||
// being used by this client. The corresponding increment should have happened
|
||||
// in PlasmaClient::Get.
|
||||
auto object_entry = objects_in_use.find(object_id);
|
||||
ARROW_CHECK(object_entry != objects_in_use.end());
|
||||
object_entry->second->count -= 1;
|
||||
CHECK(object_entry->second->count >= 0);
|
||||
/* Check if the client is no longer using this object. */
|
||||
ARROW_CHECK(object_entry->second->count >= 0);
|
||||
// Check if the client is no longer using this object.
|
||||
if (object_entry->second->count == 0) {
|
||||
/* Decrement the count of the number of objects in this memory-mapped file
|
||||
* that the client is using. The corresponding increment should have
|
||||
* happened in plasma_get. */
|
||||
// Decrement the count of the number of objects in this memory-mapped file
|
||||
// that the client is using. The corresponding increment should have
|
||||
// happened in plasma_get.
|
||||
int fd = object_entry->second->object.handle.store_fd;
|
||||
auto entry = conn->mmap_table.find(fd);
|
||||
CHECK(entry != conn->mmap_table.end());
|
||||
auto entry = mmap_table.find(fd);
|
||||
ARROW_CHECK(entry != mmap_table.end());
|
||||
entry->second->count -= 1;
|
||||
CHECK(entry->second->count >= 0);
|
||||
/* If none are being used then unmap the file. */
|
||||
ARROW_CHECK(entry->second->count >= 0);
|
||||
// If none are being used then unmap the file.
|
||||
if (entry->second->count == 0) {
|
||||
munmap(entry->second->pointer, entry->second->length);
|
||||
/* Remove the corresponding entry from the hash table. */
|
||||
// Remove the corresponding entry from the hash table.
|
||||
delete entry->second;
|
||||
conn->mmap_table.erase(fd);
|
||||
mmap_table.erase(fd);
|
||||
}
|
||||
/* Tell the store that the client no longer needs the object. */
|
||||
CHECK(plasma_send_ReleaseRequest(conn->store_conn, conn->builder,
|
||||
object_id) >= 0);
|
||||
/* Update the in_use_object_bytes. */
|
||||
conn->in_use_object_bytes -= (object_entry->second->object.data_size +
|
||||
object_entry->second->object.metadata_size);
|
||||
DCHECK(conn->in_use_object_bytes >= 0);
|
||||
/* Remove the entry from the hash table of objects currently in use. */
|
||||
// Tell the store that the client no longer needs the object.
|
||||
RETURN_NOT_OK(SendReleaseRequest(store_conn, object_id));
|
||||
// Update the in_use_object_bytes.
|
||||
in_use_object_bytes -= (object_entry->second->object.data_size +
|
||||
object_entry->second->object.metadata_size);
|
||||
DCHECK(in_use_object_bytes >= 0);
|
||||
// Remove the entry from the hash table of objects currently in use.
|
||||
delete object_entry->second;
|
||||
conn->objects_in_use.erase(object_id);
|
||||
objects_in_use.erase(object_id);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void plasma_release(PlasmaConnection *conn, ObjectID obj_id) {
|
||||
/* Add the new object to the release history. */
|
||||
conn->release_history.push_front(obj_id);
|
||||
/* If there are too many bytes in use by the client or if there are too many
|
||||
* pending release calls, and there are at least some pending release calls in
|
||||
* the release_history list, then release some objects. */
|
||||
while ((conn->in_use_object_bytes >
|
||||
MIN(L3_CACHE_SIZE_BYTES, conn->store_capacity / 100) ||
|
||||
conn->release_history.size() > conn->config.release_delay) &&
|
||||
conn->release_history.size() > 0) {
|
||||
/* Perform a release for the object ID for the first pending release. */
|
||||
plasma_perform_release(conn, conn->release_history.back());
|
||||
/* Remove the last entry from the release history. */
|
||||
conn->release_history.pop_back();
|
||||
Status PlasmaClient::Release(ObjectID object_id) {
|
||||
// Add the new object to the release history.
|
||||
release_history.push_front(object_id);
|
||||
// If there are too many bytes in use by the client or if there are too many
|
||||
// pending release calls, and there are at least some pending release calls in
|
||||
// the release_history list, then release some objects.
|
||||
while ((in_use_object_bytes >
|
||||
std::min(kL3CacheSizeBytes, store_capacity / 100) ||
|
||||
release_history.size() > config.release_delay) &&
|
||||
release_history.size() > 0) {
|
||||
// Perform a release for the object ID for the first pending release.
|
||||
RETURN_NOT_OK(PerformRelease(release_history.back()));
|
||||
// Remove the last entry from the release history.
|
||||
release_history.pop_back();
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* This method is used to query whether the plasma store contains an object. */
|
||||
void plasma_contains(PlasmaConnection *conn, ObjectID obj_id, int *has_object) {
|
||||
/* Check if we already have a reference to the object. */
|
||||
if (conn->objects_in_use.count(obj_id) > 0) {
|
||||
// This method is used to query whether the plasma store contains an object.
|
||||
Status PlasmaClient::Contains(ObjectID object_id, int *has_object) {
|
||||
// Check if we already have a reference to the object.
|
||||
if (objects_in_use.count(object_id) > 0) {
|
||||
*has_object = 1;
|
||||
} else {
|
||||
/* If we don't already have a reference to the object, check with the store
|
||||
* to see if we have the object. */
|
||||
plasma_send_ContainsRequest(conn->store_conn, conn->builder, obj_id);
|
||||
uint8_t *reply_data =
|
||||
plasma_receive(conn->store_conn, MessageType_PlasmaContainsReply);
|
||||
// If we don't already have a reference to the object, check with the store
|
||||
// to see if we have the object.
|
||||
RETURN_NOT_OK(SendContainsRequest(store_conn, object_id));
|
||||
std::vector<uint8_t> buffer;
|
||||
RETURN_NOT_OK(
|
||||
PlasmaReceive(store_conn, MessageType_PlasmaContainsReply, buffer));
|
||||
ObjectID object_id2;
|
||||
plasma_read_ContainsReply(reply_data, &object_id2, has_object);
|
||||
free(reply_data);
|
||||
RETURN_NOT_OK(ReadContainsReply(buffer.data(), &object_id2, has_object));
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static void compute_block_hash(const unsigned char *data,
|
||||
@@ -441,18 +377,18 @@ static void compute_block_hash(const unsigned char *data,
|
||||
static inline bool compute_object_hash_parallel(XXH64_state_t *hash_state,
|
||||
const unsigned char *data,
|
||||
int64_t nbytes) {
|
||||
/* Note that this function will likely be faster if the address of data is
|
||||
* aligned on a 64-byte boundary. */
|
||||
const uint64_t num_threads = THREADPOOL_SIZE;
|
||||
// Note that this function will likely be faster if the address of data is
|
||||
// aligned on a 64-byte boundary.
|
||||
const uint64_t num_threads = kThreadPoolSize;
|
||||
uint64_t threadhash[num_threads + 1];
|
||||
const uint64_t data_address = reinterpret_cast<uint64_t>(data);
|
||||
const uint64_t num_blocks = nbytes / BLOCK_SIZE;
|
||||
const uint64_t chunk_size = (num_blocks / num_threads) * BLOCK_SIZE;
|
||||
const uint64_t right_address = data_address + chunk_size * num_threads;
|
||||
const uint64_t suffix = (data_address + nbytes) - right_address;
|
||||
/* Now the data layout is | k * num_threads * block_size | suffix | ==
|
||||
* | num_threads * chunk_size | suffix |, where chunk_size = k * block_size.
|
||||
* Each thread gets a "chunk" of k blocks, except the suffix thread. */
|
||||
// Now the data layout is | k * num_threads * block_size | suffix | ==
|
||||
// | num_threads * chunk_size | suffix |, where chunk_size = k * block_size.
|
||||
// Each thread gets a "chunk" of k blocks, except the suffix thread.
|
||||
|
||||
for (int i = 0; i < num_threads; i++) {
|
||||
threadpool_[i] =
|
||||
@@ -463,7 +399,7 @@ static inline bool compute_object_hash_parallel(XXH64_state_t *hash_state,
|
||||
compute_block_hash(reinterpret_cast<uint8_t *>(right_address), suffix,
|
||||
&threadhash[num_threads]);
|
||||
|
||||
/* Join the threads. */
|
||||
// Join the threads.
|
||||
for (auto &t : threadpool_) {
|
||||
if (t.joinable()) {
|
||||
t.join();
|
||||
@@ -477,7 +413,7 @@ static inline bool compute_object_hash_parallel(XXH64_state_t *hash_state,
|
||||
static uint64_t compute_object_hash(const ObjectBuffer &obj_buffer) {
|
||||
XXH64_state_t hash_state;
|
||||
XXH64_reset(&hash_state, XXH64_DEFAULT_SEED);
|
||||
if (obj_buffer.data_size >= BYTES_IN_MB) {
|
||||
if (obj_buffer.data_size >= kBytesInMB) {
|
||||
compute_object_hash_parallel(&hash_state, (unsigned char *) obj_buffer.data,
|
||||
obj_buffer.data_size);
|
||||
} else {
|
||||
@@ -489,198 +425,181 @@ static uint64_t compute_object_hash(const ObjectBuffer &obj_buffer) {
|
||||
return XXH64_digest(&hash_state);
|
||||
}
|
||||
|
||||
bool plasma_compute_object_hash(PlasmaConnection *conn,
|
||||
bool plasma_compute_object_hash(PlasmaClient *conn,
|
||||
ObjectID obj_id,
|
||||
unsigned char *digest) {
|
||||
/* Get the plasma object data. We pass in a timeout of 0 to indicate that
|
||||
* the operation should timeout immediately. */
|
||||
// Get the plasma object data. We pass in a timeout of 0 to indicate that
|
||||
// the operation should timeout immediately.
|
||||
ObjectBuffer obj_buffer;
|
||||
ObjectID obj_id_array[1] = {obj_id};
|
||||
uint64_t hash;
|
||||
|
||||
plasma_get(conn, obj_id_array, 1, 0, &obj_buffer);
|
||||
/* If the object was not retrieved, return false. */
|
||||
ARROW_CHECK_OK(conn->Get(obj_id_array, 1, 0, &obj_buffer));
|
||||
// If the object was not retrieved, return false.
|
||||
if (obj_buffer.data_size == -1) {
|
||||
return false;
|
||||
}
|
||||
/* Compute the hash. */
|
||||
// Compute the hash.
|
||||
hash = compute_object_hash(obj_buffer);
|
||||
memcpy(digest, &hash, sizeof(hash));
|
||||
/* Release the plasma object. */
|
||||
plasma_release(conn, obj_id);
|
||||
// Release the plasma object.
|
||||
ARROW_CHECK_OK(conn->Release(obj_id));
|
||||
return true;
|
||||
}
|
||||
|
||||
void plasma_seal(PlasmaConnection *conn, ObjectID object_id) {
|
||||
/* Make sure this client has a reference to the object before sending the
|
||||
* request to Plasma. */
|
||||
auto object_entry = conn->objects_in_use.find(object_id);
|
||||
CHECKM(object_entry != conn->objects_in_use.end(),
|
||||
"Plasma client called seal an object without a reference to it");
|
||||
CHECKM(!object_entry->second->is_sealed,
|
||||
"Plasma client called seal an already sealed object");
|
||||
Status PlasmaClient::Seal(ObjectID object_id) {
|
||||
// Make sure this client has a reference to the object before sending the
|
||||
// request to Plasma.
|
||||
auto object_entry = objects_in_use.find(object_id);
|
||||
ARROW_CHECK(object_entry != objects_in_use.end())
|
||||
<< "Plasma client called seal an object without a reference to it";
|
||||
ARROW_CHECK(!object_entry->second->is_sealed)
|
||||
<< "Plasma client called seal an already sealed object";
|
||||
object_entry->second->is_sealed = true;
|
||||
/* Send the seal request to Plasma. */
|
||||
static unsigned char digest[DIGEST_SIZE];
|
||||
CHECK(plasma_compute_object_hash(conn, object_id, &digest[0]));
|
||||
CHECK(plasma_send_SealRequest(conn->store_conn, conn->builder, object_id,
|
||||
&digest[0]) >= 0);
|
||||
/* We call plasma_release to decrement the number of instances of this object
|
||||
* that are currently being used by this client. The corresponding increment
|
||||
* happened in plasma_create and was used to ensure that the object was not
|
||||
* released before the call to plasma_seal. */
|
||||
plasma_release(conn, object_id);
|
||||
/// Send the seal request to Plasma.
|
||||
static unsigned char digest[kDigestSize];
|
||||
ARROW_CHECK(plasma_compute_object_hash(this, object_id, &digest[0]));
|
||||
RETURN_NOT_OK(SendSealRequest(store_conn, object_id, &digest[0]));
|
||||
// We call PlasmaClient::Release to decrement the number of instances of this
|
||||
// object
|
||||
// that are currently being used by this client. The corresponding increment
|
||||
// happened in plasma_create and was used to ensure that the object was not
|
||||
// released before the call to PlasmaClient::Seal.
|
||||
return Release(object_id);
|
||||
}
|
||||
|
||||
void plasma_delete(PlasmaConnection *conn, ObjectID object_id) {
|
||||
/* TODO(rkn): In the future, we can use this method to give hints to the
|
||||
* eviction policy about when an object will no longer be needed. */
|
||||
Status PlasmaClient::Delete(ObjectID object_id) {
|
||||
// TODO(rkn): In the future, we can use this method to give hints to the
|
||||
// eviction policy about when an object will no longer be needed.
|
||||
return Status::NotImplemented("PlasmaClient::Delete is not implemented.");
|
||||
}
|
||||
|
||||
int64_t plasma_evict(PlasmaConnection *conn, int64_t num_bytes) {
|
||||
/* Send a request to the store to evict objects. */
|
||||
CHECK(plasma_send_EvictRequest(conn->store_conn, conn->builder, num_bytes) >=
|
||||
0);
|
||||
/* Wait for a response with the number of bytes actually evicted. */
|
||||
Status PlasmaClient::Evict(int64_t num_bytes, int64_t &num_bytes_evicted) {
|
||||
// Send a request to the store to evict objects.
|
||||
RETURN_NOT_OK(SendEvictRequest(store_conn, num_bytes));
|
||||
// Wait for a response with the number of bytes actually evicted.
|
||||
std::vector<uint8_t> buffer;
|
||||
int64_t type;
|
||||
int64_t length;
|
||||
uint8_t *reply_data;
|
||||
read_message(conn->store_conn, &type, &length, &reply_data);
|
||||
int64_t num_bytes_evicted;
|
||||
plasma_read_EvictReply(reply_data, &num_bytes_evicted);
|
||||
free(reply_data);
|
||||
return num_bytes_evicted;
|
||||
RETURN_NOT_OK(ReadMessage(store_conn, &type, buffer));
|
||||
return ReadEvictReply(buffer.data(), num_bytes_evicted);
|
||||
}
|
||||
|
||||
int plasma_subscribe(PlasmaConnection *conn) {
|
||||
int fd[2];
|
||||
/* TODO: Just create 1 socket, bind it to port 0 to find a free port, and
|
||||
* send the port number instead, and let the client connect. */
|
||||
/* 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, fd);
|
||||
/* Make the socket non-blocking. */
|
||||
int flags = fcntl(fd[1], F_GETFL, 0);
|
||||
CHECK(fcntl(fd[1], F_SETFL, flags | O_NONBLOCK) == 0);
|
||||
/* Tell the Plasma store about the subscription. */
|
||||
CHECK(plasma_send_SubscribeRequest(conn->store_conn, conn->builder) >= 0);
|
||||
/* Send the file descriptor that the Plasma store should use to push
|
||||
* notifications about sealed objects to this client. */
|
||||
CHECK(send_fd(conn->store_conn, fd[1]) >= 0);
|
||||
close(fd[1]);
|
||||
/* Return the file descriptor that the client should use to read notifications
|
||||
* about sealed objects. */
|
||||
return fd[0];
|
||||
Status PlasmaClient::Subscribe(int &fd) {
|
||||
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);
|
||||
// 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();
|
||||
}
|
||||
|
||||
PlasmaConnection *plasma_connect(const char *store_socket_name,
|
||||
const char *manager_socket_name,
|
||||
int release_delay) {
|
||||
/* Initialize the store connection struct */
|
||||
PlasmaConnection *result = new PlasmaConnection();
|
||||
result->store_conn = connect_ipc_sock_retry(store_socket_name, -1, -1);
|
||||
if (manager_socket_name != NULL) {
|
||||
result->manager_conn = connect_ipc_sock_retry(manager_socket_name, -1, -1);
|
||||
Status PlasmaClient::Connect(const std::string &store_socket_name,
|
||||
const std::string &manager_socket_name,
|
||||
int release_delay) {
|
||||
store_conn = connect_ipc_sock_retry(store_socket_name, -1, -1);
|
||||
if (manager_socket_name != "") {
|
||||
manager_conn = connect_ipc_sock_retry(manager_socket_name, -1, -1);
|
||||
} else {
|
||||
result->manager_conn = -1;
|
||||
manager_conn = -1;
|
||||
}
|
||||
result->builder = make_protocol_builder();
|
||||
result->config.release_delay = release_delay;
|
||||
result->in_use_object_bytes = 0;
|
||||
/* Send a ConnectRequest to the store to get its memory capacity. */
|
||||
plasma_send_ConnectRequest(result->store_conn, result->builder);
|
||||
uint8_t *reply_data =
|
||||
plasma_receive(result->store_conn, MessageType_PlasmaConnectReply);
|
||||
plasma_read_ConnectReply(reply_data, &result->store_capacity);
|
||||
free(reply_data);
|
||||
return result;
|
||||
config.release_delay = release_delay;
|
||||
in_use_object_bytes = 0;
|
||||
// Send a ConnectRequest to the store to get its memory capacity.
|
||||
RETURN_NOT_OK(SendConnectRequest(store_conn));
|
||||
std::vector<uint8_t> buffer;
|
||||
RETURN_NOT_OK(
|
||||
PlasmaReceive(store_conn, MessageType_PlasmaConnectReply, buffer));
|
||||
RETURN_NOT_OK(ReadConnectReply(buffer.data(), &store_capacity));
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
void plasma_disconnect(PlasmaConnection *conn) {
|
||||
/* NOTE: We purposefully do not finish sending release calls for objects in
|
||||
* use, so that we don't duplicate plasma_release calls (when handling a
|
||||
* SIGTERM, for example). */
|
||||
for (auto &entry : conn->objects_in_use) {
|
||||
Status PlasmaClient::Disconnect() {
|
||||
// NOTE: We purposefully do not finish sending release calls for objects in
|
||||
// use, so that we don't duplicate PlasmaClient::Release calls (when handling
|
||||
// a
|
||||
// SIGTERM, for example).
|
||||
for (auto &entry : objects_in_use) {
|
||||
delete entry.second;
|
||||
}
|
||||
for (auto &entry : conn->mmap_table) {
|
||||
for (auto &entry : mmap_table) {
|
||||
delete entry.second;
|
||||
}
|
||||
free_protocol_builder(conn->builder);
|
||||
/* Close the connections to Plasma. The Plasma store will release the objects
|
||||
* that were in use by us when handling the SIGPIPE. */
|
||||
close(conn->store_conn);
|
||||
if (conn->manager_conn >= 0) {
|
||||
close(conn->manager_conn);
|
||||
// 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);
|
||||
if (manager_conn >= 0) {
|
||||
close(manager_conn);
|
||||
}
|
||||
delete conn;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
bool plasma_manager_is_connected(PlasmaConnection *conn) {
|
||||
bool plasma_manager_is_connected(PlasmaClient *conn) {
|
||||
return conn->manager_conn >= 0;
|
||||
}
|
||||
|
||||
#define h_addr h_addr_list[0]
|
||||
|
||||
void plasma_transfer(PlasmaConnection *conn,
|
||||
const char *address,
|
||||
int port,
|
||||
ObjectID object_id) {
|
||||
CHECK(plasma_send_DataRequest(conn->manager_conn, conn->builder, object_id,
|
||||
address, port) >= 0);
|
||||
Status PlasmaClient::Transfer(const char *address,
|
||||
int port,
|
||||
ObjectID object_id) {
|
||||
return SendDataRequest(manager_conn, object_id, address, port);
|
||||
}
|
||||
|
||||
void plasma_fetch(PlasmaConnection *conn,
|
||||
int num_object_ids,
|
||||
ObjectID object_ids[]) {
|
||||
CHECK(conn != NULL);
|
||||
CHECK(conn->manager_conn >= 0);
|
||||
CHECK(plasma_send_FetchRequest(conn->manager_conn, conn->builder, object_ids,
|
||||
num_object_ids) >= 0);
|
||||
Status PlasmaClient::Fetch(int num_object_ids, ObjectID object_ids[]) {
|
||||
ARROW_CHECK(manager_conn >= 0);
|
||||
return SendFetchRequest(manager_conn, object_ids, num_object_ids);
|
||||
}
|
||||
|
||||
int get_manager_fd(PlasmaConnection *conn) {
|
||||
int get_manager_fd(PlasmaClient *conn) {
|
||||
return conn->manager_conn;
|
||||
}
|
||||
|
||||
int plasma_status(PlasmaConnection *conn, ObjectID object_id) {
|
||||
CHECK(conn != NULL);
|
||||
CHECK(conn->manager_conn >= 0);
|
||||
Status PlasmaClient::Info(ObjectID object_id, int *object_status) {
|
||||
ARROW_CHECK(manager_conn >= 0);
|
||||
|
||||
plasma_send_StatusRequest(conn->manager_conn, conn->builder, &object_id, 1);
|
||||
uint8_t *reply_data =
|
||||
plasma_receive(conn->manager_conn, MessageType_PlasmaStatusReply);
|
||||
int object_status;
|
||||
plasma_read_StatusReply(reply_data, &object_id, &object_status, 1);
|
||||
free(reply_data);
|
||||
return object_status;
|
||||
RETURN_NOT_OK(SendStatusRequest(manager_conn, &object_id, 1));
|
||||
std::vector<uint8_t> buffer;
|
||||
RETURN_NOT_OK(
|
||||
PlasmaReceive(manager_conn, MessageType_PlasmaStatusReply, buffer));
|
||||
return ReadStatusReply(buffer.data(), &object_id, object_status, 1);
|
||||
}
|
||||
|
||||
int plasma_wait(PlasmaConnection *conn,
|
||||
int num_object_requests,
|
||||
ObjectRequest object_requests[],
|
||||
int num_ready_objects,
|
||||
uint64_t timeout_ms) {
|
||||
CHECK(conn != NULL);
|
||||
CHECK(conn->manager_conn >= 0);
|
||||
CHECK(num_object_requests > 0);
|
||||
CHECK(num_ready_objects > 0);
|
||||
CHECK(num_ready_objects <= num_object_requests);
|
||||
Status PlasmaClient::Wait(int num_object_requests,
|
||||
ObjectRequest object_requests[],
|
||||
int num_ready_objects,
|
||||
uint64_t timeout_ms,
|
||||
int &num_objects_ready) {
|
||||
ARROW_CHECK(manager_conn >= 0);
|
||||
ARROW_CHECK(num_object_requests > 0);
|
||||
ARROW_CHECK(num_ready_objects > 0);
|
||||
ARROW_CHECK(num_ready_objects <= num_object_requests);
|
||||
|
||||
for (int i = 0; i < num_object_requests; ++i) {
|
||||
CHECK(object_requests[i].type == PLASMA_QUERY_LOCAL ||
|
||||
object_requests[i].type == PLASMA_QUERY_ANYWHERE);
|
||||
ARROW_CHECK(object_requests[i].type == PLASMA_QUERY_LOCAL ||
|
||||
object_requests[i].type == PLASMA_QUERY_ANYWHERE);
|
||||
}
|
||||
|
||||
CHECK(plasma_send_WaitRequest(conn->manager_conn, conn->builder,
|
||||
object_requests, num_object_requests,
|
||||
num_ready_objects, timeout_ms) >= 0);
|
||||
uint8_t *reply_data =
|
||||
plasma_receive(conn->manager_conn, MessageType_PlasmaWaitReply);
|
||||
plasma_read_WaitReply(reply_data, object_requests, &num_ready_objects);
|
||||
free(reply_data);
|
||||
RETURN_NOT_OK(SendWaitRequest(manager_conn, object_requests,
|
||||
num_object_requests, num_ready_objects,
|
||||
timeout_ms));
|
||||
std::vector<uint8_t> buffer;
|
||||
RETURN_NOT_OK(
|
||||
PlasmaReceive(manager_conn, MessageType_PlasmaWaitReply, buffer));
|
||||
RETURN_NOT_OK(
|
||||
ReadWaitReply(buffer.data(), object_requests, &num_ready_objects));
|
||||
|
||||
int num_objects_ready = 0;
|
||||
num_objects_ready = 0;
|
||||
for (int i = 0; i < num_object_requests; ++i) {
|
||||
int type = object_requests[i].type;
|
||||
int status = object_requests[i].status;
|
||||
@@ -694,12 +613,12 @@ int plasma_wait(PlasmaConnection *conn,
|
||||
if (status == ObjectStatus_Local || status == ObjectStatus_Remote) {
|
||||
num_objects_ready += 1;
|
||||
} else {
|
||||
CHECK(status == ObjectStatus_Nonexistent);
|
||||
ARROW_CHECK(status == ObjectStatus_Nonexistent);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL("This code should be unreachable.");
|
||||
ARROW_LOG(FATAL) << "This code should be unreachable.";
|
||||
}
|
||||
}
|
||||
return num_objects_ready;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
+293
-293
@@ -4,258 +4,311 @@
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <deque>
|
||||
|
||||
#include "plasma.h"
|
||||
|
||||
using arrow::Status;
|
||||
|
||||
#define PLASMA_DEFAULT_RELEASE_DELAY 64
|
||||
/* Use 100MB as an overestimate of the L3 cache size. */
|
||||
#define L3_CACHE_SIZE_BYTES 100000000
|
||||
|
||||
typedef struct PlasmaConnection PlasmaConnection;
|
||||
// Use 100MB as an overestimate of the L3 cache size.
|
||||
constexpr int64_t kL3CacheSizeBytes = 100000000;
|
||||
|
||||
/**
|
||||
* Try to connect to the socket several times. If unsuccessful, fail.
|
||||
*
|
||||
* @param socket_name Name of the Unix domain socket to connect to.
|
||||
* @param num_retries Number of retries.
|
||||
* @param timeout Timeout in milliseconds.
|
||||
* @return File descriptor of the socket.
|
||||
*/
|
||||
int socket_connect_retry(const char *socket_name,
|
||||
int num_retries,
|
||||
int64_t timeout);
|
||||
|
||||
/**
|
||||
* Connect to the local plasma store and plasma manager. Return
|
||||
* the resulting connection.
|
||||
*
|
||||
* @param store_socket_name The name of the UNIX domain socket to use to
|
||||
* connect to the Plasma store.
|
||||
* @param manager_socket_name The name of the UNIX domain socket to use to
|
||||
* connect to the local Plasma manager. If this is NULL, then this
|
||||
* function will not connect to a manager.
|
||||
* @return The object containing the connection state.
|
||||
*/
|
||||
PlasmaConnection *plasma_connect(const char *store_socket_name,
|
||||
const char *manager_socket_name,
|
||||
int release_delay);
|
||||
|
||||
/**
|
||||
* Disconnect from the local plasma instance, including the local store and
|
||||
* manager.
|
||||
*
|
||||
* @param conn The connection to the local plasma store and plasma manager.
|
||||
* @return Void.
|
||||
*/
|
||||
void plasma_disconnect(PlasmaConnection *conn);
|
||||
|
||||
/**
|
||||
* Return true if the plasma manager is connected.
|
||||
*
|
||||
* @param conn The connection to the local plasma store and plasma manager.
|
||||
* @return True if the plasma manager is connected and false otherwise.
|
||||
*/
|
||||
bool plasma_manager_is_connected(PlasmaConnection *conn);
|
||||
|
||||
/**
|
||||
* Try to connect to a possibly remote Plasma Manager.
|
||||
*
|
||||
* @param addr The IP address of the Plasma Manager to connect to.
|
||||
* @param port The port of the Plasma Manager to connect to.
|
||||
* @return The file descriptor to use to send messages to the
|
||||
* Plasma Manager. If connection was unsuccessful, this
|
||||
* value is -1.
|
||||
*/
|
||||
int plasma_manager_connect(const char *addr, int port);
|
||||
|
||||
/**
|
||||
* Create an object in the Plasma Store. Any metadata for this object must be
|
||||
* be passed in when the object is created.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param object_id The ID to use for the newly created object.
|
||||
* @param size The size in bytes of the space to be allocated for this object's
|
||||
data (this does not include space used for metadata).
|
||||
* @param metadata The object's metadata. If there is no metadata, this pointer
|
||||
should be NULL.
|
||||
* @param metadata_size The size in bytes of the metadata. If there is no
|
||||
metadata, this should be 0.
|
||||
* @param data The address of the newly created object will be written here.
|
||||
* @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
|
||||
* plasma_release.
|
||||
* - PlasmaError_OutOfMemory, if the store is out of memory and cannot
|
||||
* create the object. In this case, the client should not call
|
||||
* plasma_release.
|
||||
*/
|
||||
int plasma_create(PlasmaConnection *conn,
|
||||
ObjectID object_id,
|
||||
int64_t size,
|
||||
uint8_t *metadata,
|
||||
int64_t metadata_size,
|
||||
uint8_t **data);
|
||||
|
||||
/**
|
||||
* Object buffer data structure.
|
||||
*/
|
||||
typedef struct {
|
||||
/** The size in bytes of the data object. */
|
||||
/// Object buffer data structure.
|
||||
struct ObjectBuffer {
|
||||
/// The size in bytes of the data object.
|
||||
int64_t data_size;
|
||||
/** The address of the data object. */
|
||||
/// The address of the data object.
|
||||
uint8_t *data;
|
||||
/** The metadata size in bytes. */
|
||||
/// The metadata size in bytes.
|
||||
int64_t metadata_size;
|
||||
/** The address of the metadata. */
|
||||
/// The address of the metadata.
|
||||
uint8_t *metadata;
|
||||
} ObjectBuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get some objects from the Plasma Store. This function will block until the
|
||||
* objects have all been created and sealed in the Plasma Store or the timeout
|
||||
* expires. The caller is responsible for releasing any retrieved objects, but
|
||||
* the caller should not release objects that were not retrieved.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param object_ids The IDs of the objects to get.
|
||||
* @param num_object_ids The number of object IDs to get.
|
||||
* @param timeout_ms The amount of time in milliseconds to wait before this
|
||||
* request times out. If this value is -1, then no timeout is set.
|
||||
* @param object_buffers An array where the results will be stored. If the data
|
||||
* size field is -1, then the object was not retrieved.
|
||||
* @return Void.
|
||||
*/
|
||||
void plasma_get(PlasmaConnection *conn,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects,
|
||||
int64_t timeout_ms,
|
||||
ObjectBuffer object_buffers[]);
|
||||
/// Configuration options for the plasma client.
|
||||
struct PlasmaClientConfig {
|
||||
/// Number of release calls we wait until the object is actually released.
|
||||
/// This allows us to avoid invalidating the cpu cache on workers if objects
|
||||
/// are reused accross tasks.
|
||||
int release_delay;
|
||||
};
|
||||
|
||||
/**
|
||||
* Tell Plasma that the client no longer needs the object. This should be called
|
||||
* after plasma_get when the client is done with the object. After this call,
|
||||
* the address returned by plasma_get is no longer valid. This should be called
|
||||
* once for each call to plasma_get (with the same object ID).
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param object_id The ID of the object that is no longer needed.
|
||||
* @return Void.
|
||||
*/
|
||||
void plasma_release(PlasmaConnection *conn, ObjectID object_id);
|
||||
struct ClientMmapTableEntry;
|
||||
struct ObjectInUseEntry;
|
||||
|
||||
/**
|
||||
* Check if the object store contains a particular object and the object has
|
||||
* been sealed. The result will be stored in has_object.
|
||||
*
|
||||
* @todo: We may want to indicate if the object has been created but not sealed.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param object_id The ID of the object whose presence we are checking.
|
||||
* @param has_object The function will write 1 at this address if the object is
|
||||
* present and 0 if it is not present.
|
||||
* @return Void.
|
||||
*/
|
||||
void plasma_contains(PlasmaConnection *conn,
|
||||
ObjectID object_id,
|
||||
int *has_object);
|
||||
class PlasmaClient {
|
||||
public:
|
||||
/// Connect to the local plasma store and plasma manager. Return
|
||||
/// the resulting connection.
|
||||
///
|
||||
/// @param store_socket_name The name of the UNIX domain socket to use to
|
||||
/// connect to the Plasma store.
|
||||
/// @param manager_socket_name The name of the UNIX domain socket to use to
|
||||
/// connect to the local Plasma manager. If this is NULL, then this
|
||||
/// function will not connect to a manager.
|
||||
/// @param release_delay Number of released objects that are kept around
|
||||
/// and not evicted to avoid too many munmaps.
|
||||
/// @return The return status.
|
||||
Status Connect(const std::string &store_socket_name,
|
||||
const std::string &manager_socket_name,
|
||||
int release_delay);
|
||||
|
||||
/**
|
||||
* Compute the hash of an object in the object store.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param object_id The ID of the object we want to hash.
|
||||
* @param digest A pointer at which to return the hash digest of the object.
|
||||
* The pointer must have at least DIGEST_SIZE bytes allocated.
|
||||
* @return A boolean representing whether the hash operation succeeded.
|
||||
*/
|
||||
bool plasma_compute_object_hash(PlasmaConnection *conn,
|
||||
/// Create an object in the Plasma Store. Any metadata for this object must be
|
||||
/// be passed in when the object is created.
|
||||
///
|
||||
/// @param object_id The ID to use for the newly created object.
|
||||
/// @param data_size The size in bytes of the space to be allocated for this
|
||||
/// object's
|
||||
/// data (this does not include space used for metadata).
|
||||
/// @param metadata The object's metadata. If there is no metadata, this
|
||||
/// pointer
|
||||
/// should be NULL.
|
||||
/// @param metadata_size The size in bytes of the metadata. If there is no
|
||||
/// metadata, this should be 0.
|
||||
/// @param data The address of the newly created object will be written here.
|
||||
/// @return The return status.
|
||||
Status Create(ObjectID object_id,
|
||||
int64_t data_size,
|
||||
uint8_t *metadata,
|
||||
int64_t metadata_size,
|
||||
uint8_t **data);
|
||||
|
||||
/// Get some objects from the Plasma Store. This function will block until the
|
||||
/// objects have all been created and sealed in the Plasma Store or the
|
||||
/// timeout
|
||||
/// expires. The caller is responsible for releasing any retrieved objects,
|
||||
/// but
|
||||
/// the caller should not release objects that were not retrieved.
|
||||
///
|
||||
/// @param object_ids The IDs of the objects to get.
|
||||
/// @param num_object_ids The number of object IDs to get.
|
||||
/// @param timeout_ms The amount of time in milliseconds to wait before this
|
||||
/// request times out. If this value is -1, then no timeout is set.
|
||||
/// @param object_buffers An array where the results will be stored. If the
|
||||
/// data
|
||||
/// size field is -1, then the object was not retrieved.
|
||||
/// @return The return status.
|
||||
Status Get(ObjectID object_ids[],
|
||||
int64_t num_objects,
|
||||
int64_t timeout_ms,
|
||||
ObjectBuffer object_buffers[]);
|
||||
|
||||
/// Tell Plasma that the client no longer needs the object. This should be
|
||||
/// called
|
||||
/// after Get when the client is done with the object. After this call,
|
||||
/// the address returned by Get is no longer valid. This should be called
|
||||
/// once for each call to Get (with the same object ID).
|
||||
///
|
||||
/// @param object_id The ID of the object that is no longer needed.
|
||||
/// @return The return status.
|
||||
Status Release(ObjectID object_id);
|
||||
|
||||
/// Check if the object store contains a particular object and the object has
|
||||
/// been sealed. The result will be stored in has_object.
|
||||
///
|
||||
/// @todo: We may want to indicate if the object has been created but not
|
||||
/// sealed.
|
||||
///
|
||||
/// @param object_id The ID of the object whose presence we are checking.
|
||||
/// @param has_object The function will write 1 at this address if the object
|
||||
/// is
|
||||
/// present and 0 if it is not present.
|
||||
/// @return The return status.
|
||||
Status Contains(ObjectID object_id, int *has_object);
|
||||
|
||||
/// Seal an object in the object store. The object will be immutable after
|
||||
/// this
|
||||
/// call.
|
||||
///
|
||||
/// @param object_id The ID of the object to seal.
|
||||
/// @return The return status.
|
||||
Status Seal(ObjectID object_id);
|
||||
|
||||
/// Delete an object from the object store. This currently assumes that the
|
||||
/// object is present and has been sealed.
|
||||
///
|
||||
/// @todo We may want to allow the deletion of objects that are not present or
|
||||
/// haven't been sealed.
|
||||
///
|
||||
/// @param object_id The ID of the object to delete.
|
||||
/// @return The return status.
|
||||
Status Delete(ObjectID object_id);
|
||||
|
||||
/// Delete objects until we have freed up num_bytes bytes or there are no more
|
||||
/// released objects that can be deleted.
|
||||
///
|
||||
/// @param num_bytes The number of bytes to try to free up.
|
||||
/// @param num_bytes_evicted Out parameter for total number of bytes of space
|
||||
/// retrieved.
|
||||
/// @return The return status.
|
||||
Status Evict(int64_t num_bytes, int64_t &num_bytes_evicted);
|
||||
|
||||
/// Subscribe to notifications when objects are sealed in the object store.
|
||||
/// 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);
|
||||
|
||||
/// Disconnect from the local plasma instance, including the local store and
|
||||
/// manager.
|
||||
///
|
||||
/// @return The return status.
|
||||
Status Disconnect();
|
||||
|
||||
/// Attempt to initiate the transfer of some objects from remote Plasma
|
||||
/// Stores.
|
||||
/// This method does not guarantee that the fetched objects will arrive
|
||||
/// locally.
|
||||
///
|
||||
/// For an object that is available in the local Plasma Store, this method
|
||||
/// will
|
||||
/// not do anything. For an object that is not available locally, it will
|
||||
/// check
|
||||
/// if the object are already being fetched. If so, it will not do anything.
|
||||
/// If
|
||||
/// not, it will query the object table for a list of Plasma Managers that
|
||||
/// have
|
||||
/// the object. The object table will return a non-empty list, and this Plasma
|
||||
/// Manager will attempt to initiate transfers from one of those Plasma
|
||||
/// Managers.
|
||||
///
|
||||
/// This function is non-blocking.
|
||||
///
|
||||
/// This method is idempotent in the sense that it is ok to call it multiple
|
||||
/// times.
|
||||
///
|
||||
/// @param num_object_ids The number of object IDs fetch is being called on.
|
||||
/// @param object_ids The IDs of the objects that fetch is being called on.
|
||||
/// @return The return status.
|
||||
Status Fetch(int num_object_ids, ObjectID object_ids[]);
|
||||
|
||||
/// Wait for (1) a specified number of objects to be available (sealed) in the
|
||||
/// local Plasma Store or in a remote Plasma Store, or (2) for a timeout to
|
||||
/// expire. This is a blocking call.
|
||||
///
|
||||
/// @param num_object_requests Size of the object_requests array.
|
||||
/// @param object_requests Object event array. Each element contains a request
|
||||
/// for a particular object_id. The type of request is specified in the
|
||||
/// "type" field.
|
||||
/// - A PLASMA_QUERY_LOCAL request is satisfied when object_id becomes
|
||||
/// available in the local Plasma Store. In this case, this function
|
||||
/// sets the "status" field to ObjectStatus_Local. Note, if the
|
||||
/// status
|
||||
/// is not ObjectStatus_Local, it will be ObjectStatus_Nonexistent,
|
||||
/// but it may exist elsewhere in the system.
|
||||
/// - A PLASMA_QUERY_ANYWHERE request is satisfied when object_id
|
||||
/// becomes
|
||||
/// available either at the local Plasma Store or on a remote Plasma
|
||||
/// Store. In this case, the functions sets the "status" field to
|
||||
/// ObjectStatus_Local or ObjectStatus_Remote.
|
||||
/// @param num_ready_objects The number of requests in object_requests array
|
||||
/// that
|
||||
/// must be satisfied before the function returns, unless it timeouts.
|
||||
/// The num_ready_objects should be no larger than num_object_requests.
|
||||
/// @param timeout_ms Timeout value in milliseconds. If this timeout expires
|
||||
/// before min_num_ready_objects of requests are satisfied, the
|
||||
/// function
|
||||
/// returns.
|
||||
/// @param num_objects_ready Out parameter for number of satisfied requests in
|
||||
/// the object_requests list. If the returned number is less than
|
||||
/// min_num_ready_objects this means that timeout expired.
|
||||
/// @return The return status.
|
||||
Status Wait(int num_object_requests,
|
||||
ObjectRequest object_requests[],
|
||||
int num_ready_objects,
|
||||
uint64_t timeout_ms,
|
||||
int &num_objects_ready);
|
||||
|
||||
/// Transfer local object to a different plasma manager.
|
||||
///
|
||||
/// @param conn The object containing the connection state.
|
||||
/// @param addr IP address of the plasma manager we are transfering to.
|
||||
/// @param port Port of the plasma manager we are transfering to.
|
||||
/// @object_id ObjectID of the object we are transfering.
|
||||
/// @return The return status.
|
||||
Status Transfer(const char *addr, int port, ObjectID object_id);
|
||||
|
||||
/// Return the status of a given object. This method may query the object
|
||||
/// table.
|
||||
///
|
||||
/// @param conn The object containing the connection state.
|
||||
/// @param object_id The ID of the object whose status we query.
|
||||
/// @param object_status Out parameter for object status. Can take the
|
||||
/// following values.
|
||||
/// - PLASMA_CLIENT_LOCAL, if object is stored in the local Plasma
|
||||
/// Store.
|
||||
/// has been already scheduled by the Plasma Manager.
|
||||
/// - PLASMA_CLIENT_TRANSFER, if the object is either currently being
|
||||
/// transferred or just scheduled.
|
||||
/// - PLASMA_CLIENT_REMOTE, if the object is stored at a remote
|
||||
/// Plasma Store.
|
||||
/// - PLASMA_CLIENT_DOES_NOT_EXIST, if the object doesn’t exist in the
|
||||
/// system.
|
||||
/// @return The return status.
|
||||
Status Info(ObjectID object_id, int *object_status);
|
||||
|
||||
// private:
|
||||
|
||||
Status PerformRelease(ObjectID object_id);
|
||||
|
||||
/// File descriptor of the Unix domain socket that connects to the store.
|
||||
int store_conn;
|
||||
/// File descriptor of the Unix domain socket that connects to the manager.
|
||||
int manager_conn;
|
||||
/// File descriptor of the Unix domain socket on which client receives event
|
||||
/// notifications for the objects it subscribes for when these objects are
|
||||
/// sealed either locally or remotely.
|
||||
int manager_conn_subscribe;
|
||||
/// 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.
|
||||
std::unordered_map<int, ClientMmapTableEntry *> mmap_table;
|
||||
/// A hash table of the object IDs that are currently being used by this
|
||||
/// client.
|
||||
std::unordered_map<ObjectID, ObjectInUseEntry *, UniqueIDHasher>
|
||||
objects_in_use;
|
||||
/// Object IDs of the last few release calls. This is a deque and
|
||||
/// is used to delay releasing objects to see if they can be reused by
|
||||
/// subsequent tasks so we do not unneccessarily invalidate cpu caches.
|
||||
/// TODO(pcm): replace this with a proper lru cache using the size of the L3
|
||||
/// cache.
|
||||
std::deque<ObjectID> release_history;
|
||||
/// The number of bytes in the combined objects that are held in the release
|
||||
/// history doubly-linked list. If this is too large then the client starts
|
||||
/// releasing objects.
|
||||
int64_t in_use_object_bytes;
|
||||
/// Configuration options for the plasma client.
|
||||
PlasmaClientConfig config;
|
||||
/// The amount of memory available to the Plasma store. The client needs this
|
||||
/// information to make sure that it does not delay in releasing so much
|
||||
/// memory that the store is unable to evict enough objects to free up space.
|
||||
int64_t store_capacity;
|
||||
};
|
||||
|
||||
/// Return true if the plasma manager is connected.
|
||||
///
|
||||
/// @param conn The connection to the local plasma store and plasma manager.
|
||||
/// @return True if the plasma manager is connected and false otherwise.
|
||||
bool plasma_manager_is_connected(PlasmaClient *conn);
|
||||
|
||||
/// Compute the hash of an object in the object store.
|
||||
///
|
||||
/// @param conn The object containing the connection state.
|
||||
/// @param object_id The ID of the object we want to hash.
|
||||
/// @param digest A pointer at which to return the hash digest of the object.
|
||||
/// The pointer must have at least DIGEST_SIZE bytes allocated.
|
||||
/// @return A boolean representing whether the hash operation succeeded.
|
||||
bool plasma_compute_object_hash(PlasmaClient *conn,
|
||||
ObjectID object_id,
|
||||
unsigned char *digest);
|
||||
|
||||
/**
|
||||
* Seal an object in the object store. The object will be immutable after this
|
||||
* call.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param object_id The ID of the object to seal.
|
||||
* @return Void.
|
||||
*/
|
||||
void plasma_seal(PlasmaConnection *conn, ObjectID object_id);
|
||||
|
||||
/**
|
||||
* Delete an object from the object store. This currently assumes that the
|
||||
* object is present and has been sealed.
|
||||
*
|
||||
* @todo We may want to allow the deletion of objects that are not present or
|
||||
* haven't been sealed.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param object_id The ID of the object to delete.
|
||||
* @return Void.
|
||||
*/
|
||||
void plasma_delete(PlasmaConnection *conn, ObjectID object_id);
|
||||
|
||||
/**
|
||||
* Delete objects until we have freed up num_bytes bytes or there are no more
|
||||
* released objects that can be deleted.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param num_bytes The number of bytes to try to free up.
|
||||
* @return The total number of bytes of space retrieved.
|
||||
*/
|
||||
int64_t plasma_evict(PlasmaConnection *conn, int64_t num_bytes);
|
||||
|
||||
/**
|
||||
* Attempt to initiate the transfer of some objects from remote Plasma Stores.
|
||||
* This method does not guarantee that the fetched objects will arrive locally.
|
||||
*
|
||||
* For an object that is available in the local Plasma Store, this method will
|
||||
* not do anything. For an object that is not available locally, it will check
|
||||
* if the object are already being fetched. If so, it will not do anything. If
|
||||
* not, it will query the object table for a list of Plasma Managers that have
|
||||
* the object. The object table will return a non-empty list, and this Plasma
|
||||
* Manager will attempt to initiate transfers from one of those Plasma Managers.
|
||||
*
|
||||
* This function is non-blocking.
|
||||
*
|
||||
* This method is idempotent in the sense that it is ok to call it multiple
|
||||
* times.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param num_object_ids The number of object IDs fetch is being called on.
|
||||
* @param object_ids The IDs of the objects that fetch is being called on.
|
||||
* @return Void.
|
||||
*/
|
||||
void plasma_fetch(PlasmaConnection *conn,
|
||||
int num_object_ids,
|
||||
ObjectID object_ids[]);
|
||||
|
||||
/**
|
||||
* Transfer local object to a different plasma manager.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param addr IP address of the plasma manager we are transfering to.
|
||||
* @param port Port of the plasma manager we are transfering to.
|
||||
* @object_id ObjectID of the object we are transfering.
|
||||
*
|
||||
* @return Void.
|
||||
*/
|
||||
void plasma_transfer(PlasmaConnection *conn,
|
||||
const char *addr,
|
||||
int port,
|
||||
ObjectID object_id);
|
||||
|
||||
/**
|
||||
* Subscribe to notifications when objects are sealed in the object store.
|
||||
* Whenever an object is sealed, a message will be written to the client socket
|
||||
* that is returned by this method.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @return The file descriptor that the client should use to read notifications
|
||||
from the object store about sealed objects.
|
||||
*/
|
||||
int plasma_subscribe(PlasmaConnection *conn);
|
||||
|
||||
/**
|
||||
* Get the file descriptor for the socket connection to the plasma manager.
|
||||
*
|
||||
@@ -263,25 +316,7 @@ int plasma_subscribe(PlasmaConnection *conn);
|
||||
* @return The file descriptor for the manager connection. If there is no
|
||||
* connection to the manager, this is -1.
|
||||
*/
|
||||
int get_manager_fd(PlasmaConnection *conn);
|
||||
|
||||
/**
|
||||
* Return the status of a given object. This method may query the object table.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param object_id The ID of the object whose status we query.
|
||||
* @return Status as returned by get_status() function. Status can take the
|
||||
* following values.
|
||||
* - PLASMA_CLIENT_LOCAL, if object is stored in the local Plasma Store.
|
||||
* has been already scheduled by the Plasma Manager.
|
||||
* - PLASMA_CLIENT_TRANSFER, if the object is either currently being
|
||||
* transferred or just scheduled.
|
||||
* - PLASMA_CLIENT_REMOTE, if the object is stored at a remote
|
||||
* Plasma Store.
|
||||
* - PLASMA_CLIENT_DOES_NOT_EXIST, if the object doesn’t exist in the
|
||||
* system.
|
||||
*/
|
||||
int plasma_status(PlasmaConnection *conn, ObjectID object_id);
|
||||
int get_manager_fd(PlasmaClient *conn);
|
||||
|
||||
/**
|
||||
* Return the information associated to a given object.
|
||||
@@ -293,43 +328,8 @@ int plasma_status(PlasmaConnection *conn, ObjectID object_id);
|
||||
* PLASMA_CLIENT_NOT_LOCAL, if not. In this case, the caller needs to
|
||||
* ignore data, metadata_size, and metadata fields.
|
||||
*/
|
||||
int plasma_info(PlasmaConnection *conn,
|
||||
ObjectID object_id,
|
||||
ObjectInfo *object_info);
|
||||
|
||||
/**
|
||||
* Wait for (1) a specified number of objects to be available (sealed) in the
|
||||
* local Plasma Store or in a remote Plasma Store, or (2) for a timeout to
|
||||
* expire. This is a blocking call.
|
||||
*
|
||||
* @param conn The object containing the connection state.
|
||||
* @param num_object_requests Size of the object_requests array.
|
||||
* @param object_requests Object event array. Each element contains a request
|
||||
* for a particular object_id. The type of request is specified in the
|
||||
* "type" field.
|
||||
* - A PLASMA_QUERY_LOCAL request is satisfied when object_id becomes
|
||||
* available in the local Plasma Store. In this case, this function
|
||||
* sets the "status" field to ObjectStatus_Local. Note, if the status
|
||||
* is not ObjectStatus_Local, it will be ObjectStatus_Nonexistent,
|
||||
* but it may exist elsewhere in the system.
|
||||
* - A PLASMA_QUERY_ANYWHERE request is satisfied when object_id becomes
|
||||
* available either at the local Plasma Store or on a remote Plasma
|
||||
* Store. In this case, the functions sets the "status" field to
|
||||
* ObjectStatus_Local or ObjectStatus_Remote.
|
||||
* @param num_ready_objects The number of requests in object_requests array that
|
||||
* must be satisfied before the function returns, unless it timeouts.
|
||||
* The num_ready_objects should be no larger than num_object_requests.
|
||||
* @param timeout_ms Timeout value in milliseconds. If this timeout expires
|
||||
* before min_num_ready_objects of requests are satisfied, the function
|
||||
* returns.
|
||||
* @return Number of satisfied requests in the object_requests list. If the
|
||||
* returned number is less than min_num_ready_objects this means that
|
||||
* timeout expired.
|
||||
*/
|
||||
int plasma_wait(PlasmaConnection *conn,
|
||||
int num_object_requests,
|
||||
ObjectRequest object_requests[],
|
||||
int num_ready_objects,
|
||||
uint64_t timeout_ms);
|
||||
// int plasma_info(PlasmaConnection *conn,
|
||||
// ObjectID object_id,
|
||||
// ObjectInfo *object_info);
|
||||
|
||||
#endif /* PLASMA_CLIENT_H */
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#include "plasma_common.h"
|
||||
|
||||
#include <random>
|
||||
|
||||
#include "format/plasma_generated.h"
|
||||
|
||||
using arrow::Status;
|
||||
|
||||
UniqueID UniqueID::from_random() {
|
||||
UniqueID id;
|
||||
uint8_t *data = id.mutable_data();
|
||||
std::random_device engine;
|
||||
for (int i = 0; i < kUniqueIDSize; i++) {
|
||||
data[i] = engine();
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
UniqueID UniqueID::from_binary(const std::string &binary) {
|
||||
UniqueID id;
|
||||
std::memcpy(&id, binary.data(), sizeof(id));
|
||||
return id;
|
||||
}
|
||||
|
||||
const uint8_t *UniqueID::data() const {
|
||||
return id_;
|
||||
}
|
||||
|
||||
uint8_t *UniqueID::mutable_data() {
|
||||
return id_;
|
||||
}
|
||||
|
||||
std::string UniqueID::binary() const {
|
||||
return std::string(reinterpret_cast<const char *>(id_), kUniqueIDSize);
|
||||
}
|
||||
|
||||
std::string UniqueID::hex() const {
|
||||
constexpr char hex[] = "0123456789abcdef";
|
||||
std::string result;
|
||||
for (int i = 0; i < sizeof(UniqueID); i++) {
|
||||
unsigned int val = id_[i];
|
||||
result.push_back(hex[val >> 4]);
|
||||
result.push_back(hex[val & 0xf]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool UniqueID::operator==(const UniqueID &rhs) const {
|
||||
return std::memcmp(data(), rhs.data(), kUniqueIDSize) == 0;
|
||||
}
|
||||
|
||||
Status plasma_error_status(int plasma_error) {
|
||||
switch (plasma_error) {
|
||||
case PlasmaError_OK:
|
||||
return Status::OK();
|
||||
case PlasmaError_ObjectExists:
|
||||
return Status::PlasmaObjectExists(
|
||||
"object already exists in the plasma store");
|
||||
case PlasmaError_ObjectNonexistent:
|
||||
return Status::PlasmaObjectNonexistent(
|
||||
"object does not exist in the plasma store");
|
||||
case PlasmaError_OutOfMemory:
|
||||
return Status::PlasmaStoreFull("object does not fit in the plasma store");
|
||||
default:
|
||||
ARROW_LOG(FATAL) << "unknown plasma error code " << plasma_error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#ifndef PLASMA_COMMON_H
|
||||
#define PLASMA_COMMON_H
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "logging.h"
|
||||
#include "status.h"
|
||||
|
||||
constexpr int64_t kUniqueIDSize = 20;
|
||||
|
||||
class UniqueID {
|
||||
public:
|
||||
static UniqueID from_random();
|
||||
static UniqueID from_binary(const std::string &binary);
|
||||
bool operator==(const UniqueID &rhs) const;
|
||||
const uint8_t *data() const;
|
||||
uint8_t *mutable_data();
|
||||
std::string binary() const;
|
||||
std::string hex() const;
|
||||
|
||||
private:
|
||||
uint8_t id_[kUniqueIDSize];
|
||||
};
|
||||
|
||||
static_assert(std::is_pod<UniqueID>::value, "UniqueID must be plain old data");
|
||||
|
||||
struct UniqueIDHasher {
|
||||
/* ObjectID hashing function. */
|
||||
size_t operator()(const UniqueID &id) const {
|
||||
size_t result;
|
||||
std::memcpy(&result, id.data(), sizeof(size_t));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
typedef UniqueID ObjectID;
|
||||
|
||||
arrow::Status plasma_error_status(int plasma_error);
|
||||
|
||||
#endif // PLASMA_COMMON_H
|
||||
@@ -29,10 +29,10 @@ bool EventLoop::add_file_event(int fd, int events, FileCallback callback) {
|
||||
}
|
||||
auto data = std::unique_ptr<FileCallback>(new FileCallback(callback));
|
||||
void *context = reinterpret_cast<void *>(data.get());
|
||||
/* Try to add the file descriptor. */
|
||||
// Try to add the file descriptor.
|
||||
int err = aeCreateFileEvent(loop_, fd, events, EventLoop::file_event_callback,
|
||||
context);
|
||||
/* If it cannot be added, increase the size of the event loop. */
|
||||
// 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) {
|
||||
@@ -41,7 +41,7 @@ bool EventLoop::add_file_event(int fd, int events, FileCallback callback) {
|
||||
err = aeCreateFileEvent(loop_, fd, events, EventLoop::file_event_callback,
|
||||
context);
|
||||
}
|
||||
/* In any case, test if there were errors. */
|
||||
// In any case, test if there were errors.
|
||||
if (err == AE_OK) {
|
||||
file_callbacks_.emplace(fd, std::move(data));
|
||||
return true;
|
||||
|
||||
+35
-46
@@ -9,73 +9,62 @@ extern "C" {
|
||||
#include "ae/ae.h"
|
||||
}
|
||||
|
||||
/** Constant specifying that the timer is done and it will be removed. */
|
||||
/// Constant specifying that the timer is done and it will be removed.
|
||||
constexpr int kEventLoopTimerDone = AE_NOMORE;
|
||||
|
||||
/** Read event on the file descriptor. */
|
||||
/// Read event on the file descriptor.
|
||||
constexpr int kEventLoopRead = AE_READABLE;
|
||||
|
||||
/** Write event on the file descriptor. */
|
||||
/// Write event on the file descriptor.
|
||||
constexpr int kEventLoopWrite = AE_WRITABLE;
|
||||
|
||||
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).
|
||||
*/
|
||||
// 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).
|
||||
typedef std::function<void(int)> FileCallback;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
// 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.
|
||||
typedef std::function<int(int64_t)> TimerCallback;
|
||||
|
||||
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.
|
||||
*/
|
||||
/// 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 add_file_event(int fd, int events, FileCallback callback);
|
||||
|
||||
/**
|
||||
* Remove a file event handler from the event loop.
|
||||
*
|
||||
* @param fd The file descriptor of the event handler.
|
||||
* @return Void.
|
||||
*/
|
||||
/// Remove a file event handler from the event loop.
|
||||
///
|
||||
/// @param fd The file descriptor of the event handler.
|
||||
/// @return Void.
|
||||
void remove_file_event(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.
|
||||
*/
|
||||
/// 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 add_timer(int64_t timeout, 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
|
||||
*/
|
||||
/// 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 remove_timer(int64_t timer_id);
|
||||
|
||||
/**
|
||||
* Run the event loop.
|
||||
*
|
||||
* @return Void.
|
||||
*/
|
||||
/// Run the event loop.
|
||||
///
|
||||
/// @return Void.
|
||||
void run();
|
||||
|
||||
private:
|
||||
@@ -93,4 +82,4 @@ class EventLoop {
|
||||
std::unordered_map<int64_t, std::unique_ptr<TimerCallback>> timer_callbacks_;
|
||||
};
|
||||
|
||||
#endif /* PLASMA_EVENTS */
|
||||
#endif // PLASMA_EVENTS
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#include <Python.h>
|
||||
#include "bytesobject.h"
|
||||
|
||||
#include "common_extension.h"
|
||||
#include "common.h"
|
||||
#include "io.h"
|
||||
#include "plasma_io.h"
|
||||
#include "plasma_common.h"
|
||||
#include "plasma_protocol.h"
|
||||
#include "plasma_client.h"
|
||||
|
||||
@@ -20,38 +19,35 @@ PyObject *PyPlasma_connect(PyObject *self, PyObject *args) {
|
||||
&release_delay)) {
|
||||
return NULL;
|
||||
}
|
||||
PlasmaConnection *conn;
|
||||
if (strlen(manager_socket_name) == 0) {
|
||||
conn = plasma_connect(store_socket_name, NULL, release_delay);
|
||||
} else {
|
||||
conn =
|
||||
plasma_connect(store_socket_name, manager_socket_name, release_delay);
|
||||
}
|
||||
return PyCapsule_New(conn, "plasma", NULL);
|
||||
PlasmaClient *client = new PlasmaClient();
|
||||
ARROW_CHECK_OK(
|
||||
client->Connect(store_socket_name, manager_socket_name, release_delay));
|
||||
|
||||
return PyCapsule_New(client, "plasma", NULL);
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_disconnect(PyObject *self, PyObject *args) {
|
||||
PyObject *conn_capsule;
|
||||
PlasmaConnection *conn;
|
||||
if (!PyArg_ParseTuple(args, "O", &conn_capsule)) {
|
||||
PyObject *client_capsule;
|
||||
if (!PyArg_ParseTuple(args, "O", &client_capsule)) {
|
||||
return NULL;
|
||||
}
|
||||
CHECK(PyObjectToPlasmaConnection(conn_capsule, &conn));
|
||||
plasma_disconnect(conn);
|
||||
PlasmaClient *client;
|
||||
ARROW_CHECK(PyObjectToPlasmaClient(client_capsule, &client));
|
||||
ARROW_CHECK_OK(client->Disconnect());
|
||||
/* We use the context of the connection capsule to indicate if the connection
|
||||
* is still active (if the context is NULL) or if it is closed (if the context
|
||||
* is (void*) 0x1). This is neccessary because the primary pointer of the
|
||||
* capsule cannot be NULL. */
|
||||
PyCapsule_SetContext(conn_capsule, (void *) 0x1);
|
||||
PyCapsule_SetContext(client_capsule, (void *) 0x1);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_create(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
ObjectID object_id;
|
||||
long long size;
|
||||
PyObject *metadata;
|
||||
if (!PyArg_ParseTuple(args, "O&O&LO", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&O&LO", PyObjectToPlasmaClient, &client,
|
||||
PyStringToUniqueID, &object_id, &size, &metadata)) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -60,22 +56,22 @@ PyObject *PyPlasma_create(PyObject *self, PyObject *args) {
|
||||
return NULL;
|
||||
}
|
||||
uint8_t *data;
|
||||
int error_code = plasma_create(conn, object_id, size,
|
||||
(uint8_t *) PyByteArray_AsString(metadata),
|
||||
PyByteArray_Size(metadata), &data);
|
||||
if (error_code == PlasmaError_ObjectExists) {
|
||||
Status s = client->Create(object_id, size,
|
||||
(uint8_t *) PyByteArray_AsString(metadata),
|
||||
PyByteArray_Size(metadata), &data);
|
||||
if (s.IsPlasmaObjectExists()) {
|
||||
PyErr_SetString(PlasmaObjectExistsError,
|
||||
"An object with this ID already exists in the plasma "
|
||||
"store.");
|
||||
return NULL;
|
||||
}
|
||||
if (error_code == PlasmaError_OutOfMemory) {
|
||||
if (s.IsPlasmaStoreFull()) {
|
||||
PyErr_SetString(PlasmaOutOfMemoryError,
|
||||
"The plasma store ran out of memory and could not create "
|
||||
"this object.");
|
||||
return NULL;
|
||||
}
|
||||
CHECK(error_code == PlasmaError_OK);
|
||||
ARROW_CHECK(s.ok());
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
return PyMemoryView_FromMemory((char *) data, (Py_ssize_t) size, PyBUF_WRITE);
|
||||
@@ -85,17 +81,17 @@ PyObject *PyPlasma_create(PyObject *self, PyObject *args) {
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_hash(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
ObjectID object_id;
|
||||
if (!PyArg_ParseTuple(args, "O&O&", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&O&", PyObjectToPlasmaClient, &client,
|
||||
PyStringToUniqueID, &object_id)) {
|
||||
return NULL;
|
||||
}
|
||||
unsigned char digest[DIGEST_SIZE];
|
||||
bool success = plasma_compute_object_hash(conn, object_id, digest);
|
||||
unsigned char digest[kDigestSize];
|
||||
bool success = plasma_compute_object_hash(client, object_id, digest);
|
||||
if (success) {
|
||||
PyObject *digest_string =
|
||||
PyBytes_FromStringAndSize((char *) digest, DIGEST_SIZE);
|
||||
PyBytes_FromStringAndSize((char *) digest, kDigestSize);
|
||||
return digest_string;
|
||||
} else {
|
||||
Py_RETURN_NONE;
|
||||
@@ -103,32 +99,32 @@ PyObject *PyPlasma_hash(PyObject *self, PyObject *args) {
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_seal(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
ObjectID object_id;
|
||||
if (!PyArg_ParseTuple(args, "O&O&", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&O&", PyObjectToPlasmaClient, &client,
|
||||
PyStringToUniqueID, &object_id)) {
|
||||
return NULL;
|
||||
}
|
||||
plasma_seal(conn, object_id);
|
||||
ARROW_CHECK_OK(client->Seal(object_id));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_release(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
ObjectID object_id;
|
||||
if (!PyArg_ParseTuple(args, "O&O&", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&O&", PyObjectToPlasmaClient, &client,
|
||||
PyStringToUniqueID, &object_id)) {
|
||||
return NULL;
|
||||
}
|
||||
plasma_release(conn, object_id);
|
||||
ARROW_CHECK_OK(client->Release(object_id));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_get(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
PyObject *object_id_list;
|
||||
long long timeout_ms;
|
||||
if (!PyArg_ParseTuple(args, "O&OL", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&OL", PyObjectToPlasmaClient, &client,
|
||||
&object_id_list, &timeout_ms)) {
|
||||
return NULL;
|
||||
}
|
||||
@@ -143,7 +139,8 @@ PyObject *PyPlasma_get(PyObject *self, PyObject *args) {
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
plasma_get(conn, object_ids, num_object_ids, timeout_ms, object_buffers);
|
||||
ARROW_CHECK_OK(
|
||||
client->Get(object_ids, num_object_ids, timeout_ms, object_buffers));
|
||||
Py_END_ALLOW_THREADS;
|
||||
free(object_ids);
|
||||
|
||||
@@ -182,14 +179,14 @@ PyObject *PyPlasma_get(PyObject *self, PyObject *args) {
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_contains(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
ObjectID object_id;
|
||||
if (!PyArg_ParseTuple(args, "O&O&", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&O&", PyObjectToPlasmaClient, &client,
|
||||
PyStringToUniqueID, &object_id)) {
|
||||
return NULL;
|
||||
}
|
||||
int has_object;
|
||||
plasma_contains(conn, object_id, &has_object);
|
||||
ARROW_CHECK_OK(client->Contains(object_id, &has_object));
|
||||
|
||||
if (has_object)
|
||||
Py_RETURN_TRUE;
|
||||
@@ -198,13 +195,13 @@ PyObject *PyPlasma_contains(PyObject *self, PyObject *args) {
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_fetch(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
PyObject *object_id_list;
|
||||
if (!PyArg_ParseTuple(args, "O&O", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&O", PyObjectToPlasmaClient, &client,
|
||||
&object_id_list)) {
|
||||
return NULL;
|
||||
}
|
||||
if (!plasma_manager_is_connected(conn)) {
|
||||
if (!plasma_manager_is_connected(client)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Not connected to the plasma manager");
|
||||
return NULL;
|
||||
}
|
||||
@@ -213,23 +210,23 @@ PyObject *PyPlasma_fetch(PyObject *self, PyObject *args) {
|
||||
for (int i = 0; i < n; ++i) {
|
||||
PyStringToUniqueID(PyList_GetItem(object_id_list, i), &object_ids[i]);
|
||||
}
|
||||
plasma_fetch(conn, (int) n, object_ids);
|
||||
ARROW_CHECK_OK(client->Fetch((int) n, object_ids));
|
||||
free(object_ids);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_wait(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
PyObject *object_id_list;
|
||||
long long timeout;
|
||||
int num_returns;
|
||||
if (!PyArg_ParseTuple(args, "O&OLi", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&OLi", PyObjectToPlasmaClient, &client,
|
||||
&object_id_list, &timeout, &num_returns)) {
|
||||
return NULL;
|
||||
}
|
||||
Py_ssize_t n = PyList_Size(object_id_list);
|
||||
|
||||
if (!plasma_manager_is_connected(conn)) {
|
||||
if (!plasma_manager_is_connected(client)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Not connected to the plasma manager");
|
||||
return NULL;
|
||||
}
|
||||
@@ -254,19 +251,19 @@ PyObject *PyPlasma_wait(PyObject *self, PyObject *args) {
|
||||
ObjectRequest *object_requests =
|
||||
(ObjectRequest *) malloc(sizeof(ObjectRequest) * n);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
CHECK(PyStringToUniqueID(PyList_GetItem(object_id_list, i),
|
||||
&object_requests[i].object_id) == 1);
|
||||
ARROW_CHECK(PyStringToUniqueID(PyList_GetItem(object_id_list, i),
|
||||
&object_requests[i].object_id) == 1);
|
||||
object_requests[i].type = PLASMA_QUERY_ANYWHERE;
|
||||
}
|
||||
/* Drop the global interpreter lock while we are waiting, so other threads can
|
||||
* run. */
|
||||
int num_return_objects;
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
num_return_objects = plasma_wait(conn, (int) n, object_requests, num_returns,
|
||||
(uint64_t) timeout);
|
||||
ARROW_CHECK_OK(client->Wait((int) n, object_requests, num_returns,
|
||||
(uint64_t) timeout, num_return_objects));
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
int num_to_return = MIN(num_return_objects, num_returns);
|
||||
int num_to_return = std::min(num_return_objects, num_returns);
|
||||
PyObject *ready_ids = PyList_New(num_to_return);
|
||||
PyObject *waiting_ids = PySet_New(object_id_list);
|
||||
int num_returned = 0;
|
||||
@@ -277,16 +274,16 @@ PyObject *PyPlasma_wait(PyObject *self, PyObject *args) {
|
||||
if (object_requests[i].status == ObjectStatus_Local ||
|
||||
object_requests[i].status == ObjectStatus_Remote) {
|
||||
PyObject *ready =
|
||||
PyBytes_FromStringAndSize((char *) object_requests[i].object_id.id,
|
||||
PyBytes_FromStringAndSize((char *) &object_requests[i].object_id,
|
||||
sizeof(object_requests[i].object_id));
|
||||
PyList_SetItem(ready_ids, num_returned, ready);
|
||||
PySet_Discard(waiting_ids, ready);
|
||||
num_returned += 1;
|
||||
} else {
|
||||
CHECK(object_requests[i].status == ObjectStatus_Nonexistent);
|
||||
ARROW_CHECK(object_requests[i].status == ObjectStatus_Nonexistent);
|
||||
}
|
||||
}
|
||||
CHECK(num_returned == num_to_return);
|
||||
ARROW_CHECK(num_returned == num_to_return);
|
||||
/* Return both the ready IDs and the remaining IDs. */
|
||||
PyObject *t = PyTuple_New(2);
|
||||
PyTuple_SetItem(t, 0, ready_ids);
|
||||
@@ -295,53 +292,55 @@ PyObject *PyPlasma_wait(PyObject *self, PyObject *args) {
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_evict(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
long long num_bytes;
|
||||
if (!PyArg_ParseTuple(args, "O&L", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&L", PyObjectToPlasmaClient, &client,
|
||||
&num_bytes)) {
|
||||
return NULL;
|
||||
}
|
||||
int64_t evicted_bytes = plasma_evict(conn, (int64_t) num_bytes);
|
||||
int64_t evicted_bytes;
|
||||
ARROW_CHECK_OK(client->Evict((int64_t) num_bytes, evicted_bytes));
|
||||
return PyLong_FromLong((long) evicted_bytes);
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_delete(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
ObjectID object_id;
|
||||
if (!PyArg_ParseTuple(args, "O&O&", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&O&", PyObjectToPlasmaClient, &client,
|
||||
PyStringToUniqueID, &object_id)) {
|
||||
return NULL;
|
||||
}
|
||||
plasma_delete(conn, object_id);
|
||||
ARROW_CHECK_OK(client->Delete(object_id));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_transfer(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
PlasmaClient *client;
|
||||
ObjectID object_id;
|
||||
const char *addr;
|
||||
int port;
|
||||
if (!PyArg_ParseTuple(args, "O&O&si", PyObjectToPlasmaConnection, &conn,
|
||||
if (!PyArg_ParseTuple(args, "O&O&si", PyObjectToPlasmaClient, &client,
|
||||
PyStringToUniqueID, &object_id, &addr, &port)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!plasma_manager_is_connected(conn)) {
|
||||
if (!plasma_manager_is_connected(client)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "Not connected to the plasma manager");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
plasma_transfer(conn, addr, port, object_id);
|
||||
ARROW_CHECK_OK(client->Transfer(addr, port, object_id));
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *PyPlasma_subscribe(PyObject *self, PyObject *args) {
|
||||
PlasmaConnection *conn;
|
||||
if (!PyArg_ParseTuple(args, "O&", PyObjectToPlasmaConnection, &conn)) {
|
||||
PlasmaClient *client;
|
||||
if (!PyArg_ParseTuple(args, "O&", PyObjectToPlasmaClient, &client)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sock = plasma_subscribe(conn);
|
||||
int sock;
|
||||
ARROW_CHECK_OK(client->Subscribe(sock));
|
||||
return PyLong_FromLong(sock);
|
||||
}
|
||||
|
||||
@@ -355,7 +354,7 @@ PyObject *PyPlasma_receive_notification(PyObject *self, PyObject *args) {
|
||||
* object was added, return a tuple of its fields: ObjectID, data_size,
|
||||
* metadata_size. If the object was deleted, data_size and metadata_size will
|
||||
* be set to -1. */
|
||||
uint8_t *notification = read_message_async(NULL, plasma_sock);
|
||||
uint8_t *notification = read_message_async(plasma_sock);
|
||||
if (notification == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"Failed to read object notification from Plasma socket");
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
#ifndef PLASMA_EXTENSION_H
|
||||
#define PLASMA_EXTENSION_H
|
||||
|
||||
static int PyObjectToPlasmaConnection(PyObject *object,
|
||||
PlasmaConnection **conn) {
|
||||
static int PyObjectToPlasmaClient(PyObject *object, PlasmaClient **client) {
|
||||
if (PyCapsule_IsValid(object, "plasma")) {
|
||||
*conn = (PlasmaConnection *) PyCapsule_GetPointer(object, "plasma");
|
||||
*client = (PlasmaClient *) PyCapsule_GetPointer(object, "plasma");
|
||||
return 1;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError, "must be a 'plasma' capsule");
|
||||
@@ -12,4 +11,14 @@ static int PyObjectToPlasmaConnection(PyObject *object,
|
||||
}
|
||||
}
|
||||
|
||||
int PyStringToUniqueID(PyObject *object, ObjectID *object_id) {
|
||||
if (PyBytes_Check(object)) {
|
||||
memcpy(object_id, PyBytes_AsString(object), sizeof(ObjectID));
|
||||
return 1;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_TypeError, "must be a 20 character string");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* PLASMA_EXTENSION_H */
|
||||
|
||||
@@ -0,0 +1,220 @@
|
||||
#include "plasma_io.h"
|
||||
#include "plasma_common.h"
|
||||
|
||||
using arrow::Status;
|
||||
|
||||
/* Number of times we try binding to a socket. */
|
||||
#define NUM_BIND_ATTEMPTS 5
|
||||
#define BIND_TIMEOUT_MS 100
|
||||
|
||||
/* Number of times we try connecting to a socket. */
|
||||
#define NUM_CONNECT_ATTEMPTS 50
|
||||
#define CONNECT_TIMEOUT_MS 100
|
||||
|
||||
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(std::string(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, int64_t type, int64_t length, uint8_t *bytes) {
|
||||
int64_t version = PLASMA_PROTOCOL_VERSION;
|
||||
RETURN_NOT_OK(
|
||||
WriteBytes(fd, reinterpret_cast<uint8_t *>(&version), sizeof(version)));
|
||||
RETURN_NOT_OK(
|
||||
WriteBytes(fd, reinterpret_cast<uint8_t *>(&type), sizeof(type)));
|
||||
RETURN_NOT_OK(
|
||||
WriteBytes(fd, reinterpret_cast<uint8_t *>(&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(std::string(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, int64_t *type, std::vector<uint8_t> &buffer) {
|
||||
int64_t version;
|
||||
RETURN_NOT_OK_ELSE(
|
||||
ReadBytes(fd, reinterpret_cast<uint8_t *>(&version), sizeof(version)),
|
||||
*type = DISCONNECT_CLIENT);
|
||||
ARROW_CHECK(version == PLASMA_PROTOCOL_VERSION) << "version = " << version;
|
||||
int64_t length;
|
||||
RETURN_NOT_OK_ELSE(
|
||||
ReadBytes(fd, reinterpret_cast<uint8_t *>(type), sizeof(*type)),
|
||||
*type = DISCONNECT_CLIENT);
|
||||
RETURN_NOT_OK_ELSE(
|
||||
ReadBytes(fd, reinterpret_cast<uint8_t *>(&length), sizeof(length)),
|
||||
*type = DISCONNECT_CLIENT);
|
||||
if (length > buffer.size()) {
|
||||
buffer.resize(length);
|
||||
}
|
||||
RETURN_NOT_OK_ELSE(ReadBytes(fd, buffer.data(), length),
|
||||
*type = DISCONNECT_CLIENT);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int bind_ipc_sock(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, (char *) &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, (struct sockaddr *) &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, 5) == -1) {
|
||||
ARROW_LOG(ERROR) << "Could not listen to socket " << pathname;
|
||||
close(socket_fd);
|
||||
return -1;
|
||||
}
|
||||
return socket_fd;
|
||||
}
|
||||
|
||||
int connect_ipc_sock_retry(const std::string &pathname,
|
||||
int num_retries,
|
||||
int64_t timeout) {
|
||||
/* Pick the default values if the user did not specify. */
|
||||
if (num_retries < 0) {
|
||||
num_retries = NUM_CONNECT_ATTEMPTS;
|
||||
}
|
||||
if (timeout < 0) {
|
||||
timeout = CONNECT_TIMEOUT_MS;
|
||||
}
|
||||
|
||||
int fd = -1;
|
||||
for (int num_attempts = 0; num_attempts < num_retries; ++num_attempts) {
|
||||
fd = connect_ipc_sock(pathname);
|
||||
if (fd >= 0) {
|
||||
break;
|
||||
}
|
||||
if (num_attempts == 0) {
|
||||
ARROW_LOG(ERROR) << "Connection to socket failed for pathname "
|
||||
<< pathname;
|
||||
}
|
||||
/* Sleep for timeout milliseconds. */
|
||||
usleep(timeout * 1000);
|
||||
}
|
||||
/* If we could not connect to the socket, exit. */
|
||||
if (fd == -1) {
|
||||
ARROW_LOG(FATAL) << "Could not connect to socket " << pathname;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int connect_ipc_sock(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.";
|
||||
return -1;
|
||||
}
|
||||
strncpy(socket_address.sun_path, pathname.c_str(), pathname.size() + 1);
|
||||
|
||||
if (connect(socket_fd, (struct sockaddr *) &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;
|
||||
}
|
||||
|
||||
uint8_t *read_message_async(int sock) {
|
||||
int64_t size;
|
||||
Status s = ReadBytes(sock, (uint8_t *) &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;
|
||||
}
|
||||
uint8_t *message = (uint8_t *) malloc(size);
|
||||
s = ReadBytes(sock, message, 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;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "status.h"
|
||||
|
||||
// TODO(pcm): Replace our own custom message header (message type,
|
||||
// message length, plasma protocol verion) with one that is serialized
|
||||
// using flatbuffers.
|
||||
#define PLASMA_PROTOCOL_VERSION 0x0000000000000000
|
||||
#define DISCONNECT_CLIENT 0
|
||||
|
||||
arrow::Status WriteBytes(int fd, uint8_t *cursor, size_t length);
|
||||
|
||||
arrow::Status WriteMessage(int fd,
|
||||
int64_t type,
|
||||
int64_t length,
|
||||
uint8_t *bytes);
|
||||
|
||||
arrow::Status ReadBytes(int fd, uint8_t *cursor, size_t length);
|
||||
|
||||
arrow::Status ReadMessage(int fd, int64_t *type, std::vector<uint8_t> &buffer);
|
||||
|
||||
int bind_ipc_sock(const std::string &pathname, bool shall_listen);
|
||||
|
||||
int connect_ipc_sock(const std::string &pathname);
|
||||
|
||||
int connect_ipc_sock_retry(const std::string &pathname,
|
||||
int num_retries,
|
||||
int64_t timeout);
|
||||
|
||||
int AcceptClient(int socket_fd);
|
||||
|
||||
uint8_t *read_message_async(int sock);
|
||||
@@ -43,6 +43,21 @@
|
||||
#include "state/task_table.h"
|
||||
#include "state/db_client_table.h"
|
||||
|
||||
int handle_sigpipe(Status s, int fd) {
|
||||
if (s.ok()) {
|
||||
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 "
|
||||
<< fd << ". The client on the other end may "
|
||||
"have hung up.";
|
||||
return errno;
|
||||
}
|
||||
ARROW_LOG(FATAL) << "Failed to write message to client on fd " << fd << ".";
|
||||
}
|
||||
|
||||
/**
|
||||
* Process either the fetch or the status request.
|
||||
*
|
||||
@@ -200,7 +215,7 @@ struct PlasmaManagerState {
|
||||
/** Event loop. */
|
||||
event_loop *loop;
|
||||
/** Connection to the local plasma store for reading or writing data. */
|
||||
PlasmaConnection *plasma_conn;
|
||||
PlasmaClient *plasma_conn;
|
||||
/** Hash table of all contexts for active connections to
|
||||
* other plasma managers. These are used for writing data to
|
||||
* other plasma stores. */
|
||||
@@ -221,8 +236,6 @@ struct PlasmaManagerState {
|
||||
ObjectWaitRequests *object_wait_requests_remote;
|
||||
/** Initialize an empty hash map for the cache of local available object. */
|
||||
AvailableObject *local_available_objects;
|
||||
/** Buffer that holds memory for serializing plasma protocol messages. */
|
||||
protocol_builder *builder;
|
||||
};
|
||||
|
||||
PlasmaManagerState *g_manager_state = NULL;
|
||||
@@ -400,10 +413,10 @@ void remove_wait_request(PlasmaManagerState *manager_state,
|
||||
void return_from_wait(PlasmaManagerState *manager_state,
|
||||
WaitRequest *wait_req) {
|
||||
/* Send the reply to the client. */
|
||||
warn_if_sigpipe(plasma_send_WaitReply(
|
||||
wait_req->client_conn->fd, manager_state->builder,
|
||||
wait_req->object_requests, wait_req->num_object_requests),
|
||||
wait_req->client_conn->fd);
|
||||
handle_sigpipe(
|
||||
SendWaitReply(wait_req->client_conn->fd, wait_req->object_requests,
|
||||
wait_req->num_object_requests),
|
||||
wait_req->client_conn->fd);
|
||||
/* Iterate over all object IDs requested as part of this wait request.
|
||||
* Remove the wait request from each of the relevant object_wait_requests hash
|
||||
* tables if it is present there. */
|
||||
@@ -498,8 +511,9 @@ PlasmaManagerState *PlasmaManagerState_init(const char *store_socket_name,
|
||||
PlasmaManagerState *state =
|
||||
(PlasmaManagerState *) malloc(sizeof(PlasmaManagerState));
|
||||
state->loop = event_loop_create();
|
||||
state->plasma_conn =
|
||||
plasma_connect(store_socket_name, NULL, PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
state->plasma_conn = new PlasmaClient();
|
||||
ARROW_CHECK_OK(state->plasma_conn->Connect(store_socket_name, "",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
state->manager_connections = NULL;
|
||||
state->fetch_requests = NULL;
|
||||
state->object_wait_requests_local = NULL;
|
||||
@@ -534,11 +548,11 @@ PlasmaManagerState *PlasmaManagerState_init(const char *store_socket_name,
|
||||
/* Initialize an empty hash map for the cache of local available objects. */
|
||||
state->local_available_objects = NULL;
|
||||
/* Subscribe to notifications about sealed objects. */
|
||||
int plasma_fd = plasma_subscribe(state->plasma_conn);
|
||||
int plasma_fd;
|
||||
ARROW_CHECK_OK(state->plasma_conn->Subscribe(plasma_fd));
|
||||
/* Add the callback that processes the notification to the event loop. */
|
||||
event_loop_add_file(state->loop, plasma_fd, EVENT_LOOP_READ,
|
||||
process_object_notification, state);
|
||||
state->builder = make_protocol_builder();
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -582,9 +596,9 @@ void PlasmaManagerState_free(PlasmaManagerState *state) {
|
||||
free(wait_reqs);
|
||||
}
|
||||
|
||||
plasma_disconnect(state->plasma_conn);
|
||||
ARROW_CHECK_OK(state->plasma_conn->Disconnect());
|
||||
delete state->plasma_conn;
|
||||
event_loop_destroy(state->loop);
|
||||
free_protocol_builder(state->builder);
|
||||
free(state);
|
||||
}
|
||||
|
||||
@@ -624,7 +638,7 @@ int write_object_chunk(ClientConnection *conn, PlasmaRequestBuffer *buf) {
|
||||
conn->cursor = 0;
|
||||
/* We are done sending the object, so release it. The corresponding call to
|
||||
* plasma_get occurred in process_transfer_request. */
|
||||
plasma_release(conn->manager_state->plasma_conn, buf->object_id);
|
||||
ARROW_CHECK_OK(conn->manager_state->plasma_conn->Release(buf->object_id));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -649,9 +663,8 @@ void send_queued_request(event_loop *loop,
|
||||
int err = 0;
|
||||
switch (buf->type) {
|
||||
case MessageType_PlasmaDataRequest:
|
||||
err = warn_if_sigpipe(
|
||||
plasma_send_DataRequest(conn->fd, state->builder, buf->object_id,
|
||||
state->addr, state->port),
|
||||
err = handle_sigpipe(
|
||||
SendDataRequest(conn->fd, buf->object_id, state->addr, state->port),
|
||||
conn->fd);
|
||||
break;
|
||||
case MessageType_PlasmaDataReply:
|
||||
@@ -659,10 +672,9 @@ void send_queued_request(event_loop *loop,
|
||||
if (conn->cursor == 0) {
|
||||
/* If the cursor is zero, we haven't sent any requests for this object
|
||||
* yet, so send the initial data request. */
|
||||
err = warn_if_sigpipe(
|
||||
plasma_send_DataReply(conn->fd, state->builder, buf->object_id,
|
||||
buf->data_size, buf->metadata_size),
|
||||
conn->fd);
|
||||
err = handle_sigpipe(SendDataReply(conn->fd, buf->object_id,
|
||||
buf->data_size, buf->metadata_size),
|
||||
conn->fd);
|
||||
}
|
||||
if (err == 0) {
|
||||
err = write_object_chunk(conn, buf);
|
||||
@@ -743,8 +755,8 @@ void process_data_chunk(event_loop *loop,
|
||||
LOG_DEBUG("reading on channel %d finished", data_sock);
|
||||
/* The following seal also triggers notification of clients for fetch or
|
||||
* wait requests, see process_object_notification. */
|
||||
plasma_seal(conn->manager_state->plasma_conn, buf->object_id);
|
||||
plasma_release(conn->manager_state->plasma_conn, buf->object_id);
|
||||
ARROW_CHECK_OK(conn->manager_state->plasma_conn->Seal(buf->object_id));
|
||||
ARROW_CHECK_OK(conn->manager_state->plasma_conn->Release(buf->object_id));
|
||||
/* Remove the request buffer used for reading this object's data. */
|
||||
DL_DELETE(conn->transfer_queue, buf);
|
||||
free(buf);
|
||||
@@ -824,7 +836,8 @@ void process_transfer_request(event_loop *loop,
|
||||
/* Allocate and append the request to the transfer queue. */
|
||||
ObjectBuffer object_buffer;
|
||||
/* We pass in 0 to indicate that the command should return immediately. */
|
||||
plasma_get(conn->manager_state->plasma_conn, &obj_id, 1, 0, &object_buffer);
|
||||
ARROW_CHECK_OK(
|
||||
conn->manager_state->plasma_conn->Get(&obj_id, 1, 0, &object_buffer));
|
||||
if (object_buffer.data_size == -1) {
|
||||
/* If the object wasn't locally available, exit immediately. If the object
|
||||
* later appears locally, the requesting plasma manager should request the
|
||||
@@ -890,12 +903,12 @@ void process_data_request(event_loop *loop,
|
||||
|
||||
/* The corresponding call to plasma_release should happen in
|
||||
* process_data_chunk. */
|
||||
int error_code = plasma_create(conn->manager_state->plasma_conn, object_id,
|
||||
data_size, NULL, metadata_size, &(buf->data));
|
||||
Status s = conn->manager_state->plasma_conn->Create(
|
||||
object_id, data_size, NULL, metadata_size, &(buf->data));
|
||||
/* If success_create == true, a new object has been created.
|
||||
* If success_create == false the object creation has failed, possibly
|
||||
* due to an object with the same ID already existing in the Plasma Store. */
|
||||
if (error_code == PlasmaError_OK) {
|
||||
if (s.ok()) {
|
||||
/* Add buffer where the fetched data is to be stored to
|
||||
* conn->transfer_queue. */
|
||||
DL_APPEND(conn->transfer_queue, buf);
|
||||
@@ -905,7 +918,7 @@ void process_data_request(event_loop *loop,
|
||||
/* Switch to reading the data from this socket, instead of listening for
|
||||
* other requests. */
|
||||
event_loop_remove_file(loop, client_sock);
|
||||
if (error_code == PlasmaError_OK) {
|
||||
if (s.ok()) {
|
||||
bool success = event_loop_add_file(loop, client_sock, EVENT_LOOP_READ,
|
||||
process_data_chunk, conn);
|
||||
if (!success) {
|
||||
@@ -1175,12 +1188,12 @@ int wait_timeout_handler(event_loop *loop, timer_id id, void *context) {
|
||||
}
|
||||
|
||||
void process_wait_request(ClientConnection *client_conn,
|
||||
int num_object_requests,
|
||||
ObjectRequestMap &&object_requests,
|
||||
uint64_t timeout_ms,
|
||||
int num_ready_objects) {
|
||||
CHECK(client_conn != NULL);
|
||||
PlasmaManagerState *manager_state = client_conn->manager_state;
|
||||
int num_object_requests = object_requests.size();
|
||||
|
||||
/* Create a wait request for this object. */
|
||||
WaitRequest *wait_req =
|
||||
@@ -1267,10 +1280,8 @@ void request_status_done(ObjectID object_id,
|
||||
ClientConnection *client_conn = (ClientConnection *) context;
|
||||
int status =
|
||||
request_status(object_id, manager_count, manager_vector, context);
|
||||
warn_if_sigpipe(plasma_send_StatusReply(client_conn->fd,
|
||||
client_conn->manager_state->builder,
|
||||
&object_id, &status, 1),
|
||||
client_conn->fd);
|
||||
handle_sigpipe(SendStatusReply(client_conn->fd, &object_id, &status, 1),
|
||||
client_conn->fd);
|
||||
}
|
||||
|
||||
int request_status(ObjectID object_id,
|
||||
@@ -1302,19 +1313,15 @@ void process_status_request(ClientConnection *client_conn, ObjectID object_id) {
|
||||
/* Return success immediately if we already have this object. */
|
||||
if (is_object_local(client_conn->manager_state, object_id)) {
|
||||
int status = ObjectStatus_Local;
|
||||
warn_if_sigpipe(plasma_send_StatusReply(client_conn->fd,
|
||||
client_conn->manager_state->builder,
|
||||
&object_id, &status, 1),
|
||||
client_conn->fd);
|
||||
handle_sigpipe(SendStatusReply(client_conn->fd, &object_id, &status, 1),
|
||||
client_conn->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
if (client_conn->manager_state->db == NULL) {
|
||||
int status = ObjectStatus_Nonexistent;
|
||||
warn_if_sigpipe(plasma_send_StatusReply(client_conn->fd,
|
||||
client_conn->manager_state->builder,
|
||||
&object_id, &status, 1),
|
||||
client_conn->fd);
|
||||
handle_sigpipe(SendStatusReply(client_conn->fd, &object_id, &status, 1),
|
||||
client_conn->fd);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1531,7 +1538,7 @@ void process_message(event_loop *loop,
|
||||
ObjectID object_id;
|
||||
char *address;
|
||||
int port;
|
||||
plasma_read_DataRequest(data, &object_id, &address, &port);
|
||||
ARROW_CHECK_OK(ReadDataRequest(data, &object_id, &address, &port));
|
||||
process_transfer_request(loop, object_id, address, port, conn);
|
||||
free(address);
|
||||
} break;
|
||||
@@ -1540,38 +1547,34 @@ void process_message(event_loop *loop,
|
||||
ObjectID object_id;
|
||||
int64_t object_size;
|
||||
int64_t metadata_size;
|
||||
plasma_read_DataReply(data, &object_id, &object_size, &metadata_size);
|
||||
ARROW_CHECK_OK(
|
||||
ReadDataReply(data, &object_id, &object_size, &metadata_size));
|
||||
process_data_request(loop, client_sock, object_id, object_size,
|
||||
metadata_size, conn);
|
||||
} break;
|
||||
case MessageType_PlasmaFetchRequest: {
|
||||
LOG_DEBUG("Processing fetch remote");
|
||||
int64_t num_objects = plasma_read_FetchRequest_num_objects(data);
|
||||
ObjectID *object_ids_to_fetch =
|
||||
(ObjectID *) malloc(num_objects * sizeof(ObjectID));
|
||||
std::vector<ObjectID> object_ids_to_fetch;
|
||||
/* TODO(pcm): process_fetch_requests allocates an array of num_objects
|
||||
* object_ids too so these should be shared in the future. */
|
||||
plasma_read_FetchRequest(data, object_ids_to_fetch, num_objects);
|
||||
process_fetch_requests(conn, num_objects, &object_ids_to_fetch[0]);
|
||||
free(object_ids_to_fetch);
|
||||
ARROW_CHECK_OK(ReadFetchRequest(data, object_ids_to_fetch));
|
||||
process_fetch_requests(conn, object_ids_to_fetch.size(),
|
||||
object_ids_to_fetch.data());
|
||||
} break;
|
||||
case MessageType_PlasmaWaitRequest: {
|
||||
LOG_DEBUG("Processing wait");
|
||||
int num_object_ids = plasma_read_WaitRequest_num_object_ids(data);
|
||||
ObjectRequestMap object_requests;
|
||||
int64_t timeout_ms;
|
||||
int num_ready_objects;
|
||||
plasma_read_WaitRequest(data, object_requests, num_object_ids, &timeout_ms,
|
||||
&num_ready_objects);
|
||||
process_wait_request(conn, num_object_ids, std::move(object_requests),
|
||||
timeout_ms, num_ready_objects);
|
||||
ARROW_CHECK_OK(ReadWaitRequest(data, object_requests, &timeout_ms,
|
||||
&num_ready_objects));
|
||||
process_wait_request(conn, std::move(object_requests), timeout_ms,
|
||||
num_ready_objects);
|
||||
} break;
|
||||
case MessageType_PlasmaStatusRequest: {
|
||||
LOG_DEBUG("Processing status");
|
||||
ObjectID object_id;
|
||||
int64_t num_objects = plasma_read_StatusRequest_num_objects(data);
|
||||
CHECK(num_objects == 1);
|
||||
plasma_read_StatusRequest(data, &object_id, 1);
|
||||
ARROW_CHECK_OK(ReadStatusRequest(data, &object_id, 1));
|
||||
process_status_request(conn, object_id);
|
||||
} break;
|
||||
case DISCONNECT_CLIENT: {
|
||||
|
||||
+297
-337
@@ -1,406 +1,381 @@
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
#include "format/plasma_generated.h"
|
||||
|
||||
#include "plasma_common.h"
|
||||
#include "plasma_protocol.h"
|
||||
#include "common_protocol.h"
|
||||
#include "io.h"
|
||||
#include "plasma_io.h"
|
||||
|
||||
#define FLATBUFFER_BUILDER_DEFAULT_SIZE 1024
|
||||
|
||||
protocol_builder *make_protocol_builder(void) {
|
||||
return NULL;
|
||||
flatbuffers::Offset<
|
||||
flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>>
|
||||
to_flatbuffer(flatbuffers::FlatBufferBuilder &fbb,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects) {
|
||||
std::vector<flatbuffers::Offset<flatbuffers::String>> results;
|
||||
for (size_t i = 0; i < num_objects; i++) {
|
||||
results.push_back(fbb.CreateString(object_ids[i].binary()));
|
||||
}
|
||||
return fbb.CreateVector(results);
|
||||
}
|
||||
|
||||
void free_protocol_builder(protocol_builder *builder) {}
|
||||
|
||||
uint8_t *plasma_receive(int sock, int64_t message_type) {
|
||||
Status PlasmaReceive(int sock,
|
||||
int64_t message_type,
|
||||
std::vector<uint8_t> &buffer) {
|
||||
int64_t type;
|
||||
int64_t length;
|
||||
uint8_t *reply_data;
|
||||
read_message(sock, &type, &length, &reply_data);
|
||||
CHECKM(type == message_type, "type = %" PRId64 ", message_type = %" PRId64,
|
||||
type, message_type);
|
||||
return reply_data;
|
||||
RETURN_NOT_OK(ReadMessage(sock, &type, buffer));
|
||||
ARROW_CHECK(type == message_type) << "type = " << type
|
||||
<< ", message_type = " << message_type;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* Create messages. */
|
||||
|
||||
int plasma_send_CreateRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int64_t data_size,
|
||||
int64_t metadata_size) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto message = CreatePlasmaCreateRequest(fbb, to_flatbuf(fbb, object_id),
|
||||
data_size, metadata_size);
|
||||
Status SendCreateRequest(int sock,
|
||||
ObjectID object_id,
|
||||
int64_t data_size,
|
||||
int64_t metadata_size) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaCreateRequest(
|
||||
fbb, fbb.CreateString(object_id.binary()), data_size, metadata_size);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaCreateRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaCreateRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_CreateRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
int64_t *data_size,
|
||||
int64_t *metadata_size) {
|
||||
CHECK(data);
|
||||
Status ReadCreateRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
int64_t *data_size,
|
||||
int64_t *metadata_size) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaCreateRequest>(data);
|
||||
*data_size = message->data_size();
|
||||
*metadata_size = message->metadata_size();
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int plasma_send_CreateReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
PlasmaObject *object,
|
||||
int error_code) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendCreateReply(int sock,
|
||||
ObjectID object_id,
|
||||
PlasmaObject *object,
|
||||
int error_code) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
PlasmaObjectSpec plasma_object(
|
||||
object->handle.store_fd, object->handle.mmap_size, object->data_offset,
|
||||
object->data_size, object->metadata_offset, object->metadata_size);
|
||||
auto message =
|
||||
CreatePlasmaCreateReply(fbb, to_flatbuf(fbb, object_id), &plasma_object,
|
||||
(PlasmaError) error_code);
|
||||
CreatePlasmaCreateReply(fbb, fbb.CreateString(object_id.binary()),
|
||||
&plasma_object, (PlasmaError) error_code);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaCreateReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaCreateReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_CreateReply(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
PlasmaObject *object,
|
||||
int *error_code) {
|
||||
CHECK(data);
|
||||
Status ReadCreateReply(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
PlasmaObject *object) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaCreateReply>(data);
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
object->handle.store_fd = message->plasma_object()->segment_index();
|
||||
object->handle.mmap_size = message->plasma_object()->mmap_size();
|
||||
object->data_offset = message->plasma_object()->data_offset();
|
||||
object->data_size = message->plasma_object()->data_size();
|
||||
object->metadata_offset = message->plasma_object()->metadata_offset();
|
||||
object->metadata_size = message->plasma_object()->metadata_size();
|
||||
*error_code = message->error();
|
||||
return plasma_error_status(message->error());
|
||||
}
|
||||
|
||||
/* Seal messages. */
|
||||
|
||||
int plasma_send_SealRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
unsigned char *digest) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto digest_string = fbb.CreateString((char *) digest, DIGEST_SIZE);
|
||||
auto message =
|
||||
CreatePlasmaSealRequest(fbb, to_flatbuf(fbb, object_id), digest_string);
|
||||
Status SendSealRequest(int sock, ObjectID object_id, unsigned char *digest) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto digest_string = fbb.CreateString((char *) digest, kDigestSize);
|
||||
auto message = CreatePlasmaSealRequest(
|
||||
fbb, fbb.CreateString(object_id.binary()), digest_string);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaSealRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaSealRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_SealRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
unsigned char *digest) {
|
||||
CHECK(data);
|
||||
Status ReadSealRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
unsigned char *digest) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaSealRequest>(data);
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
CHECK(message->digest()->size() == DIGEST_SIZE);
|
||||
memcpy(digest, message->digest()->data(), DIGEST_SIZE);
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
ARROW_CHECK(message->digest()->size() == kDigestSize);
|
||||
memcpy(digest, message->digest()->data(), kDigestSize);
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int plasma_send_SealReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int error) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto message = CreatePlasmaSealReply(fbb, to_flatbuf(fbb, object_id),
|
||||
(PlasmaError) error);
|
||||
Status SendSealReply(int sock, ObjectID object_id, int error) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaSealReply(
|
||||
fbb, fbb.CreateString(object_id.binary()), (PlasmaError) error);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaSealReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaSealReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_SealReply(uint8_t *data, ObjectID *object_id, int *error) {
|
||||
CHECK(data);
|
||||
Status ReadSealReply(uint8_t *data, ObjectID *object_id) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaSealReply>(data);
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
*error = message->error();
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
return plasma_error_status(message->error());
|
||||
}
|
||||
|
||||
/* Release messages. */
|
||||
|
||||
int plasma_send_ReleaseRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto message = CreatePlasmaSealRequest(fbb, to_flatbuf(fbb, object_id));
|
||||
Status SendReleaseRequest(int sock, ObjectID object_id) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message =
|
||||
CreatePlasmaSealRequest(fbb, fbb.CreateString(object_id.binary()));
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaReleaseRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaReleaseRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_ReleaseRequest(uint8_t *data, ObjectID *object_id) {
|
||||
CHECK(data);
|
||||
Status ReadReleaseRequest(uint8_t *data, ObjectID *object_id) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaReleaseRequest>(data);
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int plasma_send_ReleaseReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int error) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto message = CreatePlasmaReleaseReply(fbb, to_flatbuf(fbb, object_id),
|
||||
(PlasmaError) error);
|
||||
Status SendReleaseReply(int sock, ObjectID object_id, int error) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaReleaseReply(
|
||||
fbb, fbb.CreateString(object_id.binary()), (PlasmaError) error);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaReleaseReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaReleaseReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_ReleaseReply(uint8_t *data, ObjectID *object_id, int *error) {
|
||||
CHECK(data);
|
||||
Status ReadReleaseReply(uint8_t *data, ObjectID *object_id) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaReleaseReply>(data);
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
*error = message->error();
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
return plasma_error_status(message->error());
|
||||
}
|
||||
|
||||
/* Delete messages. */
|
||||
|
||||
int plasma_send_DeleteRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto message = CreatePlasmaDeleteRequest(fbb, to_flatbuf(fbb, object_id));
|
||||
Status SendDeleteRequest(int sock, ObjectID object_id) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message =
|
||||
CreatePlasmaDeleteRequest(fbb, fbb.CreateString(object_id.binary()));
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaDeleteRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaDeleteRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_DeleteRequest(uint8_t *data, ObjectID *object_id) {
|
||||
CHECK(data);
|
||||
Status ReadDeleteRequest(uint8_t *data, ObjectID *object_id) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaReleaseReply>(data);
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int plasma_send_DeleteReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int error) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto message = CreatePlasmaDeleteReply(fbb, to_flatbuf(fbb, object_id),
|
||||
(PlasmaError) error);
|
||||
Status SendDeleteReply(int sock, ObjectID object_id, int error) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaDeleteReply(
|
||||
fbb, fbb.CreateString(object_id.binary()), (PlasmaError) error);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaDeleteReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaDeleteReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_DeleteReply(uint8_t *data, ObjectID *object_id, int *error) {
|
||||
CHECK(data);
|
||||
Status ReadDeleteReply(uint8_t *data, ObjectID *object_id) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaDeleteReply>(data);
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
*error = message->error();
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
return plasma_error_status(message->error());
|
||||
}
|
||||
|
||||
/* Satus messages. */
|
||||
|
||||
int plasma_send_StatusRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto message =
|
||||
CreatePlasmaStatusRequest(fbb, to_flatbuf(fbb, object_ids, num_objects));
|
||||
Status SendStatusRequest(int sock, ObjectID object_ids[], int64_t num_objects) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaStatusRequest(
|
||||
fbb, to_flatbuffer(fbb, object_ids, num_objects));
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaStatusRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaStatusRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
int64_t plasma_read_StatusRequest_num_objects(uint8_t *data) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaStatusRequest>(data);
|
||||
return message->object_ids()->size();
|
||||
}
|
||||
|
||||
void plasma_read_StatusRequest(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects) {
|
||||
Status ReadStatusRequest(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaStatusRequest>(data);
|
||||
for (int64_t i = 0; i < num_objects; ++i) {
|
||||
object_ids[i] = from_flatbuf(message->object_ids()->Get(i));
|
||||
object_ids[i] = ObjectID::from_binary(message->object_ids()->Get(i)->str());
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int plasma_send_StatusReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_ids[],
|
||||
int object_status[],
|
||||
int64_t num_objects) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendStatusReply(int sock,
|
||||
ObjectID object_ids[],
|
||||
int object_status[],
|
||||
int64_t num_objects) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message =
|
||||
CreatePlasmaStatusReply(fbb, to_flatbuf(fbb, object_ids, num_objects),
|
||||
CreatePlasmaStatusReply(fbb, to_flatbuffer(fbb, object_ids, num_objects),
|
||||
fbb.CreateVector(object_status, num_objects));
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaStatusReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaStatusReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
int64_t plasma_read_StatusReply_num_objects(uint8_t *data) {
|
||||
int64_t ReadStatusReply_num_objects(uint8_t *data) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaStatusReply>(data);
|
||||
return message->object_ids()->size();
|
||||
}
|
||||
|
||||
void plasma_read_StatusReply(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int object_status[],
|
||||
int64_t num_objects) {
|
||||
Status ReadStatusReply(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int object_status[],
|
||||
int64_t num_objects) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaStatusReply>(data);
|
||||
for (int64_t i = 0; i < num_objects; ++i) {
|
||||
object_ids[i] = from_flatbuf(message->object_ids()->Get(i));
|
||||
object_ids[i] = ObjectID::from_binary(message->object_ids()->Get(i)->str());
|
||||
}
|
||||
for (int64_t i = 0; i < num_objects; ++i) {
|
||||
object_status[i] = message->status()->data()[i];
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* Contains messages. */
|
||||
|
||||
int plasma_send_ContainsRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto message = CreatePlasmaContainsRequest(fbb, to_flatbuf(fbb, object_id));
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaContainsRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_ContainsRequest(uint8_t *data, ObjectID *object_id) {
|
||||
CHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaContainsRequest>(data);
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
}
|
||||
|
||||
int plasma_send_ContainsReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int has_object) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendContainsRequest(int sock, ObjectID object_id) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message =
|
||||
CreatePlasmaContainsReply(fbb, to_flatbuf(fbb, object_id), has_object);
|
||||
CreatePlasmaContainsRequest(fbb, fbb.CreateString(object_id.binary()));
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaContainsReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaContainsRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_ContainsReply(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
int *has_object) {
|
||||
CHECK(data);
|
||||
Status ReadContainsRequest(uint8_t *data, ObjectID *object_id) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaContainsRequest>(data);
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
Status SendContainsReply(int sock, ObjectID object_id, int has_object) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaContainsReply(
|
||||
fbb, fbb.CreateString(object_id.binary()), has_object);
|
||||
fbb.Finish(message);
|
||||
return WriteMessage(sock, MessageType_PlasmaContainsReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
Status ReadContainsReply(uint8_t *data, ObjectID *object_id, int *has_object) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaContainsReply>(data);
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
*has_object = message->has_object();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* Connect messages. */
|
||||
|
||||
int plasma_send_ConnectRequest(int sock, protocol_builder *B) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendConnectRequest(int sock) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaConnectRequest(fbb);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaConnectRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaConnectRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_ConnectRequest(uint8_t *data) {}
|
||||
Status ReadConnectRequest(uint8_t *data) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int plasma_send_ConnectReply(int sock,
|
||||
protocol_builder *B,
|
||||
int64_t memory_capacity) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendConnectReply(int sock, int64_t memory_capacity) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaConnectReply(fbb, memory_capacity);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaConnectReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaConnectReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_ConnectReply(uint8_t *data, int64_t *memory_capacity) {
|
||||
Status ReadConnectReply(uint8_t *data, int64_t *memory_capacity) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaConnectReply>(data);
|
||||
*memory_capacity = message->memory_capacity();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* Evict messages. */
|
||||
|
||||
int plasma_send_EvictRequest(int sock, protocol_builder *B, int64_t num_bytes) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendEvictRequest(int sock, int64_t num_bytes) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaEvictRequest(fbb, num_bytes);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaEvictRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaEvictRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_EvictRequest(uint8_t *data, int64_t *num_bytes) {
|
||||
CHECK(data);
|
||||
Status ReadEvictRequest(uint8_t *data, int64_t *num_bytes) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaEvictRequest>(data);
|
||||
*num_bytes = message->num_bytes();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int plasma_send_EvictReply(int sock, protocol_builder *B, int64_t num_bytes) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendEvictReply(int sock, int64_t num_bytes) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaEvictReply(fbb, num_bytes);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaEvictReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaEvictReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_EvictReply(uint8_t *data, int64_t *num_bytes) {
|
||||
Status ReadEvictReply(uint8_t *data, int64_t &num_bytes) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaEvictReply>(data);
|
||||
*num_bytes = message->num_bytes();
|
||||
num_bytes = message->num_bytes();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* Get messages. */
|
||||
|
||||
int plasma_send_GetRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects,
|
||||
int64_t timeout_ms) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendGetRequest(int sock,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects,
|
||||
int64_t timeout_ms) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaGetRequest(
|
||||
fbb, to_flatbuf(fbb, object_ids, num_objects), timeout_ms);
|
||||
fbb, to_flatbuffer(fbb, object_ids, num_objects), timeout_ms);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaGetRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaGetRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
int64_t plasma_read_GetRequest_num_objects(uint8_t *data) {
|
||||
Status ReadGetRequest(uint8_t *data,
|
||||
std::vector<ObjectID> &object_ids,
|
||||
int64_t *timeout_ms) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaGetRequest>(data);
|
||||
return message->object_ids()->size();
|
||||
}
|
||||
|
||||
void plasma_read_GetRequest(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int64_t *timeout_ms,
|
||||
int64_t num_objects) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaGetRequest>(data);
|
||||
for (int64_t i = 0; i < num_objects; ++i) {
|
||||
object_ids[i] = from_flatbuf(message->object_ids()->Get(i));
|
||||
for (int64_t i = 0; i < message->object_ids()->size(); ++i) {
|
||||
auto object_id = message->object_ids()->Get(i)->str();
|
||||
object_ids.push_back(ObjectID::from_binary(object_id));
|
||||
}
|
||||
*timeout_ms = message->timeout_ms();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int plasma_send_GetReply(
|
||||
Status SendGetReply(
|
||||
int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_ids[],
|
||||
std::unordered_map<ObjectID, PlasmaObject, UniqueIDHasher> &plasma_objects,
|
||||
int64_t num_objects) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
std::vector<PlasmaObjectSpec> objects;
|
||||
|
||||
for (int i = 0; i < num_objects; ++i) {
|
||||
@@ -410,21 +385,21 @@ int plasma_send_GetReply(
|
||||
object.data_size, object.metadata_offset, object.metadata_size));
|
||||
}
|
||||
auto message = CreatePlasmaGetReply(
|
||||
fbb, to_flatbuf(fbb, object_ids, num_objects),
|
||||
fbb, to_flatbuffer(fbb, object_ids, num_objects),
|
||||
fbb.CreateVectorOfStructs(objects.data(), num_objects));
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaGetReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaGetReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_GetReply(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
PlasmaObject plasma_objects[],
|
||||
int64_t num_objects) {
|
||||
CHECK(data);
|
||||
Status ReadGetReply(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
PlasmaObject plasma_objects[],
|
||||
int64_t num_objects) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaGetReply>(data);
|
||||
for (int64_t i = 0; i < num_objects; ++i) {
|
||||
object_ids[i] = from_flatbuf(message->object_ids()->Get(i));
|
||||
object_ids[i] = ObjectID::from_binary(message->object_ids()->Get(i)->str());
|
||||
}
|
||||
for (int64_t i = 0; i < num_objects; ++i) {
|
||||
const PlasmaObjectSpec *object = message->plasma_objects()->Get(i);
|
||||
@@ -435,52 +410,43 @@ void plasma_read_GetReply(uint8_t *data,
|
||||
plasma_objects[i].metadata_offset = object->metadata_offset();
|
||||
plasma_objects[i].metadata_size = object->metadata_size();
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* Fetch messages. */
|
||||
|
||||
int plasma_send_FetchRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto message =
|
||||
CreatePlasmaFetchRequest(fbb, to_flatbuf(fbb, object_ids, num_objects));
|
||||
Status SendFetchRequest(int sock, ObjectID object_ids[], int64_t num_objects) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaFetchRequest(
|
||||
fbb, to_flatbuffer(fbb, object_ids, num_objects));
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaFetchRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaFetchRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
int64_t plasma_read_FetchRequest_num_objects(uint8_t *data) {
|
||||
Status ReadFetchRequest(uint8_t *data, std::vector<ObjectID> &object_ids) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaFetchRequest>(data);
|
||||
return message->object_ids()->size();
|
||||
}
|
||||
|
||||
void plasma_read_FetchRequest(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects) {
|
||||
CHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaFetchRequest>(data);
|
||||
for (int64_t i = 0; i < num_objects; ++i) {
|
||||
object_ids[i] = from_flatbuf(message->object_ids()->Get(i));
|
||||
for (int64_t i = 0; i < message->object_ids()->size(); ++i) {
|
||||
object_ids.push_back(
|
||||
ObjectID::from_binary(message->object_ids()->Get(i)->str()));
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* Wait messages. */
|
||||
|
||||
int plasma_send_WaitRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectRequest object_requests[],
|
||||
int num_requests,
|
||||
int num_ready_objects,
|
||||
int64_t timeout_ms) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendWaitRequest(int sock,
|
||||
ObjectRequest object_requests[],
|
||||
int num_requests,
|
||||
int num_ready_objects,
|
||||
int64_t timeout_ms) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
|
||||
std::vector<flatbuffers::Offset<ObjectRequestSpec>> object_request_specs;
|
||||
for (int i = 0; i < num_requests; i++) {
|
||||
object_request_specs.push_back(CreateObjectRequestSpec(
|
||||
fbb, to_flatbuf(fbb, object_requests[i].object_id),
|
||||
fbb, fbb.CreateString(object_requests[i].object_id.binary()),
|
||||
object_requests[i].type));
|
||||
}
|
||||
|
||||
@@ -488,130 +454,124 @@ int plasma_send_WaitRequest(int sock,
|
||||
CreatePlasmaWaitRequest(fbb, fbb.CreateVector(object_request_specs),
|
||||
num_ready_objects, timeout_ms);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaWaitRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaWaitRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
int plasma_read_WaitRequest_num_object_ids(uint8_t *data) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaWaitRequest>(data);
|
||||
return message->object_requests()->size();
|
||||
}
|
||||
|
||||
void plasma_read_WaitRequest(uint8_t *data,
|
||||
ObjectRequestMap &object_requests,
|
||||
int num_object_ids,
|
||||
int64_t *timeout_ms,
|
||||
int *num_ready_objects) {
|
||||
Status ReadWaitRequest(uint8_t *data,
|
||||
ObjectRequestMap &object_requests,
|
||||
int64_t *timeout_ms,
|
||||
int *num_ready_objects) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaWaitRequest>(data);
|
||||
*num_ready_objects = message->num_ready_objects();
|
||||
*timeout_ms = message->timeout();
|
||||
|
||||
CHECK(num_object_ids == message->object_requests()->size());
|
||||
for (int i = 0; i < num_object_ids; i++) {
|
||||
ObjectID object_id =
|
||||
from_flatbuf(message->object_requests()->Get(i)->object_id());
|
||||
for (int i = 0; i < message->object_requests()->size(); i++) {
|
||||
ObjectID object_id = ObjectID::from_binary(
|
||||
message->object_requests()->Get(i)->object_id()->str());
|
||||
ObjectRequest object_request({object_id,
|
||||
message->object_requests()->Get(i)->type(),
|
||||
ObjectStatus_Nonexistent});
|
||||
object_requests[object_id] = object_request;
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int plasma_send_WaitReply(int sock,
|
||||
protocol_builder *B,
|
||||
const ObjectRequestMap &object_requests,
|
||||
int num_ready_objects) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendWaitReply(int sock,
|
||||
const ObjectRequestMap &object_requests,
|
||||
int num_ready_objects) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
|
||||
std::vector<flatbuffers::Offset<ObjectReply>> object_replies;
|
||||
for (const auto &entry : object_requests) {
|
||||
const auto &object_request = entry.second;
|
||||
object_replies.push_back(CreateObjectReply(
|
||||
fbb, to_flatbuf(fbb, object_request.object_id), object_request.status));
|
||||
fbb, fbb.CreateString(object_request.object_id.binary()),
|
||||
object_request.status));
|
||||
}
|
||||
|
||||
auto message = CreatePlasmaWaitReply(
|
||||
fbb, fbb.CreateVector(object_replies.data(), num_ready_objects),
|
||||
num_ready_objects);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaWaitReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaWaitReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_WaitReply(uint8_t *data,
|
||||
ObjectRequest object_requests[],
|
||||
int *num_ready_objects) {
|
||||
Status ReadWaitReply(uint8_t *data,
|
||||
ObjectRequest object_requests[],
|
||||
int *num_ready_objects) {
|
||||
DCHECK(data);
|
||||
|
||||
auto message = flatbuffers::GetRoot<PlasmaWaitReply>(data);
|
||||
*num_ready_objects = message->num_ready_objects();
|
||||
for (int i = 0; i < *num_ready_objects; i++) {
|
||||
object_requests[i].object_id =
|
||||
from_flatbuf(message->object_requests()->Get(i)->object_id());
|
||||
object_requests[i].object_id = ObjectID::from_binary(
|
||||
message->object_requests()->Get(i)->object_id()->str());
|
||||
object_requests[i].status = message->object_requests()->Get(i)->status();
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* Subscribe messages. */
|
||||
|
||||
int plasma_send_SubscribeRequest(int sock, protocol_builder *B) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendSubscribeRequest(int sock) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaSubscribeRequest(fbb);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaSubscribeRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaSubscribeRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
/* Data messages. */
|
||||
|
||||
int plasma_send_DataRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
const char *address,
|
||||
int port) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
Status SendDataRequest(int sock,
|
||||
ObjectID object_id,
|
||||
const char *address,
|
||||
int port) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto addr = fbb.CreateString((char *) address, strlen(address));
|
||||
auto message =
|
||||
CreatePlasmaDataRequest(fbb, to_flatbuf(fbb, object_id), addr, port);
|
||||
auto message = CreatePlasmaDataRequest(
|
||||
fbb, fbb.CreateString(object_id.binary()), addr, port);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaDataRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaDataRequest, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_DataRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
char **address,
|
||||
int *port) {
|
||||
Status ReadDataRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
char **address,
|
||||
int *port) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaDataRequest>(data);
|
||||
DCHECK(message->object_id()->size() == sizeof(object_id->id));
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
DCHECK(message->object_id()->size() == sizeof(ObjectID));
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
*address = strdup(message->address()->c_str());
|
||||
*port = message->port();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
int plasma_send_DataReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int64_t object_size,
|
||||
int64_t metadata_size) {
|
||||
flatbuffers::FlatBufferBuilder fbb(FLATBUFFER_BUILDER_DEFAULT_SIZE);
|
||||
auto message = CreatePlasmaDataReply(fbb, to_flatbuf(fbb, object_id),
|
||||
object_size, metadata_size);
|
||||
Status SendDataReply(int sock,
|
||||
ObjectID object_id,
|
||||
int64_t object_size,
|
||||
int64_t metadata_size) {
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
auto message = CreatePlasmaDataReply(
|
||||
fbb, fbb.CreateString(object_id.binary()), object_size, metadata_size);
|
||||
fbb.Finish(message);
|
||||
return write_message(sock, MessageType_PlasmaDataReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
return WriteMessage(sock, MessageType_PlasmaDataReply, fbb.GetSize(),
|
||||
fbb.GetBufferPointer());
|
||||
}
|
||||
|
||||
void plasma_read_DataReply(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
int64_t *object_size,
|
||||
int64_t *metadata_size) {
|
||||
Status ReadDataReply(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
int64_t *object_size,
|
||||
int64_t *metadata_size) {
|
||||
DCHECK(data);
|
||||
auto message = flatbuffers::GetRoot<PlasmaDataReply>(data);
|
||||
*object_id = from_flatbuf(message->object_id());
|
||||
*object_id = ObjectID::from_binary(message->object_id()->str());
|
||||
*object_size = (int64_t) message->object_size();
|
||||
*metadata_size = (int64_t) message->metadata_size();
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
+107
-166
@@ -1,253 +1,194 @@
|
||||
#ifndef PLASMA_PROTOCOL_H
|
||||
#define PLASMA_PROTOCOL_H
|
||||
|
||||
#include "status.h"
|
||||
#include "format/plasma_generated.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "plasma.h"
|
||||
|
||||
typedef void protocol_builder;
|
||||
|
||||
/* An argument to a function that a return value gets written to. */
|
||||
#define OUT
|
||||
|
||||
protocol_builder *make_protocol_builder(void);
|
||||
|
||||
void free_protocol_builder(protocol_builder *builder);
|
||||
using arrow::Status;
|
||||
|
||||
/* Plasma receive message. */
|
||||
|
||||
uint8_t *plasma_receive(int sock, int64_t message_type);
|
||||
Status PlasmaReceive(int sock,
|
||||
int64_t message_type,
|
||||
std::vector<uint8_t> &buffer);
|
||||
|
||||
/* Plasma Create message functions. */
|
||||
|
||||
int plasma_send_CreateRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int64_t data_size,
|
||||
int64_t metadata_size);
|
||||
Status SendCreateRequest(int sock,
|
||||
ObjectID object_id,
|
||||
int64_t data_size,
|
||||
int64_t metadata_size);
|
||||
|
||||
void plasma_read_CreateRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
int64_t *data_size,
|
||||
int64_t *metadata_size);
|
||||
Status ReadCreateRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
int64_t *data_size,
|
||||
int64_t *metadata_size);
|
||||
|
||||
int plasma_send_CreateReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
PlasmaObject *object,
|
||||
int error);
|
||||
Status SendCreateReply(int sock,
|
||||
ObjectID object_id,
|
||||
PlasmaObject *object,
|
||||
int error);
|
||||
|
||||
void plasma_read_CreateReply(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
PlasmaObject *object,
|
||||
int *error);
|
||||
Status ReadCreateReply(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
PlasmaObject *object);
|
||||
|
||||
/* Plasma Seal message functions. */
|
||||
|
||||
int plasma_send_SealRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
unsigned char *digest);
|
||||
Status SendSealRequest(int sock, ObjectID object_id, unsigned char *digest);
|
||||
|
||||
void plasma_read_SealRequest(uint8_t *data,
|
||||
OUT ObjectID *object_id,
|
||||
OUT unsigned char *digest);
|
||||
Status ReadSealRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
unsigned char *digest);
|
||||
|
||||
int plasma_send_SealReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int error);
|
||||
Status SendSealReply(int sock, ObjectID object_id, int error);
|
||||
|
||||
void plasma_read_SealReply(uint8_t *data, ObjectID *object_id, int *error);
|
||||
Status ReadSealReply(uint8_t *data, ObjectID *object_id);
|
||||
|
||||
/* Plasma Get message functions. */
|
||||
|
||||
int plasma_send_GetRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects,
|
||||
int64_t timeout_ms);
|
||||
Status SendGetRequest(int sock,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects,
|
||||
int64_t timeout_ms);
|
||||
|
||||
int64_t plasma_read_GetRequest_num_objects(uint8_t *data);
|
||||
Status ReadGetRequest(uint8_t *data,
|
||||
std::vector<ObjectID> &object_ids,
|
||||
int64_t *timeout_ms);
|
||||
|
||||
void plasma_read_GetRequest(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int64_t *timeout_ms,
|
||||
int64_t num_objects);
|
||||
|
||||
int plasma_send_GetReply(
|
||||
Status SendGetReply(
|
||||
int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_ids[],
|
||||
std::unordered_map<ObjectID, PlasmaObject, UniqueIDHasher> &plasma_objects,
|
||||
int64_t num_objects);
|
||||
|
||||
void plasma_read_GetReply(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
PlasmaObject plasma_objects[],
|
||||
int64_t num_objects);
|
||||
Status ReadGetReply(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
PlasmaObject plasma_objects[],
|
||||
int64_t num_objects);
|
||||
|
||||
/* Plasma Release message functions. */
|
||||
|
||||
int plasma_send_ReleaseRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id);
|
||||
Status SendReleaseRequest(int sock, ObjectID object_id);
|
||||
|
||||
void plasma_read_ReleaseRequest(uint8_t *data, ObjectID *object_id);
|
||||
Status ReadReleaseRequest(uint8_t *data, ObjectID *object_id);
|
||||
|
||||
int plasma_send_ReleaseReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int error);
|
||||
Status SendReleaseReply(int sock, ObjectID object_id, int error);
|
||||
|
||||
void plasma_read_ReleaseReply(uint8_t *data, ObjectID *object_id, int *error);
|
||||
Status ReadReleaseReply(uint8_t *data, ObjectID *object_id);
|
||||
|
||||
/* Plasma Delete message functions. */
|
||||
|
||||
int plasma_send_DeleteRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id);
|
||||
Status SendDeleteRequest(int sock, ObjectID object_id);
|
||||
|
||||
void plasma_read_DeleteRequest(uint8_t *data, ObjectID *object_id);
|
||||
Status ReadDeleteRequest(uint8_t *data, ObjectID *object_id);
|
||||
|
||||
int plasma_send_DeleteReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int error);
|
||||
Status SendDeleteReply(int sock, ObjectID object_id, int error);
|
||||
|
||||
void plasma_read_DeleteReply(uint8_t *data, ObjectID *object_id, int *error);
|
||||
Status ReadDeleteReply(uint8_t *data, ObjectID *object_id);
|
||||
|
||||
/* Plasma Status message functions. */
|
||||
/* Satus messages. */
|
||||
|
||||
int plasma_send_StatusRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects);
|
||||
Status SendStatusRequest(int sock, ObjectID object_ids[], int64_t num_objects);
|
||||
|
||||
int64_t plasma_read_StatusRequest_num_objects(uint8_t *data);
|
||||
Status ReadStatusRequest(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects);
|
||||
|
||||
void plasma_read_StatusRequest(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects);
|
||||
Status SendStatusReply(int sock,
|
||||
ObjectID object_ids[],
|
||||
int object_status[],
|
||||
int64_t num_objects);
|
||||
|
||||
int plasma_send_StatusReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_ids[],
|
||||
int object_status[],
|
||||
int64_t num_objects);
|
||||
int64_t ReadStatusReply_num_objects(uint8_t *data);
|
||||
|
||||
int64_t plasma_read_StatusReply_num_objects(uint8_t *data);
|
||||
|
||||
void plasma_read_StatusReply(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int object_status[],
|
||||
int64_t num_objects);
|
||||
Status ReadStatusReply(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int object_status[],
|
||||
int64_t num_objects);
|
||||
|
||||
/* Plasma Constains message functions. */
|
||||
|
||||
int plasma_send_ContainsRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id);
|
||||
Status SendContainsRequest(int sock, ObjectID object_id);
|
||||
|
||||
void plasma_read_ContainsRequest(uint8_t *data, ObjectID *object_id);
|
||||
Status ReadContainsRequest(uint8_t *data, ObjectID *object_id);
|
||||
|
||||
int plasma_send_ContainsReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int has_object);
|
||||
Status SendContainsReply(int sock, ObjectID object_id, int has_object);
|
||||
|
||||
void plasma_read_ContainsReply(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
int *has_object);
|
||||
Status ReadContainsReply(uint8_t *data, ObjectID *object_id, int *has_object);
|
||||
|
||||
/* Plasma Connect message functions. */
|
||||
|
||||
int plasma_send_ConnectRequest(int sock, protocol_builder *B);
|
||||
Status SendConnectRequest(int sock);
|
||||
|
||||
void plasma_read_ConnectRequest(uint8_t *data);
|
||||
Status ReadConnectRequest(uint8_t *data);
|
||||
|
||||
int plasma_send_ConnectReply(int sock,
|
||||
protocol_builder *B,
|
||||
int64_t memory_capacity);
|
||||
Status SendConnectReply(int sock, int64_t memory_capacity);
|
||||
|
||||
void plasma_read_ConnectReply(uint8_t *data, int64_t *memory_capacity);
|
||||
Status ReadConnectReply(uint8_t *data, int64_t *memory_capacity);
|
||||
|
||||
/* Plasma Evict message functions (no reply so far). */
|
||||
|
||||
int plasma_send_EvictRequest(int sock, protocol_builder *B, int64_t num_bytes);
|
||||
Status SendEvictRequest(int sock, int64_t num_bytes);
|
||||
|
||||
void plasma_read_EvictRequest(uint8_t *data, int64_t *num_bytes);
|
||||
Status ReadEvictRequest(uint8_t *data, int64_t *num_bytes);
|
||||
|
||||
int plasma_send_EvictReply(int sock, protocol_builder *B, int64_t num_bytes);
|
||||
Status SendEvictReply(int sock, int64_t num_bytes);
|
||||
|
||||
void plasma_read_EvictReply(uint8_t *data, int64_t *num_bytes);
|
||||
Status ReadEvictReply(uint8_t *data, int64_t &num_bytes);
|
||||
|
||||
/* Plasma Fetch Remote message functions. */
|
||||
|
||||
int plasma_send_FetchRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects);
|
||||
Status SendFetchRequest(int sock, ObjectID object_ids[], int64_t num_objects);
|
||||
|
||||
int64_t plasma_read_FetchRequest_num_objects(uint8_t *data);
|
||||
|
||||
void plasma_read_FetchRequest(uint8_t *data,
|
||||
ObjectID object_ids[],
|
||||
int64_t num_objects);
|
||||
Status ReadFetchRequest(uint8_t *data, std::vector<ObjectID> &object_ids);
|
||||
|
||||
/* Plasma Wait message functions. */
|
||||
|
||||
int plasma_send_WaitRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectRequest object_requests[],
|
||||
int num_requests,
|
||||
int num_ready_objects,
|
||||
int64_t timeout_ms);
|
||||
Status SendWaitRequest(int sock,
|
||||
ObjectRequest object_requests[],
|
||||
int num_requests,
|
||||
int num_ready_objects,
|
||||
int64_t timeout_ms);
|
||||
|
||||
int plasma_read_WaitRequest_num_object_ids(uint8_t *data);
|
||||
Status ReadWaitRequest(uint8_t *data,
|
||||
ObjectRequestMap &object_requests,
|
||||
int64_t *timeout_ms,
|
||||
int *num_ready_objects);
|
||||
|
||||
void plasma_read_WaitRequest(uint8_t *data,
|
||||
ObjectRequestMap &object_requests,
|
||||
int num_object_ids,
|
||||
int64_t *timeout_ms,
|
||||
int *num_ready_objects);
|
||||
Status SendWaitReply(int sock,
|
||||
const ObjectRequestMap &object_requests,
|
||||
int num_ready_objects);
|
||||
|
||||
int plasma_send_WaitReply(int sock,
|
||||
protocol_builder *B,
|
||||
const ObjectRequestMap &object_requests,
|
||||
int num_ready_objects);
|
||||
|
||||
void plasma_read_WaitReply(uint8_t *data,
|
||||
ObjectRequest object_requests[],
|
||||
int *num_ready_objects);
|
||||
Status ReadWaitReply(uint8_t *data,
|
||||
ObjectRequest object_requests[],
|
||||
int *num_ready_objects);
|
||||
|
||||
/* Plasma Subscribe message functions. */
|
||||
|
||||
int plasma_send_SubscribeRequest(int sock, protocol_builder *B);
|
||||
Status SendSubscribeRequest(int sock);
|
||||
|
||||
/* Plasma Data message functions. */
|
||||
/* Data messages. */
|
||||
|
||||
int plasma_send_DataRequest(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
const char *address,
|
||||
int port);
|
||||
Status SendDataRequest(int sock,
|
||||
ObjectID object_id,
|
||||
const char *address,
|
||||
int port);
|
||||
|
||||
void plasma_read_DataRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
char **address,
|
||||
int *port);
|
||||
Status ReadDataRequest(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
char **address,
|
||||
int *port);
|
||||
|
||||
int plasma_send_DataReply(int sock,
|
||||
protocol_builder *B,
|
||||
ObjectID object_id,
|
||||
int64_t object_size,
|
||||
int64_t metadata_size);
|
||||
Status SendDataReply(int sock,
|
||||
ObjectID object_id,
|
||||
int64_t object_size,
|
||||
int64_t metadata_size);
|
||||
|
||||
void plasma_read_DataReply(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
int64_t *object_size,
|
||||
int64_t *metadata_size);
|
||||
Status ReadDataReply(uint8_t *data,
|
||||
ObjectID *object_id,
|
||||
int64_t *object_size,
|
||||
int64_t *metadata_size);
|
||||
|
||||
#endif /* PLASMA_PROTOCOL */
|
||||
|
||||
+232
-243
@@ -1,13 +1,13 @@
|
||||
/* PLASMA STORE: This is a simple object store server process
|
||||
*
|
||||
* It accepts incoming client connections on a unix domain socket
|
||||
* (name passed in via the -s option of the executable) and uses a
|
||||
* single thread to serve the clients. Each client establishes a
|
||||
* connection and can create objects, wait for objects and seal
|
||||
* objects through that connection.
|
||||
*
|
||||
* It keeps a hash table that maps object_ids (which are 20 byte long,
|
||||
* just enough to store and SHA1 hash) to memory mapped files. */
|
||||
// PLASMA STORE: This is a simple object store server process
|
||||
//
|
||||
// It accepts incoming client connections on a unix domain socket
|
||||
// (name passed in via the -s option of the executable) and uses a
|
||||
// single thread to serve the clients. Each client establishes a
|
||||
// connection and can create objects, wait for objects and seal
|
||||
// objects through that connection.
|
||||
//
|
||||
// It keeps a hash table that maps object_ids (which are 20 byte long,
|
||||
// just enough to store and SHA1 hash) to memory mapped files.
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
@@ -23,17 +23,16 @@
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <limits.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "plasma_common.h"
|
||||
#include "plasma_store.h"
|
||||
|
||||
#include "format/common_generated.h"
|
||||
#include "io.h"
|
||||
#include "plasma_io.h"
|
||||
#include "malloc.h"
|
||||
|
||||
extern "C" {
|
||||
@@ -47,20 +46,20 @@ size_t dlmalloc_set_footprint_limit(size_t bytes);
|
||||
struct GetRequest {
|
||||
GetRequest(Client *client, const std::vector<ObjectID> &object_ids);
|
||||
|
||||
/** The client that called get. */
|
||||
/// 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. */
|
||||
/// 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;
|
||||
/** The object IDs involved in this request. This is used in the reply. */
|
||||
/// The object IDs involved in this request. This is used in the reply.
|
||||
std::vector<ObjectID> object_ids;
|
||||
/** The object information for the objects in this request. This is used in
|
||||
* the reply. */
|
||||
/// The object information for the objects in this request. This is used in
|
||||
/// the reply.
|
||||
std::unordered_map<ObjectID, PlasmaObject, UniqueIDHasher> objects;
|
||||
/** The minimum number of objects to wait for in this request. */
|
||||
/// The minimum number of objects to wait for in this request.
|
||||
int64_t num_objects_to_wait_for;
|
||||
/** The number of object requests in this wait request that are already
|
||||
* satisfied. */
|
||||
/// The number of object requests in this wait request that are already
|
||||
/// satisfied.
|
||||
int64_t num_satisfied;
|
||||
};
|
||||
|
||||
@@ -78,9 +77,7 @@ GetRequest::GetRequest(Client *client, const std::vector<ObjectID> &object_ids)
|
||||
Client::Client(int fd) : fd(fd) {}
|
||||
|
||||
PlasmaStore::PlasmaStore(EventLoop *loop, int64_t system_memory)
|
||||
: loop_(loop),
|
||||
eviction_policy_(&store_info_),
|
||||
builder_(make_protocol_builder()) {
|
||||
: loop_(loop), eviction_policy_(&store_info_) {
|
||||
store_info_.memory_capacity = system_memory;
|
||||
}
|
||||
|
||||
@@ -93,61 +90,59 @@ PlasmaStore::~PlasmaStore() {
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
free_protocol_builder(builder_);
|
||||
}
|
||||
|
||||
/* If this client is not already using the object, add the client to the
|
||||
* object's list of clients, otherwise do nothing. */
|
||||
// If this client is not already using the object, add the client to the
|
||||
// object's list of clients, otherwise do nothing.
|
||||
void PlasmaStore::add_client_to_object_clients(ObjectTableEntry *entry,
|
||||
Client *client) {
|
||||
/* Check if this client is already using the object. */
|
||||
// Check if this client is already using the object.
|
||||
if (entry->clients.find(client) != entry->clients.end()) {
|
||||
return;
|
||||
}
|
||||
/* If there are no other clients using this object, notify the eviction policy
|
||||
* that the object is being used. */
|
||||
// If there are no other clients using this object, notify the eviction policy
|
||||
// that the object is being used.
|
||||
if (entry->clients.size() == 0) {
|
||||
/* Tell the eviction policy that this object is being used. */
|
||||
// Tell the eviction policy that this object is being used.
|
||||
std::vector<ObjectID> objects_to_evict;
|
||||
eviction_policy_.begin_object_access(entry->object_id, objects_to_evict);
|
||||
delete_objects(objects_to_evict);
|
||||
}
|
||||
/* Add the client pointer to the list of clients using this object. */
|
||||
// Add the client pointer to the list of clients using this object.
|
||||
entry->clients.insert(client);
|
||||
}
|
||||
|
||||
/* Create a new object buffer in the hash table. */
|
||||
// Create a new object buffer in the hash table.
|
||||
int PlasmaStore::create_object(ObjectID object_id,
|
||||
int64_t data_size,
|
||||
int64_t metadata_size,
|
||||
Client *client,
|
||||
PlasmaObject *result) {
|
||||
LOG_DEBUG("creating object"); /* TODO(pcm): add ObjectID here */
|
||||
ARROW_LOG(DEBUG) << "creating object " << object_id.hex();
|
||||
if (store_info_.objects.count(object_id) != 0) {
|
||||
/* There is already an object with the same ID in the Plasma Store, so
|
||||
* ignore this requst. */
|
||||
// There is already an object with the same ID in the Plasma Store, so
|
||||
// ignore this requst.
|
||||
return PlasmaError_ObjectExists;
|
||||
}
|
||||
/* Try to evict objects until there is enough space. */
|
||||
// Try to evict objects until there is enough space.
|
||||
uint8_t *pointer;
|
||||
do {
|
||||
/* Allocate space for the new object. We use dlmemalign instead of dlmalloc
|
||||
* in order to align the allocated region to a 64-byte boundary. This is not
|
||||
* strictly necessary, but it is an optimization that could speed up the
|
||||
* computation of a hash of the data (see compute_object_hash_parallel in
|
||||
* plasma_client.cc). Note that even though this pointer is 64-byte aligned,
|
||||
* it is not guaranteed that the corresponding pointer in the client will be
|
||||
* 64-byte aligned, but in practice it often will be. */
|
||||
// Allocate space for the new object. We use dlmemalign instead of dlmalloc
|
||||
// in order to align the allocated region to a 64-byte boundary. This is not
|
||||
// strictly necessary, but it is an optimization that could speed up the
|
||||
// computation of a hash of the data (see compute_object_hash_parallel in
|
||||
// plasma_client.cc). Note that even though this pointer is 64-byte aligned,
|
||||
// it is not guaranteed that the corresponding pointer in the client will be
|
||||
// 64-byte aligned, but in practice it often will be.
|
||||
pointer = (uint8_t *) dlmemalign(BLOCK_SIZE, data_size + metadata_size);
|
||||
if (pointer == NULL) {
|
||||
/* Tell the eviction policy how much space we need to create this object.
|
||||
*/
|
||||
// Tell the eviction policy how much space we need to create this object.
|
||||
std::vector<ObjectID> objects_to_evict;
|
||||
bool success = eviction_policy_.require_space(data_size + metadata_size,
|
||||
objects_to_evict);
|
||||
delete_objects(objects_to_evict);
|
||||
/* Return an error to the client if not enough space could be freed to
|
||||
* create the object. */
|
||||
// Return an error to the client if not enough space could be freed to
|
||||
// create the object.
|
||||
if (!success) {
|
||||
return PlasmaError_OutOfMemory;
|
||||
}
|
||||
@@ -161,12 +156,11 @@ int PlasmaStore::create_object(ObjectID object_id,
|
||||
|
||||
auto entry = std::unique_ptr<ObjectTableEntry>(new ObjectTableEntry());
|
||||
entry->object_id = object_id;
|
||||
entry->info.object_id =
|
||||
std::string((char *) &object_id.id[0], sizeof(object_id));
|
||||
entry->info.object_id = object_id.binary();
|
||||
entry->info.data_size = data_size;
|
||||
entry->info.metadata_size = metadata_size;
|
||||
entry->pointer = pointer;
|
||||
/* TODO(pcm): set the other fields */
|
||||
// TODO(pcm): Set the other fields.
|
||||
entry->fd = fd;
|
||||
entry->map_size = map_size;
|
||||
entry->offset = offset;
|
||||
@@ -179,11 +173,11 @@ int PlasmaStore::create_object(ObjectID object_id,
|
||||
result->metadata_offset = offset + data_size;
|
||||
result->data_size = data_size;
|
||||
result->metadata_size = metadata_size;
|
||||
/* Notify the eviction policy that this object was created. This must be done
|
||||
* immediately before the call to add_client_to_object_clients so that the
|
||||
* eviction policy does not have an opportunity to evict the object. */
|
||||
// Notify the eviction policy that this object was created. This must be done
|
||||
// immediately before the call to add_client_to_object_clients so that the
|
||||
// eviction policy does not have an opportunity to evict the object.
|
||||
eviction_policy_.object_created(object_id);
|
||||
/* Record that this client is using this object. */
|
||||
// Record that this client is using this object.
|
||||
add_client_to_object_clients(store_info_.objects[object_id].get(), client);
|
||||
return PlasmaError_OK;
|
||||
}
|
||||
@@ -201,30 +195,28 @@ void PlasmaObject_init(PlasmaObject *object, ObjectTableEntry *entry) {
|
||||
}
|
||||
|
||||
void PlasmaStore::return_from_get(GetRequest *get_req) {
|
||||
/* Send the get reply to the client. */
|
||||
int status = plasma_send_GetReply(get_req->client->fd, builder_,
|
||||
&get_req->object_ids[0], get_req->objects,
|
||||
get_req->object_ids.size());
|
||||
warn_if_sigpipe(status, get_req->client->fd);
|
||||
/* If we successfully sent the get reply message to the client, then also send
|
||||
* the file descriptors. */
|
||||
if (status >= 0) {
|
||||
/* Send all of the file descriptors for the present objects. */
|
||||
// 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());
|
||||
warn_if_sigpipe(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 (const auto &object_id : get_req->object_ids) {
|
||||
PlasmaObject &object = get_req->objects[object_id];
|
||||
/* We use the data size to indicate whether the object is present or not.
|
||||
*/
|
||||
// We use the data size to indicate whether the object is present or not.
|
||||
if (object.data_size != -1) {
|
||||
int error_code = send_fd(get_req->client->fd, object.handle.store_fd);
|
||||
/* If we failed to send the file descriptor, loop until we have sent it
|
||||
* successfully. TODO(rkn): This is problematic for two reasons. First
|
||||
* of all, sending the file descriptor should just succeed without any
|
||||
* errors, but sometimes I see a "Message too long" error number.
|
||||
* Second, looping like this allows a client to potentially block the
|
||||
* plasma store event loop which should never happen. */
|
||||
// If we failed to send the file descriptor, loop until we have sent it
|
||||
// successfully. TODO(rkn): This is problematic for two reasons. First
|
||||
// of all, sending the file descriptor should just succeed without any
|
||||
// errors, but sometimes I see a "Message too long" error number.
|
||||
// Second, looping like this allows a client to potentially block the
|
||||
// plasma store event loop which should never happen.
|
||||
while (error_code < 0) {
|
||||
if (errno == EMSGSIZE) {
|
||||
LOG_WARN("Failed to send file descriptor, retrying.");
|
||||
ARROW_LOG(WARNING) << "Failed to send file descriptor, retrying.";
|
||||
error_code = send_fd(get_req->client->fd, object.handle.store_fd);
|
||||
continue;
|
||||
}
|
||||
@@ -235,20 +227,20 @@ void PlasmaStore::return_from_get(GetRequest *get_req) {
|
||||
}
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
// 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.
|
||||
for (ObjectID &object_id : get_req->object_ids) {
|
||||
auto &get_requests = object_get_requests_[object_id];
|
||||
/* Erase get_req from the vector. */
|
||||
// Erase get_req from the vector.
|
||||
auto it = std::find(get_requests.begin(), get_requests.end(), get_req);
|
||||
if (it != get_requests.end()) {
|
||||
get_requests.erase(it);
|
||||
}
|
||||
}
|
||||
/* Remove the get request. */
|
||||
// Remove the get request.
|
||||
if (get_req->timer != -1) {
|
||||
CHECK(loop_->remove_timer(get_req->timer) == AE_OK);
|
||||
ARROW_CHECK(loop_->remove_timer(get_req->timer) == AE_OK);
|
||||
}
|
||||
delete get_req;
|
||||
}
|
||||
@@ -260,65 +252,65 @@ void PlasmaStore::update_object_get_requests(ObjectID object_id) {
|
||||
for (int i = 0; i < num_requests; ++i) {
|
||||
GetRequest *get_req = get_requests[index];
|
||||
auto entry = get_object_table_entry(&store_info_, object_id);
|
||||
CHECK(entry != NULL);
|
||||
ARROW_CHECK(entry != NULL);
|
||||
|
||||
PlasmaObject_init(&get_req->objects[object_id], entry);
|
||||
get_req->num_satisfied += 1;
|
||||
/* Record the fact that this client will be using this object and will
|
||||
* be responsible for releasing this object. */
|
||||
// Record the fact that this client will be using this object and will
|
||||
// be responsible for releasing this object.
|
||||
add_client_to_object_clients(entry, get_req->client);
|
||||
|
||||
/* If this get request is done, reply to the client. */
|
||||
// If this get request is done, reply to the client.
|
||||
if (get_req->num_satisfied == get_req->num_objects_to_wait_for) {
|
||||
return_from_get(get_req);
|
||||
} else {
|
||||
/* The call to return_from_get will remove the current element in the
|
||||
* array, so we only increment the counter in the else branch. */
|
||||
// The call to return_from_get will remove the current element in the
|
||||
// array, so we only increment the counter in the else branch.
|
||||
index += 1;
|
||||
}
|
||||
}
|
||||
|
||||
DCHECK(index == get_requests.size());
|
||||
/* Remove the array of get requests for this object, since no one should be
|
||||
* waiting for this object anymore. */
|
||||
// Remove the array of get requests for this object, since no one should be
|
||||
// waiting for this object anymore.
|
||||
object_get_requests_.erase(object_id);
|
||||
}
|
||||
|
||||
void PlasmaStore::process_get_request(Client *client,
|
||||
const std::vector<ObjectID> &object_ids,
|
||||
uint64_t timeout_ms) {
|
||||
/* Create a get request for this object. */
|
||||
// Create a get request for this object.
|
||||
GetRequest *get_req = new GetRequest(client, object_ids);
|
||||
|
||||
for (auto object_id : object_ids) {
|
||||
/* Check if this object is already present locally. If so, record that the
|
||||
* object is being used and mark it as accounted for. */
|
||||
// Check if this object is already present locally. If so, record that the
|
||||
// object is being used and mark it as accounted for.
|
||||
auto entry = get_object_table_entry(&store_info_, object_id);
|
||||
if (entry && entry->state == PLASMA_SEALED) {
|
||||
/* Update the get request to take into account the present object. */
|
||||
// Update the get request to take into account the present object.
|
||||
PlasmaObject_init(&get_req->objects[object_id], entry);
|
||||
get_req->num_satisfied += 1;
|
||||
/* If necessary, record that this client is using this object. In the case
|
||||
* where entry == NULL, this will be called from seal_object. */
|
||||
// If necessary, record that this client is using this object. In the case
|
||||
// where entry == NULL, this will be called from seal_object.
|
||||
add_client_to_object_clients(entry, client);
|
||||
} else {
|
||||
/* Add a placeholder plasma object to the get request to indicate that the
|
||||
* object is not present. This will be parsed by the client. We set the
|
||||
* data size to -1 to indicate that the object is not present. */
|
||||
// Add a placeholder plasma object to the get request to indicate that the
|
||||
// object is not present. This will be parsed by the client. We set the
|
||||
// data size to -1 to indicate that the object is not present.
|
||||
get_req->objects[object_id].data_size = -1;
|
||||
/* Add the get request to the relevant data structures. */
|
||||
// Add the get request to the relevant data structures.
|
||||
object_get_requests_[object_id].push_back(get_req);
|
||||
}
|
||||
}
|
||||
|
||||
/* If all of the objects are present already or if the timeout is 0, return to
|
||||
* the client. */
|
||||
// If all of the objects are present already or if the timeout is 0, return to
|
||||
// the client.
|
||||
if (get_req->num_satisfied == get_req->num_objects_to_wait_for ||
|
||||
timeout_ms == 0) {
|
||||
return_from_get(get_req);
|
||||
} 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. */
|
||||
// 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_->add_timer(timeout_ms, [this, get_req](int64_t timer_id) {
|
||||
return_from_get(get_req);
|
||||
@@ -332,166 +324,165 @@ int PlasmaStore::remove_client_from_object_clients(ObjectTableEntry *entry,
|
||||
auto it = entry->clients.find(client);
|
||||
if (it != entry->clients.end()) {
|
||||
entry->clients.erase(it);
|
||||
/* If no more clients are using this object, notify the eviction policy
|
||||
* that the object is no longer being used. */
|
||||
// If no more clients are using this object, notify the eviction policy
|
||||
// that the object is no longer being used.
|
||||
if (entry->clients.size() == 0) {
|
||||
/* Tell the eviction policy that this object is no longer being used. */
|
||||
// Tell the eviction policy that this object is no longer being used.
|
||||
std::vector<ObjectID> objects_to_evict;
|
||||
eviction_policy_.end_object_access(entry->object_id, objects_to_evict);
|
||||
delete_objects(objects_to_evict);
|
||||
}
|
||||
/* Return 1 to indicate that the client was removed. */
|
||||
// Return 1 to indicate that the client was removed.
|
||||
return 1;
|
||||
} else {
|
||||
/* Return 0 to indicate that the client was not removed. */
|
||||
// Return 0 to indicate that the client was not removed.
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PlasmaStore::release_object(ObjectID object_id, Client *client) {
|
||||
auto entry = get_object_table_entry(&store_info_, object_id);
|
||||
CHECK(entry != NULL);
|
||||
/* Remove the client from the object's array of clients. */
|
||||
CHECK(remove_client_from_object_clients(entry, client) == 1);
|
||||
ARROW_CHECK(entry != NULL);
|
||||
// Remove the client from the object's array of clients.
|
||||
ARROW_CHECK(remove_client_from_object_clients(entry, client) == 1);
|
||||
}
|
||||
|
||||
/* Check if an object is present. */
|
||||
// Check if an object is present.
|
||||
int PlasmaStore::contains_object(ObjectID object_id) {
|
||||
auto entry = get_object_table_entry(&store_info_, object_id);
|
||||
return entry && (entry->state == PLASMA_SEALED) ? OBJECT_FOUND
|
||||
: OBJECT_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Seal an object that has been created in the hash table. */
|
||||
// Seal an object that has been created in the hash table.
|
||||
void PlasmaStore::seal_object(ObjectID object_id, unsigned char digest[]) {
|
||||
LOG_DEBUG("sealing object"); // TODO(pcm): add ObjectID here
|
||||
ARROW_LOG(DEBUG) << "sealing object " << object_id.hex();
|
||||
auto entry = get_object_table_entry(&store_info_, object_id);
|
||||
CHECK(entry != NULL);
|
||||
CHECK(entry->state == PLASMA_CREATED);
|
||||
/* Set the state of object to SEALED. */
|
||||
ARROW_CHECK(entry != NULL);
|
||||
ARROW_CHECK(entry->state == PLASMA_CREATED);
|
||||
// Set the state of object to SEALED.
|
||||
entry->state = PLASMA_SEALED;
|
||||
/* Set the object digest. */
|
||||
entry->info.digest = std::string((char *) &digest[0], DIGEST_SIZE);
|
||||
/* Inform all subscribers that a new object has been sealed. */
|
||||
// Set the object digest.
|
||||
entry->info.digest = std::string((char *) &digest[0], kDigestSize);
|
||||
// Inform all subscribers that a new object has been sealed.
|
||||
push_notification(&entry->info);
|
||||
|
||||
/* Update all get requests that involve this object. */
|
||||
// Update all get requests that involve this object.
|
||||
update_object_get_requests(object_id);
|
||||
}
|
||||
|
||||
void PlasmaStore::delete_objects(const std::vector<ObjectID> &object_ids) {
|
||||
for (const auto &object_id : object_ids) {
|
||||
LOG_DEBUG("deleting object");
|
||||
ARROW_LOG(DEBUG) << "deleting object " << object_id.hex();
|
||||
auto entry = get_object_table_entry(&store_info_, object_id);
|
||||
/* TODO(rkn): This should probably not fail, but should instead throw an
|
||||
* error. Maybe we should also support deleting objects that have been
|
||||
* created but not sealed. */
|
||||
CHECKM(entry != NULL,
|
||||
"To delete an object it must be in the object table.");
|
||||
CHECKM(entry->state == PLASMA_SEALED,
|
||||
"To delete an object it must have been sealed.");
|
||||
CHECKM(entry->clients.size() == 0,
|
||||
"To delete an object, there must be no clients currently using it.");
|
||||
// TODO(rkn): This should probably not fail, but should instead throw an
|
||||
// error. Maybe we should also support deleting objects that have been
|
||||
// created but not sealed.
|
||||
ARROW_CHECK(entry != NULL)
|
||||
<< "To delete an object it must be in the object table.";
|
||||
ARROW_CHECK(entry->state == PLASMA_SEALED)
|
||||
<< "To delete an object it must have been sealed.";
|
||||
ARROW_CHECK(entry->clients.size() == 0)
|
||||
<< "To delete an object, there must be no clients currently using it.";
|
||||
dlfree(entry->pointer);
|
||||
store_info_.objects.erase(object_id);
|
||||
/* Inform all subscribers that the object has been deleted. */
|
||||
// Inform all subscribers that the object has been deleted.
|
||||
ObjectInfoT notification;
|
||||
notification.object_id =
|
||||
std::string((char *) &object_id.id[0], sizeof(object_id));
|
||||
notification.object_id = object_id.binary();
|
||||
notification.is_deletion = true;
|
||||
push_notification(¬ification);
|
||||
}
|
||||
}
|
||||
|
||||
void PlasmaStore::connect_client(int listener_sock) {
|
||||
int client_fd = accept_client(listener_sock);
|
||||
/* This is freed in disconnect_client. */
|
||||
int client_fd = AcceptClient(listener_sock);
|
||||
// This is freed in disconnect_client.
|
||||
Client *client = new Client(client_fd);
|
||||
/* Add a callback to handle events on this socket.
|
||||
* TODO(pcm): Check return value. */
|
||||
// Add a callback to handle events on this socket.
|
||||
// TODO(pcm): Check return value.
|
||||
loop_->add_file_event(client_fd, kEventLoopRead, [this, client](int events) {
|
||||
process_message(client);
|
||||
});
|
||||
LOG_DEBUG("New connection with fd %d", client_fd);
|
||||
ARROW_LOG(DEBUG) << "New connection with fd " << client_fd;
|
||||
}
|
||||
|
||||
void PlasmaStore::disconnect_client(Client *client) {
|
||||
loop_->remove_file_event(client->fd);
|
||||
/* If this client was using any objects, remove it from the appropriate
|
||||
* lists. */
|
||||
// If this client was using any objects, remove it from the appropriate
|
||||
// lists.
|
||||
for (const auto &entry : store_info_.objects) {
|
||||
remove_client_from_object_clients(entry.second.get(), client);
|
||||
}
|
||||
/* Note, the store may still attempt to send a message to the disconnected
|
||||
* client (for example, when an object ID that the client was waiting for
|
||||
* is ready). In these cases, the attempt to send the message will fail, but
|
||||
* the store should just ignore the failure. */
|
||||
// Note, the store may still attempt to send a message to the disconnected
|
||||
// client (for example, when an object ID that the client was waiting for
|
||||
// is ready). In these cases, the attempt to send the message will fail, but
|
||||
// the store should just ignore the failure.
|
||||
delete client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send notifications about sealed objects to the subscribers. This is called
|
||||
* in seal_object. 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.
|
||||
*
|
||||
* @param client The client to send the notification to.
|
||||
* @return Void.
|
||||
*/
|
||||
/// Send notifications about sealed objects to the subscribers. This is called
|
||||
/// in seal_object. 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.
|
||||
///
|
||||
/// @param client The client to send the notification to.
|
||||
/// @return Void.
|
||||
void PlasmaStore::send_notifications(int client_fd) {
|
||||
auto it = pending_notifications_.find(client_fd);
|
||||
|
||||
int num_processed = 0;
|
||||
bool closed = false;
|
||||
/* Loop over the array of pending notifications and send as many of them as
|
||||
* possible. */
|
||||
// Loop over the array of pending notifications and send as many of them as
|
||||
// possible.
|
||||
for (int i = 0; i < it->second.object_notifications.size(); ++i) {
|
||||
uint8_t *notification = (uint8_t *) it->second.object_notifications.at(i);
|
||||
/* Decode the length, which is the first bytes of the message. */
|
||||
// Decode the length, which is the first bytes of the message.
|
||||
int64_t size = *((int64_t *) notification);
|
||||
|
||||
/* Attempt to send a notification about this object ID. */
|
||||
// Attempt to send a notification about this object ID.
|
||||
int nbytes = send(client_fd, notification, sizeof(int64_t) + size, 0);
|
||||
if (nbytes >= 0) {
|
||||
CHECK(nbytes == sizeof(int64_t) + size);
|
||||
ARROW_CHECK(nbytes == sizeof(int64_t) + size);
|
||||
} else if (nbytes == -1 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR)) {
|
||||
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.*/
|
||||
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_->add_file_event(
|
||||
client_fd, kEventLoopWrite,
|
||||
[this, client_fd](int events) { send_notifications(client_fd); });
|
||||
break;
|
||||
} else {
|
||||
LOG_WARN("Failed to send notification to client on fd %d", client_fd);
|
||||
ARROW_LOG(WARNING) << "Failed to send notification to client on fd "
|
||||
<< client_fd;
|
||||
if (errno == EPIPE) {
|
||||
closed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
num_processed += 1;
|
||||
/* The corresponding malloc happened in create_object_info_buffer
|
||||
* within push_notification. */
|
||||
// The corresponding malloc happened in create_object_info_buffer
|
||||
// within push_notification.
|
||||
free(notification);
|
||||
}
|
||||
/* Remove the sent notifications from the array. */
|
||||
// Remove the sent notifications from the array.
|
||||
it->second.object_notifications.erase(
|
||||
it->second.object_notifications.begin(),
|
||||
it->second.object_notifications.begin() + num_processed);
|
||||
|
||||
/* Stop sending notifications if the pipe was broken. */
|
||||
// Stop sending notifications if the pipe was broken.
|
||||
if (closed) {
|
||||
close(client_fd);
|
||||
pending_notifications_.erase(client_fd);
|
||||
}
|
||||
|
||||
/* If we have sent all notifications, remove the fd from the event loop. */
|
||||
// If we have sent all notifications, remove the fd from the event loop.
|
||||
if (it->second.object_notifications.empty()) {
|
||||
loop_->remove_file_event(client_fd);
|
||||
}
|
||||
@@ -502,121 +493,114 @@ void PlasmaStore::push_notification(ObjectInfoT *object_info) {
|
||||
uint8_t *notification = create_object_info_buffer(object_info);
|
||||
element.second.object_notifications.push_back(notification);
|
||||
send_notifications(element.first);
|
||||
/* The notification gets freed in send_notifications when the notification
|
||||
* is sent over the socket. */
|
||||
// The notification gets freed in send_notifications when the notification
|
||||
// is sent over the socket.
|
||||
}
|
||||
}
|
||||
|
||||
/* Subscribe to notifications about sealed objects. */
|
||||
// Subscribe to notifications about sealed objects.
|
||||
void PlasmaStore::subscribe_to_updates(Client *client) {
|
||||
LOG_DEBUG("subscribing to updates");
|
||||
/* TODO(rkn): The store could block here if the client doesn't send a file
|
||||
* descriptor. */
|
||||
ARROW_LOG(DEBUG) << "subscribing to updates on fd " << client->fd;
|
||||
// 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. */
|
||||
LOG_WARN("Failed to receive file descriptor from client on fd %d.",
|
||||
client->fd);
|
||||
// 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 << ".";
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create a new array to buffer notifications that can't be sent to the
|
||||
* subscriber yet because the socket send buffer is full. TODO(rkn): the queue
|
||||
* never gets freed. */
|
||||
// Create a new array to buffer notifications that can't be sent to the
|
||||
// subscriber yet because the socket send buffer is full. TODO(rkn): the queue
|
||||
// never gets freed.
|
||||
NotificationQueue &queue = pending_notifications_[fd];
|
||||
|
||||
/* Push notifications to the new subscriber about existing objects. */
|
||||
// Push notifications to the new subscriber about existing objects.
|
||||
for (const auto &entry : store_info_.objects) {
|
||||
push_notification(&entry.second->info);
|
||||
}
|
||||
send_notifications(fd);
|
||||
}
|
||||
|
||||
void PlasmaStore::process_message(Client *client) {
|
||||
Status PlasmaStore::process_message(Client *client) {
|
||||
int64_t type;
|
||||
read_vector(client->fd, &type, input_buffer_);
|
||||
Status s = ReadMessage(client->fd, &type, input_buffer_);
|
||||
ARROW_CHECK(s.ok() || s.IsIOError());
|
||||
|
||||
uint8_t *input = input_buffer_.data();
|
||||
ObjectID object_id;
|
||||
PlasmaObject object;
|
||||
/* TODO(pcm): Get rid of the following. */
|
||||
// TODO(pcm): Get rid of the following.
|
||||
memset(&object, 0, sizeof(object));
|
||||
|
||||
/* Process the different types of requests. */
|
||||
// Process the different types of requests.
|
||||
switch (type) {
|
||||
case MessageType_PlasmaCreateRequest: {
|
||||
int64_t data_size;
|
||||
int64_t metadata_size;
|
||||
plasma_read_CreateRequest(input, &object_id, &data_size, &metadata_size);
|
||||
RETURN_NOT_OK(
|
||||
ReadCreateRequest(input, &object_id, &data_size, &metadata_size));
|
||||
int error_code =
|
||||
create_object(object_id, data_size, metadata_size, client, &object);
|
||||
warn_if_sigpipe(plasma_send_CreateReply(client->fd, builder_, object_id,
|
||||
&object, error_code),
|
||||
client->fd);
|
||||
HANDLE_SIGPIPE(SendCreateReply(client->fd, object_id, &object, error_code),
|
||||
client->fd);
|
||||
if (error_code == PlasmaError_OK) {
|
||||
warn_if_sigpipe(send_fd(client->fd, object.handle.store_fd), client->fd);
|
||||
}
|
||||
} break;
|
||||
case MessageType_PlasmaGetRequest: {
|
||||
int num_objects = plasma_read_GetRequest_num_objects(input);
|
||||
std::vector<ObjectID> object_ids_to_get(num_objects);
|
||||
std::vector<ObjectID> object_ids_to_get;
|
||||
int64_t timeout_ms;
|
||||
plasma_read_GetRequest(input, object_ids_to_get.data(), &timeout_ms,
|
||||
num_objects);
|
||||
RETURN_NOT_OK(ReadGetRequest(input, object_ids_to_get, &timeout_ms));
|
||||
process_get_request(client, object_ids_to_get, timeout_ms);
|
||||
} break;
|
||||
case MessageType_PlasmaReleaseRequest:
|
||||
plasma_read_ReleaseRequest(input, &object_id);
|
||||
RETURN_NOT_OK(ReadReleaseRequest(input, &object_id));
|
||||
release_object(object_id, client);
|
||||
break;
|
||||
case MessageType_PlasmaContainsRequest:
|
||||
plasma_read_ContainsRequest(input, &object_id);
|
||||
RETURN_NOT_OK(ReadContainsRequest(input, &object_id));
|
||||
if (contains_object(object_id) == OBJECT_FOUND) {
|
||||
warn_if_sigpipe(
|
||||
plasma_send_ContainsReply(client->fd, builder_, object_id, 1),
|
||||
client->fd);
|
||||
HANDLE_SIGPIPE(SendContainsReply(client->fd, object_id, 1), client->fd);
|
||||
} else {
|
||||
warn_if_sigpipe(
|
||||
plasma_send_ContainsReply(client->fd, builder_, object_id, 0),
|
||||
client->fd);
|
||||
HANDLE_SIGPIPE(SendContainsReply(client->fd, object_id, 0), client->fd);
|
||||
}
|
||||
break;
|
||||
case MessageType_PlasmaSealRequest: {
|
||||
unsigned char digest[DIGEST_SIZE];
|
||||
plasma_read_SealRequest(input, &object_id, &digest[0]);
|
||||
unsigned char digest[kDigestSize];
|
||||
RETURN_NOT_OK(ReadSealRequest(input, &object_id, &digest[0]));
|
||||
seal_object(object_id, &digest[0]);
|
||||
} break;
|
||||
case MessageType_PlasmaEvictRequest: {
|
||||
/* This code path should only be used for testing. */
|
||||
// This code path should only be used for testing.
|
||||
int64_t num_bytes;
|
||||
plasma_read_EvictRequest(input, &num_bytes);
|
||||
RETURN_NOT_OK(ReadEvictRequest(input, &num_bytes));
|
||||
std::vector<ObjectID> objects_to_evict;
|
||||
int64_t num_bytes_evicted =
|
||||
eviction_policy_.choose_objects_to_evict(num_bytes, objects_to_evict);
|
||||
delete_objects(objects_to_evict);
|
||||
warn_if_sigpipe(
|
||||
plasma_send_EvictReply(client->fd, builder_, num_bytes_evicted),
|
||||
client->fd);
|
||||
HANDLE_SIGPIPE(SendEvictReply(client->fd, num_bytes_evicted), client->fd);
|
||||
} break;
|
||||
case MessageType_PlasmaSubscribeRequest:
|
||||
subscribe_to_updates(client);
|
||||
break;
|
||||
case MessageType_PlasmaConnectRequest: {
|
||||
warn_if_sigpipe(plasma_send_ConnectReply(client->fd, builder_,
|
||||
store_info_.memory_capacity),
|
||||
client->fd);
|
||||
HANDLE_SIGPIPE(SendConnectReply(client->fd, store_info_.memory_capacity),
|
||||
client->fd);
|
||||
} break;
|
||||
case DISCONNECT_CLIENT:
|
||||
LOG_INFO("Disconnecting client on fd %d", client->fd);
|
||||
ARROW_LOG(DEBUG) << "Disconnecting client on fd " << client->fd;
|
||||
disconnect_client(client);
|
||||
break;
|
||||
default:
|
||||
/* This code should be unreachable. */
|
||||
CHECK(0);
|
||||
// This code should be unreachable.
|
||||
ARROW_CHECK(0);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/* Report "success" to valgrind. */
|
||||
// Report "success" to valgrind.
|
||||
void signal_handler(int signal) {
|
||||
if (signal == SIGTERM) {
|
||||
exit(0);
|
||||
@@ -624,15 +608,15 @@ void signal_handler(int signal) {
|
||||
}
|
||||
|
||||
void start_server(char *socket_name, int64_t system_memory) {
|
||||
/* 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. */
|
||||
// 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);
|
||||
/* Create the event loop. */
|
||||
// Create the event loop.
|
||||
EventLoop loop;
|
||||
PlasmaStore store(&loop, system_memory);
|
||||
int socket = bind_ipc_sock(socket_name, true);
|
||||
CHECK(socket >= 0);
|
||||
/* TODO(pcm): Check return value. */
|
||||
ARROW_CHECK(socket >= 0);
|
||||
// TODO(pcm): Check return value.
|
||||
loop.add_file_event(socket, kEventLoopRead, [&store, socket](int events) {
|
||||
store.connect_client(socket);
|
||||
});
|
||||
@@ -652,9 +636,10 @@ int main(int argc, char *argv[]) {
|
||||
case 'm': {
|
||||
char extra;
|
||||
int scanned = sscanf(optarg, "%" SCNd64 "%c", &system_memory, &extra);
|
||||
CHECK(scanned == 1);
|
||||
LOG_INFO("Allowing the Plasma store to use up to %.2fGB of memory.",
|
||||
((double) system_memory) / 1000000000);
|
||||
ARROW_CHECK(scanned == 1);
|
||||
ARROW_LOG(INFO) << "Allowing the Plasma store to use up to "
|
||||
<< ((double) system_memory) / 1000000000
|
||||
<< "GB of memory.";
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -662,34 +647,38 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
if (!socket_name) {
|
||||
LOG_FATAL("please specify socket for incoming connections with -s switch");
|
||||
ARROW_LOG(FATAL)
|
||||
<< "please specify socket for incoming connections with -s switch";
|
||||
}
|
||||
if (system_memory == -1) {
|
||||
LOG_FATAL("please specify the amount of system memory with -m switch");
|
||||
ARROW_LOG(FATAL)
|
||||
<< "please specify the amount of system memory with -m switch";
|
||||
}
|
||||
#ifdef __linux__
|
||||
/* On Linux, check that the amount of memory available in /dev/shm is large
|
||||
* enough to accommodate the request. If it isn't, then fail. */
|
||||
// On Linux, check that the amount of memory available in /dev/shm is large
|
||||
// enough to accommodate the request. If it isn't, then fail.
|
||||
int shm_fd = open("/dev/shm", O_RDONLY);
|
||||
struct statvfs shm_vfs_stats;
|
||||
fstatvfs(shm_fd, &shm_vfs_stats);
|
||||
/* The value shm_vfs_stats.f_bsize is the block size, and the value
|
||||
* shm_vfs_stats.f_bavail is the number of available blocks. */
|
||||
// The value shm_vfs_stats.f_bsize is the block size, and the value
|
||||
// shm_vfs_stats.f_bavail is the number of available blocks.
|
||||
int64_t shm_mem_avail = shm_vfs_stats.f_bsize * shm_vfs_stats.f_bavail;
|
||||
close(shm_fd);
|
||||
if (system_memory > shm_mem_avail) {
|
||||
LOG_FATAL(
|
||||
"System memory request exceeds memory available in /dev/shm. The "
|
||||
"request is for %" PRId64 " bytes, and the amount available is %" PRId64
|
||||
" bytes. You may be able to free up space by deleting files in "
|
||||
"/dev/shm. If you are inside a Docker container, you may need to pass "
|
||||
"an argument with the flag '--shm-size' to 'docker run'.",
|
||||
system_memory, shm_mem_avail);
|
||||
ARROW_LOG(FATAL)
|
||||
<< "System memory request exceeds memory available in /dev/shm. The "
|
||||
"request is for "
|
||||
<< system_memory << " bytes, and the amount available is "
|
||||
<< shm_mem_avail
|
||||
<< " bytes. You may be able to free up space by deleting files in "
|
||||
"/dev/shm. If you are inside a Docker container, you may need to "
|
||||
"pass "
|
||||
"an argument with the flag '--shm-size' to 'docker run'.";
|
||||
}
|
||||
#endif
|
||||
/* Make it so dlmalloc fails if we try to request more memory than is
|
||||
* available. */
|
||||
// Make it so dlmalloc fails if we try to request more memory than is
|
||||
// available.
|
||||
dlmalloc_set_footprint_limit((size_t) system_memory);
|
||||
LOG_DEBUG("starting server listening on %s", socket_name);
|
||||
ARROW_LOG(DEBUG) << "starting server listening on " << socket_name;
|
||||
start_server(socket_name, system_memory);
|
||||
}
|
||||
|
||||
+80
-98
@@ -1,25 +1,25 @@
|
||||
#ifndef PLASMA_STORE_H
|
||||
#define PLASMA_STORE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "eviction_policy.h"
|
||||
#include "plasma.h"
|
||||
#include "plasma_common.h"
|
||||
#include "plasma_events.h"
|
||||
#include "plasma_protocol.h"
|
||||
|
||||
class 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. */
|
||||
/// The object notifications for clients. We notify the client about the
|
||||
/// objects in the order that the objects were sealed or deleted.
|
||||
std::deque<uint8_t *> object_notifications;
|
||||
};
|
||||
|
||||
/** Contains all information that is associated with a Plasma store client. */
|
||||
/// Contains all information that is associated with a Plasma store client.
|
||||
struct Client {
|
||||
Client(int fd);
|
||||
|
||||
/** The file descriptor used to communicate with the client. */
|
||||
/// The file descriptor used to communicate with the client.
|
||||
int fd;
|
||||
};
|
||||
|
||||
@@ -29,109 +29,93 @@ class PlasmaStore {
|
||||
|
||||
~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.
|
||||
* @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
|
||||
* plasma_release.
|
||||
* - PlasmaError_OutOfMemory, if the store is out of memory and cannot
|
||||
* create the object. In this case, the client should not call
|
||||
* plasma_release.
|
||||
*/
|
||||
/// 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.
|
||||
/// @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
|
||||
/// plasma_release.
|
||||
/// - PlasmaError_OutOfMemory, if the store is out of memory and
|
||||
/// cannot create the object. In this case, the client should not call
|
||||
/// plasma_release.
|
||||
int create_object(ObjectID object_id,
|
||||
int64_t data_size,
|
||||
int64_t metadata_size,
|
||||
Client *client,
|
||||
PlasmaObject *result);
|
||||
|
||||
/**
|
||||
* Delete objects that have been created in the hash table. This should only
|
||||
* be called on objects that are returned by the eviction policy to evict.
|
||||
*
|
||||
* @param object_ids Object IDs of the objects to be deleted.
|
||||
* @return Void.
|
||||
*/
|
||||
/// Delete objects that have been created in the hash table. This should only
|
||||
/// be called on objects that are returned by the eviction policy to evict.
|
||||
///
|
||||
/// @param object_ids Object IDs of the objects to be deleted.
|
||||
/// @return Void.
|
||||
void delete_objects(const std::vector<ObjectID> &object_ids);
|
||||
|
||||
/**
|
||||
* Process a get request from a client. This method assumes that we will
|
||||
* eventually have these objects sealed. If one of the objects has not yet
|
||||
* been sealed, the client that requested the object will be notified when it
|
||||
* is sealed.
|
||||
*
|
||||
* 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.
|
||||
* @return Void.
|
||||
*/
|
||||
/// Process a get request from a client. This method assumes that we will
|
||||
/// eventually have these objects sealed. If one of the objects has not yet
|
||||
/// been sealed, the client that requested the object will be notified when it
|
||||
/// is sealed.
|
||||
///
|
||||
/// 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.
|
||||
/// @return Void.
|
||||
void process_get_request(Client *client,
|
||||
const std::vector<ObjectID> &object_ids,
|
||||
uint64_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 objects
|
||||
* with the same object ID are the same.
|
||||
* @return Void.
|
||||
*/
|
||||
/// 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
|
||||
/// objects
|
||||
/// with the same object ID are the same.
|
||||
/// @return Void.
|
||||
void seal_object(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 not
|
||||
*/
|
||||
/// 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
|
||||
/// not
|
||||
int contains_object(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.
|
||||
* @param Void.
|
||||
*/
|
||||
/// 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.
|
||||
/// @param Void.
|
||||
void release_object(ObjectID object_id, Client *client);
|
||||
|
||||
/**
|
||||
* Subscribe a file descriptor to updates about new sealed objects.
|
||||
*
|
||||
* @param client The client making this request.
|
||||
* @return Void.
|
||||
*/
|
||||
/// Subscribe a file descriptor to updates about new sealed objects.
|
||||
///
|
||||
/// @param client The client making this request.
|
||||
/// @return Void.
|
||||
void subscribe_to_updates(Client *client);
|
||||
|
||||
/**
|
||||
* Connect a new client to the PlasmaStore.
|
||||
*
|
||||
* @param listener_sock The socket that is listening to incoming connections.
|
||||
* @return Void.
|
||||
*/
|
||||
/// Connect a new client to the PlasmaStore.
|
||||
///
|
||||
/// @param listener_sock The socket that is listening to incoming connections.
|
||||
/// @return Void.
|
||||
void connect_client(int listener_sock);
|
||||
|
||||
/**
|
||||
* Disconnect a client from the PlasmaStore.
|
||||
*
|
||||
* @param client The client that is disconnected.
|
||||
* @return Void.
|
||||
*/
|
||||
/// Disconnect a client from the PlasmaStore.
|
||||
///
|
||||
/// @param client The client that is disconnected.
|
||||
/// @return Void.
|
||||
void disconnect_client(Client *client);
|
||||
|
||||
void send_notifications(int client_fd);
|
||||
|
||||
void process_message(Client *client);
|
||||
Status process_message(Client *client);
|
||||
|
||||
private:
|
||||
void push_notification(ObjectInfoT *object_notification);
|
||||
@@ -145,28 +129,26 @@ class PlasmaStore {
|
||||
int remove_client_from_object_clients(ObjectTableEntry *entry,
|
||||
Client *client);
|
||||
|
||||
/* Event loop of the plasma store. */
|
||||
/// Event loop of the plasma store.
|
||||
EventLoop *loop_;
|
||||
/** The plasma store information, including the object tables, that is exposed
|
||||
* to the eviction policy. */
|
||||
/// 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. */
|
||||
/// 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. */
|
||||
/// Input buffer. This is allocated only once to avoid mallocs for every
|
||||
/// call to process_message.
|
||||
std::vector<uint8_t> input_buffer_;
|
||||
/** Buffer that holds memory for serializing plasma protocol messages. */
|
||||
protocol_builder *builder_;
|
||||
/** A hash table mapping object IDs to a vector of the get requests that are
|
||||
* waiting for the object to arrive. */
|
||||
/// A hash table mapping object IDs to a vector of the get requests that are
|
||||
/// waiting for the object to arrive.
|
||||
std::unordered_map<ObjectID, std::vector<GetRequest *>, UniqueIDHasher>
|
||||
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. */
|
||||
/// 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.
|
||||
std::unordered_map<int, NotificationQueue> pending_notifications_;
|
||||
};
|
||||
|
||||
#endif /* PLASMA_STORE_H */
|
||||
#endif // PLASMA_STORE_H
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
//
|
||||
// A Status encapsulates the result of an operation. It may indicate success,
|
||||
// or it may indicate an error with an associated error message.
|
||||
//
|
||||
// Multiple threads can invoke const methods on a Status without
|
||||
// external synchronization, but if any of the threads may call a
|
||||
// non-const method, all threads accessing the same Status must use
|
||||
// external synchronization.
|
||||
|
||||
#include "status.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace arrow {
|
||||
|
||||
Status::Status(StatusCode code, const std::string &msg, int16_t posix_code) {
|
||||
assert(code != StatusCode::OK);
|
||||
const uint32_t size = static_cast<uint32_t>(msg.size());
|
||||
char *result = new char[size + 7];
|
||||
memcpy(result, &size, sizeof(size));
|
||||
result[4] = static_cast<char>(code);
|
||||
memcpy(result + 5, &posix_code, sizeof(posix_code));
|
||||
memcpy(result + 7, msg.c_str(), msg.size());
|
||||
state_ = result;
|
||||
}
|
||||
|
||||
const char *Status::CopyState(const char *state) {
|
||||
uint32_t size;
|
||||
memcpy(&size, state, sizeof(size));
|
||||
char *result = new char[size + 7];
|
||||
memcpy(result, state, size + 7);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Status::CodeAsString() const {
|
||||
if (state_ == NULL) {
|
||||
return "OK";
|
||||
}
|
||||
|
||||
const char *type;
|
||||
switch (code()) {
|
||||
case StatusCode::OK:
|
||||
type = "OK";
|
||||
break;
|
||||
case StatusCode::OutOfMemory:
|
||||
type = "Out of memory";
|
||||
break;
|
||||
case StatusCode::KeyError:
|
||||
type = "Key error";
|
||||
break;
|
||||
case StatusCode::TypeError:
|
||||
type = "Type error";
|
||||
break;
|
||||
case StatusCode::Invalid:
|
||||
type = "Invalid";
|
||||
break;
|
||||
case StatusCode::IOError:
|
||||
type = "IOError";
|
||||
break;
|
||||
case StatusCode::UnknownError:
|
||||
type = "Unknown error";
|
||||
break;
|
||||
case StatusCode::NotImplemented:
|
||||
type = "NotImplemented";
|
||||
break;
|
||||
default:
|
||||
type = "Unknown";
|
||||
break;
|
||||
}
|
||||
return std::string(type);
|
||||
}
|
||||
|
||||
std::string Status::ToString() const {
|
||||
std::string result(CodeAsString());
|
||||
if (state_ == NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result.append(": ");
|
||||
|
||||
uint32_t length;
|
||||
memcpy(&length, state_, sizeof(length));
|
||||
result.append(reinterpret_cast<const char *>(state_ + 7), length);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace arrow
|
||||
@@ -0,0 +1,226 @@
|
||||
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
//
|
||||
// A Status encapsulates the result of an operation. It may indicate success,
|
||||
// or it may indicate an error with an associated error message.
|
||||
//
|
||||
// Multiple threads can invoke const methods on a Status without
|
||||
// external synchronization, but if any of the threads may call a
|
||||
// non-const method, all threads accessing the same Status must use
|
||||
// external synchronization.
|
||||
|
||||
// Adapted from Kudu github.com/cloudera/kudu
|
||||
|
||||
#ifndef ARROW_STATUS_H_
|
||||
#define ARROW_STATUS_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
// Return the given status if it is not OK.
|
||||
#define ARROW_RETURN_NOT_OK(s) \
|
||||
do { \
|
||||
::arrow::Status _s = (s); \
|
||||
if (!_s.ok()) { \
|
||||
return _s; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
// Return the given status if it is not OK, but first clone it and
|
||||
// prepend the given message.
|
||||
#define ARROW_RETURN_NOT_OK_PREPEND(s, msg) \
|
||||
do { \
|
||||
::arrow::Status _s = (s); \
|
||||
if (::gutil::PREDICT_FALSE(!_s.ok())) \
|
||||
return _s.CloneAndPrepend(msg); \
|
||||
} while (0);
|
||||
|
||||
// Return 'to_return' if 'to_call' returns a bad status.
|
||||
// The substitution for 'to_return' may reference the variable
|
||||
// 's' for the bad status.
|
||||
#define ARROW_RETURN_NOT_OK_RET(to_call, to_return) \
|
||||
do { \
|
||||
::arrow::Status s = (to_call); \
|
||||
if (::gutil::PREDICT_FALSE(!s.ok())) \
|
||||
return (to_return); \
|
||||
} while (0);
|
||||
|
||||
// If 'to_call' returns a bad status, CHECK immediately with a logged message
|
||||
// of 'msg' followed by the status.
|
||||
#define ARROW_CHECK_OK_PREPEND(to_call, msg) \
|
||||
do { \
|
||||
::arrow::Status _s = (to_call); \
|
||||
ARROW_CHECK(_s.ok()) << (msg) << ": " << _s.ToString(); \
|
||||
} while (0);
|
||||
|
||||
// If the status is bad, CHECK immediately, appending the status to the
|
||||
// logged message.
|
||||
#define ARROW_CHECK_OK(s) ARROW_CHECK_OK_PREPEND(s, "Bad status")
|
||||
|
||||
namespace arrow {
|
||||
|
||||
#define RETURN_NOT_OK(s) \
|
||||
do { \
|
||||
Status _s = (s); \
|
||||
if (!_s.ok()) { \
|
||||
return _s; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define RETURN_NOT_OK_ELSE(s, else_) \
|
||||
do { \
|
||||
Status _s = (s); \
|
||||
if (!_s.ok()) { \
|
||||
else_; \
|
||||
return _s; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
enum class StatusCode : char {
|
||||
OK = 0,
|
||||
OutOfMemory = 1,
|
||||
KeyError = 2,
|
||||
TypeError = 3,
|
||||
Invalid = 4,
|
||||
IOError = 5,
|
||||
UnknownError = 9,
|
||||
NotImplemented = 10,
|
||||
PlasmaObjectExists = 20,
|
||||
PlasmaObjectNonexistent = 21,
|
||||
PlasmaStoreFull = 22
|
||||
};
|
||||
|
||||
class Status {
|
||||
public:
|
||||
// Create a success status.
|
||||
Status() : state_(NULL) {}
|
||||
~Status() { delete[] state_; }
|
||||
|
||||
Status(StatusCode code, const std::string &msg) : Status(code, msg, -1) {}
|
||||
|
||||
// Copy the specified status.
|
||||
Status(const Status &s);
|
||||
void operator=(const Status &s);
|
||||
|
||||
// Return a success status.
|
||||
static Status OK() { return Status(); }
|
||||
|
||||
// Return error status of an appropriate type.
|
||||
static Status OutOfMemory(const std::string &msg, int16_t posix_code = -1) {
|
||||
return Status(StatusCode::OutOfMemory, msg, posix_code);
|
||||
}
|
||||
|
||||
static Status KeyError(const std::string &msg) {
|
||||
return Status(StatusCode::KeyError, msg, -1);
|
||||
}
|
||||
|
||||
static Status TypeError(const std::string &msg) {
|
||||
return Status(StatusCode::TypeError, msg, -1);
|
||||
}
|
||||
|
||||
static Status UnknownError(const std::string &msg) {
|
||||
return Status(StatusCode::UnknownError, msg, -1);
|
||||
}
|
||||
|
||||
static Status NotImplemented(const std::string &msg) {
|
||||
return Status(StatusCode::NotImplemented, msg, -1);
|
||||
}
|
||||
|
||||
static Status Invalid(const std::string &msg) {
|
||||
return Status(StatusCode::Invalid, msg, -1);
|
||||
}
|
||||
|
||||
static Status IOError(const std::string &msg) {
|
||||
return Status(StatusCode::IOError, msg, -1);
|
||||
}
|
||||
|
||||
static Status PlasmaObjectExists(const std::string &msg) {
|
||||
return Status(StatusCode::PlasmaObjectExists, msg, -1);
|
||||
}
|
||||
|
||||
static Status PlasmaObjectNonexistent(const std::string &msg) {
|
||||
return Status(StatusCode::PlasmaObjectNonexistent, msg, -1);
|
||||
}
|
||||
|
||||
static Status PlasmaStoreFull(const std::string &msg) {
|
||||
return Status(StatusCode::PlasmaStoreFull, msg, -1);
|
||||
}
|
||||
|
||||
// Returns true iff the status indicates success.
|
||||
bool ok() const { return (state_ == NULL); }
|
||||
|
||||
bool IsOutOfMemory() const { return code() == StatusCode::OutOfMemory; }
|
||||
bool IsKeyError() const { return code() == StatusCode::KeyError; }
|
||||
bool IsInvalid() const { return code() == StatusCode::Invalid; }
|
||||
bool IsIOError() const { return code() == StatusCode::IOError; }
|
||||
bool IsTypeError() const { return code() == StatusCode::TypeError; }
|
||||
bool IsUnknownError() const { return code() == StatusCode::UnknownError; }
|
||||
bool IsNotImplemented() const { return code() == StatusCode::NotImplemented; }
|
||||
// An object with this object ID already exists in the plasma store.
|
||||
bool IsPlasmaObjectExists() const {
|
||||
return code() == StatusCode::PlasmaObjectExists;
|
||||
}
|
||||
// An object was requested that doesn't exist in the plasma store.
|
||||
bool IsPlasmaObjectNonexistent() const {
|
||||
return code() == StatusCode::PlasmaObjectNonexistent;
|
||||
}
|
||||
// An object is too large to fit into the plasma store.
|
||||
bool IsPlasmaStoreFull() const {
|
||||
return code() == StatusCode::PlasmaStoreFull;
|
||||
}
|
||||
|
||||
// Return a string representation of this status suitable for printing.
|
||||
// Returns the string "OK" for success.
|
||||
std::string ToString() const;
|
||||
|
||||
// Return a string representation of the status code, without the message
|
||||
// text or posix code information.
|
||||
std::string CodeAsString() const;
|
||||
|
||||
// Get the POSIX code associated with this Status, or -1 if there is none.
|
||||
int16_t posix_code() const;
|
||||
|
||||
StatusCode code() const {
|
||||
return ((state_ == NULL) ? StatusCode::OK
|
||||
: static_cast<StatusCode>(state_[4]));
|
||||
}
|
||||
|
||||
std::string message() const {
|
||||
uint32_t length;
|
||||
memcpy(&length, state_, sizeof(length));
|
||||
std::string msg;
|
||||
msg.append((state_ + 7), length);
|
||||
return msg;
|
||||
}
|
||||
|
||||
private:
|
||||
// OK status has a NULL state_. Otherwise, state_ is a new[] array
|
||||
// of the following form:
|
||||
// state_[0..3] == length of message
|
||||
// state_[4] == code
|
||||
// state_[5..6] == posix_code
|
||||
// state_[7..] == message
|
||||
const char *state_;
|
||||
|
||||
Status(StatusCode code, const std::string &msg, int16_t posix_code);
|
||||
static const char *CopyState(const char *s);
|
||||
};
|
||||
|
||||
inline Status::Status(const Status &s) {
|
||||
state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);
|
||||
}
|
||||
|
||||
inline void Status::operator=(const Status &s) {
|
||||
// The following condition catches both aliasing (when this == &s),
|
||||
// and the common case where both s and *this are ok.
|
||||
if (state_ != s.state_) {
|
||||
delete[] state_;
|
||||
state_ = (s.state_ == NULL) ? NULL : CopyState(s.state_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace arrow
|
||||
|
||||
#endif // ARROW_STATUS_H_
|
||||
+111
-91
@@ -4,6 +4,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "plasma_common.h"
|
||||
#include "plasma.h"
|
||||
#include "plasma_protocol.h"
|
||||
#include "plasma_client.h"
|
||||
@@ -11,14 +12,17 @@
|
||||
SUITE(plasma_client_tests);
|
||||
|
||||
TEST plasma_status_tests(void) {
|
||||
PlasmaConnection *plasma_conn1 = plasma_connect(
|
||||
"/tmp/store1", "/tmp/manager1", PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
PlasmaConnection *plasma_conn2 = plasma_connect(
|
||||
"/tmp/store2", "/tmp/manager2", PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
ObjectID oid1 = globally_unique_id();
|
||||
PlasmaClient client1;
|
||||
ARROW_CHECK_OK(client1.Connect("/tmp/store1", "/tmp/manager1",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
PlasmaClient client2;
|
||||
ARROW_CHECK_OK(client2.Connect("/tmp/store2", "/tmp/manager2",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
ObjectID oid1 = ObjectID::from_random();
|
||||
|
||||
/* Test for object non-existence. */
|
||||
int status = plasma_status(plasma_conn1, oid1);
|
||||
int status;
|
||||
ARROW_CHECK_OK(client1.Info(oid1, &status));
|
||||
ASSERT(status == ObjectStatus_Nonexistent);
|
||||
|
||||
/* Test for the object being in local Plasma store. */
|
||||
@@ -27,36 +31,39 @@ TEST plasma_status_tests(void) {
|
||||
uint8_t metadata[] = {5};
|
||||
int64_t metadata_size = sizeof(metadata);
|
||||
uint8_t *data;
|
||||
plasma_create(plasma_conn1, oid1, data_size, metadata, metadata_size, &data);
|
||||
plasma_seal(plasma_conn1, oid1);
|
||||
ARROW_CHECK_OK(
|
||||
client1.Create(oid1, data_size, metadata, metadata_size, &data));
|
||||
ARROW_CHECK_OK(client1.Seal(oid1));
|
||||
/* Sleep to avoid race condition of Plasma Manager waiting for notification.
|
||||
*/
|
||||
sleep(1);
|
||||
status = plasma_status(plasma_conn1, oid1);
|
||||
ARROW_CHECK_OK(client1.Info(oid1, &status));
|
||||
ASSERT(status == ObjectStatus_Local);
|
||||
|
||||
/* Test for object being remote. */
|
||||
status = plasma_status(plasma_conn2, oid1);
|
||||
ARROW_CHECK_OK(client2.Info(oid1, &status));
|
||||
ASSERT(status == ObjectStatus_Remote);
|
||||
|
||||
plasma_disconnect(plasma_conn1);
|
||||
plasma_disconnect(plasma_conn2);
|
||||
ARROW_CHECK_OK(client1.Disconnect());
|
||||
ARROW_CHECK_OK(client2.Disconnect());
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_fetch_tests(void) {
|
||||
PlasmaConnection *plasma_conn1 = plasma_connect(
|
||||
"/tmp/store1", "/tmp/manager1", PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
PlasmaConnection *plasma_conn2 = plasma_connect(
|
||||
"/tmp/store2", "/tmp/manager2", PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
ObjectID oid1 = globally_unique_id();
|
||||
PlasmaClient client1;
|
||||
ARROW_CHECK_OK(client1.Connect("/tmp/store1", "/tmp/manager1",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
PlasmaClient client2;
|
||||
ARROW_CHECK_OK(client2.Connect("/tmp/store2", "/tmp/manager2",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
ObjectID oid1 = ObjectID::from_random();
|
||||
|
||||
/* Test for object non-existence. */
|
||||
int status;
|
||||
|
||||
/* No object in the system */
|
||||
status = plasma_status(plasma_conn1, oid1);
|
||||
ARROW_CHECK_OK(client1.Info(oid1, &status));
|
||||
ASSERT(status == ObjectStatus_Nonexistent);
|
||||
|
||||
/* Test for the object being in local Plasma store. */
|
||||
@@ -65,37 +72,38 @@ TEST plasma_fetch_tests(void) {
|
||||
uint8_t metadata[] = {5};
|
||||
int64_t metadata_size = sizeof(metadata);
|
||||
uint8_t *data;
|
||||
plasma_create(plasma_conn1, oid1, data_size, metadata, metadata_size, &data);
|
||||
plasma_seal(plasma_conn1, oid1);
|
||||
ARROW_CHECK_OK(
|
||||
client1.Create(oid1, data_size, metadata, metadata_size, &data));
|
||||
ARROW_CHECK_OK(client1.Seal(oid1));
|
||||
|
||||
/* Object with ID oid1 has been just inserted. On the next fetch we might
|
||||
* either find the object or not, depending on whether the Plasma Manager has
|
||||
* received the notification from the Plasma Store or not. */
|
||||
ObjectID oid_array1[1] = {oid1};
|
||||
plasma_fetch(plasma_conn1, 1, oid_array1);
|
||||
status = plasma_status(plasma_conn1, oid1);
|
||||
ARROW_CHECK_OK(client1.Fetch(1, oid_array1));
|
||||
ARROW_CHECK_OK(client1.Info(oid1, &status));
|
||||
ASSERT((status == ObjectStatus_Local) ||
|
||||
(status == ObjectStatus_Nonexistent));
|
||||
|
||||
/* Sleep to make sure Plasma Manager got the notification. */
|
||||
sleep(1);
|
||||
status = plasma_status(plasma_conn1, oid1);
|
||||
ARROW_CHECK_OK(client1.Info(oid1, &status));
|
||||
ASSERT(status == ObjectStatus_Local);
|
||||
|
||||
/* Test for object being remote. */
|
||||
status = plasma_status(plasma_conn2, oid1);
|
||||
ARROW_CHECK_OK(client2.Info(oid1, &status));
|
||||
ASSERT(status == ObjectStatus_Remote);
|
||||
|
||||
/* Sleep to make sure the object has been fetched and it is now stored in the
|
||||
* local Plasma Store. */
|
||||
plasma_fetch(plasma_conn2, 1, oid_array1);
|
||||
ARROW_CHECK_OK(client2.Fetch(1, oid_array1));
|
||||
sleep(1);
|
||||
status = plasma_status(plasma_conn2, oid1);
|
||||
ARROW_CHECK_OK(client2.Info(oid1, &status));
|
||||
ASSERT(status == ObjectStatus_Local);
|
||||
|
||||
sleep(1);
|
||||
plasma_disconnect(plasma_conn1);
|
||||
plasma_disconnect(plasma_conn2);
|
||||
ARROW_CHECK_OK(client1.Disconnect());
|
||||
ARROW_CHECK_OK(client2.Disconnect());
|
||||
|
||||
PASS();
|
||||
}
|
||||
@@ -116,14 +124,15 @@ bool is_equal_data_123(uint8_t *data1, uint8_t *data2, uint64_t size) {
|
||||
}
|
||||
|
||||
TEST plasma_nonblocking_get_tests(void) {
|
||||
PlasmaConnection *plasma_conn = plasma_connect("/tmp/store1", "/tmp/manager1",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
ObjectID oid = globally_unique_id();
|
||||
PlasmaClient client;
|
||||
ARROW_CHECK_OK(client.Connect("/tmp/store1", "/tmp/manager1",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
ObjectID oid = ObjectID::from_random();
|
||||
ObjectID oid_array[1] = {oid};
|
||||
ObjectBuffer obj_buffer;
|
||||
|
||||
/* Test for object non-existence. */
|
||||
plasma_get(plasma_conn, oid_array, 1, 0, &obj_buffer);
|
||||
ARROW_CHECK_OK(client.Get(oid_array, 1, 0, &obj_buffer));
|
||||
ASSERT(obj_buffer.data_size == -1);
|
||||
|
||||
/* Test for the object being in local Plasma store. */
|
||||
@@ -132,27 +141,29 @@ TEST plasma_nonblocking_get_tests(void) {
|
||||
uint8_t metadata[] = {5};
|
||||
int64_t metadata_size = sizeof(metadata);
|
||||
uint8_t *data;
|
||||
plasma_create(plasma_conn, oid, data_size, metadata, metadata_size, &data);
|
||||
ARROW_CHECK_OK(client.Create(oid, data_size, metadata, metadata_size, &data));
|
||||
init_data_123(data, data_size, 0);
|
||||
plasma_seal(plasma_conn, oid);
|
||||
ARROW_CHECK_OK(client.Seal(oid));
|
||||
|
||||
sleep(1);
|
||||
plasma_get(plasma_conn, oid_array, 1, 0, &obj_buffer);
|
||||
ARROW_CHECK_OK(client.Get(oid_array, 1, 0, &obj_buffer));
|
||||
ASSERT(is_equal_data_123(data, obj_buffer.data, data_size) == true);
|
||||
|
||||
sleep(1);
|
||||
plasma_disconnect(plasma_conn);
|
||||
ARROW_CHECK_OK(client.Disconnect());
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_wait_for_objects_tests(void) {
|
||||
PlasmaConnection *plasma_conn1 = plasma_connect(
|
||||
"/tmp/store1", "/tmp/manager1", PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
PlasmaConnection *plasma_conn2 = plasma_connect(
|
||||
"/tmp/store2", "/tmp/manager2", PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
ObjectID oid1 = globally_unique_id();
|
||||
ObjectID oid2 = globally_unique_id();
|
||||
PlasmaClient client1;
|
||||
ARROW_CHECK_OK(client1.Connect("/tmp/store1", "/tmp/manager1",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
PlasmaClient client2;
|
||||
ARROW_CHECK_OK(client2.Connect("/tmp/store2", "/tmp/manager2",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
ObjectID oid1 = ObjectID::from_random();
|
||||
ObjectID oid2 = ObjectID::from_random();
|
||||
#define NUM_OBJ_REQUEST 2
|
||||
#define WAIT_TIMEOUT_MS 1000
|
||||
ObjectRequest obj_requests[NUM_OBJ_REQUEST];
|
||||
@@ -164,8 +175,9 @@ TEST plasma_wait_for_objects_tests(void) {
|
||||
|
||||
struct timeval start, end;
|
||||
gettimeofday(&start, NULL);
|
||||
int n = plasma_wait(plasma_conn1, NUM_OBJ_REQUEST, obj_requests,
|
||||
NUM_OBJ_REQUEST, WAIT_TIMEOUT_MS);
|
||||
int n;
|
||||
ARROW_CHECK_OK(client1.Wait(NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS, n));
|
||||
ASSERT(n == 0);
|
||||
gettimeofday(&end, NULL);
|
||||
float diff_ms = (end.tv_sec - start.tv_sec);
|
||||
@@ -178,48 +190,51 @@ TEST plasma_wait_for_objects_tests(void) {
|
||||
uint8_t metadata[] = {5};
|
||||
int64_t metadata_size = sizeof(metadata);
|
||||
uint8_t *data;
|
||||
plasma_create(plasma_conn1, oid1, data_size, metadata, metadata_size, &data);
|
||||
plasma_seal(plasma_conn1, oid1);
|
||||
ARROW_CHECK_OK(
|
||||
client1.Create(oid1, data_size, metadata, metadata_size, &data));
|
||||
ARROW_CHECK_OK(client1.Seal(oid1));
|
||||
|
||||
n = plasma_wait(plasma_conn1, NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS);
|
||||
ARROW_CHECK_OK(client1.Wait(NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS, n));
|
||||
ASSERT(n == 1);
|
||||
|
||||
/* Create and insert an object in plasma_conn2. */
|
||||
plasma_create(plasma_conn2, oid2, data_size, metadata, metadata_size, &data);
|
||||
plasma_seal(plasma_conn2, oid2);
|
||||
/* Create and insert an object in client2. */
|
||||
ARROW_CHECK_OK(
|
||||
client2.Create(oid2, data_size, metadata, metadata_size, &data));
|
||||
ARROW_CHECK_OK(client2.Seal(oid2));
|
||||
|
||||
n = plasma_wait(plasma_conn1, NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS);
|
||||
ARROW_CHECK_OK(client1.Wait(NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS, n));
|
||||
ASSERT(n == 2);
|
||||
|
||||
n = plasma_wait(plasma_conn2, NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS);
|
||||
ARROW_CHECK_OK(client2.Wait(NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS, n));
|
||||
ASSERT(n == 2);
|
||||
|
||||
obj_requests[0].type = PLASMA_QUERY_LOCAL;
|
||||
obj_requests[1].type = PLASMA_QUERY_LOCAL;
|
||||
n = plasma_wait(plasma_conn1, NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS);
|
||||
ARROW_CHECK_OK(client1.Wait(NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS, n));
|
||||
ASSERT(n == 1);
|
||||
|
||||
n = plasma_wait(plasma_conn2, NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS);
|
||||
ARROW_CHECK_OK(client2.Wait(NUM_OBJ_REQUEST, obj_requests, NUM_OBJ_REQUEST,
|
||||
WAIT_TIMEOUT_MS, n));
|
||||
ASSERT(n == 1);
|
||||
|
||||
plasma_disconnect(plasma_conn1);
|
||||
plasma_disconnect(plasma_conn2);
|
||||
ARROW_CHECK_OK(client1.Disconnect());
|
||||
ARROW_CHECK_OK(client2.Disconnect());
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_get_tests(void) {
|
||||
PlasmaConnection *plasma_conn1 = plasma_connect(
|
||||
"/tmp/store1", "/tmp/manager1", PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
PlasmaConnection *plasma_conn2 = plasma_connect(
|
||||
"/tmp/store2", "/tmp/manager2", PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
ObjectID oid1 = globally_unique_id();
|
||||
ObjectID oid2 = globally_unique_id();
|
||||
PlasmaClient client1, client2;
|
||||
ARROW_CHECK_OK(client1.Connect("/tmp/store1", "/tmp/manager1",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
ARROW_CHECK_OK(client2.Connect("/tmp/store2", "/tmp/manager2",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
ObjectID oid1 = ObjectID::from_random();
|
||||
ObjectID oid2 = ObjectID::from_random();
|
||||
ObjectBuffer obj_buffer;
|
||||
|
||||
ObjectID oid_array1[1] = {oid1};
|
||||
@@ -229,35 +244,38 @@ TEST plasma_get_tests(void) {
|
||||
uint8_t metadata[] = {5};
|
||||
int64_t metadata_size = sizeof(metadata);
|
||||
uint8_t *data;
|
||||
plasma_create(plasma_conn1, oid1, data_size, metadata, metadata_size, &data);
|
||||
ARROW_CHECK_OK(
|
||||
client1.Create(oid1, data_size, metadata, metadata_size, &data));
|
||||
init_data_123(data, data_size, 1);
|
||||
plasma_seal(plasma_conn1, oid1);
|
||||
ARROW_CHECK_OK(client1.Seal(oid1));
|
||||
|
||||
plasma_get(plasma_conn1, oid_array1, 1, -1, &obj_buffer);
|
||||
ARROW_CHECK_OK(client1.Get(oid_array1, 1, -1, &obj_buffer));
|
||||
ASSERT(data[0] == obj_buffer.data[0]);
|
||||
|
||||
plasma_create(plasma_conn2, oid2, data_size, metadata, metadata_size, &data);
|
||||
ARROW_CHECK_OK(
|
||||
client2.Create(oid2, data_size, metadata, metadata_size, &data));
|
||||
init_data_123(data, data_size, 2);
|
||||
plasma_seal(plasma_conn2, oid2);
|
||||
ARROW_CHECK_OK(client2.Seal(oid2));
|
||||
|
||||
plasma_fetch(plasma_conn1, 1, oid_array2);
|
||||
plasma_get(plasma_conn1, oid_array2, 1, -1, &obj_buffer);
|
||||
ARROW_CHECK_OK(client1.Fetch(1, oid_array2));
|
||||
ARROW_CHECK_OK(client1.Get(oid_array2, 1, -1, &obj_buffer));
|
||||
ASSERT(data[0] == obj_buffer.data[0]);
|
||||
|
||||
sleep(1);
|
||||
plasma_disconnect(plasma_conn1);
|
||||
plasma_disconnect(plasma_conn2);
|
||||
ARROW_CHECK_OK(client1.Disconnect());
|
||||
ARROW_CHECK_OK(client2.Disconnect());
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_get_multiple_tests(void) {
|
||||
PlasmaConnection *plasma_conn1 = plasma_connect(
|
||||
"/tmp/store1", "/tmp/manager1", PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
PlasmaConnection *plasma_conn2 = plasma_connect(
|
||||
"/tmp/store2", "/tmp/manager2", PLASMA_DEFAULT_RELEASE_DELAY);
|
||||
ObjectID oid1 = globally_unique_id();
|
||||
ObjectID oid2 = globally_unique_id();
|
||||
PlasmaClient client1, client2;
|
||||
ARROW_CHECK_OK(client1.Connect("/tmp/store1", "/tmp/manager1",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
ARROW_CHECK_OK(client2.Connect("/tmp/store2", "/tmp/manager2",
|
||||
PLASMA_DEFAULT_RELEASE_DELAY));
|
||||
ObjectID oid1 = ObjectID::from_random();
|
||||
ObjectID oid2 = ObjectID::from_random();
|
||||
ObjectID obj_ids[NUM_OBJ_REQUEST];
|
||||
ObjectBuffer obj_buffer[NUM_OBJ_REQUEST];
|
||||
int obj1_first = 1, obj2_first = 2;
|
||||
@@ -269,26 +287,28 @@ TEST plasma_get_multiple_tests(void) {
|
||||
uint8_t metadata[] = {5};
|
||||
int64_t metadata_size = sizeof(metadata);
|
||||
uint8_t *data;
|
||||
plasma_create(plasma_conn1, oid1, data_size, metadata, metadata_size, &data);
|
||||
ARROW_CHECK_OK(
|
||||
client1.Create(oid1, data_size, metadata, metadata_size, &data));
|
||||
init_data_123(data, data_size, obj1_first);
|
||||
plasma_seal(plasma_conn1, oid1);
|
||||
ARROW_CHECK_OK(client1.Seal(oid1));
|
||||
|
||||
/* This only waits for oid1. */
|
||||
plasma_get(plasma_conn1, obj_ids, 1, -1, obj_buffer);
|
||||
ARROW_CHECK_OK(client1.Get(obj_ids, 1, -1, obj_buffer));
|
||||
ASSERT(data[0] == obj_buffer[0].data[0]);
|
||||
|
||||
plasma_create(plasma_conn2, oid2, data_size, metadata, metadata_size, &data);
|
||||
ARROW_CHECK_OK(
|
||||
client2.Create(oid2, data_size, metadata, metadata_size, &data));
|
||||
init_data_123(data, data_size, obj2_first);
|
||||
plasma_seal(plasma_conn2, oid2);
|
||||
ARROW_CHECK_OK(client2.Seal(oid2));
|
||||
|
||||
plasma_fetch(plasma_conn1, 2, obj_ids);
|
||||
plasma_get(plasma_conn1, obj_ids, 2, -1, obj_buffer);
|
||||
ARROW_CHECK_OK(client1.Fetch(2, obj_ids));
|
||||
ARROW_CHECK_OK(client1.Get(obj_ids, 2, -1, obj_buffer));
|
||||
ASSERT(obj1_first == obj_buffer[0].data[0]);
|
||||
ASSERT(obj2_first == obj_buffer[1].data[0]);
|
||||
|
||||
sleep(1);
|
||||
plasma_disconnect(plasma_conn1);
|
||||
plasma_disconnect(plasma_conn2);
|
||||
ARROW_CHECK_OK(client1.Disconnect());
|
||||
ARROW_CHECK_OK(client2.Disconnect());
|
||||
|
||||
PASS();
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ typedef struct {
|
||||
ClientConnection *read_conn;
|
||||
/* Connect a new client to the local plasma manager and mock a request to an
|
||||
* object. */
|
||||
PlasmaConnection *plasma_conn;
|
||||
PlasmaClient *plasma_client;
|
||||
ClientConnection *client_conn;
|
||||
} plasma_mock;
|
||||
|
||||
@@ -85,8 +85,9 @@ plasma_mock *init_plasma_mock(plasma_mock *remote_mock) {
|
||||
}
|
||||
/* Connect a new client to the local plasma manager and mock a request to an
|
||||
* object. */
|
||||
mock->plasma_conn = plasma_connect(plasma_store_socket_name,
|
||||
utstring_body(manager_socket_name), 0);
|
||||
mock->plasma_client = new PlasmaClient();
|
||||
ARROW_CHECK_OK(mock->plasma_client->Connect(
|
||||
plasma_store_socket_name, utstring_body(manager_socket_name), 0));
|
||||
wait_for_pollin(mock->manager_local_fd);
|
||||
mock->client_conn = ClientConnection_listen(
|
||||
mock->loop, mock->manager_local_fd, mock->state, 0);
|
||||
@@ -96,7 +97,8 @@ plasma_mock *init_plasma_mock(plasma_mock *remote_mock) {
|
||||
|
||||
void destroy_plasma_mock(plasma_mock *mock) {
|
||||
PlasmaManagerState_free(mock->state);
|
||||
plasma_disconnect(mock->plasma_conn);
|
||||
ARROW_CHECK_OK(mock->plasma_client->Disconnect());
|
||||
delete mock->plasma_client;
|
||||
close(mock->local_store);
|
||||
close(mock->manager_local_fd);
|
||||
close(mock->manager_remote_fd);
|
||||
@@ -127,17 +129,18 @@ TEST request_transfer_test(void) {
|
||||
local_mock->state);
|
||||
event_loop_run(local_mock->loop);
|
||||
int read_fd = get_client_sock(remote_mock->read_conn);
|
||||
uint8_t *request_data =
|
||||
plasma_receive(read_fd, MessageType_PlasmaDataRequest);
|
||||
std::vector<uint8_t> request_data;
|
||||
ARROW_CHECK_OK(
|
||||
PlasmaReceive(read_fd, MessageType_PlasmaDataRequest, request_data));
|
||||
ObjectID object_id2;
|
||||
char *address;
|
||||
int port;
|
||||
plasma_read_DataRequest(request_data, &object_id2, &address, &port);
|
||||
ARROW_CHECK_OK(
|
||||
ReadDataRequest(request_data.data(), &object_id2, &address, &port));
|
||||
ASSERT(ObjectID_equal(object_id, object_id2));
|
||||
free(address);
|
||||
/* Clean up. */
|
||||
utstring_free(addr);
|
||||
free(request_data);
|
||||
destroy_plasma_mock(remote_mock);
|
||||
destroy_plasma_mock(local_mock);
|
||||
PASS();
|
||||
@@ -180,18 +183,19 @@ TEST request_transfer_retry_test(void) {
|
||||
event_loop_run(local_mock->loop);
|
||||
|
||||
int read_fd = get_client_sock(remote_mock2->read_conn);
|
||||
uint8_t *request_data =
|
||||
plasma_receive(read_fd, MessageType_PlasmaDataRequest);
|
||||
std::vector<uint8_t> request_data;
|
||||
ARROW_CHECK_OK(
|
||||
PlasmaReceive(read_fd, MessageType_PlasmaDataRequest, request_data));
|
||||
ObjectID object_id2;
|
||||
char *address;
|
||||
int port;
|
||||
plasma_read_DataRequest(request_data, &object_id2, &address, &port);
|
||||
ARROW_CHECK_OK(
|
||||
ReadDataRequest(request_data.data(), &object_id2, &address, &port));
|
||||
free(address);
|
||||
ASSERT(ObjectID_equal(object_id, object_id2));
|
||||
/* Clean up. */
|
||||
utstring_free(addr0);
|
||||
utstring_free(addr1);
|
||||
free(request_data);
|
||||
destroy_plasma_mock(remote_mock2);
|
||||
destroy_plasma_mock(remote_mock1);
|
||||
destroy_plasma_mock(local_mock);
|
||||
|
||||
@@ -3,16 +3,13 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "plasma_common.h"
|
||||
#include "plasma.h"
|
||||
#include "plasma_io.h"
|
||||
#include "plasma_protocol.h"
|
||||
#include "common.h"
|
||||
#include "io.h"
|
||||
#include "../plasma.h"
|
||||
|
||||
SUITE(plasma_serialization_tests);
|
||||
|
||||
protocol_builder *g_B;
|
||||
|
||||
/**
|
||||
* Create a temporary file. Needs to be closed by the caller.
|
||||
*
|
||||
@@ -34,14 +31,13 @@ int create_temp_file(void) {
|
||||
* @return Pointer to the content of the message. Needs to be freed by the
|
||||
* caller.
|
||||
*/
|
||||
uint8_t *read_message_from_file(int fd, int message_type) {
|
||||
std::vector<uint8_t> read_message_from_file(int fd, int message_type) {
|
||||
/* Go to the beginning of the file. */
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
int64_t type;
|
||||
int64_t length;
|
||||
uint8_t *data;
|
||||
read_message(fd, &type, &length, &data);
|
||||
CHECK(type == message_type);
|
||||
std::vector<uint8_t> data;
|
||||
ARROW_CHECK_OK(ReadMessage(fd, &type, data));
|
||||
ARROW_CHECK(type == message_type);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -60,70 +56,68 @@ PlasmaObject random_plasma_object(void) {
|
||||
|
||||
TEST plasma_create_request_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_id1 = globally_unique_id();
|
||||
ObjectID object_id1 = ObjectID::from_random();
|
||||
int64_t data_size1 = 42;
|
||||
int64_t metadata_size1 = 11;
|
||||
plasma_send_CreateRequest(fd, g_B, object_id1, data_size1, metadata_size1);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaCreateRequest);
|
||||
ARROW_CHECK_OK(SendCreateRequest(fd, object_id1, data_size1, metadata_size1));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaCreateRequest);
|
||||
ObjectID object_id2;
|
||||
int64_t data_size2;
|
||||
int64_t metadata_size2;
|
||||
plasma_read_CreateRequest(data, &object_id2, &data_size2, &metadata_size2);
|
||||
ARROW_CHECK_OK(ReadCreateRequest(data.data(), &object_id2, &data_size2,
|
||||
&metadata_size2));
|
||||
ASSERT_EQ(data_size1, data_size2);
|
||||
ASSERT_EQ(metadata_size1, metadata_size2);
|
||||
ASSERT(ObjectID_equal(object_id1, object_id2));
|
||||
free(data);
|
||||
ASSERT(object_id1 == object_id2);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_create_reply_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_id1 = globally_unique_id();
|
||||
ObjectID object_id1 = ObjectID::from_random();
|
||||
PlasmaObject object1 = random_plasma_object();
|
||||
plasma_send_CreateReply(fd, g_B, object_id1, &object1, 0);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaCreateReply);
|
||||
ARROW_CHECK_OK(SendCreateReply(fd, object_id1, &object1, 0));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaCreateReply);
|
||||
ObjectID object_id2;
|
||||
PlasmaObject object2;
|
||||
memset(&object2, 0, sizeof(object2));
|
||||
int error_code;
|
||||
plasma_read_CreateReply(data, &object_id2, &object2, &error_code);
|
||||
ASSERT(ObjectID_equal(object_id1, object_id2));
|
||||
ARROW_CHECK_OK(ReadCreateReply(data.data(), &object_id2, &object2));
|
||||
ASSERT(object_id1 == object_id2);
|
||||
ASSERT(memcmp(&object1, &object2, sizeof(object1)) == 0);
|
||||
free(data);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_seal_request_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_id1 = globally_unique_id();
|
||||
unsigned char digest1[DIGEST_SIZE];
|
||||
memset(&digest1[0], 7, DIGEST_SIZE);
|
||||
plasma_send_SealRequest(fd, g_B, object_id1, &digest1[0]);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaSealRequest);
|
||||
ObjectID object_id1 = ObjectID::from_random();
|
||||
unsigned char digest1[kDigestSize];
|
||||
memset(&digest1[0], 7, kDigestSize);
|
||||
ARROW_CHECK_OK(SendSealRequest(fd, object_id1, &digest1[0]));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaSealRequest);
|
||||
ObjectID object_id2;
|
||||
unsigned char digest2[DIGEST_SIZE];
|
||||
plasma_read_SealRequest(data, &object_id2, &digest2[0]);
|
||||
ASSERT(ObjectID_equal(object_id1, object_id2));
|
||||
ASSERT(memcmp(&digest1[0], &digest2[0], DIGEST_SIZE) == 0);
|
||||
free(data);
|
||||
unsigned char digest2[kDigestSize];
|
||||
ARROW_CHECK_OK(ReadSealRequest(data.data(), &object_id2, &digest2[0]));
|
||||
ASSERT(object_id1 == object_id2);
|
||||
ASSERT(memcmp(&digest1[0], &digest2[0], kDigestSize) == 0);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_seal_reply_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_id1 = globally_unique_id();
|
||||
int error1 = 5;
|
||||
plasma_send_SealReply(fd, g_B, object_id1, error1);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaSealReply);
|
||||
ObjectID object_id1 = ObjectID::from_random();
|
||||
ARROW_CHECK_OK(SendSealReply(fd, object_id1, PlasmaError_ObjectExists));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaSealReply);
|
||||
ObjectID object_id2;
|
||||
int error2;
|
||||
plasma_read_SealReply(data, &object_id2, &error2);
|
||||
ASSERT(ObjectID_equal(object_id1, object_id2));
|
||||
ASSERT(error1 == error2);
|
||||
free(data);
|
||||
Status s = ReadSealReply(data.data(), &object_id2);
|
||||
ASSERT(object_id1 == object_id2);
|
||||
ASSERT(s.IsPlasmaObjectExists());
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
@@ -131,18 +125,19 @@ TEST plasma_seal_reply_test(void) {
|
||||
TEST plasma_get_request_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_ids[2];
|
||||
object_ids[0] = globally_unique_id();
|
||||
object_ids[1] = globally_unique_id();
|
||||
object_ids[0] = ObjectID::from_random();
|
||||
object_ids[1] = ObjectID::from_random();
|
||||
int64_t timeout_ms = 1234;
|
||||
plasma_send_GetRequest(fd, g_B, object_ids, 2, timeout_ms);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaGetRequest);
|
||||
ObjectID object_ids_return[2];
|
||||
ARROW_CHECK_OK(SendGetRequest(fd, object_ids, 2, timeout_ms));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaGetRequest);
|
||||
std::vector<ObjectID> object_ids_return;
|
||||
int64_t timeout_ms_return;
|
||||
plasma_read_GetRequest(data, &object_ids_return[0], &timeout_ms_return, 2);
|
||||
ASSERT(ObjectID_equal(object_ids[0], object_ids_return[0]));
|
||||
ASSERT(ObjectID_equal(object_ids[1], object_ids_return[1]));
|
||||
ARROW_CHECK_OK(
|
||||
ReadGetRequest(data.data(), object_ids_return, &timeout_ms_return));
|
||||
ASSERT(object_ids[0] == object_ids_return[0]);
|
||||
ASSERT(object_ids[1] == object_ids_return[1]);
|
||||
ASSERT(timeout_ms == timeout_ms_return);
|
||||
free(data);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
@@ -150,101 +145,97 @@ TEST plasma_get_request_test(void) {
|
||||
TEST plasma_get_reply_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_ids[2];
|
||||
object_ids[0] = globally_unique_id();
|
||||
object_ids[1] = globally_unique_id();
|
||||
object_ids[0] = ObjectID::from_random();
|
||||
object_ids[1] = ObjectID::from_random();
|
||||
std::unordered_map<ObjectID, PlasmaObject, UniqueIDHasher> plasma_objects;
|
||||
plasma_objects[object_ids[0]] = random_plasma_object();
|
||||
plasma_objects[object_ids[1]] = random_plasma_object();
|
||||
plasma_send_GetReply(fd, g_B, object_ids, plasma_objects, 2);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaGetReply);
|
||||
int64_t num_objects = plasma_read_GetRequest_num_objects(data);
|
||||
ObjectID object_ids_return[num_objects];
|
||||
ARROW_CHECK_OK(SendGetReply(fd, object_ids, plasma_objects, 2));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaGetReply);
|
||||
ObjectID object_ids_return[2];
|
||||
PlasmaObject plasma_objects_return[2];
|
||||
memset(&plasma_objects_return, 0, sizeof(plasma_objects_return));
|
||||
plasma_read_GetReply(data, object_ids_return, &plasma_objects_return[0],
|
||||
num_objects);
|
||||
ASSERT(ObjectID_equal(object_ids[0], object_ids_return[0]));
|
||||
ASSERT(ObjectID_equal(object_ids[1], object_ids_return[1]));
|
||||
ARROW_CHECK_OK(ReadGetReply(data.data(), object_ids_return,
|
||||
&plasma_objects_return[0], 2));
|
||||
ASSERT(object_ids[0] == object_ids_return[0]);
|
||||
ASSERT(object_ids[1] == object_ids_return[1]);
|
||||
ASSERT(memcmp(&plasma_objects[object_ids[0]], &plasma_objects_return[0],
|
||||
sizeof(PlasmaObject)) == 0);
|
||||
ASSERT(memcmp(&plasma_objects[object_ids[1]], &plasma_objects_return[1],
|
||||
sizeof(PlasmaObject)) == 0);
|
||||
free(data);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_release_request_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_id1 = globally_unique_id();
|
||||
plasma_send_ReleaseRequest(fd, g_B, object_id1);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaReleaseRequest);
|
||||
ObjectID object_id1 = ObjectID::from_random();
|
||||
ARROW_CHECK_OK(SendReleaseRequest(fd, object_id1));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaReleaseRequest);
|
||||
ObjectID object_id2;
|
||||
plasma_read_ReleaseRequest(data, &object_id2);
|
||||
ASSERT(ObjectID_equal(object_id1, object_id2));
|
||||
free(data);
|
||||
ARROW_CHECK_OK(ReadReleaseRequest(data.data(), &object_id2));
|
||||
ASSERT(object_id1 == object_id2);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_release_reply_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_id1 = globally_unique_id();
|
||||
int error1 = 5;
|
||||
plasma_send_ReleaseReply(fd, g_B, object_id1, error1);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaReleaseReply);
|
||||
ObjectID object_id1 = ObjectID::from_random();
|
||||
ARROW_CHECK_OK(SendReleaseReply(fd, object_id1, PlasmaError_ObjectExists));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaReleaseReply);
|
||||
ObjectID object_id2;
|
||||
int error2;
|
||||
plasma_read_ReleaseReply(data, &object_id2, &error2);
|
||||
ASSERT(ObjectID_equal(object_id1, object_id2));
|
||||
ASSERT(error1 == error2);
|
||||
free(data);
|
||||
Status s = ReadReleaseReply(data.data(), &object_id2);
|
||||
ASSERT(object_id1 == object_id2);
|
||||
ASSERT(s.IsPlasmaObjectExists());
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_delete_request_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_id1 = globally_unique_id();
|
||||
plasma_send_DeleteRequest(fd, g_B, object_id1);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaDeleteRequest);
|
||||
ObjectID object_id1 = ObjectID::from_random();
|
||||
ARROW_CHECK_OK(SendDeleteRequest(fd, object_id1));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaDeleteRequest);
|
||||
ObjectID object_id2;
|
||||
plasma_read_DeleteRequest(data, &object_id2);
|
||||
ASSERT(ObjectID_equal(object_id1, object_id2));
|
||||
free(data);
|
||||
ARROW_CHECK_OK(ReadDeleteRequest(data.data(), &object_id2));
|
||||
ASSERT(object_id1 == object_id2);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_delete_reply_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_id1 = globally_unique_id();
|
||||
int error1 = 5;
|
||||
plasma_send_DeleteReply(fd, g_B, object_id1, error1);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaDeleteReply);
|
||||
ObjectID object_id1 = ObjectID::from_random();
|
||||
int error1 = PlasmaError_ObjectExists;
|
||||
ARROW_CHECK_OK(SendDeleteReply(fd, object_id1, error1));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaDeleteReply);
|
||||
ObjectID object_id2;
|
||||
int error2;
|
||||
plasma_read_DeleteReply(data, &object_id2, &error2);
|
||||
ASSERT(ObjectID_equal(object_id1, object_id2));
|
||||
ASSERT(error1 == error2);
|
||||
free(data);
|
||||
Status s = ReadDeleteReply(data.data(), &object_id2);
|
||||
ASSERT(object_id1 == object_id2);
|
||||
ASSERT(s.IsPlasmaObjectExists());
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_status_request_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_ids[2];
|
||||
object_ids[0] = globally_unique_id();
|
||||
object_ids[1] = globally_unique_id();
|
||||
plasma_send_StatusRequest(fd, g_B, object_ids, 2);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaStatusRequest);
|
||||
int64_t num_objects = plasma_read_StatusRequest_num_objects(data);
|
||||
int64_t num_objects = 2;
|
||||
ObjectID object_ids[num_objects];
|
||||
object_ids[0] = ObjectID::from_random();
|
||||
object_ids[1] = ObjectID::from_random();
|
||||
ARROW_CHECK_OK(SendStatusRequest(fd, object_ids, num_objects));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaStatusRequest);
|
||||
ObjectID object_ids_read[num_objects];
|
||||
plasma_read_StatusRequest(data, object_ids_read, num_objects);
|
||||
ASSERT(ObjectID_equal(object_ids[0], object_ids_read[0]));
|
||||
ASSERT(ObjectID_equal(object_ids[1], object_ids_read[1]));
|
||||
free(data);
|
||||
ARROW_CHECK_OK(ReadStatusRequest(data.data(), object_ids_read, num_objects));
|
||||
ASSERT(object_ids[0] == object_ids_read[0]);
|
||||
ASSERT(object_ids[1] == object_ids_read[1]);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
@@ -252,21 +243,21 @@ TEST plasma_status_request_test(void) {
|
||||
TEST plasma_status_reply_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_ids[2];
|
||||
object_ids[0] = globally_unique_id();
|
||||
object_ids[1] = globally_unique_id();
|
||||
object_ids[0] = ObjectID::from_random();
|
||||
object_ids[1] = ObjectID::from_random();
|
||||
int object_statuses[2] = {42, 43};
|
||||
plasma_send_StatusReply(fd, g_B, object_ids, object_statuses, 2);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaStatusReply);
|
||||
int64_t num_objects = plasma_read_StatusReply_num_objects(data);
|
||||
ARROW_CHECK_OK(SendStatusReply(fd, object_ids, object_statuses, 2));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaStatusReply);
|
||||
int64_t num_objects = ReadStatusReply_num_objects(data.data());
|
||||
ObjectID object_ids_read[num_objects];
|
||||
int object_statuses_read[num_objects];
|
||||
plasma_read_StatusReply(data, object_ids_read, object_statuses_read,
|
||||
num_objects);
|
||||
ASSERT(ObjectID_equal(object_ids[0], object_ids_read[0]));
|
||||
ASSERT(ObjectID_equal(object_ids[1], object_ids_read[1]));
|
||||
ARROW_CHECK_OK(ReadStatusReply(data.data(), object_ids_read,
|
||||
object_statuses_read, num_objects));
|
||||
ASSERT(object_ids[0] == object_ids_read[0]);
|
||||
ASSERT(object_ids[1] == object_ids_read[1]);
|
||||
ASSERT_EQ(object_statuses[0], object_statuses_read[0]);
|
||||
ASSERT_EQ(object_statuses[1], object_statuses_read[1]);
|
||||
free(data);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
@@ -274,12 +265,12 @@ TEST plasma_status_reply_test(void) {
|
||||
TEST plasma_evict_request_test(void) {
|
||||
int fd = create_temp_file();
|
||||
int64_t num_bytes = 111;
|
||||
plasma_send_EvictRequest(fd, g_B, num_bytes);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaEvictRequest);
|
||||
ARROW_CHECK_OK(SendEvictRequest(fd, num_bytes));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaEvictRequest);
|
||||
int64_t num_bytes_received;
|
||||
plasma_read_EvictRequest(data, &num_bytes_received);
|
||||
ARROW_CHECK_OK(ReadEvictRequest(data.data(), &num_bytes_received));
|
||||
ASSERT_EQ(num_bytes, num_bytes_received);
|
||||
free(data);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
@@ -287,12 +278,12 @@ TEST plasma_evict_request_test(void) {
|
||||
TEST plasma_evict_reply_test(void) {
|
||||
int fd = create_temp_file();
|
||||
int64_t num_bytes = 111;
|
||||
plasma_send_EvictReply(fd, g_B, num_bytes);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaEvictReply);
|
||||
ARROW_CHECK_OK(SendEvictReply(fd, num_bytes));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaEvictReply);
|
||||
int64_t num_bytes_received;
|
||||
plasma_read_EvictReply(data, &num_bytes_received);
|
||||
ARROW_CHECK_OK(ReadEvictReply(data.data(), num_bytes_received));
|
||||
ASSERT_EQ(num_bytes, num_bytes_received);
|
||||
free(data);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
@@ -300,15 +291,15 @@ TEST plasma_evict_reply_test(void) {
|
||||
TEST plasma_fetch_request_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_ids[2];
|
||||
object_ids[0] = globally_unique_id();
|
||||
object_ids[1] = globally_unique_id();
|
||||
plasma_send_FetchRequest(fd, g_B, object_ids, 2);
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaFetchRequest);
|
||||
ObjectID object_ids_read[2];
|
||||
plasma_read_FetchRequest(data, &object_ids_read[0], 2);
|
||||
ASSERT(ObjectID_equal(object_ids[0], object_ids_read[0]));
|
||||
ASSERT(ObjectID_equal(object_ids[1], object_ids_read[1]));
|
||||
free(data);
|
||||
object_ids[0] = ObjectID::from_random();
|
||||
object_ids[1] = ObjectID::from_random();
|
||||
ARROW_CHECK_OK(SendFetchRequest(fd, object_ids, 2));
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaFetchRequest);
|
||||
std::vector<ObjectID> object_ids_read;
|
||||
ARROW_CHECK_OK(ReadFetchRequest(data.data(), object_ids_read));
|
||||
ASSERT(object_ids[0] == object_ids_read[0]);
|
||||
ASSERT(object_ids[1] == object_ids_read[1]);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
@@ -317,22 +308,21 @@ TEST plasma_wait_request_test(void) {
|
||||
int fd = create_temp_file();
|
||||
const int num_objects_in = 2;
|
||||
ObjectRequest object_requests_in[num_objects_in] = {
|
||||
ObjectRequest({globally_unique_id(), PLASMA_QUERY_ANYWHERE, 0}),
|
||||
ObjectRequest({globally_unique_id(), PLASMA_QUERY_LOCAL, 0})};
|
||||
ObjectRequest({ObjectID::from_random(), PLASMA_QUERY_ANYWHERE, 0}),
|
||||
ObjectRequest({ObjectID::from_random(), PLASMA_QUERY_LOCAL, 0})};
|
||||
const int num_ready_objects_in = 1;
|
||||
int64_t timeout_ms = 1000;
|
||||
|
||||
plasma_send_WaitRequest(fd, g_B, &object_requests_in[0], num_objects_in,
|
||||
num_ready_objects_in, timeout_ms);
|
||||
ARROW_CHECK_OK(SendWaitRequest(fd, &object_requests_in[0], num_objects_in,
|
||||
num_ready_objects_in, timeout_ms));
|
||||
/* Read message back. */
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaWaitRequest);
|
||||
int num_object_ids_out = plasma_read_WaitRequest_num_object_ids(data);
|
||||
ASSERT_EQ(num_object_ids_out, num_objects_in);
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaWaitRequest);
|
||||
int num_ready_objects_out;
|
||||
int64_t timeout_ms_read;
|
||||
ObjectRequestMap object_requests_out;
|
||||
plasma_read_WaitRequest(data, object_requests_out, num_object_ids_out,
|
||||
&timeout_ms_read, &num_ready_objects_out);
|
||||
ARROW_CHECK_OK(ReadWaitRequest(data.data(), object_requests_out,
|
||||
&timeout_ms_read, &num_ready_objects_out));
|
||||
ASSERT_EQ(num_objects_in, object_requests_out.size());
|
||||
ASSERT_EQ(num_ready_objects_out, num_ready_objects_in);
|
||||
for (int i = 0; i < num_objects_in; i++) {
|
||||
@@ -340,11 +330,9 @@ TEST plasma_wait_request_test(void) {
|
||||
ASSERT_EQ(1, object_requests_out.count(object_id));
|
||||
const auto &entry = object_requests_out.find(object_id);
|
||||
ASSERT(entry != object_requests_out.end());
|
||||
ASSERT(ObjectID_equal(entry->second.object_id,
|
||||
object_requests_in[i].object_id));
|
||||
ASSERT(entry->second.object_id == object_requests_in[i].object_id);
|
||||
ASSERT_EQ(entry->second.type, object_requests_in[i].type);
|
||||
}
|
||||
free(data);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
@@ -354,68 +342,69 @@ TEST plasma_wait_reply_test(void) {
|
||||
const int num_objects_in = 2;
|
||||
/* Create a map with two ObjectRequests in it. */
|
||||
ObjectRequestMap objects_in(num_objects_in);
|
||||
ObjectID id1 = globally_unique_id();
|
||||
ObjectID id1 = ObjectID::from_random();
|
||||
objects_in[id1] = ObjectRequest({id1, 0, ObjectStatus_Local});
|
||||
ObjectID id2 = globally_unique_id();
|
||||
ObjectID id2 = ObjectID::from_random();
|
||||
objects_in[id2] = ObjectRequest({id2, 0, ObjectStatus_Nonexistent});
|
||||
|
||||
plasma_send_WaitReply(fd, g_B, objects_in, num_objects_in);
|
||||
ARROW_CHECK_OK(SendWaitReply(fd, objects_in, num_objects_in));
|
||||
/* Read message back. */
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaWaitReply);
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaWaitReply);
|
||||
ObjectRequest objects_out[2];
|
||||
int num_objects_out;
|
||||
plasma_read_WaitReply(data, &objects_out[0], &num_objects_out);
|
||||
ARROW_CHECK_OK(ReadWaitReply(data.data(), &objects_out[0], &num_objects_out));
|
||||
ASSERT(num_objects_in == num_objects_out);
|
||||
for (int i = 0; i < num_objects_out; i++) {
|
||||
/* Each object request must appear exactly once. */
|
||||
ASSERT(1 == objects_in.count(objects_out[i].object_id));
|
||||
const auto &entry = objects_in.find(objects_out[i].object_id);
|
||||
ASSERT(entry != objects_in.end());
|
||||
ASSERT(ObjectID_equal(entry->second.object_id, objects_out[i].object_id));
|
||||
ASSERT(entry->second.object_id == objects_out[i].object_id);
|
||||
ASSERT(entry->second.status == objects_out[i].status);
|
||||
}
|
||||
free(data);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_data_request_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_id1 = globally_unique_id();
|
||||
ObjectID object_id1 = ObjectID::from_random();
|
||||
const char *address1 = "address1";
|
||||
int port1 = 12345;
|
||||
plasma_send_DataRequest(fd, g_B, object_id1, address1, port1);
|
||||
ARROW_CHECK_OK(SendDataRequest(fd, object_id1, address1, port1));
|
||||
/* Reading message back. */
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaDataRequest);
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaDataRequest);
|
||||
ObjectID object_id2;
|
||||
char *address2;
|
||||
int port2;
|
||||
plasma_read_DataRequest(data, &object_id2, &address2, &port2);
|
||||
ASSERT(ObjectID_equal(object_id1, object_id2));
|
||||
ARROW_CHECK_OK(ReadDataRequest(data.data(), &object_id2, &address2, &port2));
|
||||
ASSERT(object_id1 == object_id2);
|
||||
ASSERT(strcmp(address1, address2) == 0);
|
||||
ASSERT(port1 == port2);
|
||||
free(address2);
|
||||
free(data);
|
||||
close(fd);
|
||||
PASS();
|
||||
}
|
||||
|
||||
TEST plasma_data_reply_test(void) {
|
||||
int fd = create_temp_file();
|
||||
ObjectID object_id1 = globally_unique_id();
|
||||
ObjectID object_id1 = ObjectID::from_random();
|
||||
int64_t object_size1 = 146;
|
||||
int64_t metadata_size1 = 198;
|
||||
plasma_send_DataReply(fd, g_B, object_id1, object_size1, metadata_size1);
|
||||
ARROW_CHECK_OK(SendDataReply(fd, object_id1, object_size1, metadata_size1));
|
||||
/* Reading message back. */
|
||||
uint8_t *data = read_message_from_file(fd, MessageType_PlasmaDataReply);
|
||||
std::vector<uint8_t> data =
|
||||
read_message_from_file(fd, MessageType_PlasmaDataReply);
|
||||
ObjectID object_id2;
|
||||
int64_t object_size2;
|
||||
int64_t metadata_size2;
|
||||
plasma_read_DataReply(data, &object_id2, &object_size2, &metadata_size2);
|
||||
ASSERT(ObjectID_equal(object_id1, object_id2));
|
||||
ARROW_CHECK_OK(
|
||||
ReadDataReply(data.data(), &object_id2, &object_size2, &metadata_size2));
|
||||
ASSERT(object_id1 == object_id2);
|
||||
ASSERT(object_size1 == object_size2);
|
||||
ASSERT(metadata_size1 == metadata_size2);
|
||||
free(data);
|
||||
PASS();
|
||||
}
|
||||
|
||||
@@ -444,9 +433,7 @@ SUITE(plasma_serialization_tests) {
|
||||
GREATEST_MAIN_DEFS();
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
g_B = make_protocol_builder();
|
||||
GREATEST_MAIN_BEGIN();
|
||||
RUN_SUITE(plasma_serialization_tests);
|
||||
GREATEST_MAIN_END();
|
||||
free_protocol_builder(g_B);
|
||||
}
|
||||
|
||||
Vendored
+465
@@ -0,0 +1,465 @@
|
||||
/* 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 <antirez at gmail dot 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 <stdio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ae.h"
|
||||
#include "zmalloc.h"
|
||||
#include "config.h"
|
||||
|
||||
/* Include the best multiplexing layer supported by this system.
|
||||
* The following should be ordered by performances, descending. */
|
||||
#ifdef HAVE_EVPORT
|
||||
#include "ae_evport.c"
|
||||
#else
|
||||
#ifdef HAVE_EPOLL
|
||||
#include "ae_epoll.c"
|
||||
#else
|
||||
#ifdef HAVE_KQUEUE
|
||||
#include "ae_kqueue.c"
|
||||
#else
|
||||
#include "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;
|
||||
}
|
||||
Vendored
+123
@@ -0,0 +1,123 @@
|
||||
/* 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 <antirez at gmail dot 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.
|
||||
*/
|
||||
|
||||
#ifndef __AE_H__
|
||||
#define __AE_H__
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#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
|
||||
Vendored
+135
@@ -0,0 +1,135 @@
|
||||
/* Linux epoll(2) based ae.c module
|
||||
*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot 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 <sys/epoll.h>
|
||||
|
||||
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 = {0}; /* 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 = {0}; /* 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";
|
||||
}
|
||||
Vendored
+320
@@ -0,0 +1,320 @@
|
||||
/* 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 <assert.h>
|
||||
#include <errno.h>
|
||||
#include <port.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
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";
|
||||
}
|
||||
Vendored
+138
@@ -0,0 +1,138 @@
|
||||
/* 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 <sys/types.h>
|
||||
#include <sys/event.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
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";
|
||||
}
|
||||
Vendored
+106
@@ -0,0 +1,106 @@
|
||||
/* Select()-based ae.c module.
|
||||
*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot 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 <sys/select.h>
|
||||
#include <string.h>
|
||||
|
||||
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";
|
||||
}
|
||||
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot 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.
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H
|
||||
#define __CONFIG_H
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <AvailabilityMacros.h>
|
||||
#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 <sys/feature_tests.h>
|
||||
#ifdef _DTRACE_VERSION
|
||||
#define HAVE_EVPORT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
#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 */
|
||||
@@ -163,7 +163,7 @@ class ComponentFailureTest(unittest.TestCase):
|
||||
if check_component_alive:
|
||||
self.assertTrue(component.poll() is None)
|
||||
else:
|
||||
self.assertTrue(component.poll() <= 0)
|
||||
self.assertTrue(not component.poll() is None)
|
||||
|
||||
def testLocalSchedulerFailed(self):
|
||||
# Kill all local schedulers on worker nodes.
|
||||
|
||||
Reference in New Issue
Block a user