opengris-scaler 1.12.7__cp310-cp310-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,85 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
#ifdef __linux__
|
|
3
|
+
|
|
4
|
+
// System
|
|
5
|
+
#include <sys/epoll.h>
|
|
6
|
+
|
|
7
|
+
// C++
|
|
8
|
+
#include <functional>
|
|
9
|
+
#include <queue>
|
|
10
|
+
|
|
11
|
+
#include "scaler/io/ymq/configuration.h"
|
|
12
|
+
#include "scaler/io/ymq/timed_queue.h"
|
|
13
|
+
|
|
14
|
+
// First-party
|
|
15
|
+
#include "scaler/io/ymq/file_descriptor.h"
|
|
16
|
+
#include "scaler/io/ymq/interruptive_concurrent_queue.h"
|
|
17
|
+
#include "scaler/io/ymq/timestamp.h"
|
|
18
|
+
|
|
19
|
+
namespace scaler {
|
|
20
|
+
namespace ymq {
|
|
21
|
+
|
|
22
|
+
class EventManager;
|
|
23
|
+
|
|
24
|
+
// In the constructor, the epoll context should register eventfd/timerfd from
|
|
25
|
+
// This way, the queues need not know about the event manager. We don't use callbacks.
|
|
26
|
+
class EpollContext {
|
|
27
|
+
public:
|
|
28
|
+
using Function = Configuration::ExecutionFunction;
|
|
29
|
+
using DelayedFunctionQueue = std::queue<Function>;
|
|
30
|
+
using Identifier = Configuration::ExecutionCancellationIdentifier;
|
|
31
|
+
|
|
32
|
+
EpollContext()
|
|
33
|
+
{
|
|
34
|
+
_epfd = epoll_create1(0);
|
|
35
|
+
epoll_event event {};
|
|
36
|
+
|
|
37
|
+
event.events = EPOLLIN | EPOLLET;
|
|
38
|
+
event.data.u64 = _isInterruptiveFd;
|
|
39
|
+
epoll_ctl(_epfd, EPOLL_CTL_ADD, _interruptiveFunctions.eventFd(), &event);
|
|
40
|
+
|
|
41
|
+
event = {};
|
|
42
|
+
event.events = EPOLLIN | EPOLLET;
|
|
43
|
+
event.data.u64 = _isTimingFd;
|
|
44
|
+
epoll_ctl(_epfd, EPOLL_CTL_ADD, _timingFunctions.timingFd(), &event);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
~EpollContext()
|
|
48
|
+
{
|
|
49
|
+
epoll_ctl(_epfd, EPOLL_CTL_DEL, _interruptiveFunctions.eventFd(), nullptr);
|
|
50
|
+
epoll_ctl(_epfd, EPOLL_CTL_DEL, _timingFunctions.timingFd(), nullptr);
|
|
51
|
+
|
|
52
|
+
close(_epfd);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
void loop();
|
|
56
|
+
|
|
57
|
+
void addFdToLoop(int fd, uint64_t events, EventManager* manager);
|
|
58
|
+
void removeFdFromLoop(int fd);
|
|
59
|
+
|
|
60
|
+
// NOTE: Thread-safe method to communicate with the event loop thread
|
|
61
|
+
void executeNow(Function func) { _interruptiveFunctions.enqueue(std::move(func)); }
|
|
62
|
+
// WARN: NOT thread-safe. Thread safety is guaranteed by executeNow.
|
|
63
|
+
void executeLater(Function func) { _delayedFunctions.emplace(std::move(func)); }
|
|
64
|
+
// WARN: NOT thread-safe. Thread safety is guaranteed by executeNow.
|
|
65
|
+
Identifier executeAt(Timestamp timestamp, Function callback)
|
|
66
|
+
{
|
|
67
|
+
return _timingFunctions.push(timestamp, std::move(callback));
|
|
68
|
+
}
|
|
69
|
+
void cancelExecution(Identifier identifier) { _timingFunctions.cancelExecution(identifier); }
|
|
70
|
+
|
|
71
|
+
private:
|
|
72
|
+
void execPendingFunctions();
|
|
73
|
+
int _epfd;
|
|
74
|
+
TimedQueue _timingFunctions;
|
|
75
|
+
DelayedFunctionQueue _delayedFunctions;
|
|
76
|
+
InterruptiveConcurrentQueue<Function> _interruptiveFunctions;
|
|
77
|
+
constexpr static const size_t _isInterruptiveFd = 0;
|
|
78
|
+
constexpr static const size_t _isTimingFd = 1;
|
|
79
|
+
constexpr static const size_t _reventSize = 1024;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
} // namespace ymq
|
|
83
|
+
} // namespace scaler
|
|
84
|
+
|
|
85
|
+
#endif // __linux__
|
scaler/io/ymq/error.h
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <exception> // std::terminate
|
|
5
|
+
#include <format>
|
|
6
|
+
#include <functional>
|
|
7
|
+
#include <print>
|
|
8
|
+
#include <string>
|
|
9
|
+
|
|
10
|
+
#include "scaler/io/ymq/timestamp.h"
|
|
11
|
+
#include "scaler/io/ymq/utils.h"
|
|
12
|
+
|
|
13
|
+
namespace scaler {
|
|
14
|
+
namespace ymq {
|
|
15
|
+
|
|
16
|
+
struct Error: public std::exception {
|
|
17
|
+
enum struct ErrorCode {
|
|
18
|
+
Uninit,
|
|
19
|
+
InvalidPortFormat,
|
|
20
|
+
InvalidAddressFormat,
|
|
21
|
+
ConfigurationError,
|
|
22
|
+
SignalNotSupported,
|
|
23
|
+
CoreBug,
|
|
24
|
+
RepetetiveIOSocketIdentity,
|
|
25
|
+
RedundantIOSocketRefCount,
|
|
26
|
+
MultipleConnectToNotSupported,
|
|
27
|
+
MultipleBindToNotSupported,
|
|
28
|
+
InitialConnectFailedWithInProgress,
|
|
29
|
+
SendMessageRequestCouldNotComplete,
|
|
30
|
+
SetSockOptNonFatalFailure,
|
|
31
|
+
IPv6NotSupported,
|
|
32
|
+
RemoteEndDisconnectedOnSocketWithoutGuaranteedDelivery,
|
|
33
|
+
ConnectorSocketClosedByRemoteEnd,
|
|
34
|
+
IOSocketStopRequested,
|
|
35
|
+
BinderSendMessageWithNoAddress,
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// NOTE:
|
|
39
|
+
// Format:
|
|
40
|
+
// [Timestamp, ": ", Error Explanation, ": ", Other]
|
|
41
|
+
// For user calls errors:
|
|
42
|
+
// Other := ["Originated from", Function Name, items...]
|
|
43
|
+
// For system calls errors:
|
|
44
|
+
// Other := ["Originated from", Function Name, "Errno is", strerror(errno), items...]
|
|
45
|
+
template <typename... Args>
|
|
46
|
+
constexpr Error(ErrorCode e, Args&&... args) noexcept
|
|
47
|
+
: _errorCode(e), _logMsg(argsToString(Timestamp {}, convertErrorToExplanation(e), std::forward<Args>(args)...))
|
|
48
|
+
{
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
Error() noexcept: _errorCode(ErrorCode::Uninit) {}
|
|
52
|
+
|
|
53
|
+
static inline constexpr std::string_view convertErrorToExplanation(ErrorCode e) noexcept
|
|
54
|
+
{
|
|
55
|
+
switch (e) {
|
|
56
|
+
case ErrorCode::Uninit: return "";
|
|
57
|
+
case ErrorCode::InvalidPortFormat: return "Invalid port format, example input \"tcp://127.0.0.1:2345\"";
|
|
58
|
+
case ErrorCode::InvalidAddressFormat:
|
|
59
|
+
return "Invalid address format, example input \"tcp://127.0.0.1:2345\"";
|
|
60
|
+
case ErrorCode::ConfigurationError:
|
|
61
|
+
return "An error generated by system call that's likely due to mis-configuration";
|
|
62
|
+
case ErrorCode::SignalNotSupported:
|
|
63
|
+
return "A function call was interrupted by signal, but signal handling is not supported";
|
|
64
|
+
case ErrorCode::CoreBug: return "Likely a bug within the library";
|
|
65
|
+
case ErrorCode::RepetetiveIOSocketIdentity:
|
|
66
|
+
return "It is NOT allowed to create two IOSocket with the same identity";
|
|
67
|
+
case ErrorCode::RedundantIOSocketRefCount:
|
|
68
|
+
return "It is NOT allowed to hold IOSocket shared_ptr after you try to remove it";
|
|
69
|
+
case ErrorCode::MultipleConnectToNotSupported:
|
|
70
|
+
return "Connect to remote end without the previous such request successfully completed or exceeds "
|
|
71
|
+
"retry limit is currently NOT supported";
|
|
72
|
+
case ErrorCode::MultipleBindToNotSupported:
|
|
73
|
+
return "Bind to multiple IP addresses is currently not supported";
|
|
74
|
+
case ErrorCode::InitialConnectFailedWithInProgress:
|
|
75
|
+
return "The first connect(2) call to an socket failed with EINPROGRESS, expected";
|
|
76
|
+
case ErrorCode::SendMessageRequestCouldNotComplete:
|
|
77
|
+
return "sendMessage request could not complete. Possibly because the underlying connection has been "
|
|
78
|
+
"destructed because it exceeds maximum retry limit";
|
|
79
|
+
case ErrorCode::SetSockOptNonFatalFailure: return "sendsockopt(3) gets unfatal failure";
|
|
80
|
+
case ErrorCode::IPv6NotSupported: return "IPv6 is currently not supported";
|
|
81
|
+
case ErrorCode::RemoteEndDisconnectedOnSocketWithoutGuaranteedDelivery:
|
|
82
|
+
return "You are using IOSocket::Unicast or IOSocket::Multicast, which do not support guaranteed "
|
|
83
|
+
"message delivery, and the connection(s) disconnects";
|
|
84
|
+
case ErrorCode::ConnectorSocketClosedByRemoteEnd:
|
|
85
|
+
return "You have an IOSocket with Connector type but the only connection is closed by remote end";
|
|
86
|
+
case ErrorCode::IOSocketStopRequested: return "Current IOSocket is requested to stop by another thread";
|
|
87
|
+
case ErrorCode::BinderSendMessageWithNoAddress:
|
|
88
|
+
return "You call sendMessage with a Binder IOSocket but failed to provide an address";
|
|
89
|
+
}
|
|
90
|
+
fprintf(stderr, "Unrecognized ErrorCode value, program exits\n");
|
|
91
|
+
std::exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
constexpr const char* what() const noexcept override { return _logMsg.c_str(); }
|
|
95
|
+
|
|
96
|
+
ErrorCode _errorCode;
|
|
97
|
+
std::string _logMsg;
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
} // namespace ymq
|
|
101
|
+
} // namespace scaler
|
|
102
|
+
|
|
103
|
+
template <>
|
|
104
|
+
struct std::formatter<scaler::ymq::Error, char> {
|
|
105
|
+
template <class ParseContext>
|
|
106
|
+
constexpr ParseContext::iterator parse(ParseContext& ctx) noexcept
|
|
107
|
+
{
|
|
108
|
+
return ctx.begin();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
template <class FmtContext>
|
|
112
|
+
constexpr FmtContext::iterator format(scaler::ymq::Error e, FmtContext& ctx) const noexcept
|
|
113
|
+
{
|
|
114
|
+
return std::ranges::copy(e._logMsg, ctx.out()).out;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
using UnrecoverableErrorFunctionHookPtr = std::function<void(scaler::ymq::Error)>;
|
|
119
|
+
|
|
120
|
+
[[noreturn]] inline void defaultUnrecoverableError(scaler::ymq::Error e) noexcept
|
|
121
|
+
{
|
|
122
|
+
std::print(stderr, "{}\n", e);
|
|
123
|
+
std::exit(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
inline UnrecoverableErrorFunctionHookPtr unrecoverableErrorFunctionHookPtr = defaultUnrecoverableError;
|
|
127
|
+
|
|
128
|
+
[[noreturn]] inline void unrecoverableError(scaler::ymq::Error e) noexcept
|
|
129
|
+
{
|
|
130
|
+
unrecoverableErrorFunctionHookPtr(std::move(e));
|
|
131
|
+
std::exit(1);
|
|
132
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// C++
|
|
4
|
+
#include <concepts>
|
|
5
|
+
#include <cstdint> // uint64_t
|
|
6
|
+
#include <functional>
|
|
7
|
+
|
|
8
|
+
// First-party
|
|
9
|
+
#include "scaler/io/ymq/configuration.h"
|
|
10
|
+
#include "scaler/io/ymq/epoll_context.h"
|
|
11
|
+
#include "scaler/io/ymq/iocp_context.h"
|
|
12
|
+
|
|
13
|
+
namespace scaler {
|
|
14
|
+
namespace ymq {
|
|
15
|
+
|
|
16
|
+
struct Timestamp;
|
|
17
|
+
class EventManager;
|
|
18
|
+
|
|
19
|
+
template <class Backend>
|
|
20
|
+
concept EventLoopBackend = requires(Backend backend, Backend::Function f) {
|
|
21
|
+
{ backend.executeNow(std::move(f)) } -> std::same_as<void>;
|
|
22
|
+
{ backend.executeLater(std::move(f)) } -> std::same_as<void>;
|
|
23
|
+
{ backend.executeAt(Timestamp {}, std::move(f)) } -> std::integral;
|
|
24
|
+
{ backend.cancelExecution(0) } -> std::same_as<void>;
|
|
25
|
+
|
|
26
|
+
backend.addFdToLoop(int {}, uint64_t {}, (EventManager*)nullptr);
|
|
27
|
+
{ backend.removeFdFromLoop(int {}) } -> std::same_as<void>;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
template <EventLoopBackend Backend = EpollContext>
|
|
31
|
+
class EventLoop {
|
|
32
|
+
Backend backend;
|
|
33
|
+
|
|
34
|
+
public:
|
|
35
|
+
using Function = Backend::Function;
|
|
36
|
+
using Identifier = Backend::Identifier;
|
|
37
|
+
|
|
38
|
+
void loop() { backend.loop(); }
|
|
39
|
+
|
|
40
|
+
void executeNow(Function func) { backend.executeNow(std::move(func)); }
|
|
41
|
+
void executeLater(Function func) { backend.executeLater(std::move(func)); }
|
|
42
|
+
|
|
43
|
+
Identifier executeAt(Timestamp timestamp, Function func) { return backend.executeAt(timestamp, std::move(func)); }
|
|
44
|
+
void cancelExecution(Identifier identifier) { backend.cancelExecution(identifier); }
|
|
45
|
+
|
|
46
|
+
auto addFdToLoop(int fd, uint64_t events, EventManager* manager)
|
|
47
|
+
{
|
|
48
|
+
return backend.addFdToLoop(fd, events, manager);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
void removeFdFromLoop(int fd) { backend.removeFdFromLoop(fd); }
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
} // namespace ymq
|
|
55
|
+
} // namespace scaler
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
|
|
2
|
+
#include "scaler/io/ymq/event_loop_thread.h"
|
|
3
|
+
|
|
4
|
+
#include <cassert>
|
|
5
|
+
#include <memory>
|
|
6
|
+
|
|
7
|
+
#include "scaler/io/ymq/error.h"
|
|
8
|
+
#include "scaler/io/ymq/event_manager.h"
|
|
9
|
+
#include "scaler/io/ymq/io_socket.h"
|
|
10
|
+
|
|
11
|
+
namespace scaler {
|
|
12
|
+
namespace ymq {
|
|
13
|
+
|
|
14
|
+
void EventLoopThread::createIOSocket(std::string identity, IOSocketType socketType, CreateIOSocketCallback callback)
|
|
15
|
+
{
|
|
16
|
+
if (thread.get_id() == std::thread::id()) {
|
|
17
|
+
thread = std::jthread([this](std::stop_token token) {
|
|
18
|
+
while (!token.stop_requested()) {
|
|
19
|
+
this->_eventLoop.loop();
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
_eventLoop.executeNow([this, callback = std::move(callback), identity = std::move(identity), socketType] mutable {
|
|
25
|
+
auto [iterator, inserted] = _identityToIOSocket.try_emplace(
|
|
26
|
+
identity, std::make_shared<IOSocket>(shared_from_this(), identity, socketType));
|
|
27
|
+
|
|
28
|
+
if (!inserted) {
|
|
29
|
+
unrecoverableError({
|
|
30
|
+
Error::ErrorCode::RepetetiveIOSocketIdentity,
|
|
31
|
+
"Originated from (in EventLoopThread::createIOSocket)",
|
|
32
|
+
__PRETTY_FUNCTION__,
|
|
33
|
+
"Your input identity",
|
|
34
|
+
identity,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
auto ptr = iterator->second;
|
|
39
|
+
|
|
40
|
+
callback(ptr);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
void EventLoopThread::removeIOSocket(IOSocket* target)
|
|
45
|
+
{
|
|
46
|
+
auto useCount = _identityToIOSocket[target->identity()].use_count();
|
|
47
|
+
if (useCount != 1) {
|
|
48
|
+
unrecoverableError({
|
|
49
|
+
Error::ErrorCode::RedundantIOSocketRefCount,
|
|
50
|
+
"Originated from",
|
|
51
|
+
__PRETTY_FUNCTION__,
|
|
52
|
+
"use_count",
|
|
53
|
+
useCount,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
_identityToIOSocket.erase(target->identity());
|
|
58
|
+
if (_identityToIOSocket.empty()) {
|
|
59
|
+
thread.request_stop();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
} // namespace ymq
|
|
64
|
+
} // namespace scaler
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <cstdint>
|
|
4
|
+
#include <functional>
|
|
5
|
+
#include <map>
|
|
6
|
+
#include <memory>
|
|
7
|
+
#include <thread>
|
|
8
|
+
|
|
9
|
+
#include "scaler/io/ymq/configuration.h"
|
|
10
|
+
#include "scaler/io/ymq/event_loop.h"
|
|
11
|
+
#include "scaler/io/ymq/typedefs.h"
|
|
12
|
+
|
|
13
|
+
namespace scaler {
|
|
14
|
+
namespace ymq {
|
|
15
|
+
|
|
16
|
+
class IOSocket;
|
|
17
|
+
|
|
18
|
+
class EventLoopThread: public std::enable_shared_from_this<EventLoopThread> {
|
|
19
|
+
public:
|
|
20
|
+
std::map<std::string, std::shared_ptr<IOSocket>> _identityToIOSocket;
|
|
21
|
+
using PollingContext = Configuration::PollingContext;
|
|
22
|
+
using CreateIOSocketCallback = Configuration::CreateIOSocketCallback;
|
|
23
|
+
EventLoop<PollingContext> _eventLoop;
|
|
24
|
+
// Why not make the class a friend class of IOContext?
|
|
25
|
+
// Because the removeIOSocket method is a bit trickier than addIOSocket,
|
|
26
|
+
// the IOSocket that is being removed will first remove every
|
|
27
|
+
// MessageConnectionTCP managed by it from the EventLoop, before it removes
|
|
28
|
+
// it self from ioSockets. return eventLoop.executeNow(createIOSocket());
|
|
29
|
+
void createIOSocket(std::string identity, IOSocketType socketType, CreateIOSocketCallback callback);
|
|
30
|
+
|
|
31
|
+
void removeIOSocket(IOSocket* target);
|
|
32
|
+
// EventLoop<PollingContext>& getEventLoop();
|
|
33
|
+
// IOSocket* getIOSocketByIdentity(size_t identity);
|
|
34
|
+
|
|
35
|
+
bool stopRequested() { return thread.get_stop_source().stop_requested(); }
|
|
36
|
+
|
|
37
|
+
EventLoopThread(const EventLoopThread&) = delete;
|
|
38
|
+
EventLoopThread& operator=(const EventLoopThread&) = delete;
|
|
39
|
+
EventLoopThread() = default;
|
|
40
|
+
|
|
41
|
+
private:
|
|
42
|
+
std::jthread thread;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
} // namespace ymq
|
|
46
|
+
} // namespace scaler
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// C++
|
|
4
|
+
#ifdef __linux__
|
|
5
|
+
#include <sys/epoll.h>
|
|
6
|
+
#endif // __linux__
|
|
7
|
+
#ifdef _WIN32
|
|
8
|
+
#include <windows.h>
|
|
9
|
+
#endif // _WIN32
|
|
10
|
+
|
|
11
|
+
#include <concepts>
|
|
12
|
+
#include <cstdint> // uint64_t
|
|
13
|
+
#include <functional>
|
|
14
|
+
#include <memory>
|
|
15
|
+
|
|
16
|
+
// First-party
|
|
17
|
+
#include "scaler/io/ymq/configuration.h"
|
|
18
|
+
|
|
19
|
+
namespace scaler {
|
|
20
|
+
namespace ymq {
|
|
21
|
+
|
|
22
|
+
class EventLoopThread;
|
|
23
|
+
|
|
24
|
+
// TODO: Add the _fd back
|
|
25
|
+
#ifdef _WIN32
|
|
26
|
+
class EventManager: public OVERLAPPED {
|
|
27
|
+
#endif // _WIN32
|
|
28
|
+
#ifdef __linux__
|
|
29
|
+
class EventManager {
|
|
30
|
+
#endif // __linux
|
|
31
|
+
// FileDescriptor _fd;
|
|
32
|
+
|
|
33
|
+
public:
|
|
34
|
+
void onEvents(uint64_t events)
|
|
35
|
+
{
|
|
36
|
+
#ifdef __linux__
|
|
37
|
+
if constexpr (std::same_as<Configuration::PollingContext, EpollContext>) {
|
|
38
|
+
int realEvents = (int)events;
|
|
39
|
+
if ((realEvents & EPOLLHUP) && !(realEvents & EPOLLIN)) {
|
|
40
|
+
onClose();
|
|
41
|
+
}
|
|
42
|
+
if (realEvents & (EPOLLERR | EPOLLHUP)) {
|
|
43
|
+
onError();
|
|
44
|
+
}
|
|
45
|
+
if (realEvents & (EPOLLIN | EPOLLRDHUP)) {
|
|
46
|
+
onRead();
|
|
47
|
+
}
|
|
48
|
+
if (realEvents & EPOLLOUT) {
|
|
49
|
+
onWrite();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
#endif // __linux__
|
|
53
|
+
#ifdef _WIN32
|
|
54
|
+
if constexpr (std::same_as<Configuration::PollingContext, IocpContext>) {
|
|
55
|
+
onRead();
|
|
56
|
+
onWrite();
|
|
57
|
+
if (events & IOCP_SOCKET_CLOSED) {
|
|
58
|
+
onClose();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
#endif // _WIN32
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// User that registered them should have everything they need
|
|
65
|
+
// In the future, we might add more onXX() methods, for now these are all we need.
|
|
66
|
+
using OnEventCallback = std::function<void()>;
|
|
67
|
+
OnEventCallback onRead;
|
|
68
|
+
OnEventCallback onWrite;
|
|
69
|
+
OnEventCallback onClose;
|
|
70
|
+
OnEventCallback onError;
|
|
71
|
+
// EventManager(): _fd {} {}
|
|
72
|
+
EventManager()
|
|
73
|
+
{
|
|
74
|
+
#ifdef _WIN32
|
|
75
|
+
ZeroMemory(this, sizeof(*this));
|
|
76
|
+
#endif // _WIN32
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
} // namespace ymq
|
|
81
|
+
} // namespace scaler
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// System
|
|
4
|
+
#include <sys/epoll.h>
|
|
5
|
+
#include <sys/eventfd.h>
|
|
6
|
+
#include <sys/socket.h>
|
|
7
|
+
#include <sys/timerfd.h>
|
|
8
|
+
#include <unistd.h>
|
|
9
|
+
|
|
10
|
+
// C
|
|
11
|
+
#include <cerrno>
|
|
12
|
+
|
|
13
|
+
// C++
|
|
14
|
+
#include <expected>
|
|
15
|
+
#include <optional>
|
|
16
|
+
|
|
17
|
+
// First-party
|
|
18
|
+
#include "scaler/io/ymq/common.h"
|
|
19
|
+
|
|
20
|
+
class FileDescriptor {
|
|
21
|
+
int fd;
|
|
22
|
+
|
|
23
|
+
FileDescriptor(int fd): fd(fd) {}
|
|
24
|
+
|
|
25
|
+
public:
|
|
26
|
+
~FileDescriptor() noexcept(false)
|
|
27
|
+
{
|
|
28
|
+
if (auto code = close(fd) < 0)
|
|
29
|
+
throw std::system_error(errno, std::system_category(), "Failed to close file descriptor");
|
|
30
|
+
|
|
31
|
+
this->fd = -1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
FileDescriptor(): fd(-1) {}
|
|
35
|
+
|
|
36
|
+
// move-only
|
|
37
|
+
FileDescriptor(const FileDescriptor&) = delete;
|
|
38
|
+
FileDescriptor& operator=(const FileDescriptor&) = delete;
|
|
39
|
+
FileDescriptor(FileDescriptor&& other) noexcept: fd(other.fd)
|
|
40
|
+
{
|
|
41
|
+
other.fd = -1; // prevent double close
|
|
42
|
+
}
|
|
43
|
+
FileDescriptor& operator=(FileDescriptor&& other) noexcept
|
|
44
|
+
{
|
|
45
|
+
if (this != &other) {
|
|
46
|
+
if (fd >= 0) {
|
|
47
|
+
close(fd); // close current fd
|
|
48
|
+
}
|
|
49
|
+
fd = other.fd;
|
|
50
|
+
other.fd = -1; // prevent double close
|
|
51
|
+
}
|
|
52
|
+
return *this;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static std::expected<FileDescriptor, Errno> socket(int domain, int type, int protocol)
|
|
56
|
+
{
|
|
57
|
+
if (int fd = ::socket(domain, type, protocol) < 0) {
|
|
58
|
+
return std::unexpected {errno};
|
|
59
|
+
} else {
|
|
60
|
+
return FileDescriptor(fd);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static std::expected<FileDescriptor, Errno> eventfd(int initval, int flags)
|
|
65
|
+
{
|
|
66
|
+
if (int fd = ::eventfd(initval, flags) < 0) {
|
|
67
|
+
return std::unexpected {errno};
|
|
68
|
+
} else {
|
|
69
|
+
return FileDescriptor(fd);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
static std::expected<FileDescriptor, Errno> timerfd(clockid_t clock, int flags)
|
|
74
|
+
{
|
|
75
|
+
if (int fd = ::timerfd_create(clock, flags) < 0) {
|
|
76
|
+
return std::unexpected {errno};
|
|
77
|
+
} else {
|
|
78
|
+
return FileDescriptor(fd);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
static std::expected<FileDescriptor, Errno> epollfd()
|
|
83
|
+
{
|
|
84
|
+
if (int fd = ::epoll_create1(0) < 0) {
|
|
85
|
+
return std::unexpected {errno};
|
|
86
|
+
} else {
|
|
87
|
+
return FileDescriptor(fd);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
std::optional<Errno> listen(int backlog)
|
|
92
|
+
{
|
|
93
|
+
if (::listen(fd, backlog) < 0) {
|
|
94
|
+
return errno;
|
|
95
|
+
} else {
|
|
96
|
+
return std::nullopt;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
std::expected<FileDescriptor, Errno> accept(sockaddr& addr, socklen_t& addrlen)
|
|
101
|
+
{
|
|
102
|
+
if (auto fd2 = ::accept(fd, &addr, &addrlen) < 0) {
|
|
103
|
+
return std::unexpected {errno};
|
|
104
|
+
} else {
|
|
105
|
+
return FileDescriptor(fd2);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
std::optional<Errno> connect(const sockaddr& addr, socklen_t addrlen)
|
|
110
|
+
{
|
|
111
|
+
if (::connect(fd, &addr, addrlen) < 0) {
|
|
112
|
+
return errno;
|
|
113
|
+
} else {
|
|
114
|
+
return std::nullopt;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
std::optional<Errno> bind(const sockaddr& addr, socklen_t addrlen)
|
|
119
|
+
{
|
|
120
|
+
if (::bind(fd, &addr, addrlen) < 0) {
|
|
121
|
+
return errno;
|
|
122
|
+
} else {
|
|
123
|
+
return std::nullopt;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
std::expected<ssize_t, Errno> read(void* buf, size_t count)
|
|
128
|
+
{
|
|
129
|
+
ssize_t n = ::read(fd, buf, count);
|
|
130
|
+
if (n < 0) {
|
|
131
|
+
return std::unexpected {errno};
|
|
132
|
+
} else {
|
|
133
|
+
return n;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
std::expected<ssize_t, Errno> write(const void* buf, size_t count)
|
|
138
|
+
{
|
|
139
|
+
ssize_t n = ::write(fd, buf, count);
|
|
140
|
+
if (n < 0) {
|
|
141
|
+
return std::unexpected {errno};
|
|
142
|
+
} else {
|
|
143
|
+
return n;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
std::optional<Errno> eventfd_signal()
|
|
148
|
+
{
|
|
149
|
+
uint64_t u = 1;
|
|
150
|
+
if (::eventfd_write(fd, u) < 0) {
|
|
151
|
+
return errno;
|
|
152
|
+
} else {
|
|
153
|
+
return std::nullopt;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
std::optional<Errno> eventfd_wait()
|
|
158
|
+
{
|
|
159
|
+
uint64_t u;
|
|
160
|
+
if (::eventfd_read(fd, &u) < 0) {
|
|
161
|
+
return errno;
|
|
162
|
+
} else {
|
|
163
|
+
return std::nullopt;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
std::optional<Errno> timerfd_settime(const itimerspec& new_value, itimerspec* old_value = nullptr)
|
|
168
|
+
{
|
|
169
|
+
if (::timerfd_settime(fd, 0, &new_value, old_value) < 0) {
|
|
170
|
+
return errno;
|
|
171
|
+
} else {
|
|
172
|
+
return std::nullopt;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
std::optional<Errno> timerfd_wait()
|
|
177
|
+
{
|
|
178
|
+
uint64_t u;
|
|
179
|
+
if (::read(fd, &u, sizeof(u)) < 0) {
|
|
180
|
+
return errno;
|
|
181
|
+
} else {
|
|
182
|
+
return std::nullopt;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
std::optional<Errno> epoll_ctl(int op, FileDescriptor& other, epoll_event* event)
|
|
187
|
+
{
|
|
188
|
+
if (::epoll_ctl(fd, op, other.fd, event) < 0) {
|
|
189
|
+
return errno;
|
|
190
|
+
} else {
|
|
191
|
+
return std::nullopt;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
std::expected<int, Errno> epoll_wait(epoll_event* events, int maxevents, int timeout)
|
|
196
|
+
{
|
|
197
|
+
if (auto n = ::epoll_wait(fd, events, maxevents, timeout) < 0) {
|
|
198
|
+
return errno;
|
|
199
|
+
} else {
|
|
200
|
+
return n;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
};
|