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,272 @@
1
+ #pragma once
2
+
3
+ #ifdef __linux__
4
+ #include <sys/timerfd.h>
5
+ #include <unistd.h>
6
+ #endif // __linux__
7
+ #ifdef _WIN32
8
+ #include <windows.h>
9
+ #endif // _WIN32
10
+
11
+ #include <cassert>
12
+ #include <queue>
13
+ #include <set>
14
+
15
+ #include "scaler/io/ymq/configuration.h"
16
+ #include "scaler/io/ymq/error.h"
17
+ #include "scaler/io/ymq/timestamp.h"
18
+
19
+ namespace scaler {
20
+ namespace ymq {
21
+
22
+ #ifdef __linux__
23
+ inline int createTimerfd()
24
+ {
25
+ int timerfd = ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
26
+ if (timerfd >= 0) {
27
+ return timerfd;
28
+ }
29
+
30
+ const int myErrno = errno;
31
+ switch (myErrno) {
32
+ case EMFILE:
33
+ case ENFILE:
34
+ case ENODEV:
35
+ case ENOMEM:
36
+ case EPERM:
37
+ unrecoverableError({
38
+ Error::ErrorCode::ConfigurationError,
39
+ "Originated from",
40
+ __PRETTY_FUNCTION__,
41
+ "Errno is",
42
+ strerror(myErrno),
43
+ });
44
+ break;
45
+
46
+ case EINVAL:
47
+ case EBADF:
48
+ case EFAULT:
49
+ case ECANCELED:
50
+ default:
51
+ unrecoverableError({
52
+ Error::ErrorCode::CoreBug,
53
+ "Originated from",
54
+ __PRETTY_FUNCTION__,
55
+ "Errno is",
56
+ strerror(myErrno),
57
+ });
58
+ break;
59
+ }
60
+ }
61
+
62
+ class TimedQueue {
63
+ public:
64
+ using Callback = Configuration::TimedQueueCallback;
65
+ using Identifier = Configuration::ExecutionCancellationIdentifier;
66
+ using TimedFunc = std::tuple<Timestamp, Callback, Identifier>;
67
+ constexpr static auto cmp = [](const auto& x, const auto& y) { return std::get<0>(x) < std::get<0>(y); };
68
+ using PriorityQueue = std::priority_queue<TimedFunc, std::vector<TimedFunc>, decltype(cmp)>;
69
+
70
+ TimedQueue(): _timerFd(createTimerfd()), _currentId {} { assert(_timerFd); }
71
+ ~TimedQueue()
72
+ {
73
+ if (_timerFd >= 0)
74
+ close(_timerFd);
75
+ }
76
+
77
+ Identifier push(Timestamp timestamp, Callback cb)
78
+ {
79
+ auto ts = convertToItimerspec(timestamp);
80
+ if (pq.empty() || timestamp < std::get<0>(pq.top())) {
81
+ int ret = timerfd_settime(_timerFd, 0, &ts, nullptr);
82
+ if (ret == -1) {
83
+ unrecoverableError({
84
+ Error::ErrorCode::CoreBug,
85
+ "Originated from",
86
+ __PRETTY_FUNCTION__,
87
+ "Errno is",
88
+ strerror(errno),
89
+ });
90
+ }
91
+ }
92
+ pq.push({timestamp, std::move(cb), _currentId});
93
+ return _currentId++;
94
+ }
95
+
96
+ void cancelExecution(Identifier id) { _cancelledFunctions.insert(id); }
97
+
98
+ std::vector<Callback> dequeue()
99
+ {
100
+ uint64_t numItems;
101
+ ssize_t n = read(_timerFd, &numItems, sizeof numItems);
102
+ if (n != sizeof numItems) [[unlikely]] {
103
+ // This should never happen anyway
104
+ unrecoverableError({
105
+ Error::ErrorCode::CoreBug,
106
+ "Originated from",
107
+ __PRETTY_FUNCTION__,
108
+ "Errno is",
109
+ strerror(errno),
110
+ });
111
+ }
112
+
113
+ std::vector<Callback> callbacks;
114
+
115
+ Timestamp now;
116
+ while (pq.size()) {
117
+ if (std::get<0>(pq.top()) < now) {
118
+ auto [ts, cb, id] = std::move(const_cast<PriorityQueue::reference>(pq.top()));
119
+ pq.pop();
120
+ auto cancelled = _cancelledFunctions.find(id);
121
+ if (cancelled != _cancelledFunctions.end()) {
122
+ _cancelledFunctions.erase(cancelled);
123
+ } else {
124
+ callbacks.emplace_back(std::move(cb));
125
+ }
126
+ } else
127
+ break;
128
+ }
129
+
130
+ if (!pq.empty()) {
131
+ auto nextTs = std::get<0>(pq.top());
132
+ auto ts = convertToItimerspec(nextTs);
133
+ int ret = timerfd_settime(_timerFd, 0, &ts, nullptr);
134
+ if (ret == -1) {
135
+ const int myErrno = errno;
136
+ switch (myErrno) {
137
+ case EMFILE:
138
+ case ENFILE:
139
+ case ENODEV:
140
+ case ENOMEM:
141
+ case EPERM:
142
+ unrecoverableError({
143
+ Error::ErrorCode::ConfigurationError,
144
+ "Originated from",
145
+ __PRETTY_FUNCTION__,
146
+ "Errno is",
147
+ strerror(myErrno),
148
+ });
149
+ break;
150
+
151
+ case EINVAL:
152
+ case EBADF:
153
+ case EFAULT:
154
+ case ECANCELED:
155
+ default:
156
+ unrecoverableError({
157
+ Error::ErrorCode::CoreBug,
158
+ "Originated from",
159
+ __PRETTY_FUNCTION__,
160
+ "Errno is",
161
+ strerror(myErrno),
162
+ });
163
+ break;
164
+ }
165
+ }
166
+ }
167
+ return callbacks;
168
+ }
169
+
170
+ int timingFd() const { return _timerFd; }
171
+
172
+ private:
173
+ int _timerFd;
174
+ Identifier _currentId;
175
+ PriorityQueue pq;
176
+ std::set<Identifier> _cancelledFunctions;
177
+ };
178
+
179
+ #endif // __linux__
180
+
181
+ #ifdef _WIN32
182
+ class TimedQueue {
183
+ public:
184
+ using Callback = Configuration::TimedQueueCallback;
185
+ using Identifier = Configuration::ExecutionCancellationIdentifier;
186
+ using TimedFunc = std::tuple<Timestamp, Callback, Identifier>;
187
+ constexpr static auto cmp = [](const auto& x, const auto& y) { return std::get<0>(x) < std::get<0>(y); };
188
+ using PriorityQueue = std::priority_queue<TimedFunc, std::vector<TimedFunc>, decltype(cmp)>;
189
+ HANDLE _completionPort;
190
+ const size_t _key;
191
+
192
+ // TODO: Handle error for system calls
193
+ TimedQueue(HANDLE completionPort, size_t key)
194
+ : _completionPort(completionPort), _key(key), _timerFd(CreateWaitableTimer(NULL, 0, NULL)), _currentId {}
195
+ {
196
+ assert(_timerFd);
197
+ }
198
+ ~TimedQueue()
199
+ {
200
+ if (_timerFd) {
201
+ CloseHandle(_timerFd);
202
+ }
203
+ }
204
+
205
+ Identifier push(Timestamp timestamp, Callback cb)
206
+ {
207
+ auto ts = convertToLARGE_INTEGER(timestamp);
208
+ if (pq.empty() || timestamp < std::get<0>(pq.top())) {
209
+ SetWaitableTimer(
210
+ _timerFd,
211
+ (LARGE_INTEGER*)&ts,
212
+ 0,
213
+ [](LPVOID thisPointer, DWORD, DWORD) {
214
+ auto* self = (TimedQueue*)thisPointer;
215
+ PostQueuedCompletionStatus(self->_completionPort, 0, (ULONG_PTR)(self->_timerFd), nullptr);
216
+ },
217
+ (LPVOID)this,
218
+ false);
219
+ }
220
+ pq.push({timestamp, std::move(cb), _currentId});
221
+ return _currentId++;
222
+ }
223
+
224
+ void cancelExecution(Identifier id) { _cancelledFunctions.insert(id); }
225
+
226
+ std::vector<Callback> dequeue()
227
+ {
228
+ std::vector<Callback> callbacks;
229
+
230
+ Timestamp now;
231
+ while (pq.size()) {
232
+ if (std::get<0>(pq.top()) < now) {
233
+ auto [ts, cb, id] = std::move(const_cast<PriorityQueue::reference>(pq.top()));
234
+ pq.pop();
235
+ auto cancelled = _cancelledFunctions.find(id);
236
+ if (cancelled != _cancelledFunctions.end()) {
237
+ _cancelledFunctions.erase(cancelled);
238
+ } else {
239
+ callbacks.emplace_back(std::move(cb));
240
+ }
241
+ } else
242
+ break;
243
+ }
244
+
245
+ if (!pq.empty()) {
246
+ auto nextTs = std::get<0>(pq.top());
247
+ auto ts = convertToLARGE_INTEGER(nextTs);
248
+ SetWaitableTimer(
249
+ _timerFd,
250
+ (LARGE_INTEGER*)&ts,
251
+ 0,
252
+ [](LPVOID thisPointer, DWORD, DWORD) {
253
+ auto* self = (TimedQueue*)thisPointer;
254
+ PostQueuedCompletionStatus(self->_completionPort, 0, (ULONG_PTR)(self->_timerFd), nullptr);
255
+ },
256
+ (LPVOID)this,
257
+ false);
258
+ }
259
+ return callbacks;
260
+ }
261
+
262
+ private:
263
+ HANDLE _timerFd;
264
+ Identifier _currentId;
265
+ PriorityQueue pq;
266
+ std::set<Identifier> _cancelledFunctions;
267
+ };
268
+
269
+ #endif // _WIN32
270
+
271
+ } // namespace ymq
272
+ } // namespace scaler
@@ -0,0 +1,102 @@
1
+ #pragma once
2
+
3
+ #ifdef __linux__
4
+ #include <sys/time.h> // itimerspec
5
+ #endif // __linux__
6
+ #ifdef _WIN32
7
+ #include <windows.h>
8
+ #endif // _WIN32
9
+
10
+ #include <cassert>
11
+ #include <chrono>
12
+ #include <ostream>
13
+ #include <sstream> // stringify
14
+
15
+ namespace scaler {
16
+ namespace ymq {
17
+
18
+ // Simple timestamp utility
19
+ struct Timestamp {
20
+ std::chrono::time_point<std::chrono::system_clock> timestamp;
21
+
22
+ friend std::strong_ordering operator<=>(Timestamp x, Timestamp y) { return x.timestamp <=> y.timestamp; }
23
+
24
+ Timestamp(): timestamp(std::chrono::system_clock::now()) {}
25
+ Timestamp(std::chrono::time_point<std::chrono::system_clock> t) { timestamp = std::move(t); }
26
+
27
+ template <class Rep, class Period = std::ratio<1>>
28
+ Timestamp createTimestampByOffsetDuration(std::chrono::duration<Rep, Period> offset)
29
+ {
30
+ return {timestamp + offset};
31
+ }
32
+ };
33
+
34
+ // For possibly logging purposes
35
+ inline std::string stringifyTimestamp(Timestamp ts)
36
+ {
37
+ std::ostringstream oss;
38
+ const auto ts_point {std::chrono::floor<std::chrono::seconds>(ts.timestamp)};
39
+ const std::chrono::zoned_time z {std::chrono::current_zone(), ts_point};
40
+ oss << std::format("{0:%F %T%z}", z);
41
+ return oss.str();
42
+ }
43
+
44
+ inline std::ostream& operator<<(std::ostream& os, const Timestamp& ts)
45
+ {
46
+ // Use the existing stringify function
47
+ os << stringifyTimestamp(ts);
48
+ return os;
49
+ }
50
+
51
+ #ifdef __linux__
52
+ // For timerfd
53
+ inline itimerspec convertToItimerspec(Timestamp ts)
54
+ {
55
+ using namespace std::chrono;
56
+
57
+ itimerspec timerspec {};
58
+ const auto duration = ts.timestamp - std::chrono::system_clock::now();
59
+ assert(duration.count() >= 0);
60
+
61
+ const auto secs = duration_cast<seconds>(duration);
62
+ const auto nanosecs = duration_cast<nanoseconds>(duration - secs);
63
+ timerspec.it_value.tv_sec = secs.count();
64
+ timerspec.it_value.tv_nsec = nanosecs.count();
65
+
66
+ return timerspec;
67
+ }
68
+ #endif // __linux__
69
+ #ifdef _WIN32
70
+ // For timerfd
71
+ inline LARGE_INTEGER convertToLARGE_INTEGER(Timestamp ts)
72
+ {
73
+ using namespace std::chrono;
74
+ const auto duration = ts.timestamp - std::chrono::system_clock::now();
75
+ assert(duration.count() >= 0);
76
+ const auto nanosecs = duration_cast<nanoseconds>(duration);
77
+ long long relativeHundredNanos = 1LL * nanosecs.count() / 100 * -1;
78
+ return *(LARGE_INTEGER*)&relativeHundredNanos;
79
+ }
80
+ #endif // _WIN32
81
+
82
+ } // namespace ymq
83
+ } // namespace scaler
84
+
85
+ template <>
86
+ struct std::formatter<scaler::ymq::Timestamp, char> {
87
+ template <class ParseContext>
88
+ constexpr ParseContext::iterator parse(ParseContext& ctx)
89
+ {
90
+ return ctx.begin();
91
+ }
92
+
93
+ template <class FmtContext>
94
+ constexpr FmtContext::iterator format(scaler::ymq::Timestamp e, FmtContext& ctx) const
95
+ {
96
+ std::ostringstream out;
97
+ const auto ts {std::chrono::floor<std::chrono::seconds>(e.timestamp)};
98
+ const std::chrono::zoned_time z {std::chrono::current_zone(), ts};
99
+ out << std::format("{0:%F %T%z}", z);
100
+ return std::ranges::copy(std::move(out).str(), ctx.out()).out;
101
+ }
102
+ };
@@ -0,0 +1,20 @@
1
+ #pragma once
2
+
3
+ #include <cstdint>
4
+
5
+ namespace scaler {
6
+ namespace ymq {
7
+
8
+ // THIS FILE MUST NOT CONTAIN USER DEFINED TYPES
9
+ enum IOSocketType : uint8_t {
10
+ Uninit, // Not allowed from user code
11
+ Binder,
12
+ Connector,
13
+ Unicast,
14
+ Multicast,
15
+ };
16
+
17
+ enum Ownership { Owned, Borrowed };
18
+
19
+ } // namespace ymq
20
+ } // namespace scaler
scaler/io/ymq/utils.h ADDED
@@ -0,0 +1,34 @@
1
+ #pragma once
2
+
3
+ #include <algorithm>
4
+ #include <cstring>
5
+ #include <format>
6
+ #include <string>
7
+
8
+ namespace scaler {
9
+ namespace ymq {
10
+
11
+ template <std::size_t N>
12
+ requires(N > 0)
13
+ consteval auto getFormatString()
14
+ {
15
+ std::string str = "{}";
16
+ for (size_t i = 1; i < N; ++i)
17
+ str += ": {}";
18
+ std::array<char, (N - 1) * 4 + 2> arr;
19
+ std::ranges::copy(str, arr.begin());
20
+ return arr;
21
+ }
22
+
23
+ // NOTE: It seems like this two lines cannot be placed in the constructor for unknown reason.
24
+ template <typename... Args>
25
+ constexpr std::string argsToString(Args&&... args)
26
+ {
27
+ static constexpr const auto str = getFormatString<sizeof...(Args)>();
28
+
29
+ std::string res = std::format(std::string_view {str}, std::forward<Args>(args)...);
30
+ return res;
31
+ }
32
+
33
+ } // namespace ymq
34
+ } // namespace scaler
scaler/io/ymq/ymq.py ADDED
@@ -0,0 +1,130 @@
1
+ # This file wraps the interface exported by the C implementation of the module
2
+ # and provides a more ergonomic interface supporting both asynchronous and synchronous execution
3
+
4
+ __all__ = ["IOSocket", "IOContext", "Message", "IOSocketType", "YMQException", "Bytes", "ErrorCode"]
5
+
6
+ import asyncio
7
+ import concurrent.futures
8
+ from typing import Optional, Callable, TypeVar, Union
9
+
10
+ try:
11
+ from typing import ParamSpec, Concatenate # type: ignore[attr-defined]
12
+ except ImportError:
13
+ from typing_extensions import ParamSpec, Concatenate # type: ignore[assignment]
14
+
15
+ from scaler.io.ymq._ymq import BaseIOContext, BaseIOSocket, Bytes, ErrorCode, IOSocketType, Message, YMQException
16
+
17
+
18
+ class IOSocket:
19
+ _base: BaseIOSocket
20
+
21
+ def __init__(self, base: BaseIOSocket) -> None:
22
+ self._base = base
23
+
24
+ @property
25
+ def socket_type(self) -> IOSocketType:
26
+ return self._base.socket_type
27
+
28
+ @property
29
+ def identity(self) -> str:
30
+ return self._base.identity
31
+
32
+ async def bind(self, address: str) -> None:
33
+ """Bind the socket to an address and listen for incoming connections"""
34
+ await call_async(self._base.bind, address)
35
+
36
+ def bind_sync(self, address: str, /, timeout: Optional[float] = None) -> None:
37
+ """Bind the socket to an address and listen for incoming connections"""
38
+ call_sync(self._base.bind, address, timeout=timeout)
39
+
40
+ async def connect(self, address: str) -> None:
41
+ """Connect to a remote socket"""
42
+ await call_async(self._base.connect, address)
43
+
44
+ def connect_sync(self, address: str, /, timeout: Optional[float] = None) -> None:
45
+ """Connect to a remote socket"""
46
+ call_sync(self._base.connect, address, timeout=timeout)
47
+
48
+ async def send(self, message: Message) -> None:
49
+ """Send a message to one of the socket's peers"""
50
+ await call_async(self._base.send, message)
51
+
52
+ def send_sync(self, message: Message, /, timeout: Optional[float] = None) -> None:
53
+ """Send a message to one of the socket's peers"""
54
+ call_sync(self._base.send, message, timeout=timeout)
55
+
56
+ async def recv(self) -> Message:
57
+ """Receive a message from one of the socket's peers"""
58
+ return await call_async(self._base.recv)
59
+
60
+ def recv_sync(self, /, timeout: Optional[float] = None) -> Message:
61
+ """Receive a message from one of the socket's peers"""
62
+ return call_sync(self._base.recv, timeout=timeout)
63
+
64
+
65
+ class IOContext:
66
+ _base: BaseIOContext
67
+
68
+ def __init__(self, num_threads: int = 1) -> None:
69
+ self._base = BaseIOContext(num_threads)
70
+
71
+ @property
72
+ def num_threads(self) -> int:
73
+ return self._base.num_threads
74
+
75
+ async def createIOSocket(self, identity: str, socket_type: IOSocketType) -> IOSocket:
76
+ """Create an io socket with an identity and socket type"""
77
+ return IOSocket(await call_async(self._base.createIOSocket, identity, socket_type))
78
+
79
+ def createIOSocket_sync(self, identity: str, socket_type: IOSocketType) -> IOSocket:
80
+ """Create an io socket with an identity and socket type"""
81
+ return IOSocket(call_sync(self._base.createIOSocket, identity, socket_type))
82
+
83
+
84
+ P = ParamSpec("P")
85
+ T = TypeVar("T")
86
+
87
+
88
+ async def call_async(
89
+ func: Callable[Concatenate[Callable[[Union[T, Exception]], None], P], None], # type: ignore
90
+ *args: P.args, # type: ignore
91
+ **kwargs: P.kwargs, # type: ignore
92
+ ) -> T:
93
+ future = asyncio.get_event_loop().create_future()
94
+
95
+ def callback(result: Union[T, Exception]):
96
+ if future.done():
97
+ return
98
+
99
+ loop = future.get_loop()
100
+
101
+ if isinstance(result, Exception):
102
+ loop.call_soon_threadsafe(future.set_exception, result)
103
+ else:
104
+ loop.call_soon_threadsafe(future.set_result, result)
105
+
106
+ func(callback, *args, **kwargs)
107
+ return await future
108
+
109
+
110
+ # about the ignore directives: mypy cannot properly handle typing extension's ParamSpec and Concatenate in python <=3.9
111
+ # these type hints are correctly understood in Python 3.10+
112
+ def call_sync( # type: ignore[valid-type]
113
+ func: Callable[Concatenate[Callable[[Union[T, Exception]], None], P], None], # type: ignore
114
+ *args: P.args, # type: ignore
115
+ timeout: Optional[float] = None,
116
+ **kwargs: P.kwargs, # type: ignore
117
+ ) -> T: # type: ignore
118
+ future: concurrent.futures.Future = concurrent.futures.Future()
119
+
120
+ def callback(result: Union[T, Exception]):
121
+ if future.done():
122
+ return
123
+
124
+ if isinstance(result, Exception):
125
+ future.set_exception(result)
126
+ else:
127
+ future.set_result(result)
128
+
129
+ func(callback, *args, **kwargs)
130
+ return future.result(timeout)
@@ -0,0 +1,50 @@
1
+ # capnp_objs ===========================================================================================================
2
+ # compile object storage schema capnp
3
+ set(CAPNPC_SRC_PREFIX "${PROJECT_SOURCE_DIR}/scaler/protocol/capnp" CACHE STRING "" FORCE)
4
+ set(CAPNPC_OUTPUT_DIR "${PROJECT_SOURCE_DIR}/scaler/protocol/capnp" CACHE STRING "" FORCE)
5
+ file(MAKE_DIRECTORY "${CAPNPC_OUTPUT_DIR}")
6
+ capnp_generate_cpp(OBJECT_STORAGE_CAPNP_SRCS OBJECT_STORAGE_CAPNP_HEADERS "../protocol/capnp/object_storage.capnp")
7
+
8
+ add_library(capnp_objs OBJECT
9
+ ${OBJECT_STORAGE_CAPNP_SRCS}
10
+ ${OBJECT_STORAGE_CAPNP_HEADERS}
11
+ )
12
+
13
+ # object_storage_server_objs ===========================================================================================
14
+ add_library(object_storage_server_objs OBJECT
15
+ io_helper.cpp
16
+ message.cpp
17
+ object_storage_server.cpp
18
+ object_manager.cpp
19
+ )
20
+
21
+ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/scaler/object_storage)
22
+
23
+ # object_storage_server python =========================================================================================
24
+ find_package(Python3 REQUIRED COMPONENTS Development.Module)
25
+
26
+ add_library(py_object_storage_server MODULE
27
+ pymod_object_storage_server.cpp
28
+ )
29
+
30
+ set_target_properties(py_object_storage_server PROPERTIES
31
+ PREFIX ""
32
+ OUTPUT_NAME "object_storage_server"
33
+ )
34
+
35
+ target_link_libraries(py_object_storage_server PRIVATE
36
+ $<$<CXX_COMPILER_ID:GNU,Clang>:-Wl,-Bstatic>
37
+ capnp_objs
38
+ ymq_objs
39
+ object_storage_server_objs
40
+ $<$<CXX_COMPILER_ID:GNU,Clang>:-Wl,-Bdynamic>
41
+ CapnProto::capnp
42
+ CapnProto::kj
43
+ Python3::Module
44
+ )
45
+
46
+ install(
47
+ TARGETS py_object_storage_server
48
+ LIBRARY DESTINATION scaler/object_storage/
49
+ COMPONENT object_storage_server
50
+ )
File without changes
@@ -0,0 +1,11 @@
1
+ #pragma once
2
+
3
+ namespace scaler {
4
+ namespace object_storage {
5
+
6
+ static constexpr size_t MEMORY_LIMIT_IN_BYTES = 6uz << 40; // 6 TB
7
+ static constexpr const char* DEFAULT_ADDR = "127.0.0.1";
8
+ static constexpr const char* DEFAULT_PORT = "55555";
9
+
10
+ }; // namespace object_storage
11
+ }; // namespace scaler
@@ -0,0 +1,14 @@
1
+ #pragma once
2
+
3
+ #include <memory> // std::shared_ptr
4
+
5
+ #include "scaler/io/ymq/bytes.h"
6
+
7
+ namespace scaler {
8
+ namespace object_storage {
9
+
10
+ using ObjectPayload = Bytes;
11
+ using SharedObjectPayload = std::shared_ptr<ObjectPayload>;
12
+
13
+ }; // namespace object_storage
14
+ }; // namespace scaler
@@ -0,0 +1,44 @@
1
+ #include "io_helper.h"
2
+
3
+ #include <netinet/in.h> // sockaddr_in
4
+ #include <sys/socket.h> // socket(2)
5
+ #include <unistd.h> // close(2)
6
+
7
+ #include <exception>
8
+ #include <iostream>
9
+
10
+ namespace scaler {
11
+ namespace object_storage {
12
+
13
+ int getAvailableTCPPort()
14
+ {
15
+ int sockfd = socket(AF_INET, SOCK_STREAM, 0);
16
+ if (sockfd < 0) {
17
+ return -1;
18
+ }
19
+
20
+ sockaddr_in addr {};
21
+ addr.sin_family = AF_INET;
22
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
23
+ addr.sin_port = 0; // Let OS choose port
24
+
25
+ if (bind(sockfd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
26
+ close(sockfd);
27
+ throw std::runtime_error("bind() failed");
28
+ }
29
+
30
+ socklen_t len = sizeof(addr);
31
+ if (getsockname(sockfd, reinterpret_cast<sockaddr*>(&addr), &len) < 0) {
32
+ close(sockfd);
33
+ throw std::runtime_error("getsockname() failed");
34
+ }
35
+
36
+ const int port = ntohs(addr.sin_port);
37
+
38
+ close(sockfd);
39
+
40
+ return port;
41
+ }
42
+
43
+ }; // namespace object_storage
44
+ }; // namespace scaler
@@ -0,0 +1,9 @@
1
+ #pragma once
2
+
3
+ namespace scaler {
4
+ namespace object_storage {
5
+
6
+ int getAvailableTCPPort();
7
+
8
+ }; // namespace object_storage
9
+ }; // namespace scaler