opengris-scaler 1.12.7__cp313-cp313-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,121 @@
1
+ #pragma once
2
+
3
+ #ifdef _WIN32
4
+ // clang-format off
5
+ #include <winsock2.h>
6
+ #include <mswsock.h>
7
+ // clang-format on
8
+ #undef SendMessageCallback
9
+ #endif // _WIN32
10
+
11
+ // C++
12
+ #include <atomic>
13
+ #include <map>
14
+ #include <memory>
15
+ #include <optional>
16
+ #include <queue>
17
+ #include <string>
18
+
19
+ // First-party
20
+ #include "scaler/io/ymq/configuration.h"
21
+ #include "scaler/io/ymq/message.h"
22
+ #include "scaler/io/ymq/tcp_client.h"
23
+ #include "scaler/io/ymq/tcp_server.h"
24
+ #include "scaler/io/ymq/typedefs.h"
25
+
26
+ namespace scaler {
27
+ namespace ymq {
28
+
29
+ class EventLoopThread;
30
+ class MessageConnectionTCP;
31
+ class TcpWriteOperation;
32
+
33
+ class IOSocket {
34
+ public:
35
+ using ConnectReturnCallback = Configuration::ConnectReturnCallback;
36
+ using BindReturnCallback = Configuration::BindReturnCallback;
37
+ using SendMessageCallback = Configuration::SendMessageCallback;
38
+ using RecvMessageCallback = Configuration::RecvMessageCallback;
39
+ using Identity = Configuration::IOSocketIdentity;
40
+
41
+ IOSocket(std::shared_ptr<EventLoopThread> eventLoopThread, Identity identity, IOSocketType socketType) noexcept;
42
+ IOSocket(const IOSocket&) = delete;
43
+ IOSocket& operator=(const IOSocket&) = delete;
44
+ IOSocket(IOSocket&&) = delete;
45
+ IOSocket& operator=(IOSocket&&) = delete;
46
+ ~IOSocket() noexcept;
47
+
48
+ // NOTE: BELOW FIVE FUNCTIONS ARE USERSPACE API
49
+ void sendMessage(Message message, SendMessageCallback onMessageSent) noexcept;
50
+ void recvMessage(RecvMessageCallback onRecvMessage) noexcept;
51
+
52
+ void connectTo(sockaddr addr, ConnectReturnCallback onConnectReturn, size_t maxRetryTimes = 8) noexcept;
53
+ void connectTo(
54
+ std::string networkAddress, ConnectReturnCallback onConnectReturn, size_t maxRetryTimes = 8) noexcept;
55
+
56
+ void bindTo(std::string networkAddress, BindReturnCallback onBindReturn) noexcept;
57
+
58
+ void closeConnection(Identity remoteSocketIdentity) noexcept;
59
+
60
+ [[nodiscard]] constexpr Identity identity() const { return _identity; }
61
+
62
+ [[nodiscard]] constexpr IOSocketType socketType() const { return _socketType; }
63
+
64
+ // From Connection Class only
65
+ // TODO: Maybe figure out a better name than keepInBook. When keepInBook is true, the system will remember this
66
+ // remote identity and will treat the next connection with that identity as the reincarnation of this identity.
67
+ // Thus, keeping the identity in the book.
68
+ void onConnectionDisconnected(MessageConnectionTCP* conn, bool keepInBook = true) noexcept;
69
+ // From Connection Class only
70
+ void onConnectionIdentityReceived(MessageConnectionTCP* conn) noexcept;
71
+
72
+ // NOTE: These two functions are called respectively by sendMessage and server/client.
73
+ // Notice that in the each case only the needed information are passed in; so it's less
74
+ // likely the user passed in combinations that does not make sense. These two calls are
75
+ // mutual exclusive. Perhaps we need better name, but I failed to come up with one. - gxu
76
+ void onConnectionCreated(std::string remoteIOSocketIdentity) noexcept;
77
+ void onConnectionCreated(int fd, sockaddr localAddr, sockaddr remoteAddr, bool responsibleForRetry) noexcept;
78
+
79
+ // From TcpClient class only
80
+ void removeConnectedTcpClient() noexcept;
81
+
82
+ void requestStop() noexcept;
83
+
84
+ std::shared_ptr<EventLoopThread> _eventLoopThread;
85
+
86
+ private:
87
+ const Identity _identity;
88
+ const IOSocketType _socketType;
89
+
90
+ // NOTE: Owning one TcpClient means the user cannot issue another connectTo
91
+ // when some message connection is retring to connect.
92
+ std::optional<TcpClient> _tcpClient;
93
+
94
+ // NOTE: Owning one TcpServer means the user cannot bindTo multiple addresses.
95
+ std::optional<TcpServer> _tcpServer;
96
+
97
+ // Remote identity to connection map
98
+ std::map<std::string, std::unique_ptr<MessageConnectionTCP>> _identityToConnection;
99
+
100
+ // NOTE: An unestablished connection can be in the following states:
101
+ // 1. The underlying socket is not yet defined. This happens when user call sendMessage
102
+ // before connectTo finishes.
103
+ // 2. The underlying connection haven't exchange remote identity with its peer. This
104
+ // happens upon new socket being created.
105
+ // 3. The underlying connection contains peer's identity, but connection is broken. This
106
+ // happens upon remote end close the socket (or network issue).
107
+ // On the other hand, `Established Connection` are stored in _identityToConnection map.
108
+ // An established connection is a network connection that is currently connected, and
109
+ // exchanged their identity.
110
+ std::vector<std::unique_ptr<MessageConnectionTCP>> _unestablishedConnection;
111
+
112
+ // NOTE: This variable needs to present in the IOSocket level because the user
113
+ // does not care which connection a message is coming from.
114
+ std::shared_ptr<std::queue<RecvMessageCallback>> _pendingRecvMessages;
115
+
116
+ bool _stopped;
117
+ bool _connectorDisconnected;
118
+ };
119
+
120
+ } // namespace ymq
121
+ } // namespace scaler
@@ -0,0 +1,102 @@
1
+ #ifdef _WIN32
2
+
3
+ #include "scaler/io/ymq/iocp_context.h"
4
+
5
+ #include <cerrno>
6
+ #include <functional>
7
+
8
+ #include "scaler/io/ymq/error.h"
9
+ #include "scaler/io/ymq/event_manager.h"
10
+
11
+ namespace scaler {
12
+ namespace ymq {
13
+
14
+ void IocpContext::execPendingFunctions()
15
+ {
16
+ while (_delayedFunctions.size()) {
17
+ auto top = std::move(_delayedFunctions.front());
18
+ top();
19
+ _delayedFunctions.pop();
20
+ }
21
+ }
22
+
23
+ void IocpContext::loop()
24
+ {
25
+ std::array<OVERLAPPED_ENTRY, _reventSize> events {};
26
+ ULONG n = 0;
27
+ const bool res = GetQueuedCompletionStatusEx(_completionPort, events.data(), _reventSize, &n, INFINITE, true);
28
+ uint64_t revent = 0;
29
+ if (!res) {
30
+ const int lastError = GetLastError();
31
+ if (lastError == WAIT_IO_COMPLETION) {
32
+ auto vec = _timingFunctions.dequeue();
33
+ std::ranges::for_each(vec, [](auto& x) { x(); });
34
+ return;
35
+ }
36
+
37
+ if (lastError == ERROR_ABANDONED_WAIT_0) {
38
+ revent |= IOCP_SOCKET_CLOSED;
39
+ } else {
40
+ unrecoverableError({
41
+ Error::ErrorCode::CoreBug,
42
+ "Originated from",
43
+ "GetQueuedCompletionStatusEx",
44
+ "Errno is",
45
+ lastError,
46
+ });
47
+ }
48
+ }
49
+
50
+ // NOTE: Timer events are handled above
51
+ for (auto it = events.begin(); it != events.begin() + n; ++it) {
52
+ auto current_event = *it;
53
+ if (current_event.lpCompletionKey == _isInterruptiveFd) {
54
+ auto vec = _interruptiveFunctions.dequeue();
55
+ std::ranges::for_each(vec, [](auto&& x) { x(); });
56
+ continue;
57
+ }
58
+ if (current_event.lpCompletionKey == _isSocket) {
59
+ auto event = (EventManager*)(current_event.lpOverlapped);
60
+ // TODO: Figure out whether there is a better way to remove overlapped entry from the IOCP queue
61
+ if (!event) {
62
+ continue;
63
+ }
64
+ // TODO: Figure out the best stuff to put in
65
+ event->onEvents(revent);
66
+ }
67
+ }
68
+ execPendingFunctions();
69
+ }
70
+
71
+ void IocpContext::addFdToLoop(int fd, uint64_t, EventManager*)
72
+ {
73
+ const DWORD threadCount = 1;
74
+ if (!CreateIoCompletionPort((HANDLE)(SOCKET)fd, _completionPort, _isSocket, threadCount)) {
75
+ const int lastError = GetLastError();
76
+ // NOTE: This is when the same fd being added to the loop more than once, normal.
77
+ if (lastError == ERROR_INVALID_PARAMETER) {
78
+ return;
79
+ }
80
+
81
+ unrecoverableError({
82
+ Error::ErrorCode::CoreBug,
83
+ "Originated from",
84
+ "CreateIoCompletionPort",
85
+ "Errno is",
86
+ lastError,
87
+ });
88
+ }
89
+ }
90
+
91
+ // NOTE: IOCP is based on single action instead of the file handle.
92
+ // The file handle is automaticaly released when one call closesocket(fd).
93
+ // This interface is required by the concept, and we need it for select(2) or poll(2).
94
+ // Instead of relaxing constraint, we leave the implementation empty.
95
+ void IocpContext::removeFdFromLoop(int fd)
96
+ {
97
+ }
98
+
99
+ } // namespace ymq
100
+ } // namespace scaler
101
+
102
+ #endif // _WIN32
@@ -0,0 +1,83 @@
1
+ #pragma once
2
+ #ifdef _WIN32
3
+
4
+ // clang-format off
5
+ #include <windows.h>
6
+ #include <winsock2.h>
7
+ // clang-format on
8
+
9
+ // C++
10
+ #include <functional>
11
+ #include <queue>
12
+
13
+ #include "scaler/io/ymq/configuration.h"
14
+ #include "scaler/io/ymq/timed_queue.h"
15
+
16
+ // First-party
17
+ #include "scaler/io/ymq/interruptive_concurrent_queue.h"
18
+ #include "scaler/io/ymq/timestamp.h"
19
+
20
+ namespace scaler {
21
+ namespace ymq {
22
+
23
+ class EventManager;
24
+
25
+ // In the constructor, the epoll context should register eventfd/timerfd from
26
+ // This way, the queues need not know about the event manager. We don't use callbacks.
27
+ class IocpContext {
28
+ public:
29
+ using Function = Configuration::ExecutionFunction;
30
+ using DelayedFunctionQueue = std::queue<Function>;
31
+ using Identifier = Configuration::ExecutionCancellationIdentifier;
32
+ HANDLE _completionPort;
33
+
34
+ // TODO: Handle error with unrecoverable error in the next PR.
35
+ IocpContext()
36
+ : _completionPort(CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, (ULONG_PTR)0, 1))
37
+ , _timingFunctions(_completionPort, _isTimingFd)
38
+ , _interruptiveFunctions(_completionPort, _isInterruptiveFd)
39
+ {
40
+ if (!_completionPort) {
41
+ unrecoverableError({
42
+ Error::ErrorCode::CoreBug,
43
+ "Originated from",
44
+ "CreateIoCompletionPort",
45
+ "Errno is",
46
+ GetLastError(),
47
+ });
48
+ }
49
+ }
50
+
51
+ ~IocpContext() { CloseHandle(_completionPort); }
52
+
53
+ void loop();
54
+
55
+ void addFdToLoop(int fd, uint64_t, EventManager*);
56
+ void removeFdFromLoop(int fd);
57
+
58
+ // NOTE: Thread-safe method to communicate with the event loop thread
59
+ void executeNow(Function func) { _interruptiveFunctions.enqueue(std::move(func)); }
60
+ // WARN: NOT thread-safe. Thread safety is guaranteed by executeNow.
61
+ void executeLater(Function func) { _delayedFunctions.emplace(std::move(func)); }
62
+ // WARN: NOT thread-safe. Thread safety is guaranteed by executeNow.
63
+ Identifier executeAt(Timestamp timestamp, Function callback)
64
+ {
65
+ return _timingFunctions.push(timestamp, std::move(callback));
66
+ }
67
+ void cancelExecution(Identifier identifier) { _timingFunctions.cancelExecution(identifier); }
68
+
69
+ private:
70
+ void execPendingFunctions();
71
+ TimedQueue _timingFunctions;
72
+ DelayedFunctionQueue _delayedFunctions;
73
+ InterruptiveConcurrentQueue<Function> _interruptiveFunctions;
74
+ constexpr static const size_t _isInterruptiveFd = 0;
75
+ constexpr static const size_t _isTimingFd = 1;
76
+ constexpr static const size_t _isSocket = 2;
77
+ constexpr static const size_t _reventSize = 128; // Reduced for linter.
78
+ };
79
+
80
+ } // namespace ymq
81
+ } // namespace scaler
82
+
83
+ #endif // _WIN32
@@ -0,0 +1,163 @@
1
+ #pragma once
2
+
3
+ #include <concepts>
4
+ #include <cstddef>
5
+ #include <format>
6
+ #include <fstream>
7
+ #include <memory>
8
+ #include <print>
9
+ #include <string>
10
+ #include <type_traits>
11
+ #include <vector>
12
+
13
+ #include "scaler/io/ymq/timestamp.h"
14
+ #include "scaler/io/ymq/utils.h"
15
+
16
+ namespace scaler {
17
+ namespace ymq {
18
+
19
+ class Logger {
20
+ public:
21
+ enum LoggingLevel { critical = 0, error = 1, warning = 2, info = 3, debug = 4, notset = 5 };
22
+
23
+ // Sound default logging level based on build type.
24
+ #ifdef NDEBUG // Release build
25
+ static constexpr LoggingLevel DEFAULT_LOGGING_LEVEL = LoggingLevel::info;
26
+ #else // Debug build
27
+ static constexpr LoggingLevel DEFAULT_LOGGING_LEVEL = LoggingLevel::debug;
28
+ #endif
29
+
30
+ Logger(
31
+ std::string log_format = "%(levelname)s: %(message)s",
32
+ std::vector<std::string> log_paths = {"/dev/stdout"},
33
+ LoggingLevel level = DEFAULT_LOGGING_LEVEL)
34
+ : _log_paths(std::move(log_paths)), _level(level)
35
+ {
36
+ preprocessFormat(log_format);
37
+ }
38
+
39
+ static LoggingLevel stringToLogLevel(std::string_view level_sv)
40
+ {
41
+ if (level_sv == "CRITICAL")
42
+ return LoggingLevel::critical;
43
+ if (level_sv == "ERROR")
44
+ return LoggingLevel::error;
45
+ if (level_sv == "WARNING")
46
+ return LoggingLevel::warning;
47
+ if (level_sv == "INFO")
48
+ return LoggingLevel::info;
49
+ if (level_sv == "DEBUG")
50
+ return LoggingLevel::debug;
51
+ return LoggingLevel::info; // Default
52
+ }
53
+
54
+ static constexpr std::string_view convertLevelToString(LoggingLevel level)
55
+ {
56
+ switch (level) {
57
+ case debug: return "DEBG";
58
+ case info: return "INFO";
59
+ case error: return "EROR";
60
+ case warning: return "WARN";
61
+ case critical: return "CTIC";
62
+ case notset: return "NOTSET";
63
+ }
64
+ return "UNKNOWN";
65
+ }
66
+
67
+ template <typename... Args>
68
+ void log(LoggingLevel level, Args&&... args) const
69
+ {
70
+ if (level > _level) {
71
+ return;
72
+ }
73
+
74
+ std::ostringstream output_stream;
75
+ for (const auto& part: _processed_format) {
76
+ if (part.is_token) {
77
+ if (part.content == "levelname") {
78
+ output_stream << convertLevelToString(level);
79
+ } else if (part.content == "asctime") {
80
+ output_stream << Timestamp {};
81
+ } else if (part.content == "message") {
82
+ if constexpr (sizeof...(args) > 0) {
83
+ (output_stream << ... << std::forward<Args>(args));
84
+ }
85
+ } else if (part.content == "name") {
86
+ output_stream << "cpp-logger";
87
+ } else if (part.content == "lineno") {
88
+ output_stream << "0";
89
+ } else {
90
+ // Unknown token, print literally
91
+ output_stream << "%(" << part.content << ")s";
92
+ }
93
+ } else {
94
+ output_stream << part.content;
95
+ }
96
+ }
97
+
98
+ std::string formatted_message = output_stream.str();
99
+
100
+ for (auto log_path: _log_paths) {
101
+ if (log_path.empty() || log_path == "/dev/stdout") {
102
+ // Use std::print and flush for immediate output to the terminal
103
+ std::print("{}\n", formatted_message);
104
+ std::fflush(stdout);
105
+ } else {
106
+ // Open the file in append mode and write the log message
107
+ std::ofstream log_file(log_path, std::ios_base::app);
108
+ if (log_file.is_open()) {
109
+ log_file << formatted_message << std::endl;
110
+ } else {
111
+ throw std::runtime_error("Error: Could not open log file: " + log_path + "\n" + formatted_message);
112
+ }
113
+ }
114
+ }
115
+ }
116
+
117
+ private:
118
+ struct FormatPart {
119
+ std::string content;
120
+ bool is_token;
121
+ };
122
+
123
+ std::vector<FormatPart> _processed_format;
124
+ std::vector<std::string> _log_paths;
125
+ LoggingLevel _level;
126
+
127
+ void preprocessFormat(const std::string& format)
128
+ {
129
+ size_t last_pos = 0;
130
+ size_t find_pos = 0;
131
+
132
+ while ((find_pos = format.find('%', last_pos)) != std::string::npos) {
133
+ if (find_pos > last_pos) {
134
+ _processed_format.push_back({format.substr(last_pos, find_pos - last_pos), false});
135
+ }
136
+
137
+ if (format.length() > find_pos + 1 && format[find_pos + 1] == '%') {
138
+ _processed_format.push_back({"%", false});
139
+ last_pos = find_pos + 2;
140
+ continue;
141
+ }
142
+
143
+ if (format.length() > find_pos + 1 && format[find_pos + 1] == '(') {
144
+ size_t token_end = format.find(")s", find_pos + 2);
145
+ if (token_end != std::string::npos) {
146
+ std::string token = format.substr(find_pos + 2, token_end - (find_pos + 2));
147
+ _processed_format.push_back({token, true});
148
+ last_pos = token_end + 2;
149
+ continue;
150
+ }
151
+ }
152
+ _processed_format.push_back({"%", false});
153
+ last_pos = find_pos + 1;
154
+ }
155
+
156
+ if (last_pos < format.length()) {
157
+ _processed_format.push_back({format.substr(last_pos), false});
158
+ }
159
+ }
160
+ };
161
+
162
+ } // namespace ymq
163
+ } // namespace scaler
@@ -0,0 +1,15 @@
1
+
2
+ #pragma once
3
+
4
+ #include "scaler/io/ymq/bytes.h"
5
+
6
+ namespace scaler {
7
+ namespace ymq {
8
+
9
+ struct Message {
10
+ Bytes address; // Address of the message
11
+ Bytes payload; // Payload of the message
12
+ };
13
+
14
+ } // namespace ymq
15
+ } // namespace scaler
@@ -0,0 +1,16 @@
1
+ #pragma once
2
+
3
+ // C++
4
+ #include <functional>
5
+
6
+ // First-party
7
+ #include "scaler/io/ymq/bytes.h"
8
+
9
+ class MessageConnection {
10
+ public:
11
+ using SendMessageContinuation = std::function<void()>;
12
+ using RecvMessageContinuation = std::function<void(Bytes)>;
13
+
14
+ void send(Bytes data, SendMessageContinuation k);
15
+ void recv(RecvMessageContinuation k);
16
+ };