opengris-scaler 1.12.7__cp311-cp311-manylinux_2_28_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of opengris-scaler might be problematic. Click here for more details.

Files changed (232) hide show
  1. opengris_scaler-1.12.7.dist-info/METADATA +729 -0
  2. opengris_scaler-1.12.7.dist-info/RECORD +232 -0
  3. opengris_scaler-1.12.7.dist-info/WHEEL +5 -0
  4. opengris_scaler-1.12.7.dist-info/entry_points.txt +9 -0
  5. opengris_scaler-1.12.7.dist-info/licenses/LICENSE +201 -0
  6. opengris_scaler-1.12.7.dist-info/licenses/LICENSE.spdx +7 -0
  7. opengris_scaler-1.12.7.dist-info/licenses/NOTICE +8 -0
  8. opengris_scaler.libs/libcapnp-1-b787335c.1.0.so +0 -0
  9. opengris_scaler.libs/libkj-1-094aa318.1.0.so +0 -0
  10. scaler/CMakeLists.txt +11 -0
  11. scaler/__init__.py +14 -0
  12. scaler/about.py +5 -0
  13. scaler/client/__init__.py +0 -0
  14. scaler/client/agent/__init__.py +0 -0
  15. scaler/client/agent/client_agent.py +210 -0
  16. scaler/client/agent/disconnect_manager.py +27 -0
  17. scaler/client/agent/future_manager.py +112 -0
  18. scaler/client/agent/heartbeat_manager.py +74 -0
  19. scaler/client/agent/mixins.py +89 -0
  20. scaler/client/agent/object_manager.py +98 -0
  21. scaler/client/agent/task_manager.py +64 -0
  22. scaler/client/client.py +635 -0
  23. scaler/client/future.py +252 -0
  24. scaler/client/object_buffer.py +129 -0
  25. scaler/client/object_reference.py +25 -0
  26. scaler/client/serializer/__init__.py +0 -0
  27. scaler/client/serializer/default.py +16 -0
  28. scaler/client/serializer/mixins.py +38 -0
  29. scaler/cluster/__init__.py +0 -0
  30. scaler/cluster/cluster.py +115 -0
  31. scaler/cluster/combo.py +148 -0
  32. scaler/cluster/object_storage_server.py +45 -0
  33. scaler/cluster/scheduler.py +83 -0
  34. scaler/config/__init__.py +0 -0
  35. scaler/config/defaults.py +87 -0
  36. scaler/config/loader.py +95 -0
  37. scaler/config/mixins.py +15 -0
  38. scaler/config/section/__init__.py +0 -0
  39. scaler/config/section/cluster.py +56 -0
  40. scaler/config/section/native_worker_adapter.py +44 -0
  41. scaler/config/section/object_storage_server.py +7 -0
  42. scaler/config/section/scheduler.py +53 -0
  43. scaler/config/section/symphony_worker_adapter.py +47 -0
  44. scaler/config/section/top.py +13 -0
  45. scaler/config/section/webui.py +16 -0
  46. scaler/config/types/__init__.py +0 -0
  47. scaler/config/types/object_storage_server.py +45 -0
  48. scaler/config/types/worker.py +57 -0
  49. scaler/config/types/zmq.py +79 -0
  50. scaler/entry_points/__init__.py +0 -0
  51. scaler/entry_points/cluster.py +133 -0
  52. scaler/entry_points/object_storage_server.py +41 -0
  53. scaler/entry_points/scheduler.py +135 -0
  54. scaler/entry_points/top.py +286 -0
  55. scaler/entry_points/webui.py +26 -0
  56. scaler/entry_points/worker_adapter_native.py +137 -0
  57. scaler/entry_points/worker_adapter_symphony.py +102 -0
  58. scaler/io/__init__.py +0 -0
  59. scaler/io/async_binder.py +85 -0
  60. scaler/io/async_connector.py +95 -0
  61. scaler/io/async_object_storage_connector.py +185 -0
  62. scaler/io/mixins.py +154 -0
  63. scaler/io/sync_connector.py +68 -0
  64. scaler/io/sync_object_storage_connector.py +185 -0
  65. scaler/io/sync_subscriber.py +83 -0
  66. scaler/io/utility.py +31 -0
  67. scaler/io/ymq/CMakeLists.txt +98 -0
  68. scaler/io/ymq/__init__.py +0 -0
  69. scaler/io/ymq/_ymq.pyi +96 -0
  70. scaler/io/ymq/_ymq.so +0 -0
  71. scaler/io/ymq/bytes.h +114 -0
  72. scaler/io/ymq/common.h +29 -0
  73. scaler/io/ymq/configuration.h +60 -0
  74. scaler/io/ymq/epoll_context.cpp +185 -0
  75. scaler/io/ymq/epoll_context.h +85 -0
  76. scaler/io/ymq/error.h +132 -0
  77. scaler/io/ymq/event_loop.h +55 -0
  78. scaler/io/ymq/event_loop_thread.cpp +64 -0
  79. scaler/io/ymq/event_loop_thread.h +46 -0
  80. scaler/io/ymq/event_manager.h +81 -0
  81. scaler/io/ymq/file_descriptor.h +203 -0
  82. scaler/io/ymq/interruptive_concurrent_queue.h +169 -0
  83. scaler/io/ymq/io_context.cpp +98 -0
  84. scaler/io/ymq/io_context.h +44 -0
  85. scaler/io/ymq/io_socket.cpp +299 -0
  86. scaler/io/ymq/io_socket.h +121 -0
  87. scaler/io/ymq/iocp_context.cpp +102 -0
  88. scaler/io/ymq/iocp_context.h +83 -0
  89. scaler/io/ymq/logging.h +163 -0
  90. scaler/io/ymq/message.h +15 -0
  91. scaler/io/ymq/message_connection.h +16 -0
  92. scaler/io/ymq/message_connection_tcp.cpp +672 -0
  93. scaler/io/ymq/message_connection_tcp.h +96 -0
  94. scaler/io/ymq/network_utils.h +179 -0
  95. scaler/io/ymq/pymod_ymq/bytes.h +113 -0
  96. scaler/io/ymq/pymod_ymq/exception.h +124 -0
  97. scaler/io/ymq/pymod_ymq/gil.h +15 -0
  98. scaler/io/ymq/pymod_ymq/io_context.h +166 -0
  99. scaler/io/ymq/pymod_ymq/io_socket.h +285 -0
  100. scaler/io/ymq/pymod_ymq/message.h +99 -0
  101. scaler/io/ymq/pymod_ymq/python.h +153 -0
  102. scaler/io/ymq/pymod_ymq/ymq.cpp +23 -0
  103. scaler/io/ymq/pymod_ymq/ymq.h +357 -0
  104. scaler/io/ymq/readme.md +114 -0
  105. scaler/io/ymq/simple_interface.cpp +80 -0
  106. scaler/io/ymq/simple_interface.h +24 -0
  107. scaler/io/ymq/tcp_client.cpp +367 -0
  108. scaler/io/ymq/tcp_client.h +75 -0
  109. scaler/io/ymq/tcp_operations.h +41 -0
  110. scaler/io/ymq/tcp_server.cpp +410 -0
  111. scaler/io/ymq/tcp_server.h +79 -0
  112. scaler/io/ymq/third_party/concurrentqueue.h +3747 -0
  113. scaler/io/ymq/timed_queue.h +272 -0
  114. scaler/io/ymq/timestamp.h +102 -0
  115. scaler/io/ymq/typedefs.h +20 -0
  116. scaler/io/ymq/utils.h +34 -0
  117. scaler/io/ymq/ymq.py +130 -0
  118. scaler/object_storage/CMakeLists.txt +50 -0
  119. scaler/object_storage/__init__.py +0 -0
  120. scaler/object_storage/constants.h +11 -0
  121. scaler/object_storage/defs.h +14 -0
  122. scaler/object_storage/io_helper.cpp +44 -0
  123. scaler/object_storage/io_helper.h +9 -0
  124. scaler/object_storage/message.cpp +56 -0
  125. scaler/object_storage/message.h +130 -0
  126. scaler/object_storage/object_manager.cpp +126 -0
  127. scaler/object_storage/object_manager.h +52 -0
  128. scaler/object_storage/object_storage_server.cpp +359 -0
  129. scaler/object_storage/object_storage_server.h +126 -0
  130. scaler/object_storage/object_storage_server.so +0 -0
  131. scaler/object_storage/pymod_object_storage_server.cpp +104 -0
  132. scaler/protocol/__init__.py +0 -0
  133. scaler/protocol/capnp/__init__.py +0 -0
  134. scaler/protocol/capnp/_python.py +6 -0
  135. scaler/protocol/capnp/common.capnp +63 -0
  136. scaler/protocol/capnp/message.capnp +216 -0
  137. scaler/protocol/capnp/object_storage.capnp +52 -0
  138. scaler/protocol/capnp/status.capnp +73 -0
  139. scaler/protocol/introduction.md +105 -0
  140. scaler/protocol/python/__init__.py +0 -0
  141. scaler/protocol/python/common.py +135 -0
  142. scaler/protocol/python/message.py +726 -0
  143. scaler/protocol/python/mixins.py +13 -0
  144. scaler/protocol/python/object_storage.py +118 -0
  145. scaler/protocol/python/status.py +279 -0
  146. scaler/protocol/worker.md +228 -0
  147. scaler/scheduler/__init__.py +0 -0
  148. scaler/scheduler/allocate_policy/__init__.py +0 -0
  149. scaler/scheduler/allocate_policy/allocate_policy.py +9 -0
  150. scaler/scheduler/allocate_policy/capability_allocate_policy.py +280 -0
  151. scaler/scheduler/allocate_policy/even_load_allocate_policy.py +159 -0
  152. scaler/scheduler/allocate_policy/mixins.py +55 -0
  153. scaler/scheduler/controllers/__init__.py +0 -0
  154. scaler/scheduler/controllers/balance_controller.py +65 -0
  155. scaler/scheduler/controllers/client_controller.py +131 -0
  156. scaler/scheduler/controllers/config_controller.py +31 -0
  157. scaler/scheduler/controllers/graph_controller.py +424 -0
  158. scaler/scheduler/controllers/information_controller.py +81 -0
  159. scaler/scheduler/controllers/mixins.py +201 -0
  160. scaler/scheduler/controllers/object_controller.py +147 -0
  161. scaler/scheduler/controllers/scaling_controller.py +86 -0
  162. scaler/scheduler/controllers/task_controller.py +373 -0
  163. scaler/scheduler/controllers/worker_controller.py +168 -0
  164. scaler/scheduler/object_usage/__init__.py +0 -0
  165. scaler/scheduler/object_usage/object_tracker.py +131 -0
  166. scaler/scheduler/scheduler.py +253 -0
  167. scaler/scheduler/task/__init__.py +0 -0
  168. scaler/scheduler/task/task_state_machine.py +92 -0
  169. scaler/scheduler/task/task_state_manager.py +61 -0
  170. scaler/ui/__init__.py +0 -0
  171. scaler/ui/constants.py +9 -0
  172. scaler/ui/live_display.py +118 -0
  173. scaler/ui/memory_window.py +146 -0
  174. scaler/ui/setting_page.py +47 -0
  175. scaler/ui/task_graph.py +370 -0
  176. scaler/ui/task_log.py +83 -0
  177. scaler/ui/utility.py +35 -0
  178. scaler/ui/webui.py +125 -0
  179. scaler/ui/worker_processors.py +85 -0
  180. scaler/utility/__init__.py +0 -0
  181. scaler/utility/debug.py +19 -0
  182. scaler/utility/event_list.py +63 -0
  183. scaler/utility/event_loop.py +58 -0
  184. scaler/utility/exceptions.py +42 -0
  185. scaler/utility/formatter.py +44 -0
  186. scaler/utility/graph/__init__.py +0 -0
  187. scaler/utility/graph/optimization.py +27 -0
  188. scaler/utility/graph/topological_sorter.py +11 -0
  189. scaler/utility/graph/topological_sorter_graphblas.py +174 -0
  190. scaler/utility/identifiers.py +105 -0
  191. scaler/utility/logging/__init__.py +0 -0
  192. scaler/utility/logging/decorators.py +25 -0
  193. scaler/utility/logging/scoped_logger.py +33 -0
  194. scaler/utility/logging/utility.py +183 -0
  195. scaler/utility/many_to_many_dict.py +123 -0
  196. scaler/utility/metadata/__init__.py +0 -0
  197. scaler/utility/metadata/profile_result.py +31 -0
  198. scaler/utility/metadata/task_flags.py +30 -0
  199. scaler/utility/mixins.py +13 -0
  200. scaler/utility/network_util.py +7 -0
  201. scaler/utility/one_to_many_dict.py +72 -0
  202. scaler/utility/queues/__init__.py +0 -0
  203. scaler/utility/queues/async_indexed_queue.py +37 -0
  204. scaler/utility/queues/async_priority_queue.py +70 -0
  205. scaler/utility/queues/async_sorted_priority_queue.py +45 -0
  206. scaler/utility/queues/indexed_queue.py +114 -0
  207. scaler/utility/serialization.py +9 -0
  208. scaler/version.txt +1 -0
  209. scaler/worker/__init__.py +0 -0
  210. scaler/worker/agent/__init__.py +0 -0
  211. scaler/worker/agent/heartbeat_manager.py +107 -0
  212. scaler/worker/agent/mixins.py +137 -0
  213. scaler/worker/agent/processor/__init__.py +0 -0
  214. scaler/worker/agent/processor/object_cache.py +107 -0
  215. scaler/worker/agent/processor/processor.py +279 -0
  216. scaler/worker/agent/processor/streaming_buffer.py +28 -0
  217. scaler/worker/agent/processor_holder.py +145 -0
  218. scaler/worker/agent/processor_manager.py +365 -0
  219. scaler/worker/agent/profiling_manager.py +109 -0
  220. scaler/worker/agent/task_manager.py +150 -0
  221. scaler/worker/agent/timeout_manager.py +19 -0
  222. scaler/worker/preload.py +84 -0
  223. scaler/worker/worker.py +264 -0
  224. scaler/worker_adapter/__init__.py +0 -0
  225. scaler/worker_adapter/native.py +154 -0
  226. scaler/worker_adapter/symphony/__init__.py +0 -0
  227. scaler/worker_adapter/symphony/callback.py +45 -0
  228. scaler/worker_adapter/symphony/heartbeat_manager.py +79 -0
  229. scaler/worker_adapter/symphony/message.py +24 -0
  230. scaler/worker_adapter/symphony/task_manager.py +288 -0
  231. scaler/worker_adapter/symphony/worker.py +205 -0
  232. scaler/worker_adapter/symphony/worker_adapter.py +142 -0
@@ -0,0 +1,672 @@
1
+
2
+ #include "scaler/io/ymq/message_connection_tcp.h"
3
+
4
+ #include "scaler/io/ymq/configuration.h"
5
+
6
+ #ifdef __linux__
7
+ #include <unistd.h>
8
+ #endif // __linux__
9
+ #ifdef _WIN32
10
+ // clang-format off
11
+ #include <windows.h>
12
+ #include <winsock2.h>
13
+ #include <mswsock.h>
14
+ // clang-format on
15
+ #endif // _WIN32
16
+
17
+ #include <algorithm>
18
+ #include <cerrno>
19
+ #include <cstddef>
20
+ #include <cstdint>
21
+ #include <cstdio>
22
+ #include <expected>
23
+ #include <functional>
24
+ #include <memory>
25
+ #include <optional>
26
+
27
+ #include "scaler/io/ymq/error.h"
28
+ #include "scaler/io/ymq/event_loop_thread.h"
29
+ #include "scaler/io/ymq/event_manager.h"
30
+ #include "scaler/io/ymq/io_socket.h"
31
+ #include "scaler/io/ymq/network_utils.h"
32
+
33
+ namespace scaler {
34
+ namespace ymq {
35
+
36
+ static constexpr const size_t HEADER_SIZE = sizeof(uint64_t);
37
+
38
+ constexpr bool MessageConnectionTCP::isCompleteMessage(const TcpReadOperation& x)
39
+ {
40
+ if (x._cursor < HEADER_SIZE) {
41
+ return false;
42
+ }
43
+ if (x._cursor == x._header + HEADER_SIZE && x._payload.data() != nullptr) {
44
+ return true;
45
+ }
46
+ return false;
47
+ }
48
+
49
+ MessageConnectionTCP::MessageConnectionTCP(
50
+ std::shared_ptr<EventLoopThread> eventLoopThread,
51
+ int connFd,
52
+ sockaddr localAddr,
53
+ sockaddr remoteAddr,
54
+ std::string localIOSocketIdentity,
55
+ bool responsibleForRetry,
56
+ std::shared_ptr<std::queue<RecvMessageCallback>> pendingRecvMessageCallbacks) noexcept
57
+ : _eventLoopThread(eventLoopThread)
58
+ , _remoteAddr(std::move(remoteAddr))
59
+ , _responsibleForRetry(responsibleForRetry)
60
+ , _remoteIOSocketIdentity(std::nullopt)
61
+ , _eventManager(std::make_unique<EventManager>())
62
+ , _connFd(std::move(connFd))
63
+ , _localAddr(std::move(localAddr))
64
+ , _localIOSocketIdentity(std::move(localIOSocketIdentity))
65
+ , _sendCursor {}
66
+ , _pendingRecvMessageCallbacks(pendingRecvMessageCallbacks)
67
+ , _disconnect {false}
68
+ {
69
+ _eventManager->onRead = [this] { this->onRead(); };
70
+ _eventManager->onWrite = [this] { this->onWrite(); };
71
+ _eventManager->onClose = [this] { this->onClose(); };
72
+ _eventManager->onError = [this] { this->onError(); };
73
+ }
74
+
75
+ MessageConnectionTCP::MessageConnectionTCP(
76
+ std::shared_ptr<EventLoopThread> eventLoopThread,
77
+ std::string localIOSocketIdentity,
78
+ std::string remoteIOSocketIdentity,
79
+ std::shared_ptr<std::queue<RecvMessageCallback>> pendingRecvMessageCallbacks) noexcept
80
+ : _eventLoopThread(eventLoopThread)
81
+ , _remoteAddr {}
82
+ , _responsibleForRetry(false)
83
+ , _remoteIOSocketIdentity(std::move(remoteIOSocketIdentity))
84
+ , _eventManager(std::make_unique<EventManager>())
85
+ , _connFd {}
86
+ , _localAddr {}
87
+ , _localIOSocketIdentity(std::move(localIOSocketIdentity))
88
+ , _sendCursor {}
89
+ , _pendingRecvMessageCallbacks(pendingRecvMessageCallbacks)
90
+ , _disconnect {false}
91
+ {
92
+ _eventManager->onRead = [this] { this->onRead(); };
93
+ _eventManager->onWrite = [this] { this->onWrite(); };
94
+ _eventManager->onClose = [this] { this->onClose(); };
95
+ _eventManager->onError = [this] { this->onError(); };
96
+ }
97
+
98
+ void MessageConnectionTCP::onCreated()
99
+ {
100
+ if (_connFd != 0) {
101
+ #ifdef __linux__
102
+ this->_eventLoopThread->_eventLoop.addFdToLoop(
103
+ _connFd, EPOLLIN | EPOLLOUT | EPOLLET, this->_eventManager.get());
104
+ _writeOperations.emplace_back(
105
+ Bytes {_localIOSocketIdentity.data(), _localIOSocketIdentity.size()}, [](auto) {});
106
+ #endif // __linux__
107
+ #ifdef _WIN32
108
+ // This probably need handle the addtwice problem
109
+ this->_eventLoopThread->_eventLoop.addFdToLoop(_connFd, 0, nullptr);
110
+ _writeOperations.emplace_back(
111
+ Bytes {_localIOSocketIdentity.data(), _localIOSocketIdentity.size()}, [](auto) {});
112
+ onWrite();
113
+ const bool ok = ReadFile((HANDLE)(SOCKET)_connFd, nullptr, 0, nullptr, this->_eventManager.get());
114
+ if (ok) {
115
+ onRead();
116
+ return;
117
+ }
118
+ const int lastError = GetLastError();
119
+ if (lastError == ERROR_IO_PENDING) {
120
+ return;
121
+ }
122
+ unrecoverableError({
123
+ Error::ErrorCode::CoreBug,
124
+ "Originated from",
125
+ "ReadFile",
126
+ "Errno is",
127
+ lastError,
128
+ "_connfd",
129
+ _connFd,
130
+ });
131
+ #endif // _WIN32
132
+ }
133
+ }
134
+
135
+ std::expected<void, MessageConnectionTCP::IOError> MessageConnectionTCP::tryReadOneMessage()
136
+ {
137
+ if (_receivedReadOperations.empty() || isCompleteMessage(_receivedReadOperations.back())) {
138
+ _receivedReadOperations.emplace();
139
+ }
140
+ while (!isCompleteMessage(_receivedReadOperations.back())) {
141
+ char* readTo = nullptr;
142
+ size_t remainingSize = 0;
143
+
144
+ auto& message = _receivedReadOperations.back();
145
+ if (message._cursor < HEADER_SIZE) {
146
+ readTo = (char*)&message._header + message._cursor;
147
+ remainingSize = HEADER_SIZE - message._cursor;
148
+ } else if (message._cursor == HEADER_SIZE) {
149
+ if (message._header >= LARGEST_PAYLOAD_SIZE) {
150
+ return std::unexpected {IOError::MessageTooLarge};
151
+ }
152
+ message._payload = Bytes::alloc(message._header);
153
+ readTo = (char*)message._payload.data();
154
+ remainingSize = message._payload.len();
155
+ } else {
156
+ readTo = (char*)message._payload.data() + (message._cursor - HEADER_SIZE);
157
+ remainingSize = message._payload.len() - (message._cursor - HEADER_SIZE);
158
+ }
159
+
160
+ // We have received an empty message, which is allowed
161
+ if (remainingSize == 0) {
162
+ return {};
163
+ }
164
+
165
+ int n = ::recv(_connFd, readTo, remainingSize, 0);
166
+ if (n == 0) {
167
+ return std::unexpected {IOError::Disconnected};
168
+ } else if (n == -1) {
169
+ const int myErrno = GetErrorCode();
170
+ #ifdef _WIN32
171
+ if (myErrno == WSAEWOULDBLOCK) {
172
+ return std::unexpected {IOError::Drained};
173
+ }
174
+ if (myErrno == WSAECONNRESET || myErrno == WSAENOTSOCK) {
175
+ return std::unexpected {IOError::Aborted};
176
+ } else {
177
+ // NOTE: On Windows we don't have signals and weird IO Errors
178
+ unrecoverableError({
179
+ Error::ErrorCode::CoreBug,
180
+ "Originated from",
181
+ "recv",
182
+ "Errno is",
183
+ myErrno,
184
+ "_connfd",
185
+ _connFd,
186
+ "readTo",
187
+ (void*)readTo,
188
+ "remainingSize",
189
+ remainingSize,
190
+ });
191
+ }
192
+ #endif // _WIN32
193
+ #ifdef __linux__
194
+ if (myErrno == ECONNRESET) {
195
+ return std::unexpected {IOError::Aborted};
196
+ }
197
+ if (myErrno == EAGAIN || myErrno == EWOULDBLOCK) {
198
+ return std::unexpected {IOError::Drained};
199
+ } else {
200
+ const int myErrno = errno;
201
+ switch (myErrno) {
202
+ case EBADF:
203
+ case EISDIR:
204
+ case EINVAL:
205
+ unrecoverableError({
206
+ Error::ErrorCode::CoreBug,
207
+ "Originated from",
208
+ "read(2)",
209
+ "Errno is",
210
+ strerror(myErrno),
211
+ "_connfd",
212
+ _connFd,
213
+ "readTo",
214
+ (void*)readTo,
215
+ "remainingSize",
216
+ remainingSize,
217
+ });
218
+
219
+ case EINTR:
220
+ unrecoverableError({
221
+ Error::ErrorCode::SignalNotSupported,
222
+ "Originated from",
223
+ "read(2)",
224
+ "Errno is",
225
+ strerror(myErrno),
226
+ });
227
+
228
+ case EFAULT:
229
+ case EIO:
230
+ default:
231
+ unrecoverableError({
232
+ Error::ErrorCode::ConfigurationError,
233
+ "Originated from",
234
+ "read(2)",
235
+ "Errno is",
236
+ strerror(myErrno),
237
+ });
238
+ }
239
+ }
240
+ #endif // __linux__
241
+ } else {
242
+ message._cursor += n;
243
+ }
244
+ }
245
+ return {};
246
+ }
247
+
248
+ // on Return, unexpected value shall be interpreted as this - 0 = close, other -> errno
249
+ std::expected<void, MessageConnectionTCP::IOError> MessageConnectionTCP::tryReadMessages()
250
+ {
251
+ while (true) {
252
+ auto res = tryReadOneMessage();
253
+ if (!res) {
254
+ return res;
255
+ }
256
+ }
257
+ }
258
+
259
+ void MessageConnectionTCP::updateReadOperation()
260
+ {
261
+ while (_pendingRecvMessageCallbacks->size() && _receivedReadOperations.size()) {
262
+ if (isCompleteMessage(_receivedReadOperations.front())) {
263
+ Bytes address(_remoteIOSocketIdentity->data(), _remoteIOSocketIdentity->size());
264
+ Bytes payload(std::move(_receivedReadOperations.front()._payload));
265
+ _receivedReadOperations.pop();
266
+ auto recvMessageCallback = std::move(_pendingRecvMessageCallbacks->front());
267
+ _pendingRecvMessageCallbacks->pop();
268
+
269
+ recvMessageCallback({Message(std::move(address), std::move(payload)), {}});
270
+ } else {
271
+ assert(_pendingRecvMessageCallbacks->size());
272
+ break;
273
+ }
274
+ }
275
+ }
276
+
277
+ void MessageConnectionTCP::setRemoteIdentity() noexcept
278
+ {
279
+ if (!_remoteIOSocketIdentity &&
280
+ (_receivedReadOperations.size() && isCompleteMessage(_receivedReadOperations.front()))) {
281
+ auto id = std::move(_receivedReadOperations.front());
282
+ _remoteIOSocketIdentity.emplace((char*)id._payload.data(), id._payload.len());
283
+ _receivedReadOperations.pop();
284
+ auto sock = this->_eventLoopThread->_identityToIOSocket[_localIOSocketIdentity];
285
+ sock->onConnectionIdentityReceived(this);
286
+ }
287
+ }
288
+
289
+ void MessageConnectionTCP::onRead()
290
+ {
291
+ if (_connFd == 0) {
292
+ return;
293
+ }
294
+
295
+ auto maybeCloseConn = [this](IOError err) -> std::expected<void, IOError> {
296
+ setRemoteIdentity();
297
+
298
+ if (_remoteIOSocketIdentity) {
299
+ updateReadOperation();
300
+ }
301
+
302
+ switch (err) {
303
+ case IOError::Drained: return {};
304
+ case IOError::Aborted: _disconnect = false; break;
305
+ case IOError::Disconnected: _disconnect = true; break;
306
+ case IOError::MessageTooLarge: _disconnect = true; break;
307
+ }
308
+
309
+ onClose();
310
+ return std::unexpected {err};
311
+ };
312
+
313
+ auto res = _remoteIOSocketIdentity
314
+ .or_else([this, maybeCloseConn] {
315
+ auto _ = tryReadOneMessage()
316
+ .or_else(maybeCloseConn) //
317
+ .and_then([this]() -> std::expected<void, IOError> {
318
+ setRemoteIdentity();
319
+ return {};
320
+ });
321
+ return _remoteIOSocketIdentity;
322
+ })
323
+ .and_then([this, maybeCloseConn](const std::string&) -> std::optional<std::string> {
324
+ auto _ = tryReadMessages()
325
+ .or_else(maybeCloseConn) //
326
+ .and_then([this]() -> std::expected<void, IOError> {
327
+ updateReadOperation();
328
+ return {};
329
+ });
330
+ return _remoteIOSocketIdentity;
331
+ });
332
+ if (!res) {
333
+ return;
334
+ }
335
+
336
+ #ifdef _WIN32
337
+ const bool ok = ReadFile((HANDLE)(SOCKET)_connFd, nullptr, 0, nullptr, this->_eventManager.get());
338
+ if (ok) {
339
+ onRead();
340
+ return;
341
+ }
342
+ const auto lastError = GetLastError();
343
+ if (lastError == ERROR_IO_PENDING) {
344
+ return;
345
+ }
346
+ unrecoverableError({
347
+ Error::ErrorCode::CoreBug,
348
+ "Originated from",
349
+ "ReadFile",
350
+ "Errno is",
351
+ lastError,
352
+ "_connfd",
353
+ _connFd,
354
+ });
355
+ #endif // _WIN32
356
+ }
357
+
358
+ void MessageConnectionTCP::onWrite()
359
+ {
360
+ // This is because after disconnected, onRead will be called first, and that will set
361
+ // _connFd to 0. There's no way to not call onWrite in this case. So we return early.
362
+ if (_connFd == 0) {
363
+ return;
364
+ }
365
+
366
+ auto res = trySendQueuedMessages();
367
+ if (res) {
368
+ updateWriteOperations(res.value());
369
+ return;
370
+ }
371
+
372
+ if (res.error() == IOError::Aborted) {
373
+ onClose();
374
+ return;
375
+ }
376
+
377
+ #ifdef _WIN32
378
+ // NOTE: Precondition is the queue still has messages (perhaps a partial one).
379
+ // We don't need to update the queue because trySendQueuedMessages is okay with a complete message in front.
380
+ if (res.error() == IOError::Drained) {
381
+ void* addr = nullptr;
382
+ if (_sendCursor < HEADER_SIZE) {
383
+ addr = (char*)(&_writeOperations.front()._header) + _sendCursor;
384
+ } else {
385
+ addr = (char*)_writeOperations.front()._payload.data() + _sendCursor - HEADER_SIZE;
386
+ }
387
+ ++_sendCursor; // Next onWrite() will not be called until the asyncop complete
388
+
389
+ const bool writeFileRes = WriteFile((HANDLE)(SOCKET)_connFd, addr, 1, nullptr, _eventManager.get());
390
+ if (writeFileRes) {
391
+ onWrite();
392
+ return;
393
+ }
394
+
395
+ const auto lastError = GetLastError();
396
+ if (lastError == ERROR_IO_PENDING) {
397
+ return;
398
+ }
399
+ unrecoverableError({
400
+ Error::ErrorCode::CoreBug,
401
+ "Originated from",
402
+ "WriteFile",
403
+ "Errno is",
404
+ lastError,
405
+ "_connfd",
406
+ _connFd,
407
+ });
408
+ }
409
+ #endif // _WIN32
410
+ }
411
+
412
+ void MessageConnectionTCP::onClose()
413
+ {
414
+ if (_connFd) {
415
+ _eventLoopThread->_eventLoop.removeFdFromLoop(_connFd);
416
+ CloseAndZeroSocket(_connFd);
417
+ auto& sock = _eventLoopThread->_identityToIOSocket.at(_localIOSocketIdentity);
418
+ sock->onConnectionDisconnected(this, !_disconnect);
419
+ }
420
+ };
421
+
422
+ std::expected<size_t, MessageConnectionTCP::IOError> MessageConnectionTCP::trySendQueuedMessages()
423
+ {
424
+ // typedef struct _WSABUF {
425
+ // ULONG(same to sizet on x64 machine) len; /* the length of the buffer */
426
+ // _Field_size_bytes_(len) CHAR FAR *buf; /* the pointer to the buffer */
427
+ // } WSABUF, FAR * LPWSABUF;
428
+ #ifdef _WIN32
429
+ #define iovec ::WSABUF
430
+ #define IOV_MAX (1024)
431
+ #define iov_base buf
432
+ #define iov_len len
433
+ #endif // _WIN32
434
+
435
+ std::vector<iovec> iovecs;
436
+ iovecs.reserve(IOV_MAX);
437
+ for (auto it = _writeOperations.begin(); it != _writeOperations.end(); ++it) {
438
+ if (iovecs.size() > IOV_MAX - 2) {
439
+ break;
440
+ }
441
+
442
+ iovec iovHeader {};
443
+ iovec iovPayload {};
444
+ if (it == _writeOperations.begin()) {
445
+ if (_sendCursor < HEADER_SIZE) {
446
+ iovHeader.iov_base = (char*)(&it->_header) + _sendCursor;
447
+ iovHeader.iov_len = HEADER_SIZE - _sendCursor;
448
+ iovPayload.iov_base = (char*)(it->_payload.data());
449
+ iovPayload.iov_len = it->_payload.len();
450
+ } else {
451
+ iovHeader.iov_base = nullptr;
452
+ iovHeader.iov_len = 0;
453
+ iovPayload.iov_base = (char*)(it->_payload.data()) + (_sendCursor - HEADER_SIZE);
454
+ iovPayload.iov_len = it->_payload.len() - (_sendCursor - HEADER_SIZE);
455
+ }
456
+ } else {
457
+ iovHeader.iov_base = (char*)(&it->_header);
458
+ iovHeader.iov_len = HEADER_SIZE;
459
+ iovPayload.iov_base = (char*)(it->_payload.data());
460
+ iovPayload.iov_len = it->_payload.len();
461
+ }
462
+
463
+ iovecs.push_back(iovHeader);
464
+ iovecs.push_back(iovPayload);
465
+ }
466
+
467
+ if (iovecs.empty()) {
468
+ return 0;
469
+ }
470
+
471
+ #ifdef _WIN32
472
+ DWORD bytesSent {};
473
+ const int sendToResult =
474
+ WSASendTo(_connFd, iovecs.data(), iovecs.size(), &bytesSent, 0, nullptr, 0, nullptr, nullptr);
475
+ if (sendToResult == 0) {
476
+ return bytesSent;
477
+ }
478
+ const int myErrno = GetErrorCode();
479
+ if (myErrno == WSAEWOULDBLOCK) {
480
+ return std::unexpected {IOError::Drained};
481
+ }
482
+ if (myErrno == WSAESHUTDOWN || myErrno == WSAENOTCONN) {
483
+ return std::unexpected {IOError::Aborted};
484
+ }
485
+ unrecoverableError({
486
+ Error::ErrorCode::CoreBug,
487
+ "Originated from",
488
+ "WSASendTo",
489
+ "Errno is",
490
+ myErrno,
491
+ "_connfd",
492
+ _connFd,
493
+ "iovecs.size()",
494
+ iovecs.size(),
495
+ });
496
+ #endif // _WIN32
497
+
498
+ #ifdef __linux__
499
+ struct msghdr msg {};
500
+ msg.msg_iov = iovecs.data();
501
+ msg.msg_iovlen = iovecs.size();
502
+
503
+ ssize_t bytesSent = ::sendmsg(_connFd, &msg, MSG_NOSIGNAL);
504
+ if (bytesSent == -1) {
505
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
506
+ return std::unexpected {IOError::Drained};
507
+ } else {
508
+ const int myErrno = errno;
509
+ switch (myErrno) {
510
+ case EAFNOSUPPORT:
511
+ case EBADF:
512
+ case EINVAL:
513
+ case EMSGSIZE:
514
+ case ENOTCONN:
515
+ case ENOTSOCK:
516
+ case EOPNOTSUPP:
517
+ case ENAMETOOLONG:
518
+ case ENOENT:
519
+ case ENOTDIR:
520
+ case ELOOP:
521
+ case EDESTADDRREQ:
522
+ case EHOSTUNREACH:
523
+ case EISCONN:
524
+ unrecoverableError({
525
+ Error::ErrorCode::CoreBug,
526
+ "Originated from",
527
+ "sendmsg(2)",
528
+ "Errno is",
529
+ strerror(myErrno),
530
+ "_connfd",
531
+ _connFd,
532
+ "msg.msg_iovlen",
533
+ msg.msg_iovlen,
534
+ });
535
+ break;
536
+
537
+ case ECONNRESET:
538
+ case EPIPE: return std::unexpected {IOError::Aborted}; break;
539
+
540
+ case EINTR:
541
+ unrecoverableError({
542
+ Error::ErrorCode::SignalNotSupported,
543
+ "Originated from",
544
+ "sendmsg(2)",
545
+ "Errno is",
546
+ strerror(myErrno),
547
+ });
548
+ break;
549
+
550
+ case EIO:
551
+ case EACCES:
552
+ case ENETDOWN:
553
+ case ENETUNREACH:
554
+ case ENOBUFS:
555
+ case ENOMEM:
556
+ default:
557
+ unrecoverableError({
558
+ Error::ErrorCode::ConfigurationError,
559
+ "Originated from",
560
+ "sendmsg(2)",
561
+ "Errno is",
562
+ strerror(myErrno),
563
+ });
564
+ break;
565
+ }
566
+ }
567
+ }
568
+
569
+ return bytesSent;
570
+ #endif // __linux__
571
+
572
+ #ifdef _WIN32
573
+ #undef iovec
574
+ #undef IOV_MAX
575
+ #undef iov_base
576
+ #undef iov_len
577
+ #endif // _WIN32
578
+ }
579
+
580
+ // TODO: There is a classic optimization that can (and should) be done. That is, we store
581
+ // prefix sum in each write operation, and perform binary search instead of linear search
582
+ // to find the first write operation we haven't complete. - gxu
583
+ void MessageConnectionTCP::updateWriteOperations(size_t n)
584
+ {
585
+ auto firstIncomplete = _writeOperations.begin();
586
+ _sendCursor += n;
587
+ // Post condition of the loop: firstIncomplete contains the first write op we haven't complete.
588
+ for (auto it = _writeOperations.begin(); it != _writeOperations.end(); ++it) {
589
+ size_t msgSize = it->_payload.len() + HEADER_SIZE;
590
+ if (_sendCursor < msgSize) {
591
+ firstIncomplete = it;
592
+ break;
593
+ }
594
+
595
+ if (_sendCursor == msgSize) {
596
+ firstIncomplete = it + 1;
597
+ _sendCursor = 0;
598
+ break;
599
+ }
600
+
601
+ _sendCursor -= msgSize;
602
+ }
603
+
604
+ for (auto it = _writeOperations.begin(); it != firstIncomplete; ++it) {
605
+ it->_callbackAfterCompleteWrite({});
606
+ }
607
+
608
+ const int numPopItems = std::distance(_writeOperations.begin(), firstIncomplete);
609
+ for (int i = 0; i < numPopItems; ++i) {
610
+ _writeOperations.pop_front();
611
+ }
612
+
613
+ // _writeOperations.shrink_to_fit();
614
+ }
615
+
616
+ void MessageConnectionTCP::sendMessage(Message msg, SendMessageCallback onMessageSent)
617
+ {
618
+ TcpWriteOperation writeOp(std::move(msg), std::move(onMessageSent));
619
+ _writeOperations.emplace_back(std::move(writeOp));
620
+
621
+ if (_connFd == 0) {
622
+ return;
623
+ }
624
+ onWrite();
625
+ }
626
+
627
+ bool MessageConnectionTCP::recvMessage()
628
+ {
629
+ if (_receivedReadOperations.empty() || _pendingRecvMessageCallbacks->empty() ||
630
+ !isCompleteMessage(_receivedReadOperations.front())) {
631
+ return false;
632
+ }
633
+
634
+ updateReadOperation();
635
+ return true;
636
+ }
637
+
638
+ void MessageConnectionTCP::disconnect()
639
+ {
640
+ #ifdef __linux__
641
+ _disconnect = true;
642
+ shutdown(_connFd, SHUT_WR);
643
+ onClose();
644
+ #endif
645
+ }
646
+
647
+ MessageConnectionTCP::~MessageConnectionTCP() noexcept
648
+ {
649
+ if (_connFd != 0) {
650
+ _eventLoopThread->_eventLoop.removeFdFromLoop(_connFd);
651
+
652
+ #ifdef __linux__
653
+ shutdown(_connFd, SHUT_RD);
654
+
655
+ #endif // __linux__
656
+ #ifdef _WIN32
657
+ shutdown(_connFd, SD_BOTH);
658
+ #endif // _WIN32
659
+
660
+ CloseAndZeroSocket(_connFd);
661
+ }
662
+
663
+ std::ranges::for_each(_writeOperations, [](auto&& x) {
664
+ x._callbackAfterCompleteWrite(std::unexpected {Error::ErrorCode::SendMessageRequestCouldNotComplete});
665
+ });
666
+
667
+ // TODO: What to do with this?
668
+ // std::queue<std::vector<char>> _receivedMessages;
669
+ }
670
+
671
+ } // namespace ymq
672
+ } // namespace scaler