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.
- opengris_scaler-1.12.7.dist-info/METADATA +729 -0
- opengris_scaler-1.12.7.dist-info/RECORD +232 -0
- opengris_scaler-1.12.7.dist-info/WHEEL +5 -0
- opengris_scaler-1.12.7.dist-info/entry_points.txt +9 -0
- opengris_scaler-1.12.7.dist-info/licenses/LICENSE +201 -0
- opengris_scaler-1.12.7.dist-info/licenses/LICENSE.spdx +7 -0
- opengris_scaler-1.12.7.dist-info/licenses/NOTICE +8 -0
- opengris_scaler.libs/libcapnp-1-b787335c.1.0.so +0 -0
- opengris_scaler.libs/libkj-1-094aa318.1.0.so +0 -0
- scaler/CMakeLists.txt +11 -0
- scaler/__init__.py +14 -0
- scaler/about.py +5 -0
- scaler/client/__init__.py +0 -0
- scaler/client/agent/__init__.py +0 -0
- scaler/client/agent/client_agent.py +210 -0
- scaler/client/agent/disconnect_manager.py +27 -0
- scaler/client/agent/future_manager.py +112 -0
- scaler/client/agent/heartbeat_manager.py +74 -0
- scaler/client/agent/mixins.py +89 -0
- scaler/client/agent/object_manager.py +98 -0
- scaler/client/agent/task_manager.py +64 -0
- scaler/client/client.py +635 -0
- scaler/client/future.py +252 -0
- scaler/client/object_buffer.py +129 -0
- scaler/client/object_reference.py +25 -0
- scaler/client/serializer/__init__.py +0 -0
- scaler/client/serializer/default.py +16 -0
- scaler/client/serializer/mixins.py +38 -0
- scaler/cluster/__init__.py +0 -0
- scaler/cluster/cluster.py +115 -0
- scaler/cluster/combo.py +148 -0
- scaler/cluster/object_storage_server.py +45 -0
- scaler/cluster/scheduler.py +83 -0
- scaler/config/__init__.py +0 -0
- scaler/config/defaults.py +87 -0
- scaler/config/loader.py +95 -0
- scaler/config/mixins.py +15 -0
- scaler/config/section/__init__.py +0 -0
- scaler/config/section/cluster.py +56 -0
- scaler/config/section/native_worker_adapter.py +44 -0
- scaler/config/section/object_storage_server.py +7 -0
- scaler/config/section/scheduler.py +53 -0
- scaler/config/section/symphony_worker_adapter.py +47 -0
- scaler/config/section/top.py +13 -0
- scaler/config/section/webui.py +16 -0
- scaler/config/types/__init__.py +0 -0
- scaler/config/types/object_storage_server.py +45 -0
- scaler/config/types/worker.py +57 -0
- scaler/config/types/zmq.py +79 -0
- scaler/entry_points/__init__.py +0 -0
- scaler/entry_points/cluster.py +133 -0
- scaler/entry_points/object_storage_server.py +41 -0
- scaler/entry_points/scheduler.py +135 -0
- scaler/entry_points/top.py +286 -0
- scaler/entry_points/webui.py +26 -0
- scaler/entry_points/worker_adapter_native.py +137 -0
- scaler/entry_points/worker_adapter_symphony.py +102 -0
- scaler/io/__init__.py +0 -0
- scaler/io/async_binder.py +85 -0
- scaler/io/async_connector.py +95 -0
- scaler/io/async_object_storage_connector.py +185 -0
- scaler/io/mixins.py +154 -0
- scaler/io/sync_connector.py +68 -0
- scaler/io/sync_object_storage_connector.py +185 -0
- scaler/io/sync_subscriber.py +83 -0
- scaler/io/utility.py +31 -0
- scaler/io/ymq/CMakeLists.txt +98 -0
- scaler/io/ymq/__init__.py +0 -0
- scaler/io/ymq/_ymq.pyi +96 -0
- scaler/io/ymq/_ymq.so +0 -0
- scaler/io/ymq/bytes.h +114 -0
- scaler/io/ymq/common.h +29 -0
- scaler/io/ymq/configuration.h +60 -0
- scaler/io/ymq/epoll_context.cpp +185 -0
- scaler/io/ymq/epoll_context.h +85 -0
- scaler/io/ymq/error.h +132 -0
- scaler/io/ymq/event_loop.h +55 -0
- scaler/io/ymq/event_loop_thread.cpp +64 -0
- scaler/io/ymq/event_loop_thread.h +46 -0
- scaler/io/ymq/event_manager.h +81 -0
- scaler/io/ymq/file_descriptor.h +203 -0
- scaler/io/ymq/interruptive_concurrent_queue.h +169 -0
- scaler/io/ymq/io_context.cpp +98 -0
- scaler/io/ymq/io_context.h +44 -0
- scaler/io/ymq/io_socket.cpp +299 -0
- scaler/io/ymq/io_socket.h +121 -0
- scaler/io/ymq/iocp_context.cpp +102 -0
- scaler/io/ymq/iocp_context.h +83 -0
- scaler/io/ymq/logging.h +163 -0
- scaler/io/ymq/message.h +15 -0
- scaler/io/ymq/message_connection.h +16 -0
- scaler/io/ymq/message_connection_tcp.cpp +672 -0
- scaler/io/ymq/message_connection_tcp.h +96 -0
- scaler/io/ymq/network_utils.h +179 -0
- scaler/io/ymq/pymod_ymq/bytes.h +113 -0
- scaler/io/ymq/pymod_ymq/exception.h +124 -0
- scaler/io/ymq/pymod_ymq/gil.h +15 -0
- scaler/io/ymq/pymod_ymq/io_context.h +166 -0
- scaler/io/ymq/pymod_ymq/io_socket.h +285 -0
- scaler/io/ymq/pymod_ymq/message.h +99 -0
- scaler/io/ymq/pymod_ymq/python.h +153 -0
- scaler/io/ymq/pymod_ymq/ymq.cpp +23 -0
- scaler/io/ymq/pymod_ymq/ymq.h +357 -0
- scaler/io/ymq/readme.md +114 -0
- scaler/io/ymq/simple_interface.cpp +80 -0
- scaler/io/ymq/simple_interface.h +24 -0
- scaler/io/ymq/tcp_client.cpp +367 -0
- scaler/io/ymq/tcp_client.h +75 -0
- scaler/io/ymq/tcp_operations.h +41 -0
- scaler/io/ymq/tcp_server.cpp +410 -0
- scaler/io/ymq/tcp_server.h +79 -0
- scaler/io/ymq/third_party/concurrentqueue.h +3747 -0
- scaler/io/ymq/timed_queue.h +272 -0
- scaler/io/ymq/timestamp.h +102 -0
- scaler/io/ymq/typedefs.h +20 -0
- scaler/io/ymq/utils.h +34 -0
- scaler/io/ymq/ymq.py +130 -0
- scaler/object_storage/CMakeLists.txt +50 -0
- scaler/object_storage/__init__.py +0 -0
- scaler/object_storage/constants.h +11 -0
- scaler/object_storage/defs.h +14 -0
- scaler/object_storage/io_helper.cpp +44 -0
- scaler/object_storage/io_helper.h +9 -0
- scaler/object_storage/message.cpp +56 -0
- scaler/object_storage/message.h +130 -0
- scaler/object_storage/object_manager.cpp +126 -0
- scaler/object_storage/object_manager.h +52 -0
- scaler/object_storage/object_storage_server.cpp +359 -0
- scaler/object_storage/object_storage_server.h +126 -0
- scaler/object_storage/object_storage_server.so +0 -0
- scaler/object_storage/pymod_object_storage_server.cpp +104 -0
- scaler/protocol/__init__.py +0 -0
- scaler/protocol/capnp/__init__.py +0 -0
- scaler/protocol/capnp/_python.py +6 -0
- scaler/protocol/capnp/common.capnp +63 -0
- scaler/protocol/capnp/message.capnp +216 -0
- scaler/protocol/capnp/object_storage.capnp +52 -0
- scaler/protocol/capnp/status.capnp +73 -0
- scaler/protocol/introduction.md +105 -0
- scaler/protocol/python/__init__.py +0 -0
- scaler/protocol/python/common.py +135 -0
- scaler/protocol/python/message.py +726 -0
- scaler/protocol/python/mixins.py +13 -0
- scaler/protocol/python/object_storage.py +118 -0
- scaler/protocol/python/status.py +279 -0
- scaler/protocol/worker.md +228 -0
- scaler/scheduler/__init__.py +0 -0
- scaler/scheduler/allocate_policy/__init__.py +0 -0
- scaler/scheduler/allocate_policy/allocate_policy.py +9 -0
- scaler/scheduler/allocate_policy/capability_allocate_policy.py +280 -0
- scaler/scheduler/allocate_policy/even_load_allocate_policy.py +159 -0
- scaler/scheduler/allocate_policy/mixins.py +55 -0
- scaler/scheduler/controllers/__init__.py +0 -0
- scaler/scheduler/controllers/balance_controller.py +65 -0
- scaler/scheduler/controllers/client_controller.py +131 -0
- scaler/scheduler/controllers/config_controller.py +31 -0
- scaler/scheduler/controllers/graph_controller.py +424 -0
- scaler/scheduler/controllers/information_controller.py +81 -0
- scaler/scheduler/controllers/mixins.py +201 -0
- scaler/scheduler/controllers/object_controller.py +147 -0
- scaler/scheduler/controllers/scaling_controller.py +86 -0
- scaler/scheduler/controllers/task_controller.py +373 -0
- scaler/scheduler/controllers/worker_controller.py +168 -0
- scaler/scheduler/object_usage/__init__.py +0 -0
- scaler/scheduler/object_usage/object_tracker.py +131 -0
- scaler/scheduler/scheduler.py +253 -0
- scaler/scheduler/task/__init__.py +0 -0
- scaler/scheduler/task/task_state_machine.py +92 -0
- scaler/scheduler/task/task_state_manager.py +61 -0
- scaler/ui/__init__.py +0 -0
- scaler/ui/constants.py +9 -0
- scaler/ui/live_display.py +118 -0
- scaler/ui/memory_window.py +146 -0
- scaler/ui/setting_page.py +47 -0
- scaler/ui/task_graph.py +370 -0
- scaler/ui/task_log.py +83 -0
- scaler/ui/utility.py +35 -0
- scaler/ui/webui.py +125 -0
- scaler/ui/worker_processors.py +85 -0
- scaler/utility/__init__.py +0 -0
- scaler/utility/debug.py +19 -0
- scaler/utility/event_list.py +63 -0
- scaler/utility/event_loop.py +58 -0
- scaler/utility/exceptions.py +42 -0
- scaler/utility/formatter.py +44 -0
- scaler/utility/graph/__init__.py +0 -0
- scaler/utility/graph/optimization.py +27 -0
- scaler/utility/graph/topological_sorter.py +11 -0
- scaler/utility/graph/topological_sorter_graphblas.py +174 -0
- scaler/utility/identifiers.py +105 -0
- scaler/utility/logging/__init__.py +0 -0
- scaler/utility/logging/decorators.py +25 -0
- scaler/utility/logging/scoped_logger.py +33 -0
- scaler/utility/logging/utility.py +183 -0
- scaler/utility/many_to_many_dict.py +123 -0
- scaler/utility/metadata/__init__.py +0 -0
- scaler/utility/metadata/profile_result.py +31 -0
- scaler/utility/metadata/task_flags.py +30 -0
- scaler/utility/mixins.py +13 -0
- scaler/utility/network_util.py +7 -0
- scaler/utility/one_to_many_dict.py +72 -0
- scaler/utility/queues/__init__.py +0 -0
- scaler/utility/queues/async_indexed_queue.py +37 -0
- scaler/utility/queues/async_priority_queue.py +70 -0
- scaler/utility/queues/async_sorted_priority_queue.py +45 -0
- scaler/utility/queues/indexed_queue.py +114 -0
- scaler/utility/serialization.py +9 -0
- scaler/version.txt +1 -0
- scaler/worker/__init__.py +0 -0
- scaler/worker/agent/__init__.py +0 -0
- scaler/worker/agent/heartbeat_manager.py +107 -0
- scaler/worker/agent/mixins.py +137 -0
- scaler/worker/agent/processor/__init__.py +0 -0
- scaler/worker/agent/processor/object_cache.py +107 -0
- scaler/worker/agent/processor/processor.py +279 -0
- scaler/worker/agent/processor/streaming_buffer.py +28 -0
- scaler/worker/agent/processor_holder.py +145 -0
- scaler/worker/agent/processor_manager.py +365 -0
- scaler/worker/agent/profiling_manager.py +109 -0
- scaler/worker/agent/task_manager.py +150 -0
- scaler/worker/agent/timeout_manager.py +19 -0
- scaler/worker/preload.py +84 -0
- scaler/worker/worker.py +264 -0
- scaler/worker_adapter/__init__.py +0 -0
- scaler/worker_adapter/native.py +154 -0
- scaler/worker_adapter/symphony/__init__.py +0 -0
- scaler/worker_adapter/symphony/callback.py +45 -0
- scaler/worker_adapter/symphony/heartbeat_manager.py +79 -0
- scaler/worker_adapter/symphony/message.py +24 -0
- scaler/worker_adapter/symphony/task_manager.py +288 -0
- scaler/worker_adapter/symphony/worker.py +205 -0
- 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
|
scaler/io/ymq/logging.h
ADDED
|
@@ -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
|
scaler/io/ymq/message.h
ADDED
|
@@ -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
|
+
};
|