Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
session_manager_base.h
Go to the documentation of this file.
1/*****************************************************************************
2BSD 3-Clause License
3
4Copyright (c) 2025, kcenon
5All rights reserved.
6*****************************************************************************/
7
8#pragma once
9
12
13#include <atomic>
14#include <chrono>
15#include <memory>
16#include <mutex>
17#include <optional>
18#include <shared_mutex>
19#include <string>
20#include <type_traits>
21#include <unordered_map>
22#include <vector>
23
24namespace kcenon::network::core {
25
31 size_t max_sessions{1000};
32 std::chrono::milliseconds idle_timeout{std::chrono::minutes(5)};
33 std::chrono::milliseconds cleanup_interval{std::chrono::seconds(30)};
36};
37
70template <typename SessionType>
72public:
73 using session_ptr = std::shared_ptr<SessionType>;
76
87
88 // Non-copyable, non-movable
93
94 virtual ~session_manager_base() = default;
95
96 // =========================================================================
97 // Connection Acceptance
98 // =========================================================================
99
104 [[nodiscard]] auto can_accept_connection() const -> bool {
105 return session_count_.load(std::memory_order_acquire) < config_.max_sessions;
106 }
107
112 [[nodiscard]] auto is_backpressure_active() const -> bool {
114 return false;
115 }
116 auto count = session_count_.load(std::memory_order_acquire);
117 auto threshold =
118 static_cast<size_t>(config_.max_sessions * config_.backpressure_threshold);
119 return count >= threshold;
120 }
121
122 // =========================================================================
123 // Session CRUD
124 // =========================================================================
125
132 auto add_session(session_ptr session, const std::string& session_id = "") -> bool {
133 if (!can_accept_connection()) {
134 total_rejected_.fetch_add(1, std::memory_order_relaxed);
135 return false;
136 }
137
138 std::unique_lock lock(sessions_mutex_);
139 std::string id = session_id.empty() ? generate_id() : session_id;
140 active_sessions_.emplace(id, info_type(std::move(session)));
141 session_count_.fetch_add(1, std::memory_order_release);
142 total_accepted_.fetch_add(1, std::memory_order_relaxed);
143
144 return true;
145 }
146
156 auto add_session_with_id(session_ptr session, const std::string& session_id = "")
157 -> std::string {
158 if (!can_accept_connection()) {
159 total_rejected_.fetch_add(1, std::memory_order_relaxed);
160 return "";
161 }
162
163 std::unique_lock lock(sessions_mutex_);
164 std::string id = session_id.empty() ? generate_id() : session_id;
165 active_sessions_.emplace(id, info_type(std::move(session)));
166 session_count_.fetch_add(1, std::memory_order_release);
167 total_accepted_.fetch_add(1, std::memory_order_relaxed);
168
169 return id;
170 }
171
177 auto remove_session(const std::string& session_id) -> bool {
178 std::unique_lock lock(sessions_mutex_);
179 auto it = active_sessions_.find(session_id);
180 if (it != active_sessions_.end()) {
181 active_sessions_.erase(it);
182 session_count_.fetch_sub(1, std::memory_order_release);
183 return true;
184 }
185 return false;
186 }
187
193 [[nodiscard]] auto get_session(const std::string& session_id) const -> session_ptr {
194 std::shared_lock lock(sessions_mutex_);
195 auto it = active_sessions_.find(session_id);
196 return (it != active_sessions_.end()) ? it->second.session : nullptr;
197 }
198
203 [[nodiscard]] auto get_all_sessions() const -> std::vector<session_ptr> {
204 std::shared_lock lock(sessions_mutex_);
205 std::vector<session_ptr> sessions;
206 sessions.reserve(active_sessions_.size());
207 for (const auto& [id, info] : active_sessions_) {
208 sessions.push_back(info.session);
209 }
210 return sessions;
211 }
212
217 [[nodiscard]] auto get_all_session_ids() const -> std::vector<std::string> {
218 std::shared_lock lock(sessions_mutex_);
219 std::vector<std::string> ids;
220 ids.reserve(active_sessions_.size());
221 for (const auto& [id, info] : active_sessions_) {
222 ids.push_back(id);
223 }
224 return ids;
225 }
226
227 // =========================================================================
228 // Activity Tracking (only available when traits::has_activity_tracking)
229 // =========================================================================
230
237 template <typename T = SessionType>
238 auto update_activity(const std::string& session_id)
239 -> std::enable_if_t<session_traits<T>::has_activity_tracking, void> {
240 std::unique_lock lock(sessions_mutex_);
241 auto it = active_sessions_.find(session_id);
242 if (it != active_sessions_.end()) {
243 it->second.update_activity();
244 }
245 }
246
254 template <typename T = SessionType>
255 [[nodiscard]] auto get_idle_duration(const std::string& session_id) const
256 -> std::enable_if_t<session_traits<T>::has_activity_tracking,
257 std::optional<std::chrono::milliseconds>> {
258 std::shared_lock lock(sessions_mutex_);
259 auto it = active_sessions_.find(session_id);
260 if (it != active_sessions_.end()) {
261 return it->second.idle_duration();
262 }
263 return std::nullopt;
264 }
265
272 template <typename T = SessionType>
274 -> std::enable_if_t<session_traits<T>::has_activity_tracking, size_t> {
275 std::vector<std::pair<std::string, session_ptr>> to_remove;
276
277 // Identify idle sessions under read lock
278 {
279 std::shared_lock lock(sessions_mutex_);
280 for (const auto& [id, info] : active_sessions_) {
281 if (info.idle_duration() > config_.idle_timeout) {
282 to_remove.emplace_back(id, info.session);
283 }
284 }
285 }
286
287 // Stop and remove idle sessions
288 size_t removed = 0;
289 for (const auto& [id, session] : to_remove) {
290 if constexpr (traits::stop_on_clear) {
291 if (session) {
292 try {
293 session->stop_session();
294 } catch (...) {
295 }
296 }
297 }
298 if (remove_session(id)) {
299 removed++;
300 }
301 }
302
303 if (removed > 0) {
304 total_cleaned_up_.fetch_add(removed, std::memory_order_relaxed);
305 }
306 return removed;
307 }
308
309 // =========================================================================
310 // Lifecycle Management
311 // =========================================================================
312
319 auto clear_all_sessions() -> void {
320 if constexpr (traits::stop_on_clear) {
321 // Get sessions under read lock
322 std::vector<session_ptr> sessions;
323 {
324 std::shared_lock lock(sessions_mutex_);
325 sessions.reserve(active_sessions_.size());
326 for (const auto& [id, info] : active_sessions_) {
327 sessions.push_back(info.session);
328 }
329 }
330
331 // Stop sessions without holding lock
332 for (auto& session : sessions) {
333 if (session) {
334 try {
335 session->stop_session();
336 } catch (...) {
337 }
338 }
339 }
340 }
341
342 std::unique_lock lock(sessions_mutex_);
343 active_sessions_.clear();
344 session_count_.store(0, std::memory_order_release);
345 }
346
353
354 // =========================================================================
355 // Metrics
356 // =========================================================================
357
362 [[nodiscard]] auto get_session_count() const -> size_t {
363 return session_count_.load(std::memory_order_acquire);
364 }
365
370 [[nodiscard]] auto get_total_accepted() const -> uint64_t {
371 return total_accepted_.load(std::memory_order_relaxed);
372 }
373
378 [[nodiscard]] auto get_total_rejected() const -> uint64_t {
379 return total_rejected_.load(std::memory_order_relaxed);
380 }
381
386 [[nodiscard]] auto get_total_cleaned_up() const -> uint64_t {
387 return total_cleaned_up_.load(std::memory_order_relaxed);
388 }
389
394 [[nodiscard]] auto get_utilization() const -> double {
395 if (config_.max_sessions == 0) {
396 return 0.0;
397 }
398 return static_cast<double>(session_count_.load(std::memory_order_acquire)) /
400 }
401
402 // =========================================================================
403 // Configuration
404 // =========================================================================
405
410 auto set_max_sessions(size_t max_sessions) -> void {
411 config_.max_sessions = max_sessions;
412 }
413
418 [[nodiscard]] auto get_config() const -> const session_config& { return config_; }
419
420 // =========================================================================
421 // Statistics (comprehensive view)
422 // =========================================================================
423
428 struct stats {
436 std::chrono::milliseconds idle_timeout;
437 };
438
443 [[nodiscard]] auto get_stats() const -> stats {
444 return stats{.active_sessions = session_count_.load(std::memory_order_acquire),
445 .max_sessions = config_.max_sessions,
446 .total_accepted = total_accepted_.load(std::memory_order_relaxed),
447 .total_rejected = total_rejected_.load(std::memory_order_relaxed),
448 .total_cleaned_up = total_cleaned_up_.load(std::memory_order_relaxed),
449 .utilization = get_utilization(),
450 .backpressure_active = is_backpressure_active(),
451 .idle_timeout = config_.idle_timeout};
452 }
453
454 // =========================================================================
455 // ID Generation (public for external use)
456 // =========================================================================
457
462 static auto generate_id() -> std::string {
463 static std::atomic<uint64_t> counter{0};
464 return std::string(traits::id_prefix) +
465 std::to_string(counter.fetch_add(1, std::memory_order_relaxed));
466 }
467
468protected:
470 mutable std::shared_mutex sessions_mutex_;
471 std::unordered_map<std::string, info_type> active_sessions_;
472
473 std::atomic<size_t> session_count_;
474 std::atomic<uint64_t> total_accepted_;
475 std::atomic<uint64_t> total_rejected_;
476 std::atomic<uint64_t> total_cleaned_up_;
477};
478
479} // namespace kcenon::network::core
Thread-safe session lifecycle management template.
session_manager_base(session_manager_base &&)=delete
auto add_session_with_id(session_ptr session, const std::string &session_id="") -> std::string
Add a session and return the assigned ID.
std::unordered_map< std::string, info_type > active_sessions_
auto get_total_cleaned_up() const -> uint64_t
Get total cleaned up sessions.
auto get_session(const std::string &session_id) const -> session_ptr
Get session by ID.
session_manager_base(const session_config &config=session_config())
Constructs a session manager with the given configuration.
auto get_all_session_ids() const -> std::vector< std::string >
Get all session IDs.
auto get_total_rejected() const -> uint64_t
Get total rejected connections.
auto get_stats() const -> stats
Get comprehensive statistics.
auto get_total_accepted() const -> uint64_t
Get total accepted connections.
auto get_idle_duration(const std::string &session_id) const -> std::enable_if_t< session_traits< T >::has_activity_tracking, std::optional< std::chrono::milliseconds > >
Get idle duration for a session.
auto update_activity(const std::string &session_id) -> std::enable_if_t< session_traits< T >::has_activity_tracking, void >
Update session activity timestamp.
auto remove_session(const std::string &session_id) -> bool
Remove session by ID.
auto get_utilization() const -> double
Get current session utilization.
auto get_config() const -> const session_config &
Get current configuration.
auto set_max_sessions(size_t max_sessions) -> void
Set maximum sessions.
auto stop_all_sessions() -> void
Stop all sessions gracefully.
session_manager_base(const session_manager_base &)=delete
auto cleanup_idle_sessions() -> std::enable_if_t< session_traits< T >::has_activity_tracking, size_t >
Cleanup idle sessions that exceeded idle_timeout.
auto can_accept_connection() const -> bool
Check if new connection can be accepted.
auto is_backpressure_active() const -> bool
Check if backpressure should be applied.
auto get_all_sessions() const -> std::vector< session_ptr >
Get all active sessions.
auto add_session(session_ptr session, const std::string &session_id="") -> bool
Add a session to the manager.
session_manager_base & operator=(const session_manager_base &)=delete
static auto generate_id() -> std::string
Generate a unique session ID.
auto get_session_count() const -> size_t
Get current session count.
auto clear_all_sessions() -> void
Clear all sessions.
session_manager_base & operator=(session_manager_base &&)=delete
tracing_config config
Definition exporters.cpp:29
Configuration for session management.
Wrapper for session with optional activity tracking.
Comprehensive session manager statistics.
Customization point for session manager behavior.
static constexpr const char * id_prefix
ID prefix for auto-generated session IDs.
static constexpr bool stop_on_clear
Call session's stop method when clearing all sessions.