opengris-scaler 1.12.7__cp311-cp311-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.

Files changed (232) hide show
  1. opengris_scaler-1.12.7.dist-info/METADATA +729 -0
  2. opengris_scaler-1.12.7.dist-info/RECORD +232 -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-b787335c.1.0.so +0 -0
  9. opengris_scaler.libs/libkj-1-094aa318.1.0.so +0 -0
  10. scaler/CMakeLists.txt +11 -0
  11. scaler/__init__.py +14 -0
  12. scaler/about.py +5 -0
  13. scaler/client/__init__.py +0 -0
  14. scaler/client/agent/__init__.py +0 -0
  15. scaler/client/agent/client_agent.py +210 -0
  16. scaler/client/agent/disconnect_manager.py +27 -0
  17. scaler/client/agent/future_manager.py +112 -0
  18. scaler/client/agent/heartbeat_manager.py +74 -0
  19. scaler/client/agent/mixins.py +89 -0
  20. scaler/client/agent/object_manager.py +98 -0
  21. scaler/client/agent/task_manager.py +64 -0
  22. scaler/client/client.py +635 -0
  23. scaler/client/future.py +252 -0
  24. scaler/client/object_buffer.py +129 -0
  25. scaler/client/object_reference.py +25 -0
  26. scaler/client/serializer/__init__.py +0 -0
  27. scaler/client/serializer/default.py +16 -0
  28. scaler/client/serializer/mixins.py +38 -0
  29. scaler/cluster/__init__.py +0 -0
  30. scaler/cluster/cluster.py +115 -0
  31. scaler/cluster/combo.py +148 -0
  32. scaler/cluster/object_storage_server.py +45 -0
  33. scaler/cluster/scheduler.py +83 -0
  34. scaler/config/__init__.py +0 -0
  35. scaler/config/defaults.py +87 -0
  36. scaler/config/loader.py +95 -0
  37. scaler/config/mixins.py +15 -0
  38. scaler/config/section/__init__.py +0 -0
  39. scaler/config/section/cluster.py +56 -0
  40. scaler/config/section/native_worker_adapter.py +44 -0
  41. scaler/config/section/object_storage_server.py +7 -0
  42. scaler/config/section/scheduler.py +53 -0
  43. scaler/config/section/symphony_worker_adapter.py +47 -0
  44. scaler/config/section/top.py +13 -0
  45. scaler/config/section/webui.py +16 -0
  46. scaler/config/types/__init__.py +0 -0
  47. scaler/config/types/object_storage_server.py +45 -0
  48. scaler/config/types/worker.py +57 -0
  49. scaler/config/types/zmq.py +79 -0
  50. scaler/entry_points/__init__.py +0 -0
  51. scaler/entry_points/cluster.py +133 -0
  52. scaler/entry_points/object_storage_server.py +41 -0
  53. scaler/entry_points/scheduler.py +135 -0
  54. scaler/entry_points/top.py +286 -0
  55. scaler/entry_points/webui.py +26 -0
  56. scaler/entry_points/worker_adapter_native.py +137 -0
  57. scaler/entry_points/worker_adapter_symphony.py +102 -0
  58. scaler/io/__init__.py +0 -0
  59. scaler/io/async_binder.py +85 -0
  60. scaler/io/async_connector.py +95 -0
  61. scaler/io/async_object_storage_connector.py +185 -0
  62. scaler/io/mixins.py +154 -0
  63. scaler/io/sync_connector.py +68 -0
  64. scaler/io/sync_object_storage_connector.py +185 -0
  65. scaler/io/sync_subscriber.py +83 -0
  66. scaler/io/utility.py +31 -0
  67. scaler/io/ymq/CMakeLists.txt +98 -0
  68. scaler/io/ymq/__init__.py +0 -0
  69. scaler/io/ymq/_ymq.pyi +96 -0
  70. scaler/io/ymq/_ymq.so +0 -0
  71. scaler/io/ymq/bytes.h +114 -0
  72. scaler/io/ymq/common.h +29 -0
  73. scaler/io/ymq/configuration.h +60 -0
  74. scaler/io/ymq/epoll_context.cpp +185 -0
  75. scaler/io/ymq/epoll_context.h +85 -0
  76. scaler/io/ymq/error.h +132 -0
  77. scaler/io/ymq/event_loop.h +55 -0
  78. scaler/io/ymq/event_loop_thread.cpp +64 -0
  79. scaler/io/ymq/event_loop_thread.h +46 -0
  80. scaler/io/ymq/event_manager.h +81 -0
  81. scaler/io/ymq/file_descriptor.h +203 -0
  82. scaler/io/ymq/interruptive_concurrent_queue.h +169 -0
  83. scaler/io/ymq/io_context.cpp +98 -0
  84. scaler/io/ymq/io_context.h +44 -0
  85. scaler/io/ymq/io_socket.cpp +299 -0
  86. scaler/io/ymq/io_socket.h +121 -0
  87. scaler/io/ymq/iocp_context.cpp +102 -0
  88. scaler/io/ymq/iocp_context.h +83 -0
  89. scaler/io/ymq/logging.h +163 -0
  90. scaler/io/ymq/message.h +15 -0
  91. scaler/io/ymq/message_connection.h +16 -0
  92. scaler/io/ymq/message_connection_tcp.cpp +672 -0
  93. scaler/io/ymq/message_connection_tcp.h +96 -0
  94. scaler/io/ymq/network_utils.h +179 -0
  95. scaler/io/ymq/pymod_ymq/bytes.h +113 -0
  96. scaler/io/ymq/pymod_ymq/exception.h +124 -0
  97. scaler/io/ymq/pymod_ymq/gil.h +15 -0
  98. scaler/io/ymq/pymod_ymq/io_context.h +166 -0
  99. scaler/io/ymq/pymod_ymq/io_socket.h +285 -0
  100. scaler/io/ymq/pymod_ymq/message.h +99 -0
  101. scaler/io/ymq/pymod_ymq/python.h +153 -0
  102. scaler/io/ymq/pymod_ymq/ymq.cpp +23 -0
  103. scaler/io/ymq/pymod_ymq/ymq.h +357 -0
  104. scaler/io/ymq/readme.md +114 -0
  105. scaler/io/ymq/simple_interface.cpp +80 -0
  106. scaler/io/ymq/simple_interface.h +24 -0
  107. scaler/io/ymq/tcp_client.cpp +367 -0
  108. scaler/io/ymq/tcp_client.h +75 -0
  109. scaler/io/ymq/tcp_operations.h +41 -0
  110. scaler/io/ymq/tcp_server.cpp +410 -0
  111. scaler/io/ymq/tcp_server.h +79 -0
  112. scaler/io/ymq/third_party/concurrentqueue.h +3747 -0
  113. scaler/io/ymq/timed_queue.h +272 -0
  114. scaler/io/ymq/timestamp.h +102 -0
  115. scaler/io/ymq/typedefs.h +20 -0
  116. scaler/io/ymq/utils.h +34 -0
  117. scaler/io/ymq/ymq.py +130 -0
  118. scaler/object_storage/CMakeLists.txt +50 -0
  119. scaler/object_storage/__init__.py +0 -0
  120. scaler/object_storage/constants.h +11 -0
  121. scaler/object_storage/defs.h +14 -0
  122. scaler/object_storage/io_helper.cpp +44 -0
  123. scaler/object_storage/io_helper.h +9 -0
  124. scaler/object_storage/message.cpp +56 -0
  125. scaler/object_storage/message.h +130 -0
  126. scaler/object_storage/object_manager.cpp +126 -0
  127. scaler/object_storage/object_manager.h +52 -0
  128. scaler/object_storage/object_storage_server.cpp +359 -0
  129. scaler/object_storage/object_storage_server.h +126 -0
  130. scaler/object_storage/object_storage_server.so +0 -0
  131. scaler/object_storage/pymod_object_storage_server.cpp +104 -0
  132. scaler/protocol/__init__.py +0 -0
  133. scaler/protocol/capnp/__init__.py +0 -0
  134. scaler/protocol/capnp/_python.py +6 -0
  135. scaler/protocol/capnp/common.capnp +63 -0
  136. scaler/protocol/capnp/message.capnp +216 -0
  137. scaler/protocol/capnp/object_storage.capnp +52 -0
  138. scaler/protocol/capnp/status.capnp +73 -0
  139. scaler/protocol/introduction.md +105 -0
  140. scaler/protocol/python/__init__.py +0 -0
  141. scaler/protocol/python/common.py +135 -0
  142. scaler/protocol/python/message.py +726 -0
  143. scaler/protocol/python/mixins.py +13 -0
  144. scaler/protocol/python/object_storage.py +118 -0
  145. scaler/protocol/python/status.py +279 -0
  146. scaler/protocol/worker.md +228 -0
  147. scaler/scheduler/__init__.py +0 -0
  148. scaler/scheduler/allocate_policy/__init__.py +0 -0
  149. scaler/scheduler/allocate_policy/allocate_policy.py +9 -0
  150. scaler/scheduler/allocate_policy/capability_allocate_policy.py +280 -0
  151. scaler/scheduler/allocate_policy/even_load_allocate_policy.py +159 -0
  152. scaler/scheduler/allocate_policy/mixins.py +55 -0
  153. scaler/scheduler/controllers/__init__.py +0 -0
  154. scaler/scheduler/controllers/balance_controller.py +65 -0
  155. scaler/scheduler/controllers/client_controller.py +131 -0
  156. scaler/scheduler/controllers/config_controller.py +31 -0
  157. scaler/scheduler/controllers/graph_controller.py +424 -0
  158. scaler/scheduler/controllers/information_controller.py +81 -0
  159. scaler/scheduler/controllers/mixins.py +201 -0
  160. scaler/scheduler/controllers/object_controller.py +147 -0
  161. scaler/scheduler/controllers/scaling_controller.py +86 -0
  162. scaler/scheduler/controllers/task_controller.py +373 -0
  163. scaler/scheduler/controllers/worker_controller.py +168 -0
  164. scaler/scheduler/object_usage/__init__.py +0 -0
  165. scaler/scheduler/object_usage/object_tracker.py +131 -0
  166. scaler/scheduler/scheduler.py +253 -0
  167. scaler/scheduler/task/__init__.py +0 -0
  168. scaler/scheduler/task/task_state_machine.py +92 -0
  169. scaler/scheduler/task/task_state_manager.py +61 -0
  170. scaler/ui/__init__.py +0 -0
  171. scaler/ui/constants.py +9 -0
  172. scaler/ui/live_display.py +118 -0
  173. scaler/ui/memory_window.py +146 -0
  174. scaler/ui/setting_page.py +47 -0
  175. scaler/ui/task_graph.py +370 -0
  176. scaler/ui/task_log.py +83 -0
  177. scaler/ui/utility.py +35 -0
  178. scaler/ui/webui.py +125 -0
  179. scaler/ui/worker_processors.py +85 -0
  180. scaler/utility/__init__.py +0 -0
  181. scaler/utility/debug.py +19 -0
  182. scaler/utility/event_list.py +63 -0
  183. scaler/utility/event_loop.py +58 -0
  184. scaler/utility/exceptions.py +42 -0
  185. scaler/utility/formatter.py +44 -0
  186. scaler/utility/graph/__init__.py +0 -0
  187. scaler/utility/graph/optimization.py +27 -0
  188. scaler/utility/graph/topological_sorter.py +11 -0
  189. scaler/utility/graph/topological_sorter_graphblas.py +174 -0
  190. scaler/utility/identifiers.py +105 -0
  191. scaler/utility/logging/__init__.py +0 -0
  192. scaler/utility/logging/decorators.py +25 -0
  193. scaler/utility/logging/scoped_logger.py +33 -0
  194. scaler/utility/logging/utility.py +183 -0
  195. scaler/utility/many_to_many_dict.py +123 -0
  196. scaler/utility/metadata/__init__.py +0 -0
  197. scaler/utility/metadata/profile_result.py +31 -0
  198. scaler/utility/metadata/task_flags.py +30 -0
  199. scaler/utility/mixins.py +13 -0
  200. scaler/utility/network_util.py +7 -0
  201. scaler/utility/one_to_many_dict.py +72 -0
  202. scaler/utility/queues/__init__.py +0 -0
  203. scaler/utility/queues/async_indexed_queue.py +37 -0
  204. scaler/utility/queues/async_priority_queue.py +70 -0
  205. scaler/utility/queues/async_sorted_priority_queue.py +45 -0
  206. scaler/utility/queues/indexed_queue.py +114 -0
  207. scaler/utility/serialization.py +9 -0
  208. scaler/version.txt +1 -0
  209. scaler/worker/__init__.py +0 -0
  210. scaler/worker/agent/__init__.py +0 -0
  211. scaler/worker/agent/heartbeat_manager.py +107 -0
  212. scaler/worker/agent/mixins.py +137 -0
  213. scaler/worker/agent/processor/__init__.py +0 -0
  214. scaler/worker/agent/processor/object_cache.py +107 -0
  215. scaler/worker/agent/processor/processor.py +279 -0
  216. scaler/worker/agent/processor/streaming_buffer.py +28 -0
  217. scaler/worker/agent/processor_holder.py +145 -0
  218. scaler/worker/agent/processor_manager.py +365 -0
  219. scaler/worker/agent/profiling_manager.py +109 -0
  220. scaler/worker/agent/task_manager.py +150 -0
  221. scaler/worker/agent/timeout_manager.py +19 -0
  222. scaler/worker/preload.py +84 -0
  223. scaler/worker/worker.py +264 -0
  224. scaler/worker_adapter/__init__.py +0 -0
  225. scaler/worker_adapter/native.py +154 -0
  226. scaler/worker_adapter/symphony/__init__.py +0 -0
  227. scaler/worker_adapter/symphony/callback.py +45 -0
  228. scaler/worker_adapter/symphony/heartbeat_manager.py +79 -0
  229. scaler/worker_adapter/symphony/message.py +24 -0
  230. scaler/worker_adapter/symphony/task_manager.py +288 -0
  231. scaler/worker_adapter/symphony/worker.py +205 -0
  232. scaler/worker_adapter/symphony/worker_adapter.py +142 -0
@@ -0,0 +1,96 @@
1
+ #pragma once
2
+
3
+ #include <deque>
4
+ #include <memory>
5
+ #include <optional>
6
+ #include <queue>
7
+
8
+ #include "scaler/io/ymq/configuration.h"
9
+ #include "scaler/io/ymq/io_socket.h"
10
+ #include "scaler/io/ymq/message_connection.h"
11
+ #include "scaler/io/ymq/tcp_operations.h"
12
+
13
+ namespace scaler {
14
+ namespace ymq {
15
+
16
+ class EventLoopThread;
17
+ class EventManager;
18
+
19
+ class MessageConnectionTCP: public MessageConnection {
20
+ public:
21
+ using SendMessageCallback = Configuration::SendMessageCallback;
22
+ using RecvMessageCallback = Configuration::RecvMessageCallback;
23
+
24
+ MessageConnectionTCP(
25
+ std::shared_ptr<EventLoopThread> eventLoopThread,
26
+ int connFd,
27
+ sockaddr localAddr,
28
+ sockaddr remoteAddr,
29
+ std::string localIOSocketIdentity,
30
+ bool responsibleForRetry,
31
+ std::shared_ptr<std::queue<RecvMessageCallback>> _pendingRecvMessageCallbacks) noexcept;
32
+
33
+ MessageConnectionTCP(
34
+ std::shared_ptr<EventLoopThread> eventLoopThread,
35
+ std::string localIOSocketIdentity,
36
+ std::string remoteIOSocketIdentity,
37
+ std::shared_ptr<std::queue<RecvMessageCallback>> _pendingRecvMessageCallbacks) noexcept;
38
+
39
+ ~MessageConnectionTCP() noexcept;
40
+
41
+ void onCreated();
42
+
43
+ void sendMessage(Message msg, SendMessageCallback onMessageSent);
44
+ bool recvMessage();
45
+ void disconnect();
46
+
47
+ std::shared_ptr<EventLoopThread> _eventLoopThread;
48
+ const sockaddr _remoteAddr;
49
+ const bool _responsibleForRetry;
50
+ std::optional<std::string> _remoteIOSocketIdentity;
51
+
52
+ private:
53
+ enum class IOError {
54
+ Drained,
55
+ Aborted,
56
+ Disconnected,
57
+ MessageTooLarge,
58
+ };
59
+
60
+ void onRead();
61
+ void onWrite();
62
+ void onClose();
63
+ void onError()
64
+ {
65
+ onRead();
66
+ // onClose();
67
+ };
68
+
69
+ std::expected<void, IOError> tryReadOneMessage();
70
+ std::expected<void, IOError> tryReadMessages();
71
+ std::expected<size_t, IOError> trySendQueuedMessages();
72
+ void updateWriteOperations(size_t n);
73
+ void updateReadOperation();
74
+
75
+ void setRemoteIdentity() noexcept;
76
+
77
+ std::unique_ptr<EventManager> _eventManager;
78
+ int _connFd;
79
+ sockaddr _localAddr;
80
+ std::string _localIOSocketIdentity;
81
+
82
+ std::deque<TcpWriteOperation> _writeOperations;
83
+ size_t _sendCursor;
84
+
85
+ std::shared_ptr<std::queue<RecvMessageCallback>> _pendingRecvMessageCallbacks;
86
+ std::queue<TcpReadOperation> _receivedReadOperations;
87
+
88
+ bool _disconnect;
89
+
90
+ constexpr static bool isCompleteMessage(const TcpReadOperation& x);
91
+ friend void IOSocket::onConnectionIdentityReceived(MessageConnectionTCP* conn) noexcept;
92
+ friend void IOSocket::onConnectionDisconnected(MessageConnectionTCP* conn, bool keepInBook) noexcept;
93
+ };
94
+
95
+ } // namespace ymq
96
+ } // namespace scaler
@@ -0,0 +1,179 @@
1
+ #pragma once
2
+
3
+ #ifdef __linux__
4
+ #include <arpa/inet.h>
5
+ #include <netinet/in.h>
6
+ #include <netinet/tcp.h>
7
+ #include <unistd.h>
8
+ #endif // __linux__
9
+ #ifdef _WIN32
10
+ // clang-format off
11
+ #include <windows.h>
12
+ #include <winsock2.h>
13
+ #include <ws2tcpip.h>
14
+ // clang-format on
15
+ #endif // _WIN32
16
+
17
+ #include <string.h>
18
+
19
+ #include <cassert>
20
+ #include <expected>
21
+
22
+ #include "scaler/io/ymq/error.h"
23
+
24
+ namespace scaler {
25
+ namespace ymq {
26
+
27
+ inline auto GetErrorCode()
28
+ {
29
+ #ifdef __linux__
30
+ return errno;
31
+ #endif // __linux__
32
+ #ifdef _WIN32
33
+ return WSAGetLastError();
34
+ #endif // _WIN32
35
+ }
36
+
37
+ inline constexpr void CloseAndZeroSocket(auto& fd)
38
+ {
39
+ #ifdef __linux__
40
+ close(fd);
41
+ #endif // __linux__
42
+ #ifdef _WIN32
43
+ closesocket(fd);
44
+ #endif // _WIN32
45
+ fd = 0;
46
+ }
47
+
48
+ inline std::expected<sockaddr, int> stringToSockaddr(const std::string& address)
49
+ {
50
+ // Check and strip the "tcp://" prefix
51
+ static const std::string prefix = "tcp://";
52
+ if (address.substr(0, prefix.size()) != prefix) {
53
+ unrecoverableError({
54
+ Error::ErrorCode::InvalidAddressFormat,
55
+ "Originated from",
56
+ __PRETTY_FUNCTION__,
57
+ "Your input is",
58
+ address,
59
+ });
60
+ }
61
+
62
+ std::string addr_part = address.substr(prefix.size());
63
+ size_t colon_pos = addr_part.find(':');
64
+ if (colon_pos == std::string::npos) {
65
+ unrecoverableError({
66
+ Error::ErrorCode::InvalidAddressFormat,
67
+ "Originated from",
68
+ __PRETTY_FUNCTION__,
69
+ "Your input is",
70
+ address,
71
+ });
72
+ }
73
+
74
+ std::string ip = addr_part.substr(0, colon_pos);
75
+ std::string port_str = addr_part.substr(colon_pos + 1);
76
+
77
+ int port = 0;
78
+ try {
79
+ port = std::stoi(port_str);
80
+ } catch (...) {
81
+ unrecoverableError({
82
+ Error::ErrorCode::InvalidAddressFormat,
83
+ "Originated from",
84
+ __PRETTY_FUNCTION__,
85
+ "Your input is",
86
+ address,
87
+ });
88
+ }
89
+
90
+ sockaddr_in out_addr {};
91
+ out_addr.sin_family = AF_INET;
92
+ out_addr.sin_port = htons(port);
93
+
94
+ int res = inet_pton(AF_INET, ip.c_str(), &out_addr.sin_addr);
95
+ if (res == 0) {
96
+ unrecoverableError({
97
+ Error::ErrorCode::InvalidAddressFormat,
98
+ "Originated from",
99
+ __PRETTY_FUNCTION__,
100
+ "Your input is",
101
+ address,
102
+ });
103
+ }
104
+
105
+ if (res == -1) {
106
+ unrecoverableError({
107
+ Error::ErrorCode::ConfigurationError,
108
+ "Originated from",
109
+ __PRETTY_FUNCTION__,
110
+ "Errno is",
111
+ strerror(errno),
112
+ "out_addr.sin_family",
113
+ out_addr.sin_family,
114
+ "out_addr.sin_port",
115
+ out_addr.sin_port,
116
+ });
117
+ }
118
+
119
+ return *(sockaddr*)&out_addr;
120
+ }
121
+
122
+ inline int setNoDelay(int fd)
123
+ {
124
+ int optval = 1;
125
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&optval, sizeof(optval)) == -1) {
126
+ unrecoverableError({
127
+ Error::ErrorCode::ConfigurationError,
128
+ "Originated from",
129
+ __PRETTY_FUNCTION__,
130
+ "Errno is",
131
+ strerror(errno),
132
+ "fd",
133
+ fd,
134
+ });
135
+ }
136
+
137
+ return fd;
138
+ }
139
+
140
+ inline sockaddr getLocalAddr(int fd)
141
+ {
142
+ sockaddr localAddr = {};
143
+ socklen_t localAddrLen = sizeof(localAddr);
144
+ if (getsockname(fd, &localAddr, &localAddrLen) == -1) {
145
+ unrecoverableError({
146
+ Error::ErrorCode::ConfigurationError,
147
+ "Originated from",
148
+ __PRETTY_FUNCTION__,
149
+ "Errno is",
150
+ strerror(errno),
151
+ "fd",
152
+ fd,
153
+ });
154
+ }
155
+ return localAddr;
156
+ }
157
+
158
+ inline sockaddr getRemoteAddr(int fd)
159
+ {
160
+ sockaddr remoteAddr = {};
161
+ socklen_t remoteAddrLen = sizeof(remoteAddr);
162
+
163
+ if (getpeername(fd, &remoteAddr, &remoteAddrLen) == -1) {
164
+ unrecoverableError({
165
+ Error::ErrorCode::ConfigurationError,
166
+ "Originated from",
167
+ __PRETTY_FUNCTION__,
168
+ "Errno is",
169
+ strerror(errno),
170
+ "fd",
171
+ fd,
172
+ });
173
+ }
174
+
175
+ return remoteAddr;
176
+ }
177
+
178
+ } // namespace ymq
179
+ } // namespace scaler
@@ -0,0 +1,113 @@
1
+ #pragma once
2
+
3
+ // Python
4
+ #include "scaler/io/ymq/pymod_ymq/python.h"
5
+
6
+ // First-party
7
+ #include "scaler/io/ymq/bytes.h"
8
+
9
+ struct PyBytesYMQ {
10
+ PyObject_HEAD;
11
+ Bytes bytes;
12
+ };
13
+
14
+ extern "C" {
15
+
16
+ static int PyBytesYMQ_init(PyBytesYMQ* self, PyObject* args, PyObject* kwds)
17
+ {
18
+ Py_buffer view {.buf = nullptr};
19
+ const char* keywords[] = {"bytes", nullptr};
20
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|y*", (char**)keywords, &view))
21
+ return -1; // Error parsing arguments
22
+
23
+ if (!view.buf) {
24
+ // If no bytes were provided, initialize with an empty Bytes object
25
+ self->bytes = Bytes();
26
+ return 0;
27
+ }
28
+
29
+ // copy the data into the Bytes object
30
+ // it might be possible to make this zero-copy in the future
31
+ self->bytes = Bytes((char*)view.buf, view.len);
32
+
33
+ PyBuffer_Release(&view);
34
+ return 0;
35
+ }
36
+
37
+ static void PyBytesYMQ_dealloc(PyBytesYMQ* self)
38
+ {
39
+ try {
40
+ self->bytes.~Bytes(); // Call the destructor to free the Bytes object
41
+ } catch (...) {
42
+ PyErr_SetString(PyExc_RuntimeError, "Failed to deallocate Bytes");
43
+ PyErr_WriteUnraisable((PyObject*)self);
44
+ }
45
+
46
+ auto* tp = Py_TYPE(self);
47
+ tp->tp_free(self);
48
+ Py_DECREF(tp);
49
+ }
50
+
51
+ static PyObject* PyBytesYMQ_repr(PyBytesYMQ* self)
52
+ {
53
+ if (self->bytes.is_null()) {
54
+ return PyUnicode_FromString("<Bytes: empty>");
55
+ } else {
56
+ return PyUnicode_FromFormat("<Bytes: %db>", self->bytes.len());
57
+ }
58
+ }
59
+
60
+ static PyObject* PyBytesYMQ_data_getter(PyBytesYMQ* self)
61
+ {
62
+ if (self->bytes.is_null())
63
+ Py_RETURN_NONE;
64
+
65
+ return PyBytes_FromStringAndSize((const char*)self->bytes.data(), self->bytes.len());
66
+ }
67
+
68
+ static Py_ssize_t PyBytesYMQ_len(PyBytesYMQ* self)
69
+ {
70
+ return self->bytes.len();
71
+ }
72
+
73
+ static PyObject* PyBytesYMQ_len_getter(PyBytesYMQ* self)
74
+ {
75
+ return PyLong_FromSize_t(self->bytes.len());
76
+ }
77
+
78
+ static int PyBytesYMQ_getbuffer(PyBytesYMQ* self, Py_buffer* view, int flags)
79
+ {
80
+ return PyBuffer_FillInfo(view, (PyObject*)self, (void*)self->bytes.data(), self->bytes.len(), true, flags);
81
+ }
82
+
83
+ static void PyBytesYMQ_releasebuffer(PyBytesYMQ* self, Py_buffer* view)
84
+ {
85
+ }
86
+ }
87
+
88
+ static PyGetSetDef PyBytesYMQ_properties[] = {
89
+ {"data", (getter)PyBytesYMQ_data_getter, nullptr, PyDoc_STR("Data of the Bytes object"), nullptr},
90
+ {"len", (getter)PyBytesYMQ_len_getter, nullptr, PyDoc_STR("Length of the Bytes object"), nullptr},
91
+ {nullptr, nullptr, nullptr, nullptr, nullptr}, // Sentinel
92
+ };
93
+
94
+ static PyType_Slot PyBytesYMQ_slots[] = {
95
+ {Py_tp_init, (void*)PyBytesYMQ_init},
96
+ {Py_tp_dealloc, (void*)PyBytesYMQ_dealloc},
97
+ {Py_tp_repr, (void*)PyBytesYMQ_repr},
98
+ {Py_mp_length, (void*)PyBytesYMQ_len},
99
+ {Py_tp_getset, (void*)PyBytesYMQ_properties},
100
+ #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION > 8
101
+ {Py_bf_getbuffer, (void*)PyBytesYMQ_getbuffer},
102
+ {Py_bf_releasebuffer, (void*)PyBytesYMQ_releasebuffer},
103
+ #endif
104
+ {0, nullptr},
105
+ };
106
+
107
+ static PyType_Spec PyBytesYMQ_spec = {
108
+ .name = "_ymq.Bytes",
109
+ .basicsize = sizeof(PyBytesYMQ),
110
+ .itemsize = 0,
111
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE,
112
+ .slots = PyBytesYMQ_slots,
113
+ };
@@ -0,0 +1,124 @@
1
+ #pragma once
2
+
3
+ // Python
4
+ #include "scaler/io/ymq/pymod_ymq/python.h"
5
+
6
+ // First-party
7
+ #include "scaler/io/ymq/error.h"
8
+ #include "scaler/io/ymq/pymod_ymq/ymq.h"
9
+
10
+ using namespace scaler::ymq;
11
+
12
+ // the order of the members in the exception args tuple
13
+ const Py_ssize_t YMQException_errorCodeIndex = 0;
14
+ const Py_ssize_t YMQException_messageIndex = 1;
15
+
16
+ struct YMQException {
17
+ PyException_HEAD;
18
+ };
19
+
20
+ extern "C" {
21
+
22
+ static int YMQException_init(YMQException* self, PyObject* args, PyObject* kwds)
23
+ {
24
+ auto state = YMQStateFromSelf((PyObject*)self);
25
+ if (!state)
26
+ return -1;
27
+
28
+ // no need to incref these because we don't store them
29
+ // Furthermore, this fn does not create a strong reference to the args
30
+ PyObject* errorCode = nullptr;
31
+ PyObject* errorMessage = nullptr;
32
+ if (!PyArg_ParseTuple(args, "OO", &errorCode, &errorMessage))
33
+ return -1;
34
+
35
+ if (!PyObject_IsInstance(errorCode, *state->PyErrorCodeType)) {
36
+ PyErr_SetString(PyExc_TypeError, "expected code to be of type ErrorCode");
37
+ return -1;
38
+ }
39
+
40
+ if (!PyUnicode_Check(errorMessage)) {
41
+ PyErr_SetString(PyExc_TypeError, "expected message to be a string");
42
+ return -1;
43
+ }
44
+
45
+ // delegate to the base class init
46
+ return self->ob_base.ob_type->tp_base->tp_init((PyObject*)self, args, kwds);
47
+ }
48
+
49
+ static void YMQException_dealloc(YMQException* self)
50
+ {
51
+ self->ob_base.ob_type->tp_base->tp_dealloc((PyObject*)self);
52
+
53
+ // we still need to release the reference to the heap type
54
+ auto* tp = Py_TYPE(self);
55
+ Py_DECREF(tp);
56
+ }
57
+
58
+ static PyObject* YMQException_code_getter(YMQException* self, void* Py_UNUSED(closure))
59
+ {
60
+ return PySequence_GetItem(self->args, YMQException_errorCodeIndex);
61
+ }
62
+
63
+ static PyObject* YMQException_message_getter(YMQException* self, void* Py_UNUSED(closure))
64
+ {
65
+ return PySequence_GetItem(self->args, YMQException_messageIndex);
66
+ }
67
+ }
68
+
69
+ static PyGetSetDef YMQException_getset[] = {
70
+ {"code", (getter)YMQException_code_getter, nullptr, PyDoc_STR("error code"), nullptr},
71
+ {"message", (getter)YMQException_message_getter, nullptr, PyDoc_STR("error message"), nullptr},
72
+ {nullptr} // Sentinel
73
+ };
74
+
75
+ static PyType_Slot YMQException_slots[] = {
76
+ {Py_tp_init, (void*)YMQException_init},
77
+ {Py_tp_dealloc, (void*)YMQException_dealloc},
78
+ {Py_tp_getset, (void*)YMQException_getset},
79
+ {0, 0},
80
+ };
81
+
82
+ static PyType_Spec YMQException_spec = {
83
+ "_ymq.YMQException", sizeof(YMQException), 0, Py_TPFLAGS_DEFAULT, YMQException_slots};
84
+
85
+ inline OwnedPyObject<> YMQException_argtupleFromCoreError(YMQState* state, const Error* error)
86
+ {
87
+ OwnedPyObject code = PyLong_FromLong(static_cast<long>(error->_errorCode));
88
+
89
+ if (!code)
90
+ return nullptr;
91
+
92
+ OwnedPyObject pyCode = PyObject_CallFunction(*state->PyErrorCodeType, "O", *code);
93
+
94
+ if (!pyCode)
95
+ return nullptr;
96
+
97
+ OwnedPyObject message = PyUnicode_FromString(error->what());
98
+
99
+ if (!message)
100
+ return nullptr;
101
+
102
+ return PyTuple_Pack(2, *pyCode, *message);
103
+ }
104
+
105
+ inline void YMQException_setFromCoreError(YMQState* state, const Error* error)
106
+ {
107
+ auto tuple = YMQException_argtupleFromCoreError(state, error);
108
+ if (!tuple)
109
+ return;
110
+
111
+ PyErr_SetObject(*state->PyExceptionType, *tuple);
112
+ }
113
+
114
+ inline PyObject* YMQException_createFromCoreError(YMQState* state, const Error* error)
115
+ {
116
+ auto tuple = YMQException_argtupleFromCoreError(state, error);
117
+ if (!tuple)
118
+ return nullptr;
119
+
120
+ OwnedPyObject exc = PyObject_CallObject(*state->PyExceptionType, *tuple);
121
+
122
+ // transfer ownership to caller
123
+ return exc.take();
124
+ }
@@ -0,0 +1,15 @@
1
+ #include "scaler/io/ymq/pymod_ymq/python.h"
2
+
3
+ class AcquireGIL {
4
+ public:
5
+ AcquireGIL() : _state(PyGILState_Ensure()) {}
6
+ ~AcquireGIL() { PyGILState_Release(_state); }
7
+
8
+ AcquireGIL(const AcquireGIL&) = delete;
9
+ AcquireGIL& operator=(const AcquireGIL&) = delete;
10
+ AcquireGIL(AcquireGIL&&) = delete;
11
+ AcquireGIL& operator=(AcquireGIL&&) = delete;
12
+
13
+ private:
14
+ PyGILState_STATE _state;
15
+ };
@@ -0,0 +1,166 @@
1
+ #pragma once
2
+
3
+ // Python
4
+ #include "scaler/io/ymq/pymod_ymq/python.h"
5
+
6
+ // C++
7
+ #include <memory>
8
+
9
+ // First-party
10
+ #include "scaler/io/ymq/configuration.h"
11
+ #include "scaler/io/ymq/io_context.h"
12
+ #include "scaler/io/ymq/io_socket.h"
13
+ #include "scaler/io/ymq/pymod_ymq/io_socket.h"
14
+ #include "scaler/io/ymq/pymod_ymq/ymq.h"
15
+
16
+ // TODO: move ymq's python module into this namespace
17
+ using namespace scaler::ymq;
18
+ using Identity = Configuration::IOSocketIdentity;
19
+
20
+ struct PyIOContext {
21
+ PyObject_HEAD;
22
+ std::shared_ptr<IOContext> ioContext;
23
+ };
24
+
25
+ extern "C" {
26
+
27
+ static int PyIOContext_init(PyIOContext* self, PyObject* args, PyObject* kwds)
28
+ {
29
+ // default to 1 thread if not specified
30
+ Py_ssize_t numThreads = 1;
31
+ const char* kwlist[] = {"num_threads", nullptr};
32
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|n", (char**)kwlist, &numThreads))
33
+ return -1;
34
+
35
+ try {
36
+ new (&self->ioContext) std::shared_ptr<IOContext>();
37
+ self->ioContext = std::make_shared<IOContext>(numThreads);
38
+ } catch (...) {
39
+ PyErr_SetString(PyExc_RuntimeError, "Failed to create IOContext");
40
+ return -1;
41
+ }
42
+
43
+ return 0;
44
+ }
45
+
46
+ static void PyIOContext_dealloc(PyIOContext* self)
47
+ {
48
+ try {
49
+ self->ioContext.~shared_ptr();
50
+ } catch (...) {
51
+ PyErr_SetString(PyExc_RuntimeError, "Failed to deallocate IOContext");
52
+ PyErr_WriteUnraisable((PyObject*)self);
53
+ }
54
+
55
+ auto* tp = Py_TYPE(self);
56
+ tp->tp_free(self);
57
+ Py_DECREF(tp);
58
+ }
59
+
60
+ static PyObject* PyIOContext_repr(PyIOContext* self)
61
+ {
62
+ return PyUnicode_FromFormat("<IOContext at %p>", (void*)self->ioContext.get());
63
+ }
64
+
65
+ static PyObject* PyIOContext_numThreads_getter(PyIOContext* self, void* Py_UNUSED(closure))
66
+ {
67
+ return PyLong_FromSize_t(self->ioContext->numThreads());
68
+ }
69
+
70
+ static PyObject* PyIOContext_createIOSocket(PyIOContext* self, PyObject* args, PyObject* kwargs)
71
+ {
72
+ YMQState* state = YMQStateFromSelf((PyObject*)self);
73
+ if (!state)
74
+ return nullptr;
75
+
76
+ PyObject* callback = nullptr;
77
+ const char* identity = nullptr;
78
+ Py_ssize_t identityLen = 0;
79
+ PyObject* pySocketType = nullptr;
80
+ const char* kwlist[] = {"", "identity", "socket_type", nullptr};
81
+ if (!PyArg_ParseTupleAndKeywords(
82
+ args, kwargs, "Os#O", (char**)kwlist, &callback, &identity, &identityLen, &pySocketType))
83
+ return nullptr;
84
+
85
+ if (!PyObject_IsInstance(pySocketType, *state->PyIOSocketEnumType)) {
86
+ PyErr_SetString(PyExc_TypeError, "Expected socket_type to be an instance of IOSocketType");
87
+ return nullptr;
88
+ }
89
+
90
+ OwnedPyObject value = PyObject_GetAttrString(pySocketType, "value");
91
+ if (!value)
92
+ return nullptr;
93
+
94
+ if (!PyLong_Check(*value)) {
95
+ PyErr_SetString(PyExc_TypeError, "Expected socket_type to be an integer");
96
+ return nullptr;
97
+ }
98
+
99
+ long socketTypeValue = PyLong_AsLong(*value);
100
+ if (socketTypeValue < 0 && PyErr_Occurred())
101
+ return nullptr;
102
+
103
+ IOSocketType socketType = static_cast<IOSocketType>(socketTypeValue);
104
+ OwnedPyObject<PyIOSocket> ioSocket = PyObject_New(PyIOSocket, (PyTypeObject*)*state->PyIOSocketType);
105
+ if (!ioSocket)
106
+ return nullptr;
107
+
108
+ Py_INCREF(callback);
109
+
110
+ try {
111
+ // ensure the fields are init
112
+ new (&ioSocket->socket) std::shared_ptr<IOSocket>();
113
+ new (&ioSocket->ioContext) std::shared_ptr<IOContext>();
114
+ ioSocket->ioContext = self->ioContext;
115
+
116
+ self->ioContext->createIOSocket(
117
+ std::string(identity, identityLen), socketType, [callback, ioSocket](auto socket) {
118
+ AcquireGIL _;
119
+
120
+ ioSocket->socket = socket;
121
+ OwnedPyObject _result = PyObject_CallFunctionObjArgs(callback, *ioSocket, nullptr);
122
+ Py_DECREF(callback);
123
+ });
124
+ } catch (...) {
125
+ PyErr_SetString(PyExc_RuntimeError, "Failed to create IOSocket");
126
+ return nullptr;
127
+ }
128
+
129
+ Py_RETURN_NONE;
130
+ }
131
+
132
+ } // extern "C"
133
+
134
+ static PyMethodDef PyIOContext_methods[] = {
135
+ {"createIOSocket",
136
+ (PyCFunction)PyIOContext_createIOSocket,
137
+ METH_VARARGS | METH_KEYWORDS,
138
+ PyDoc_STR("Create a new IOSocket")},
139
+ {nullptr, nullptr, 0, nullptr},
140
+ };
141
+
142
+ static PyGetSetDef PyIOContext_properties[] = {
143
+ {"num_threads",
144
+ (getter)PyIOContext_numThreads_getter,
145
+ nullptr,
146
+ PyDoc_STR("Get the number of threads in the IOContext"),
147
+ nullptr},
148
+ {nullptr, nullptr, nullptr, nullptr, nullptr},
149
+ };
150
+
151
+ static PyType_Slot PyIOContext_slots[] = {
152
+ {Py_tp_init, (void*)PyIOContext_init},
153
+ {Py_tp_dealloc, (void*)PyIOContext_dealloc},
154
+ {Py_tp_repr, (void*)PyIOContext_repr},
155
+ {Py_tp_methods, (void*)PyIOContext_methods},
156
+ {Py_tp_getset, (void*)PyIOContext_properties},
157
+ {0, nullptr},
158
+ };
159
+
160
+ static PyType_Spec PyIOContext_spec = {
161
+ .name = "_ymq.BaseIOContext",
162
+ .basicsize = sizeof(PyIOContext),
163
+ .itemsize = 0,
164
+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_BASETYPE,
165
+ .slots = PyIOContext_slots,
166
+ };