wesnoth-0001: A* pathfinding std::find on pq vector for decrease-key O(V*Q) per relaxation, fix: lazy deletion. HIGH, 1279x at N=5000. wesnoth-0002: server ip_log_ deque linear scan on login/logoff O(N) per event with N up to 500. MEDIUM, 437x at L=2000. wesnoth-0003: combine_special_notes O(N^2) vector dedup utils::contains on vector per note insertion. MEDIUM, 499x at N=1000. MOAD-0002 (Intertangle): singletons deeply embedded, not actionable. MOAD-0003 (Leaked Context): thread_local for debug/call-stack only. MOAD-0004 (Logged Secret): passwords never logged verbatim. MOAD-0005 (Thundering Herd): single-threaded game + coroutine server. 6/6 unit tests PASS.
63 lines
2 KiB
Diff
63 lines
2 KiB
Diff
# UNDF: UNDF-2026-000000971
|
|
--- a/src/server/wesnothd/server.hpp
|
|
+++ b/src/server/wesnothd/server.hpp
|
|
@@ -111,6 +111,18 @@ private:
|
|
struct connection_log
|
|
{
|
|
std::string nick, ip;
|
|
+ std::chrono::system_clock::time_point log_off;
|
|
+
|
|
+ bool operator==(const connection_log& c) const
|
|
+ {
|
|
+ // log off time does not matter to find ip-nick pairs
|
|
+ return c.nick == nick && c.ip == ip;
|
|
+ }
|
|
+ };
|
|
+
|
|
+ struct connection_log_hash
|
|
+ {
|
|
+ std::size_t operator()(const connection_log& c) const
|
|
{
|
|
+ std::size_t h1 = std::hash<std::string>{}(c.nick);
|
|
+ std::size_t h2 = std::hash<std::string>{}(c.ip);
|
|
+ return h1 ^ (h2 << 1);
|
|
}
|
|
};
|
|
|
|
- std::deque<connection_log> ip_log_;
|
|
+ // Use an unordered_set for O(1) lookup instead of linear scan on deque.
|
|
+ // Maintain a deque alongside for LRU eviction order.
|
|
+ std::deque<connection_log> ip_log_;
|
|
+ std::unordered_set<connection_log, connection_log_hash> ip_log_set_;
|
|
|
|
--- a/src/server/wesnothd/server.cpp
|
|
+++ b/src/server/wesnothd/server.cpp
|
|
@@ -896,7 +896,7 @@ void server::handle_new_client(socket_ptr socket)
|
|
connection_log ip_name { username, client_address(socket), {} };
|
|
|
|
- if(std::find(ip_log_.begin(), ip_log_.end(), ip_name) == ip_log_.end()) {
|
|
+ if(ip_log_set_.find(ip_name) == ip_log_set_.end()) {
|
|
ip_log_.push_back(ip_name);
|
|
+ ip_log_set_.insert(ip_name);
|
|
|
|
// Remove the oldest entry if the size of the IP log exceeds the maximum size
|
|
if(ip_log_.size() > max_ip_log_size_) {
|
|
+ ip_log_set_.erase(ip_log_.front());
|
|
ip_log_.pop_front();
|
|
}
|
|
}
|
|
|
|
@@ -2279,7 +2279,7 @@ void server::remove_player(player_iterator iter)
|
|
connection_log ip_name { iter->info().name(), ip, {} };
|
|
|
|
- auto i = std::find(ip_log_.begin(), ip_log_.end(), ip_name);
|
|
+ auto i = ip_log_set_.find(ip_name);
|
|
- if(i != ip_log_.end()) {
|
|
+ if(i != ip_log_set_.end()) {
|
|
- i->log_off = std::chrono::system_clock::now();
|
|
+ // Update log_off in the deque entry
|
|
+ auto di = std::find(ip_log_.begin(), ip_log_.end(), ip_name);
|
|
+ if(di != ip_log_.end()) {
|
|
+ di->log_off = std::chrono::system_clock::now();
|
|
+ }
|
|
}
|