opengris-scaler 1.12.7__cp38-cp38-manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of opengris-scaler might be problematic. Click here for more details.
- opengris_scaler-1.12.7.dist-info/METADATA +729 -0
- opengris_scaler-1.12.7.dist-info/RECORD +232 -0
- opengris_scaler-1.12.7.dist-info/WHEEL +5 -0
- opengris_scaler-1.12.7.dist-info/entry_points.txt +9 -0
- opengris_scaler-1.12.7.dist-info/licenses/LICENSE +201 -0
- opengris_scaler-1.12.7.dist-info/licenses/LICENSE.spdx +7 -0
- opengris_scaler-1.12.7.dist-info/licenses/NOTICE +8 -0
- opengris_scaler.libs/libcapnp-1-b787335c.1.0.so +0 -0
- opengris_scaler.libs/libkj-1-094aa318.1.0.so +0 -0
- scaler/CMakeLists.txt +11 -0
- scaler/__init__.py +14 -0
- scaler/about.py +5 -0
- scaler/client/__init__.py +0 -0
- scaler/client/agent/__init__.py +0 -0
- scaler/client/agent/client_agent.py +210 -0
- scaler/client/agent/disconnect_manager.py +27 -0
- scaler/client/agent/future_manager.py +112 -0
- scaler/client/agent/heartbeat_manager.py +74 -0
- scaler/client/agent/mixins.py +89 -0
- scaler/client/agent/object_manager.py +98 -0
- scaler/client/agent/task_manager.py +64 -0
- scaler/client/client.py +635 -0
- scaler/client/future.py +252 -0
- scaler/client/object_buffer.py +129 -0
- scaler/client/object_reference.py +25 -0
- scaler/client/serializer/__init__.py +0 -0
- scaler/client/serializer/default.py +16 -0
- scaler/client/serializer/mixins.py +38 -0
- scaler/cluster/__init__.py +0 -0
- scaler/cluster/cluster.py +115 -0
- scaler/cluster/combo.py +148 -0
- scaler/cluster/object_storage_server.py +45 -0
- scaler/cluster/scheduler.py +83 -0
- scaler/config/__init__.py +0 -0
- scaler/config/defaults.py +87 -0
- scaler/config/loader.py +95 -0
- scaler/config/mixins.py +15 -0
- scaler/config/section/__init__.py +0 -0
- scaler/config/section/cluster.py +56 -0
- scaler/config/section/native_worker_adapter.py +44 -0
- scaler/config/section/object_storage_server.py +7 -0
- scaler/config/section/scheduler.py +53 -0
- scaler/config/section/symphony_worker_adapter.py +47 -0
- scaler/config/section/top.py +13 -0
- scaler/config/section/webui.py +16 -0
- scaler/config/types/__init__.py +0 -0
- scaler/config/types/object_storage_server.py +45 -0
- scaler/config/types/worker.py +57 -0
- scaler/config/types/zmq.py +79 -0
- scaler/entry_points/__init__.py +0 -0
- scaler/entry_points/cluster.py +133 -0
- scaler/entry_points/object_storage_server.py +41 -0
- scaler/entry_points/scheduler.py +135 -0
- scaler/entry_points/top.py +286 -0
- scaler/entry_points/webui.py +26 -0
- scaler/entry_points/worker_adapter_native.py +137 -0
- scaler/entry_points/worker_adapter_symphony.py +102 -0
- scaler/io/__init__.py +0 -0
- scaler/io/async_binder.py +85 -0
- scaler/io/async_connector.py +95 -0
- scaler/io/async_object_storage_connector.py +185 -0
- scaler/io/mixins.py +154 -0
- scaler/io/sync_connector.py +68 -0
- scaler/io/sync_object_storage_connector.py +185 -0
- scaler/io/sync_subscriber.py +83 -0
- scaler/io/utility.py +31 -0
- scaler/io/ymq/CMakeLists.txt +98 -0
- scaler/io/ymq/__init__.py +0 -0
- scaler/io/ymq/_ymq.pyi +96 -0
- scaler/io/ymq/_ymq.so +0 -0
- scaler/io/ymq/bytes.h +114 -0
- scaler/io/ymq/common.h +29 -0
- scaler/io/ymq/configuration.h +60 -0
- scaler/io/ymq/epoll_context.cpp +185 -0
- scaler/io/ymq/epoll_context.h +85 -0
- scaler/io/ymq/error.h +132 -0
- scaler/io/ymq/event_loop.h +55 -0
- scaler/io/ymq/event_loop_thread.cpp +64 -0
- scaler/io/ymq/event_loop_thread.h +46 -0
- scaler/io/ymq/event_manager.h +81 -0
- scaler/io/ymq/file_descriptor.h +203 -0
- scaler/io/ymq/interruptive_concurrent_queue.h +169 -0
- scaler/io/ymq/io_context.cpp +98 -0
- scaler/io/ymq/io_context.h +44 -0
- scaler/io/ymq/io_socket.cpp +299 -0
- scaler/io/ymq/io_socket.h +121 -0
- scaler/io/ymq/iocp_context.cpp +102 -0
- scaler/io/ymq/iocp_context.h +83 -0
- scaler/io/ymq/logging.h +163 -0
- scaler/io/ymq/message.h +15 -0
- scaler/io/ymq/message_connection.h +16 -0
- scaler/io/ymq/message_connection_tcp.cpp +672 -0
- scaler/io/ymq/message_connection_tcp.h +96 -0
- scaler/io/ymq/network_utils.h +179 -0
- scaler/io/ymq/pymod_ymq/bytes.h +113 -0
- scaler/io/ymq/pymod_ymq/exception.h +124 -0
- scaler/io/ymq/pymod_ymq/gil.h +15 -0
- scaler/io/ymq/pymod_ymq/io_context.h +166 -0
- scaler/io/ymq/pymod_ymq/io_socket.h +285 -0
- scaler/io/ymq/pymod_ymq/message.h +99 -0
- scaler/io/ymq/pymod_ymq/python.h +153 -0
- scaler/io/ymq/pymod_ymq/ymq.cpp +23 -0
- scaler/io/ymq/pymod_ymq/ymq.h +357 -0
- scaler/io/ymq/readme.md +114 -0
- scaler/io/ymq/simple_interface.cpp +80 -0
- scaler/io/ymq/simple_interface.h +24 -0
- scaler/io/ymq/tcp_client.cpp +367 -0
- scaler/io/ymq/tcp_client.h +75 -0
- scaler/io/ymq/tcp_operations.h +41 -0
- scaler/io/ymq/tcp_server.cpp +410 -0
- scaler/io/ymq/tcp_server.h +79 -0
- scaler/io/ymq/third_party/concurrentqueue.h +3747 -0
- scaler/io/ymq/timed_queue.h +272 -0
- scaler/io/ymq/timestamp.h +102 -0
- scaler/io/ymq/typedefs.h +20 -0
- scaler/io/ymq/utils.h +34 -0
- scaler/io/ymq/ymq.py +130 -0
- scaler/object_storage/CMakeLists.txt +50 -0
- scaler/object_storage/__init__.py +0 -0
- scaler/object_storage/constants.h +11 -0
- scaler/object_storage/defs.h +14 -0
- scaler/object_storage/io_helper.cpp +44 -0
- scaler/object_storage/io_helper.h +9 -0
- scaler/object_storage/message.cpp +56 -0
- scaler/object_storage/message.h +130 -0
- scaler/object_storage/object_manager.cpp +126 -0
- scaler/object_storage/object_manager.h +52 -0
- scaler/object_storage/object_storage_server.cpp +359 -0
- scaler/object_storage/object_storage_server.h +126 -0
- scaler/object_storage/object_storage_server.so +0 -0
- scaler/object_storage/pymod_object_storage_server.cpp +104 -0
- scaler/protocol/__init__.py +0 -0
- scaler/protocol/capnp/__init__.py +0 -0
- scaler/protocol/capnp/_python.py +6 -0
- scaler/protocol/capnp/common.capnp +63 -0
- scaler/protocol/capnp/message.capnp +216 -0
- scaler/protocol/capnp/object_storage.capnp +52 -0
- scaler/protocol/capnp/status.capnp +73 -0
- scaler/protocol/introduction.md +105 -0
- scaler/protocol/python/__init__.py +0 -0
- scaler/protocol/python/common.py +135 -0
- scaler/protocol/python/message.py +726 -0
- scaler/protocol/python/mixins.py +13 -0
- scaler/protocol/python/object_storage.py +118 -0
- scaler/protocol/python/status.py +279 -0
- scaler/protocol/worker.md +228 -0
- scaler/scheduler/__init__.py +0 -0
- scaler/scheduler/allocate_policy/__init__.py +0 -0
- scaler/scheduler/allocate_policy/allocate_policy.py +9 -0
- scaler/scheduler/allocate_policy/capability_allocate_policy.py +280 -0
- scaler/scheduler/allocate_policy/even_load_allocate_policy.py +159 -0
- scaler/scheduler/allocate_policy/mixins.py +55 -0
- scaler/scheduler/controllers/__init__.py +0 -0
- scaler/scheduler/controllers/balance_controller.py +65 -0
- scaler/scheduler/controllers/client_controller.py +131 -0
- scaler/scheduler/controllers/config_controller.py +31 -0
- scaler/scheduler/controllers/graph_controller.py +424 -0
- scaler/scheduler/controllers/information_controller.py +81 -0
- scaler/scheduler/controllers/mixins.py +201 -0
- scaler/scheduler/controllers/object_controller.py +147 -0
- scaler/scheduler/controllers/scaling_controller.py +86 -0
- scaler/scheduler/controllers/task_controller.py +373 -0
- scaler/scheduler/controllers/worker_controller.py +168 -0
- scaler/scheduler/object_usage/__init__.py +0 -0
- scaler/scheduler/object_usage/object_tracker.py +131 -0
- scaler/scheduler/scheduler.py +253 -0
- scaler/scheduler/task/__init__.py +0 -0
- scaler/scheduler/task/task_state_machine.py +92 -0
- scaler/scheduler/task/task_state_manager.py +61 -0
- scaler/ui/__init__.py +0 -0
- scaler/ui/constants.py +9 -0
- scaler/ui/live_display.py +118 -0
- scaler/ui/memory_window.py +146 -0
- scaler/ui/setting_page.py +47 -0
- scaler/ui/task_graph.py +370 -0
- scaler/ui/task_log.py +83 -0
- scaler/ui/utility.py +35 -0
- scaler/ui/webui.py +125 -0
- scaler/ui/worker_processors.py +85 -0
- scaler/utility/__init__.py +0 -0
- scaler/utility/debug.py +19 -0
- scaler/utility/event_list.py +63 -0
- scaler/utility/event_loop.py +58 -0
- scaler/utility/exceptions.py +42 -0
- scaler/utility/formatter.py +44 -0
- scaler/utility/graph/__init__.py +0 -0
- scaler/utility/graph/optimization.py +27 -0
- scaler/utility/graph/topological_sorter.py +11 -0
- scaler/utility/graph/topological_sorter_graphblas.py +174 -0
- scaler/utility/identifiers.py +105 -0
- scaler/utility/logging/__init__.py +0 -0
- scaler/utility/logging/decorators.py +25 -0
- scaler/utility/logging/scoped_logger.py +33 -0
- scaler/utility/logging/utility.py +183 -0
- scaler/utility/many_to_many_dict.py +123 -0
- scaler/utility/metadata/__init__.py +0 -0
- scaler/utility/metadata/profile_result.py +31 -0
- scaler/utility/metadata/task_flags.py +30 -0
- scaler/utility/mixins.py +13 -0
- scaler/utility/network_util.py +7 -0
- scaler/utility/one_to_many_dict.py +72 -0
- scaler/utility/queues/__init__.py +0 -0
- scaler/utility/queues/async_indexed_queue.py +37 -0
- scaler/utility/queues/async_priority_queue.py +70 -0
- scaler/utility/queues/async_sorted_priority_queue.py +45 -0
- scaler/utility/queues/indexed_queue.py +114 -0
- scaler/utility/serialization.py +9 -0
- scaler/version.txt +1 -0
- scaler/worker/__init__.py +0 -0
- scaler/worker/agent/__init__.py +0 -0
- scaler/worker/agent/heartbeat_manager.py +107 -0
- scaler/worker/agent/mixins.py +137 -0
- scaler/worker/agent/processor/__init__.py +0 -0
- scaler/worker/agent/processor/object_cache.py +107 -0
- scaler/worker/agent/processor/processor.py +279 -0
- scaler/worker/agent/processor/streaming_buffer.py +28 -0
- scaler/worker/agent/processor_holder.py +145 -0
- scaler/worker/agent/processor_manager.py +365 -0
- scaler/worker/agent/profiling_manager.py +109 -0
- scaler/worker/agent/task_manager.py +150 -0
- scaler/worker/agent/timeout_manager.py +19 -0
- scaler/worker/preload.py +84 -0
- scaler/worker/worker.py +264 -0
- scaler/worker_adapter/__init__.py +0 -0
- scaler/worker_adapter/native.py +154 -0
- scaler/worker_adapter/symphony/__init__.py +0 -0
- scaler/worker_adapter/symphony/callback.py +45 -0
- scaler/worker_adapter/symphony/heartbeat_manager.py +79 -0
- scaler/worker_adapter/symphony/message.py +24 -0
- scaler/worker_adapter/symphony/task_manager.py +288 -0
- scaler/worker_adapter/symphony/worker.py +205 -0
- scaler/worker_adapter/symphony/worker_adapter.py +142 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// Python
|
|
4
|
+
#include "scaler/io/ymq/pymod_ymq/python.h"
|
|
5
|
+
|
|
6
|
+
// C++
|
|
7
|
+
#include <memory>
|
|
8
|
+
#include <utility>
|
|
9
|
+
|
|
10
|
+
// C
|
|
11
|
+
#include <object.h>
|
|
12
|
+
#include <semaphore.h>
|
|
13
|
+
#include <sys/eventfd.h>
|
|
14
|
+
#include <sys/poll.h>
|
|
15
|
+
|
|
16
|
+
// First-party
|
|
17
|
+
#include "scaler/io/ymq/bytes.h"
|
|
18
|
+
#include "scaler/io/ymq/error.h"
|
|
19
|
+
#include "scaler/io/ymq/io_context.h"
|
|
20
|
+
#include "scaler/io/ymq/io_socket.h"
|
|
21
|
+
#include "scaler/io/ymq/message.h"
|
|
22
|
+
#include "scaler/io/ymq/pymod_ymq/bytes.h"
|
|
23
|
+
#include "scaler/io/ymq/pymod_ymq/exception.h"
|
|
24
|
+
#include "scaler/io/ymq/pymod_ymq/gil.h"
|
|
25
|
+
#include "scaler/io/ymq/pymod_ymq/message.h"
|
|
26
|
+
#include "scaler/io/ymq/pymod_ymq/ymq.h"
|
|
27
|
+
|
|
28
|
+
using namespace scaler::ymq;
|
|
29
|
+
|
|
30
|
+
struct PyIOSocket {
|
|
31
|
+
PyObject_HEAD;
|
|
32
|
+
std::shared_ptr<IOSocket> socket;
|
|
33
|
+
std::shared_ptr<IOContext> ioContext;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
extern "C" {
|
|
37
|
+
|
|
38
|
+
static void PyIOSocket_dealloc(PyIOSocket* self)
|
|
39
|
+
{
|
|
40
|
+
try {
|
|
41
|
+
self->ioContext->removeIOSocket(self->socket);
|
|
42
|
+
self->ioContext.~shared_ptr();
|
|
43
|
+
self->socket.~shared_ptr();
|
|
44
|
+
} catch (...) {
|
|
45
|
+
PyErr_SetString(PyExc_RuntimeError, "Failed to deallocate IOSocket");
|
|
46
|
+
PyErr_WriteUnraisable((PyObject*)self);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
auto* tp = Py_TYPE(self);
|
|
50
|
+
tp->tp_free(self);
|
|
51
|
+
Py_DECREF(tp);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static PyObject* PyIOSocket_send(PyIOSocket* self, PyObject* args, PyObject* kwargs)
|
|
55
|
+
{
|
|
56
|
+
auto state = YMQStateFromSelf((PyObject*)self);
|
|
57
|
+
if (!state)
|
|
58
|
+
return nullptr;
|
|
59
|
+
|
|
60
|
+
PyObject* callback = nullptr;
|
|
61
|
+
PyMessage* message = nullptr;
|
|
62
|
+
|
|
63
|
+
// empty str -> positional only
|
|
64
|
+
const char* kwlist[] = {"", "message", nullptr};
|
|
65
|
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO", (char**)kwlist, &callback, &message))
|
|
66
|
+
return nullptr;
|
|
67
|
+
|
|
68
|
+
if (!PyObject_TypeCheck(message, (PyTypeObject*)*state->PyMessageType)) {
|
|
69
|
+
PyErr_SetString(PyExc_TypeError, "message must be a Message");
|
|
70
|
+
return nullptr;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
auto address = message->address.is_none() ? Bytes() : std::move(message->address->bytes);
|
|
74
|
+
auto payload = std::move(message->payload->bytes);
|
|
75
|
+
|
|
76
|
+
Py_INCREF(callback);
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
self->socket->sendMessage(
|
|
80
|
+
{.address = std::move(address), .payload = std::move(payload)}, [callback, state](auto result) {
|
|
81
|
+
AcquireGIL _;
|
|
82
|
+
|
|
83
|
+
if (result) {
|
|
84
|
+
OwnedPyObject result = PyObject_CallFunctionObjArgs(callback, Py_None, nullptr);
|
|
85
|
+
} else {
|
|
86
|
+
OwnedPyObject obj = YMQException_createFromCoreError(state, &result.error());
|
|
87
|
+
OwnedPyObject _ = PyObject_CallFunctionObjArgs(callback, *obj, nullptr);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
Py_DECREF(callback);
|
|
91
|
+
});
|
|
92
|
+
} catch (...) {
|
|
93
|
+
PyErr_SetString(PyExc_RuntimeError, "Failed to send message");
|
|
94
|
+
return nullptr;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
Py_RETURN_NONE;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
static PyObject* PyIOSocket_recv(PyIOSocket* self, PyObject* args, PyObject* kwargs)
|
|
101
|
+
{
|
|
102
|
+
auto state = YMQStateFromSelf((PyObject*)self);
|
|
103
|
+
if (!state)
|
|
104
|
+
return nullptr;
|
|
105
|
+
|
|
106
|
+
PyObject* callback = nullptr;
|
|
107
|
+
const char* kwlist[] = {"", nullptr};
|
|
108
|
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", (char**)kwlist, &callback))
|
|
109
|
+
return nullptr;
|
|
110
|
+
|
|
111
|
+
Py_INCREF(callback);
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
self->socket->recvMessage([callback, state](std::pair<Message, Error> result) {
|
|
115
|
+
AcquireGIL _;
|
|
116
|
+
|
|
117
|
+
if (result.second._errorCode != Error::ErrorCode::Uninit) {
|
|
118
|
+
OwnedPyObject obj = YMQException_createFromCoreError(state, &result.second);
|
|
119
|
+
OwnedPyObject _ = PyObject_CallFunctionObjArgs(callback, *obj, nullptr);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
auto message = result.first;
|
|
124
|
+
OwnedPyObject<PyBytesYMQ> address = (PyBytesYMQ*)PyObject_CallNoArgs(*state->PyBytesYMQType);
|
|
125
|
+
if (!address)
|
|
126
|
+
return completeCallbackWithRaisedException(callback);
|
|
127
|
+
|
|
128
|
+
address->bytes = std::move(message.address);
|
|
129
|
+
|
|
130
|
+
OwnedPyObject<PyBytesYMQ> payload = (PyBytesYMQ*)PyObject_CallNoArgs(*state->PyBytesYMQType);
|
|
131
|
+
if (!payload)
|
|
132
|
+
return completeCallbackWithRaisedException(callback);
|
|
133
|
+
|
|
134
|
+
payload->bytes = std::move(message.payload);
|
|
135
|
+
|
|
136
|
+
OwnedPyObject<PyMessage> pyMessage =
|
|
137
|
+
(PyMessage*)PyObject_CallFunction(*state->PyMessageType, "OO", *address, *payload);
|
|
138
|
+
if (!pyMessage)
|
|
139
|
+
return completeCallbackWithRaisedException(callback);
|
|
140
|
+
|
|
141
|
+
OwnedPyObject _result = PyObject_CallFunctionObjArgs(callback, *pyMessage, nullptr);
|
|
142
|
+
Py_DECREF(callback);
|
|
143
|
+
});
|
|
144
|
+
} catch (...) {
|
|
145
|
+
PyErr_SetString(PyExc_RuntimeError, "Failed to receive message");
|
|
146
|
+
return nullptr;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
Py_RETURN_NONE;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
static PyObject* PyIOSocket_bind(PyIOSocket* self, PyObject* args, PyObject* kwargs)
|
|
153
|
+
{
|
|
154
|
+
auto state = YMQStateFromSelf((PyObject*)self);
|
|
155
|
+
if (!state)
|
|
156
|
+
return nullptr;
|
|
157
|
+
|
|
158
|
+
PyObject* callback = nullptr;
|
|
159
|
+
const char* address = nullptr;
|
|
160
|
+
Py_ssize_t addressLen = 0;
|
|
161
|
+
const char* kwlist[] = {"", "address", nullptr};
|
|
162
|
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os#", (char**)kwlist, &callback, &address, &addressLen))
|
|
163
|
+
return nullptr;
|
|
164
|
+
|
|
165
|
+
Py_INCREF(callback);
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
self->socket->bindTo(std::string(address, addressLen), [callback, state](auto result) {
|
|
169
|
+
AcquireGIL _;
|
|
170
|
+
|
|
171
|
+
if (!result) {
|
|
172
|
+
OwnedPyObject exc = YMQException_createFromCoreError(state, &result.error());
|
|
173
|
+
OwnedPyObject _ = PyObject_CallFunctionObjArgs(callback, *exc, nullptr);
|
|
174
|
+
} else {
|
|
175
|
+
OwnedPyObject _ = PyObject_CallFunctionObjArgs(callback, Py_None, nullptr);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
Py_DECREF(callback);
|
|
179
|
+
});
|
|
180
|
+
} catch (...) {
|
|
181
|
+
PyErr_SetString(PyExc_RuntimeError, "Failed to bind to address");
|
|
182
|
+
return nullptr;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
Py_RETURN_NONE;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
static PyObject* PyIOSocket_connect(PyIOSocket* self, PyObject* args, PyObject* kwargs)
|
|
189
|
+
{
|
|
190
|
+
auto state = YMQStateFromSelf((PyObject*)self);
|
|
191
|
+
if (!state)
|
|
192
|
+
return nullptr;
|
|
193
|
+
|
|
194
|
+
PyObject* callback = nullptr;
|
|
195
|
+
const char* address = nullptr;
|
|
196
|
+
Py_ssize_t addressLen = 0;
|
|
197
|
+
const char* kwlist[] = {"", "address", nullptr};
|
|
198
|
+
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Os#", (char**)kwlist, &callback, &address, &addressLen))
|
|
199
|
+
return nullptr;
|
|
200
|
+
|
|
201
|
+
Py_INCREF(callback);
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
self->socket->connectTo(std::string(address, addressLen), [callback, state](auto result) {
|
|
205
|
+
AcquireGIL _;
|
|
206
|
+
|
|
207
|
+
if (result || result.error()._errorCode == Error::ErrorCode::InitialConnectFailedWithInProgress) {
|
|
208
|
+
OwnedPyObject _ = PyObject_CallFunctionObjArgs(callback, Py_None, nullptr);
|
|
209
|
+
} else {
|
|
210
|
+
OwnedPyObject exc = YMQException_createFromCoreError(state, &result.error());
|
|
211
|
+
OwnedPyObject _ = PyObject_CallFunctionObjArgs(callback, *exc, nullptr);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
Py_DECREF(callback);
|
|
215
|
+
});
|
|
216
|
+
} catch (...) {
|
|
217
|
+
PyErr_SetString(PyExc_RuntimeError, "Failed to connect to address");
|
|
218
|
+
return nullptr;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
Py_RETURN_NONE;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
static PyObject* PyIOSocket_repr(PyIOSocket* self)
|
|
225
|
+
{
|
|
226
|
+
return PyUnicode_FromFormat("<IOSocket at %p>", (void*)self->socket.get());
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
static PyObject* PyIOSocket_identity_getter(PyIOSocket* self, void* closure)
|
|
230
|
+
{
|
|
231
|
+
return PyUnicode_FromStringAndSize(self->socket->identity().data(), self->socket->identity().size());
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
static PyObject* PyIOSocket_socket_type_getter(PyIOSocket* self, void* closure)
|
|
235
|
+
{
|
|
236
|
+
auto state = YMQStateFromSelf((PyObject*)self);
|
|
237
|
+
if (!state)
|
|
238
|
+
return nullptr;
|
|
239
|
+
|
|
240
|
+
const IOSocketType socketType = self->socket->socketType();
|
|
241
|
+
OwnedPyObject socketTypeIntObj = PyLong_FromLong((long)socketType);
|
|
242
|
+
|
|
243
|
+
if (!socketTypeIntObj)
|
|
244
|
+
return nullptr;
|
|
245
|
+
|
|
246
|
+
return PyObject_CallOneArg(*state->PyIOSocketEnumType, *socketTypeIntObj);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
static PyGetSetDef PyIOSocket_properties[] = {
|
|
251
|
+
{"identity", (getter)PyIOSocket_identity_getter, nullptr, PyDoc_STR("Get the identity of the IOSocket"), nullptr},
|
|
252
|
+
{"socket_type", (getter)PyIOSocket_socket_type_getter, nullptr, PyDoc_STR("Get the type of the IOSocket"), nullptr},
|
|
253
|
+
{nullptr, nullptr, nullptr, nullptr, nullptr},
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
static PyMethodDef PyIOSocket_methods[] = {
|
|
257
|
+
{"send", (PyCFunction)PyIOSocket_send, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Send data through the IOSocket")},
|
|
258
|
+
{"recv", (PyCFunction)PyIOSocket_recv, METH_VARARGS | METH_KEYWORDS, PyDoc_STR("Receive data from the IOSocket")},
|
|
259
|
+
{"bind",
|
|
260
|
+
(PyCFunction)PyIOSocket_bind,
|
|
261
|
+
METH_VARARGS | METH_KEYWORDS,
|
|
262
|
+
PyDoc_STR("Bind to an address and listen for incoming connections")},
|
|
263
|
+
{"connect",
|
|
264
|
+
(PyCFunction)PyIOSocket_connect,
|
|
265
|
+
METH_VARARGS | METH_KEYWORDS,
|
|
266
|
+
PyDoc_STR("Connect to a remote IOSocket")},
|
|
267
|
+
{nullptr, nullptr, 0, nullptr},
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
static PyType_Slot PyIOSocket_slots[] = {
|
|
271
|
+
{Py_tp_dealloc, (void*)PyIOSocket_dealloc},
|
|
272
|
+
{Py_tp_repr, (void*)PyIOSocket_repr},
|
|
273
|
+
{Py_tp_getset, (void*)PyIOSocket_properties},
|
|
274
|
+
{Py_tp_methods, (void*)PyIOSocket_methods},
|
|
275
|
+
{Py_tp_new, nullptr},
|
|
276
|
+
{0, nullptr},
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
static PyType_Spec PyIOSocket_spec = {
|
|
280
|
+
.name = "_ymq.BaseIOSocket",
|
|
281
|
+
.basicsize = sizeof(PyIOSocket),
|
|
282
|
+
.itemsize = 0,
|
|
283
|
+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION,
|
|
284
|
+
.slots = PyIOSocket_slots,
|
|
285
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// Python
|
|
4
|
+
#include "scaler/io/ymq/pymod_ymq/python.h"
|
|
5
|
+
|
|
6
|
+
// First-party
|
|
7
|
+
#include "scaler/io/ymq/pymod_ymq/bytes.h"
|
|
8
|
+
#include "scaler/io/ymq/pymod_ymq/ymq.h"
|
|
9
|
+
|
|
10
|
+
struct PyMessage {
|
|
11
|
+
PyObject_HEAD;
|
|
12
|
+
OwnedPyObject<PyBytesYMQ> address; // Address of the message; can be None
|
|
13
|
+
OwnedPyObject<PyBytesYMQ> payload; // Payload of the message
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
extern "C" {
|
|
17
|
+
|
|
18
|
+
static int PyMessage_init(PyMessage* self, PyObject* args, PyObject* kwds)
|
|
19
|
+
{
|
|
20
|
+
auto state = YMQStateFromSelf((PyObject*)self);
|
|
21
|
+
if (!state)
|
|
22
|
+
return -1;
|
|
23
|
+
|
|
24
|
+
PyObject* address = nullptr;
|
|
25
|
+
PyObject* payload = nullptr;
|
|
26
|
+
const char* keywords[] = {"address", "payload", nullptr};
|
|
27
|
+
if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", (char**)keywords, &address, &payload))
|
|
28
|
+
return -1;
|
|
29
|
+
|
|
30
|
+
// address can be None, which means the message has no address
|
|
31
|
+
// check if the address and payload are of type PyBytesYMQ
|
|
32
|
+
if (PyObject_IsInstance(address, *state->PyBytesYMQType)) {
|
|
33
|
+
self->address = OwnedPyObject<PyBytesYMQ>::fromBorrowed((PyBytesYMQ*)address);
|
|
34
|
+
} else if (address == Py_None) {
|
|
35
|
+
self->address = OwnedPyObject<PyBytesYMQ>::none();
|
|
36
|
+
} else {
|
|
37
|
+
OwnedPyObject args = PyTuple_Pack(1, address);
|
|
38
|
+
self->address = (PyBytesYMQ*)PyObject_CallObject(*state->PyBytesYMQType, *args);
|
|
39
|
+
|
|
40
|
+
if (!self->address)
|
|
41
|
+
return -1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (PyObject_IsInstance(payload, *state->PyBytesYMQType)) {
|
|
45
|
+
self->payload = OwnedPyObject<PyBytesYMQ>::fromBorrowed((PyBytesYMQ*)payload);
|
|
46
|
+
} else {
|
|
47
|
+
OwnedPyObject args = PyTuple_Pack(1, payload);
|
|
48
|
+
self->payload = (PyBytesYMQ*)PyObject_CallObject(*state->PyBytesYMQType, *args);
|
|
49
|
+
|
|
50
|
+
if (!self->payload) {
|
|
51
|
+
return -1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
static void PyMessage_dealloc(PyMessage* self)
|
|
59
|
+
{
|
|
60
|
+
try {
|
|
61
|
+
self->address.~OwnedPyObject();
|
|
62
|
+
self->payload.~OwnedPyObject();
|
|
63
|
+
} catch (...) {
|
|
64
|
+
PyErr_SetString(PyExc_RuntimeError, "Failed to deallocate Message");
|
|
65
|
+
PyErr_WriteUnraisable((PyObject*)self);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
auto* tp = Py_TYPE(self);
|
|
69
|
+
tp->tp_free(self);
|
|
70
|
+
Py_DECREF(tp);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static PyObject* PyMessage_repr(PyMessage* self)
|
|
74
|
+
{
|
|
75
|
+
return PyUnicode_FromFormat("<Message address=%R payload=%R>", *self->address, *self->payload);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
static PyMemberDef PyMessage_members[] = {
|
|
80
|
+
{"address", T_OBJECT, offsetof(PyMessage, address), 0, PyDoc_STR("the address of the message")},
|
|
81
|
+
{"payload", T_OBJECT, offsetof(PyMessage, payload), 0, PyDoc_STR("the payload of the message")},
|
|
82
|
+
{nullptr},
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
static PyType_Slot PyMessage_slots[] = {
|
|
86
|
+
{Py_tp_init, (void*)PyMessage_init},
|
|
87
|
+
{Py_tp_dealloc, (void*)PyMessage_dealloc},
|
|
88
|
+
{Py_tp_repr, (void*)PyMessage_repr},
|
|
89
|
+
{Py_tp_members, (void*)PyMessage_members},
|
|
90
|
+
{0, nullptr},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
static PyType_Spec PyMessage_spec = {
|
|
94
|
+
.name = "_ymq.Message",
|
|
95
|
+
.basicsize = sizeof(PyMessage),
|
|
96
|
+
.itemsize = 0,
|
|
97
|
+
.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE,
|
|
98
|
+
.slots = PyMessage_slots,
|
|
99
|
+
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
// Python
|
|
2
|
+
#pragma once
|
|
3
|
+
#define PY_SSIZE_T_CLEAN
|
|
4
|
+
#include <Python.h>
|
|
5
|
+
#include <structmember.h>
|
|
6
|
+
|
|
7
|
+
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 8
|
|
8
|
+
static inline PyObject* Py_NewRef(PyObject* obj)
|
|
9
|
+
{
|
|
10
|
+
Py_INCREF(obj);
|
|
11
|
+
return obj;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static inline PyObject* Py_XNewRef(PyObject* obj)
|
|
15
|
+
{
|
|
16
|
+
Py_XINCREF(obj);
|
|
17
|
+
return obj;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// This is a very dirty hack, we basically place the raw pointer to this dict when init,
|
|
21
|
+
// see scaler/io/ymq/pymod_ymq/ymq.h for more detail
|
|
22
|
+
PyObject* PyType_GetModule(PyTypeObject* type)
|
|
23
|
+
{
|
|
24
|
+
return PyObject_GetAttrString((PyObject*)(type), "__module_object__");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
PyObject* PyType_GetModuleState(PyTypeObject* type)
|
|
28
|
+
{
|
|
29
|
+
PyObject* module = PyObject_GetAttrString((PyObject*)(type), "__module_object__");
|
|
30
|
+
if (!module)
|
|
31
|
+
return nullptr;
|
|
32
|
+
void* state = PyModule_GetState(module);
|
|
33
|
+
Py_DECREF(module);
|
|
34
|
+
return (PyObject*)state;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
static inline PyObject* PyObject_CallNoArgs(PyObject* callable)
|
|
38
|
+
{
|
|
39
|
+
return PyObject_Call(callable, PyTuple_New(0), nullptr);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static inline int PyModule_AddObjectRef(PyObject* mod, const char* name, PyObject* value)
|
|
43
|
+
{
|
|
44
|
+
Py_INCREF(value); // Since PyModule_AddObject steals a ref, we balance it
|
|
45
|
+
return PyModule_AddObject(mod, name, value);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static inline PyObject* PyType_FromModuleAndSpec(PyObject* pymodule, PyType_Spec* spec, PyObject* bases)
|
|
49
|
+
{
|
|
50
|
+
(void)pymodule;
|
|
51
|
+
if (!bases) {
|
|
52
|
+
bases = PyTuple_Pack(1, (PyObject*)&PyBaseObject_Type);
|
|
53
|
+
if (bases) {
|
|
54
|
+
PyObject* res = PyType_FromSpecWithBases(spec, bases);
|
|
55
|
+
Py_DECREF(bases); // avoid leak
|
|
56
|
+
return res;
|
|
57
|
+
}
|
|
58
|
+
PyObject* res = PyType_FromSpecWithBases(spec, bases);
|
|
59
|
+
return res;
|
|
60
|
+
}
|
|
61
|
+
return PyType_FromSpecWithBases(spec, bases);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#define Py_TPFLAGS_IMMUTABLETYPE (0)
|
|
65
|
+
#define Py_TPFLAGS_DISALLOW_INSTANTIATION (0)
|
|
66
|
+
#endif
|
|
67
|
+
|
|
68
|
+
// NOTE: We define this no matter what version of Python we use.
|
|
69
|
+
// an owned handle to a PyObject with automatic reference counting via RAII
|
|
70
|
+
template <typename T = PyObject>
|
|
71
|
+
class OwnedPyObject {
|
|
72
|
+
public:
|
|
73
|
+
OwnedPyObject(): _ptr(nullptr) {}
|
|
74
|
+
|
|
75
|
+
// steals a reference
|
|
76
|
+
OwnedPyObject(T* ptr): _ptr(ptr) {}
|
|
77
|
+
|
|
78
|
+
OwnedPyObject(const OwnedPyObject& other) { this->_ptr = (T*)Py_XNewRef((PyObject*)other._ptr); }
|
|
79
|
+
OwnedPyObject(OwnedPyObject&& other) noexcept: _ptr(other._ptr) { other._ptr = nullptr; }
|
|
80
|
+
OwnedPyObject& operator=(const OwnedPyObject& other)
|
|
81
|
+
{
|
|
82
|
+
if (this == &other)
|
|
83
|
+
return *this;
|
|
84
|
+
|
|
85
|
+
this->free();
|
|
86
|
+
this->_ptr = (T*)Py_XNewRef((PyObject*)other._ptr);
|
|
87
|
+
return *this;
|
|
88
|
+
}
|
|
89
|
+
OwnedPyObject& operator=(OwnedPyObject&& other) noexcept
|
|
90
|
+
{
|
|
91
|
+
if (this == &other)
|
|
92
|
+
return *this;
|
|
93
|
+
|
|
94
|
+
this->free();
|
|
95
|
+
this->_ptr = other._ptr;
|
|
96
|
+
other._ptr = nullptr;
|
|
97
|
+
return *this;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
~OwnedPyObject() { this->free(); }
|
|
101
|
+
|
|
102
|
+
// creates a new OwnedPyObject from a borrowed reference
|
|
103
|
+
static OwnedPyObject fromBorrowed(T* ptr) { return OwnedPyObject((T*)Py_XNewRef((PyObject*)ptr)); }
|
|
104
|
+
|
|
105
|
+
// convenience method for creating an OwnedPyObject that holds Py_None
|
|
106
|
+
static OwnedPyObject none() { return OwnedPyObject((T*)Py_NewRef(Py_None)); }
|
|
107
|
+
|
|
108
|
+
bool is_none() const { return (PyObject*)_ptr == Py_None; }
|
|
109
|
+
|
|
110
|
+
// takes the pointer out of the OwnedPyObject
|
|
111
|
+
// without decrementing the reference count
|
|
112
|
+
// use this to transfer ownership to C code
|
|
113
|
+
T* take()
|
|
114
|
+
{
|
|
115
|
+
T* ptr = this->_ptr;
|
|
116
|
+
this->_ptr = nullptr;
|
|
117
|
+
return ptr;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
void forget() { this->_ptr = nullptr; }
|
|
121
|
+
|
|
122
|
+
// operator T*() const { return _ptr; }
|
|
123
|
+
explicit operator bool() const { return _ptr != nullptr; }
|
|
124
|
+
bool operator!() const { return _ptr == nullptr; }
|
|
125
|
+
|
|
126
|
+
T* operator->() const { return _ptr; }
|
|
127
|
+
T* operator*() const { return _ptr; }
|
|
128
|
+
|
|
129
|
+
private:
|
|
130
|
+
T* _ptr;
|
|
131
|
+
|
|
132
|
+
void free()
|
|
133
|
+
{
|
|
134
|
+
if (!_ptr)
|
|
135
|
+
return;
|
|
136
|
+
|
|
137
|
+
if (!PyGILState_Check())
|
|
138
|
+
return;
|
|
139
|
+
|
|
140
|
+
Py_CLEAR(_ptr);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 8
|
|
145
|
+
static inline PyObject* PyObject_CallOneArg(PyObject* callable, PyObject* arg)
|
|
146
|
+
{
|
|
147
|
+
OwnedPyObject<> args = PyTuple_Pack(1, arg);
|
|
148
|
+
if (!args)
|
|
149
|
+
return nullptr;
|
|
150
|
+
PyObject* result = PyObject_Call(callable, *args, nullptr);
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
#endif
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#include "scaler/io/ymq/pymod_ymq/ymq.h"
|
|
2
|
+
|
|
3
|
+
#include <cstdlib>
|
|
4
|
+
|
|
5
|
+
#include "scaler/io/ymq/error.h"
|
|
6
|
+
|
|
7
|
+
inline void ymqUnrecoverableError(scaler::ymq::Error e)
|
|
8
|
+
{
|
|
9
|
+
PyGILState_STATE gstate = PyGILState_Ensure();
|
|
10
|
+
(void)gstate; // silent the warning
|
|
11
|
+
PyErr_SetString(PyExc_SystemExit, e.what());
|
|
12
|
+
PyErr_WriteUnraisable(nullptr);
|
|
13
|
+
Py_Finalize();
|
|
14
|
+
|
|
15
|
+
std::exit(EXIT_FAILURE);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
PyMODINIT_FUNC PyInit__ymq(void)
|
|
19
|
+
{
|
|
20
|
+
unrecoverableErrorFunctionHookPtr = ymqUnrecoverableError;
|
|
21
|
+
|
|
22
|
+
return PyModuleDef_Init(&YMQ_module);
|
|
23
|
+
}
|