opengris-scaler 1.12.7__cp313-cp313-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,357 @@
1
+ #pragma once
2
+
3
+ // Python
4
+ #include "scaler/io/ymq/pymod_ymq/python.h"
5
+
6
+ // C
7
+ #include <fcntl.h>
8
+ #include <unistd.h>
9
+
10
+ // C++
11
+ #include <expected>
12
+ #include <string>
13
+ #include <string_view>
14
+ #include <utility>
15
+
16
+ // First-party
17
+ #include "scaler/io/ymq/error.h"
18
+
19
+ struct YMQState {
20
+ OwnedPyObject<> enumModule; // Reference to the enum module
21
+ OwnedPyObject<> asyncioModule; // Reference to the asyncio module
22
+
23
+ OwnedPyObject<> PyIOSocketEnumType; // Reference to the IOSocketType enum
24
+ OwnedPyObject<> PyErrorCodeType; // Reference to the Error enum
25
+ OwnedPyObject<> PyBytesYMQType; // Reference to the PyBytesYMQ type
26
+ OwnedPyObject<> PyMessageType; // Reference to the Message type
27
+ OwnedPyObject<> PyIOSocketType; // Reference to the IOSocket type
28
+ OwnedPyObject<> PyIOContextType; // Reference to the IOContext type
29
+ OwnedPyObject<> PyExceptionType; // Reference to the Exception type
30
+ };
31
+
32
+ static YMQState* YMQStateFromSelf(PyObject* self)
33
+ {
34
+ // replace with PyType_GetModuleByDef(Py_TYPE(self), &YMQ_module) in a newer Python version
35
+ // https://docs.python.org/3/c-api/type.html#c.PyType_GetModuleByDef
36
+ PyObject* pyModule = PyType_GetModule(Py_TYPE(self));
37
+ if (!pyModule)
38
+ return nullptr;
39
+
40
+ #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 8
41
+ Py_DECREF(pyModule); // As we get a real ref in 3.8 backport
42
+ #endif
43
+
44
+ return (YMQState*)PyModule_GetState(pyModule);
45
+ }
46
+
47
+ PyObject* PyErr_CreateFromString(PyObject* type, const char* message)
48
+ {
49
+ OwnedPyObject args = Py_BuildValue("(s)", message);
50
+ if (!args)
51
+ return nullptr;
52
+
53
+ return PyObject_CallObject(type, *args);
54
+ }
55
+
56
+ // this is a polyfill for PyErr_GetRaisedException() added in Python 3.12+
57
+ std::expected<PyObject*, PyObject*> YMQ_GetRaisedException()
58
+ {
59
+ #if (PY_MAJOR_VERSION <= 3) && (PY_MINOR_VERSION <= 12)
60
+ PyObject *excType, *excValue, *excTraceback;
61
+ PyErr_Fetch(&excType, &excValue, &excTraceback);
62
+ Py_XDECREF(excType);
63
+ Py_XDECREF(excTraceback);
64
+ if (!excValue)
65
+ Py_RETURN_NONE;
66
+
67
+ return std::unexpected {excValue};
68
+ #else
69
+ PyObject* excValue = PyErr_GetRaisedException();
70
+ if (!excValue)
71
+ Py_RETURN_NONE;
72
+
73
+ return std::unexpected {excValue};
74
+ #endif
75
+ }
76
+
77
+ void completeCallbackWithRaisedException(PyObject* callback)
78
+ {
79
+ auto result = YMQ_GetRaisedException();
80
+ OwnedPyObject _ =PyObject_CallFunctionObjArgs(callback, result.value_or(result.error()));
81
+ }
82
+
83
+ // First-Party
84
+ #include "scaler/io/ymq/pymod_ymq/bytes.h"
85
+ #include "scaler/io/ymq/pymod_ymq/exception.h"
86
+ #include "scaler/io/ymq/pymod_ymq/io_context.h"
87
+ #include "scaler/io/ymq/pymod_ymq/io_socket.h"
88
+ #include "scaler/io/ymq/pymod_ymq/message.h"
89
+
90
+ extern "C" {
91
+
92
+ static void YMQ_free(YMQState* state)
93
+ {
94
+ try {
95
+ state->enumModule.~OwnedPyObject();
96
+ state->asyncioModule.~OwnedPyObject();
97
+ state->PyIOSocketEnumType.~OwnedPyObject();
98
+ state->PyErrorCodeType.~OwnedPyObject();
99
+ state->PyBytesYMQType.~OwnedPyObject();
100
+ state->PyMessageType.~OwnedPyObject();
101
+ state->PyIOSocketType.~OwnedPyObject();
102
+ state->PyIOContextType.~OwnedPyObject();
103
+ state->PyExceptionType.~OwnedPyObject();
104
+ } catch (...) {
105
+ PyErr_SetString(PyExc_RuntimeError, "Failed to free YMQState");
106
+ PyErr_WriteUnraisable(nullptr);
107
+ }
108
+ }
109
+
110
+ static int YMQ_createIntEnum(
111
+ PyObject* pyModule,
112
+ OwnedPyObject<>* storage,
113
+ std::string enumName,
114
+ std::vector<std::pair<std::string, int>> entries)
115
+ {
116
+ // create a python dictionary to hold the entries
117
+ OwnedPyObject enumDict = PyDict_New();
118
+ if (!enumDict)
119
+ return -1;
120
+
121
+ // add each entry to the dictionary
122
+ for (const auto& entry: entries) {
123
+ OwnedPyObject value = PyLong_FromLong(entry.second);
124
+ if (!value)
125
+ return -1;
126
+
127
+ auto status = PyDict_SetItemString(*enumDict, entry.first.c_str(), *value);
128
+ if (status < 0)
129
+ return -1;
130
+ }
131
+
132
+ auto state = (YMQState*)PyModule_GetState(pyModule);
133
+
134
+ if (!state)
135
+ return -1;
136
+
137
+ // create our class by calling enum.IntEnum(enumName, enumDict)
138
+ OwnedPyObject enumClass = PyObject_CallMethod(*state->enumModule, "IntEnum", "sO", enumName.c_str(), *enumDict);
139
+ if (!enumClass)
140
+ return -1;
141
+
142
+ *storage = enumClass;
143
+
144
+ // add the class to the module
145
+ // this increments the reference count of enumClass
146
+ return PyModule_AddObjectRef(pyModule, enumName.c_str(), *enumClass);
147
+ }
148
+
149
+ static int YMQ_createIOSocketTypeEnum(PyObject* pyModule, YMQState* state)
150
+ {
151
+ std::vector<std::pair<std::string, int>> ioSocketTypes = {
152
+ {"Uninit", (int)IOSocketType::Uninit},
153
+ {"Binder", (int)IOSocketType::Binder},
154
+ {"Connector", (int)IOSocketType::Connector},
155
+ {"Unicast", (int)IOSocketType::Unicast},
156
+ {"Multicast", (int)IOSocketType::Multicast},
157
+ };
158
+
159
+ return YMQ_createIntEnum(pyModule, &state->PyIOSocketEnumType, "IOSocketType", ioSocketTypes);
160
+ }
161
+
162
+ static PyObject* YMQErrorCode_explanation(PyObject* self, PyObject* Py_UNUSED(args))
163
+ {
164
+ OwnedPyObject pyValue = PyObject_GetAttrString(self, "value");
165
+ if (!pyValue)
166
+ return nullptr;
167
+
168
+ if (!PyLong_Check(*pyValue)) {
169
+ PyErr_SetString(PyExc_TypeError, "Expected an integer value");
170
+ return nullptr;
171
+ }
172
+
173
+ long value = PyLong_AsLong(*pyValue);
174
+
175
+ if (value == -1 && PyErr_Occurred())
176
+ return nullptr;
177
+
178
+ std::string_view explanation = Error::convertErrorToExplanation(static_cast<Error::ErrorCode>(value));
179
+ return PyUnicode_FromString(std::string(explanation).c_str());
180
+ }
181
+
182
+ // IDEA: CREATE AN INT ENUM AND ATTACH METHOD AFTERWARDS
183
+ // OR: CREATE A NON-INT ENUM AND USE A TUPLE FOR THE VALUES
184
+ static int YMQ_createErrorCodeEnum(PyObject* pyModule, YMQState* state)
185
+ {
186
+ std::vector<std::pair<std::string, int>> errorCodeValues = {
187
+ {"Uninit", (int)Error::ErrorCode::Uninit},
188
+ {"InvalidPortFormat", (int)Error::ErrorCode::InvalidPortFormat},
189
+ {"InvalidAddressFormat", (int)Error::ErrorCode::InvalidAddressFormat},
190
+ {"ConfigurationError", (int)Error::ErrorCode::ConfigurationError},
191
+ {"SignalNotSupported", (int)Error::ErrorCode::SignalNotSupported},
192
+ {"CoreBug", (int)Error::ErrorCode::CoreBug},
193
+ {"RepetetiveIOSocketIdentity", (int)Error::ErrorCode::RepetetiveIOSocketIdentity},
194
+ {"RedundantIOSocketRefCount", (int)Error::ErrorCode::RedundantIOSocketRefCount},
195
+ {"MultipleConnectToNotSupported", (int)Error::ErrorCode::MultipleConnectToNotSupported},
196
+ {"MultipleBindToNotSupported", (int)Error::ErrorCode::MultipleBindToNotSupported},
197
+ {"InitialConnectFailedWithInProgress", (int)Error::ErrorCode::InitialConnectFailedWithInProgress},
198
+ {"SendMessageRequestCouldNotComplete", (int)Error::ErrorCode::SendMessageRequestCouldNotComplete},
199
+ {"SetSockOptNonFatalFailure", (int)Error::ErrorCode::SetSockOptNonFatalFailure},
200
+ {"IPv6NotSupported", (int)Error::ErrorCode::IPv6NotSupported},
201
+ {"RemoteEndDisconnectedOnSocketWithoutGuaranteedDelivery",
202
+ (int)Error::ErrorCode::RemoteEndDisconnectedOnSocketWithoutGuaranteedDelivery},
203
+ {"ConnectorSocketClosedByRemoteEnd", (int)Error::ErrorCode::ConnectorSocketClosedByRemoteEnd},
204
+ {"IOSocketStopRequested", (int)Error::ErrorCode::IOSocketStopRequested},
205
+ {"BinderSendMessageWithNoAddress", (int)Error::ErrorCode::BinderSendMessageWithNoAddress},
206
+ };
207
+
208
+ if (YMQ_createIntEnum(pyModule, &state->PyErrorCodeType, "ErrorCode", errorCodeValues) < 0)
209
+ return -1;
210
+
211
+ static PyMethodDef YMQErrorCode_explanation_def = {
212
+ "explanation",
213
+ (PyCFunction)YMQErrorCode_explanation,
214
+ METH_NOARGS,
215
+ PyDoc_STR("Returns an explanation of a YMQ error code")};
216
+
217
+ OwnedPyObject iter = PyObject_GetIter(*state->PyErrorCodeType);
218
+ if (!iter)
219
+ return -1;
220
+
221
+ // is this the best way to add a method to each enum item?
222
+ // in python you can just write: MyEnum.new_method = ...
223
+ // for some reason this does not seem to work with the c api
224
+ // docs and examples are unfortunately scarce for this
225
+ // for now this will work just fine
226
+ OwnedPyObject item {};
227
+ while ((item = PyIter_Next(*iter))) {
228
+ OwnedPyObject fn = PyCFunction_NewEx(&YMQErrorCode_explanation_def, *item, pyModule);
229
+ if (!fn)
230
+ return -1;
231
+
232
+ auto status = PyObject_SetAttrString(*item, "explanation", *fn);
233
+ if (status < 0)
234
+ return -1;
235
+ }
236
+
237
+ return 0;
238
+ }
239
+ }
240
+
241
+ // internal convenience function to create a type and add it to the module
242
+ static int YMQ_createType(
243
+ // the module object
244
+ PyObject* pyModule,
245
+ // storage for the generated type object
246
+ OwnedPyObject<>* storage,
247
+ // the type's spec
248
+ PyType_Spec* spec,
249
+ // the name of the type, can be omitted if `add` is false
250
+ const char* name,
251
+ // whether or not to add this type to the module
252
+ bool add = true,
253
+ // the types base classes
254
+ PyObject* bases = nullptr,
255
+ getbufferproc getbuffer = nullptr,
256
+ releasebufferproc releasebuffer = nullptr)
257
+ {
258
+ assert(storage != nullptr);
259
+
260
+ *storage = PyType_FromModuleAndSpec(pyModule, spec, bases);
261
+ if (!*storage)
262
+ return -1;
263
+
264
+ #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 8
265
+ if (PyObject_SetAttrString(**storage, "__module_object__", pyModule) < 0)
266
+ return -1;
267
+
268
+ if (getbuffer && releasebuffer) {
269
+ PyTypeObject* type_obj = (PyTypeObject*)**storage;
270
+
271
+ type_obj->tp_as_buffer->bf_getbuffer = getbuffer;
272
+ type_obj->tp_as_buffer->bf_releasebuffer = releasebuffer;
273
+ type_obj->tp_flags |= 0; // Do I need to add tp_flags? Seems not
274
+ }
275
+ #endif
276
+
277
+ if (add)
278
+ if (PyModule_AddObjectRef(pyModule, name, **storage) < 0)
279
+ return -1;
280
+
281
+ return 0;
282
+ }
283
+
284
+ static int YMQ_exec(PyObject* pyModule)
285
+ {
286
+ auto state = (YMQState*)PyModule_GetState(pyModule);
287
+ if (!state)
288
+ return -1;
289
+
290
+ state->enumModule = PyImport_ImportModule("enum");
291
+ if (!state->enumModule)
292
+ return -1;
293
+
294
+ state->asyncioModule = PyImport_ImportModule("asyncio");
295
+ if (!state->asyncioModule)
296
+ return -1;
297
+
298
+ if (YMQ_createIOSocketTypeEnum(pyModule, state) < 0)
299
+ return -1;
300
+
301
+ if (YMQ_createErrorCodeEnum(pyModule, state) < 0)
302
+ return -1;
303
+
304
+ #if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION == 8
305
+ if (YMQ_createType(
306
+ pyModule,
307
+ &state->PyBytesYMQType,
308
+ &PyBytesYMQ_spec,
309
+ "Bytes",
310
+ true,
311
+ nullptr,
312
+ (getbufferproc)PyBytesYMQ_getbuffer,
313
+ (releasebufferproc)PyBytesYMQ_releasebuffer) < 0)
314
+ return -1;
315
+ #else
316
+ if (YMQ_createType(pyModule, &state->PyBytesYMQType, &PyBytesYMQ_spec, "Bytes") < 0)
317
+ return -1;
318
+ #endif
319
+
320
+ if (YMQ_createType(pyModule, &state->PyMessageType, &PyMessage_spec, "Message") < 0)
321
+ return -1;
322
+
323
+ if (YMQ_createType(pyModule, &state->PyIOSocketType, &PyIOSocket_spec, "BaseIOSocket") < 0)
324
+ return -1;
325
+
326
+ if (YMQ_createType(pyModule, &state->PyIOContextType, &PyIOContext_spec, "BaseIOContext") < 0)
327
+ return -1;
328
+
329
+ PyObject* exceptionBases = PyTuple_Pack(1, PyExc_Exception);
330
+ if (!exceptionBases)
331
+ return -1;
332
+
333
+ if (YMQ_createType(pyModule, &state->PyExceptionType, &YMQException_spec, "YMQException", true, exceptionBases) <
334
+ 0) {
335
+ Py_DECREF(exceptionBases);
336
+ return -1;
337
+ }
338
+ Py_DECREF(exceptionBases);
339
+
340
+ return 0;
341
+ }
342
+
343
+ static PyModuleDef_Slot YMQ_slots[] = {
344
+ {Py_mod_exec, (void*)YMQ_exec},
345
+ {0, nullptr},
346
+ };
347
+
348
+ static PyModuleDef YMQ_module = {
349
+ .m_base = PyModuleDef_HEAD_INIT,
350
+ .m_name = "_ymq",
351
+ .m_doc = PyDoc_STR("YMQ Python bindings"),
352
+ .m_size = sizeof(YMQState),
353
+ .m_slots = YMQ_slots,
354
+ .m_free = (freefunc)YMQ_free,
355
+ };
356
+
357
+ PyMODINIT_FUNC PyInit_ymq(void);
@@ -0,0 +1,114 @@
1
+
2
+ # YMQ
3
+
4
+ Welcome. This file contains schedule for each day, for each person.
5
+
6
+ Each person maintains a todo and done list.
7
+
8
+ ## gxu
9
+
10
+ ### DONE
11
+
12
+ - CMake integration, generate C++ stuff in build dir
13
+ - Basic coroutine API
14
+ - develop the so-called coro_context and their utility DEAD
15
+ - write up interfaces(not impl) that uses coroutine DEAD
16
+
17
+ ## DONE:
18
+ - Remember (or remove) the IOSocketIdentity of closed connection
19
+ - Basic coroutine API (DEAD)
20
+ - develop the so-called coro_context and their utility (DEAD)
21
+ - write up interfaces(not impl) that uses coroutine (DEAD)
22
+ - Use unified file path (only include dir is project dir)
23
+ - Start organize files that they can be compiled in one go
24
+ - Write delayed execution utility
25
+ - Write timed execution utility
26
+ - IOSocket exchange identity on connected
27
+ - General message passing assuming user passed in Message with header
28
+ - Guaranteed message delivery
29
+ - Retry on disconnect
30
+ - Delete fd from eventloop on disconnect
31
+ - Put Recv on iosocket level because user don't know which connection it should recv from
32
+ - cleanup: IOSocket destructor should release resources bound to it
33
+ - cleanup: Clarify Bytes ownership of send/recv messages
34
+ - Provide connect(str) function that parse the string to a sockaddr.
35
+ - make connectTo takes a callback
36
+ - Implement bind function with interface address (str) and callback
37
+ - cleanup: report error when no connection with desired identity presents
38
+ - cleanup: Give user more control about port/addr
39
+ - test the project (now working when user kills the program)
40
+ - cleanup: Provide actual remote sockaddr in the connection class
41
+ - test the user provided callback logic and think about sync issue
42
+ - connect do not happen twice, monitor for read/write instead
43
+ - remove the end of each loop hook, this is stupid
44
+ - test the abnormal breakup (break up due to network issue instead of killing)
45
+ - Per action cancellation
46
+ - refactor: Ownership, Public/Private, destructor
47
+ - cleanup: Do not constraint thee size of identity (current maximum being 128-8 bytes)
48
+ - make IO with send/recv msg
49
+ - automatically destroy threads when no ioSocket is running on it
50
+ - update numbers -> constants
51
+ - cleanup: Change InterruptiveConcurrentQueue behavior
52
+ - Fix issue lambda captures being copied instead of move
53
+ - allow user to change how many times they want to retry
54
+ - cleanup: make sure when eventloop is destructed all resources is freed
55
+ - remove bytes ownership code
56
+ - add constexpr, noexcept, overloads, explicit to the code
57
+ - make sure every call is moved instead of being copied
58
+ - iosocket behaves differently when provided with different IOSocketType
59
+ - Refactor: MessageConnectionTCP is easier to construct correctly
60
+ - provide reference implementation of the error type (Error)
61
+ - reference usage of the error type
62
+ -
63
+ -
64
+ -
65
+ -
66
+ -
67
+ - LEAVE A FEW BLANKS HERE TO AVOID CONFLICT
68
+
69
+ ## TODO:
70
+ - resolve github comment (there are still some)
71
+ - cleanup: Do not use std::string as identity type
72
+ - cleanup: Error handling
73
+ - Use one consistent print logic
74
+ - add proper logging message
75
+ - configuration won't work because we are compiliing it on github box, figure out a new way
76
+ - write tests
77
+ - examples
78
+ - performance measurement
79
+ - Determine what happens when user close socket but there are pending send/recv
80
+ - multiple connectTo issue consecutively support
81
+ -
82
+ -
83
+ -
84
+ -
85
+ -
86
+ -
87
+ -
88
+ -
89
+ -
90
+ -
91
+ -
92
+ - allow staticlly linking the project
93
+ - Namespace support, and move third_party code to top directory.
94
+ - Optimize performance in `updateWriteOperations`
95
+ - LEAVE A FEW BLANKS HERE TO AVOID CONFLICT
96
+
97
+
98
+ ## magniloquency
99
+ =======
100
+ - support for cancel of execution
101
+ -
102
+ -
103
+ -
104
+ -
105
+ - LEAVE A FEW BLANKS HERE TO AVOID CONFLICT
106
+
107
+
108
+ ### DONE
109
+
110
+ - CPython module stub
111
+
112
+ ### TODO
113
+
114
+ - ?
@@ -0,0 +1,80 @@
1
+
2
+ #include "scaler/io/ymq/simple_interface.h"
3
+
4
+ #include <optional>
5
+
6
+ namespace scaler {
7
+ namespace ymq {
8
+
9
+ std::shared_ptr<IOSocket> syncCreateSocket(IOContext& context, IOSocketType type, std::string name)
10
+ {
11
+ auto createSocketPromise = std::promise<std::shared_ptr<IOSocket>>();
12
+ auto createSocketFuture = createSocketPromise.get_future();
13
+ context.createIOSocket(
14
+ std::move(name), type, [&createSocketPromise](auto sock) { createSocketPromise.set_value(sock); });
15
+
16
+ auto clientSocket = createSocketFuture.get();
17
+ return clientSocket;
18
+ }
19
+
20
+ void syncBindSocket(std::shared_ptr<IOSocket> socket, std::string address)
21
+ {
22
+ auto bind_promise = std::promise<std::expected<void, Error>>();
23
+ auto bind_future = bind_promise.get_future();
24
+ // Optionally handle result in the callback
25
+ socket->bindTo(address, [&bind_promise](std::expected<void, Error> result) { bind_promise.set_value(result); });
26
+ bind_future.wait();
27
+ }
28
+
29
+ void syncConnectSocket(std::shared_ptr<IOSocket> socket, std::string address)
30
+ {
31
+ auto connect_promise = std::promise<std::expected<void, Error>>();
32
+ auto connect_future = connect_promise.get_future();
33
+
34
+ socket->connectTo(
35
+ address, [&connect_promise](std::expected<void, Error> result) { connect_promise.set_value(result); });
36
+
37
+ connect_future.wait();
38
+ }
39
+
40
+ std::expected<Message, Error> syncRecvMessage(std::shared_ptr<IOSocket> socket)
41
+ {
42
+ auto fut = futureRecvMessage(std::move(socket));
43
+ return fut.get();
44
+ }
45
+
46
+ std::optional<Error> syncSendMessage(std::shared_ptr<IOSocket> socket, Message message)
47
+ {
48
+ auto fut = futureSendMessage(std::move(socket), std::move(message));
49
+ return fut.get();
50
+ }
51
+
52
+ std::future<std::expected<Message, Error>> futureRecvMessage(std::shared_ptr<IOSocket> socket)
53
+ {
54
+ auto recv_promise_ptr = std::make_unique<std::promise<std::expected<Message, Error>>>();
55
+ auto recv_future = recv_promise_ptr->get_future();
56
+ socket->recvMessage([recv_promise = std::move(recv_promise_ptr)](std::pair<Message, Error> result) {
57
+ if (result.second._errorCode == Error::ErrorCode::Uninit)
58
+ recv_promise->set_value(std::move(result.first));
59
+ else
60
+ recv_promise->set_value(std::unexpected {std::move(result.second)});
61
+ });
62
+ return recv_future;
63
+ }
64
+
65
+ std::future<std::optional<Error>> futureSendMessage(std::shared_ptr<IOSocket> socket, Message message)
66
+ {
67
+ auto send_promise_ptr = std::make_unique<std::promise<std::optional<Error>>>();
68
+ auto send_future = send_promise_ptr->get_future();
69
+ socket->sendMessage(
70
+ std::move(message), [send_promise = std::move(send_promise_ptr)](std::expected<void, Error> result) {
71
+ if (result)
72
+ send_promise->set_value(std::nullopt);
73
+ else
74
+ send_promise->set_value(std::move(result.error()));
75
+ });
76
+ return send_future;
77
+ }
78
+
79
+ } // namespace ymq
80
+ } // namespace scaler
@@ -0,0 +1,24 @@
1
+ #pragma once
2
+
3
+ #include <future>
4
+ #include <memory>
5
+
6
+ #include "scaler/io/ymq/error.h"
7
+ #include "scaler/io/ymq/io_context.h"
8
+ #include "scaler/io/ymq/io_socket.h"
9
+
10
+ namespace scaler {
11
+ namespace ymq {
12
+
13
+ std::shared_ptr<IOSocket> syncCreateSocket(IOContext& context, IOSocketType type, std::string name);
14
+ void syncBindSocket(std::shared_ptr<IOSocket> socket, std::string address);
15
+ void syncConnectSocket(std::shared_ptr<IOSocket> socket, std::string address);
16
+
17
+ std::expected<Message, Error> syncRecvMessage(std::shared_ptr<IOSocket> socket);
18
+ std::optional<Error> syncSendMessage(std::shared_ptr<IOSocket> socket, Message message);
19
+
20
+ std::future<std::expected<Message, Error>> futureRecvMessage(std::shared_ptr<IOSocket> socket);
21
+ std::future<std::optional<Error>> futureSendMessage(std::shared_ptr<IOSocket> socket, Message message);
22
+
23
+ } // namespace ymq
24
+ } // namespace scaler