opengris-scaler 1.12.7__cp38-cp38-musllinux_1_2_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.

Files changed (234) hide show
  1. opengris_scaler-1.12.7.dist-info/METADATA +729 -0
  2. opengris_scaler-1.12.7.dist-info/RECORD +234 -0
  3. opengris_scaler-1.12.7.dist-info/WHEEL +5 -0
  4. opengris_scaler-1.12.7.dist-info/entry_points.txt +9 -0
  5. opengris_scaler-1.12.7.dist-info/licenses/LICENSE +201 -0
  6. opengris_scaler-1.12.7.dist-info/licenses/LICENSE.spdx +7 -0
  7. opengris_scaler-1.12.7.dist-info/licenses/NOTICE +8 -0
  8. opengris_scaler.libs/libcapnp-1-61c06778.1.0.so +0 -0
  9. opengris_scaler.libs/libgcc_s-2298274a.so.1 +0 -0
  10. opengris_scaler.libs/libkj-1-21b63b70.1.0.so +0 -0
  11. opengris_scaler.libs/libstdc++-08d5c7eb.so.6.0.33 +0 -0
  12. scaler/CMakeLists.txt +11 -0
  13. scaler/__init__.py +14 -0
  14. scaler/about.py +5 -0
  15. scaler/client/__init__.py +0 -0
  16. scaler/client/agent/__init__.py +0 -0
  17. scaler/client/agent/client_agent.py +210 -0
  18. scaler/client/agent/disconnect_manager.py +27 -0
  19. scaler/client/agent/future_manager.py +112 -0
  20. scaler/client/agent/heartbeat_manager.py +74 -0
  21. scaler/client/agent/mixins.py +89 -0
  22. scaler/client/agent/object_manager.py +98 -0
  23. scaler/client/agent/task_manager.py +64 -0
  24. scaler/client/client.py +635 -0
  25. scaler/client/future.py +252 -0
  26. scaler/client/object_buffer.py +129 -0
  27. scaler/client/object_reference.py +25 -0
  28. scaler/client/serializer/__init__.py +0 -0
  29. scaler/client/serializer/default.py +16 -0
  30. scaler/client/serializer/mixins.py +38 -0
  31. scaler/cluster/__init__.py +0 -0
  32. scaler/cluster/cluster.py +115 -0
  33. scaler/cluster/combo.py +148 -0
  34. scaler/cluster/object_storage_server.py +45 -0
  35. scaler/cluster/scheduler.py +83 -0
  36. scaler/config/__init__.py +0 -0
  37. scaler/config/defaults.py +87 -0
  38. scaler/config/loader.py +95 -0
  39. scaler/config/mixins.py +15 -0
  40. scaler/config/section/__init__.py +0 -0
  41. scaler/config/section/cluster.py +56 -0
  42. scaler/config/section/native_worker_adapter.py +44 -0
  43. scaler/config/section/object_storage_server.py +7 -0
  44. scaler/config/section/scheduler.py +53 -0
  45. scaler/config/section/symphony_worker_adapter.py +47 -0
  46. scaler/config/section/top.py +13 -0
  47. scaler/config/section/webui.py +16 -0
  48. scaler/config/types/__init__.py +0 -0
  49. scaler/config/types/object_storage_server.py +45 -0
  50. scaler/config/types/worker.py +57 -0
  51. scaler/config/types/zmq.py +79 -0
  52. scaler/entry_points/__init__.py +0 -0
  53. scaler/entry_points/cluster.py +133 -0
  54. scaler/entry_points/object_storage_server.py +41 -0
  55. scaler/entry_points/scheduler.py +135 -0
  56. scaler/entry_points/top.py +286 -0
  57. scaler/entry_points/webui.py +26 -0
  58. scaler/entry_points/worker_adapter_native.py +137 -0
  59. scaler/entry_points/worker_adapter_symphony.py +102 -0
  60. scaler/io/__init__.py +0 -0
  61. scaler/io/async_binder.py +85 -0
  62. scaler/io/async_connector.py +95 -0
  63. scaler/io/async_object_storage_connector.py +185 -0
  64. scaler/io/mixins.py +154 -0
  65. scaler/io/sync_connector.py +68 -0
  66. scaler/io/sync_object_storage_connector.py +185 -0
  67. scaler/io/sync_subscriber.py +83 -0
  68. scaler/io/utility.py +31 -0
  69. scaler/io/ymq/CMakeLists.txt +98 -0
  70. scaler/io/ymq/__init__.py +0 -0
  71. scaler/io/ymq/_ymq.pyi +96 -0
  72. scaler/io/ymq/_ymq.so +0 -0
  73. scaler/io/ymq/bytes.h +114 -0
  74. scaler/io/ymq/common.h +29 -0
  75. scaler/io/ymq/configuration.h +60 -0
  76. scaler/io/ymq/epoll_context.cpp +185 -0
  77. scaler/io/ymq/epoll_context.h +85 -0
  78. scaler/io/ymq/error.h +132 -0
  79. scaler/io/ymq/event_loop.h +55 -0
  80. scaler/io/ymq/event_loop_thread.cpp +64 -0
  81. scaler/io/ymq/event_loop_thread.h +46 -0
  82. scaler/io/ymq/event_manager.h +81 -0
  83. scaler/io/ymq/file_descriptor.h +203 -0
  84. scaler/io/ymq/interruptive_concurrent_queue.h +169 -0
  85. scaler/io/ymq/io_context.cpp +98 -0
  86. scaler/io/ymq/io_context.h +44 -0
  87. scaler/io/ymq/io_socket.cpp +299 -0
  88. scaler/io/ymq/io_socket.h +121 -0
  89. scaler/io/ymq/iocp_context.cpp +102 -0
  90. scaler/io/ymq/iocp_context.h +83 -0
  91. scaler/io/ymq/logging.h +163 -0
  92. scaler/io/ymq/message.h +15 -0
  93. scaler/io/ymq/message_connection.h +16 -0
  94. scaler/io/ymq/message_connection_tcp.cpp +672 -0
  95. scaler/io/ymq/message_connection_tcp.h +96 -0
  96. scaler/io/ymq/network_utils.h +179 -0
  97. scaler/io/ymq/pymod_ymq/bytes.h +113 -0
  98. scaler/io/ymq/pymod_ymq/exception.h +124 -0
  99. scaler/io/ymq/pymod_ymq/gil.h +15 -0
  100. scaler/io/ymq/pymod_ymq/io_context.h +166 -0
  101. scaler/io/ymq/pymod_ymq/io_socket.h +285 -0
  102. scaler/io/ymq/pymod_ymq/message.h +99 -0
  103. scaler/io/ymq/pymod_ymq/python.h +153 -0
  104. scaler/io/ymq/pymod_ymq/ymq.cpp +23 -0
  105. scaler/io/ymq/pymod_ymq/ymq.h +357 -0
  106. scaler/io/ymq/readme.md +114 -0
  107. scaler/io/ymq/simple_interface.cpp +80 -0
  108. scaler/io/ymq/simple_interface.h +24 -0
  109. scaler/io/ymq/tcp_client.cpp +367 -0
  110. scaler/io/ymq/tcp_client.h +75 -0
  111. scaler/io/ymq/tcp_operations.h +41 -0
  112. scaler/io/ymq/tcp_server.cpp +410 -0
  113. scaler/io/ymq/tcp_server.h +79 -0
  114. scaler/io/ymq/third_party/concurrentqueue.h +3747 -0
  115. scaler/io/ymq/timed_queue.h +272 -0
  116. scaler/io/ymq/timestamp.h +102 -0
  117. scaler/io/ymq/typedefs.h +20 -0
  118. scaler/io/ymq/utils.h +34 -0
  119. scaler/io/ymq/ymq.py +130 -0
  120. scaler/object_storage/CMakeLists.txt +50 -0
  121. scaler/object_storage/__init__.py +0 -0
  122. scaler/object_storage/constants.h +11 -0
  123. scaler/object_storage/defs.h +14 -0
  124. scaler/object_storage/io_helper.cpp +44 -0
  125. scaler/object_storage/io_helper.h +9 -0
  126. scaler/object_storage/message.cpp +56 -0
  127. scaler/object_storage/message.h +130 -0
  128. scaler/object_storage/object_manager.cpp +126 -0
  129. scaler/object_storage/object_manager.h +52 -0
  130. scaler/object_storage/object_storage_server.cpp +359 -0
  131. scaler/object_storage/object_storage_server.h +126 -0
  132. scaler/object_storage/object_storage_server.so +0 -0
  133. scaler/object_storage/pymod_object_storage_server.cpp +104 -0
  134. scaler/protocol/__init__.py +0 -0
  135. scaler/protocol/capnp/__init__.py +0 -0
  136. scaler/protocol/capnp/_python.py +6 -0
  137. scaler/protocol/capnp/common.capnp +63 -0
  138. scaler/protocol/capnp/message.capnp +216 -0
  139. scaler/protocol/capnp/object_storage.capnp +52 -0
  140. scaler/protocol/capnp/status.capnp +73 -0
  141. scaler/protocol/introduction.md +105 -0
  142. scaler/protocol/python/__init__.py +0 -0
  143. scaler/protocol/python/common.py +135 -0
  144. scaler/protocol/python/message.py +726 -0
  145. scaler/protocol/python/mixins.py +13 -0
  146. scaler/protocol/python/object_storage.py +118 -0
  147. scaler/protocol/python/status.py +279 -0
  148. scaler/protocol/worker.md +228 -0
  149. scaler/scheduler/__init__.py +0 -0
  150. scaler/scheduler/allocate_policy/__init__.py +0 -0
  151. scaler/scheduler/allocate_policy/allocate_policy.py +9 -0
  152. scaler/scheduler/allocate_policy/capability_allocate_policy.py +280 -0
  153. scaler/scheduler/allocate_policy/even_load_allocate_policy.py +159 -0
  154. scaler/scheduler/allocate_policy/mixins.py +55 -0
  155. scaler/scheduler/controllers/__init__.py +0 -0
  156. scaler/scheduler/controllers/balance_controller.py +65 -0
  157. scaler/scheduler/controllers/client_controller.py +131 -0
  158. scaler/scheduler/controllers/config_controller.py +31 -0
  159. scaler/scheduler/controllers/graph_controller.py +424 -0
  160. scaler/scheduler/controllers/information_controller.py +81 -0
  161. scaler/scheduler/controllers/mixins.py +201 -0
  162. scaler/scheduler/controllers/object_controller.py +147 -0
  163. scaler/scheduler/controllers/scaling_controller.py +86 -0
  164. scaler/scheduler/controllers/task_controller.py +373 -0
  165. scaler/scheduler/controllers/worker_controller.py +168 -0
  166. scaler/scheduler/object_usage/__init__.py +0 -0
  167. scaler/scheduler/object_usage/object_tracker.py +131 -0
  168. scaler/scheduler/scheduler.py +253 -0
  169. scaler/scheduler/task/__init__.py +0 -0
  170. scaler/scheduler/task/task_state_machine.py +92 -0
  171. scaler/scheduler/task/task_state_manager.py +61 -0
  172. scaler/ui/__init__.py +0 -0
  173. scaler/ui/constants.py +9 -0
  174. scaler/ui/live_display.py +118 -0
  175. scaler/ui/memory_window.py +146 -0
  176. scaler/ui/setting_page.py +47 -0
  177. scaler/ui/task_graph.py +370 -0
  178. scaler/ui/task_log.py +83 -0
  179. scaler/ui/utility.py +35 -0
  180. scaler/ui/webui.py +125 -0
  181. scaler/ui/worker_processors.py +85 -0
  182. scaler/utility/__init__.py +0 -0
  183. scaler/utility/debug.py +19 -0
  184. scaler/utility/event_list.py +63 -0
  185. scaler/utility/event_loop.py +58 -0
  186. scaler/utility/exceptions.py +42 -0
  187. scaler/utility/formatter.py +44 -0
  188. scaler/utility/graph/__init__.py +0 -0
  189. scaler/utility/graph/optimization.py +27 -0
  190. scaler/utility/graph/topological_sorter.py +11 -0
  191. scaler/utility/graph/topological_sorter_graphblas.py +174 -0
  192. scaler/utility/identifiers.py +105 -0
  193. scaler/utility/logging/__init__.py +0 -0
  194. scaler/utility/logging/decorators.py +25 -0
  195. scaler/utility/logging/scoped_logger.py +33 -0
  196. scaler/utility/logging/utility.py +183 -0
  197. scaler/utility/many_to_many_dict.py +123 -0
  198. scaler/utility/metadata/__init__.py +0 -0
  199. scaler/utility/metadata/profile_result.py +31 -0
  200. scaler/utility/metadata/task_flags.py +30 -0
  201. scaler/utility/mixins.py +13 -0
  202. scaler/utility/network_util.py +7 -0
  203. scaler/utility/one_to_many_dict.py +72 -0
  204. scaler/utility/queues/__init__.py +0 -0
  205. scaler/utility/queues/async_indexed_queue.py +37 -0
  206. scaler/utility/queues/async_priority_queue.py +70 -0
  207. scaler/utility/queues/async_sorted_priority_queue.py +45 -0
  208. scaler/utility/queues/indexed_queue.py +114 -0
  209. scaler/utility/serialization.py +9 -0
  210. scaler/version.txt +1 -0
  211. scaler/worker/__init__.py +0 -0
  212. scaler/worker/agent/__init__.py +0 -0
  213. scaler/worker/agent/heartbeat_manager.py +107 -0
  214. scaler/worker/agent/mixins.py +137 -0
  215. scaler/worker/agent/processor/__init__.py +0 -0
  216. scaler/worker/agent/processor/object_cache.py +107 -0
  217. scaler/worker/agent/processor/processor.py +279 -0
  218. scaler/worker/agent/processor/streaming_buffer.py +28 -0
  219. scaler/worker/agent/processor_holder.py +145 -0
  220. scaler/worker/agent/processor_manager.py +365 -0
  221. scaler/worker/agent/profiling_manager.py +109 -0
  222. scaler/worker/agent/task_manager.py +150 -0
  223. scaler/worker/agent/timeout_manager.py +19 -0
  224. scaler/worker/preload.py +84 -0
  225. scaler/worker/worker.py +264 -0
  226. scaler/worker_adapter/__init__.py +0 -0
  227. scaler/worker_adapter/native.py +154 -0
  228. scaler/worker_adapter/symphony/__init__.py +0 -0
  229. scaler/worker_adapter/symphony/callback.py +45 -0
  230. scaler/worker_adapter/symphony/heartbeat_manager.py +79 -0
  231. scaler/worker_adapter/symphony/message.py +24 -0
  232. scaler/worker_adapter/symphony/task_manager.py +288 -0
  233. scaler/worker_adapter/symphony/worker.py +205 -0
  234. 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
+ }