Loading plugins/media/media.cpp +28 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include <shared_mutex> #include <condition_variable> #include <atomic> #include <chrono> #include <memory> #include <algorithm> #include <cstdint> Loading Loading @@ -1828,17 +1829,43 @@ namespace blogi { size_t sendSize = 0; size_t produced = 0; int tid = 0; std::chrono::steady_clock::time_point last_activity = std::chrono::steady_clock::now(); }; // Plugins get no callback when the browser-facing connection dies // mid-stream (no Disconnect hook in PluginApi), so a StreamState // whose owning req is abandoned would otherwise sit in _streams // forever — Response() simply stops being called for it, holding // its pooled mediadb connection open (and un-drained) permanently. // Sweep those out opportunistically whenever a new stream starts. static constexpr std::chrono::seconds STREAM_IDLE_TIMEOUT{30}; void _reapStaleStreamsLocked(){ const auto now = std::chrono::steady_clock::now(); for(auto it = _streams.begin(); it != _streams.end();){ if(now - it->second.last_activity > STREAM_IDLE_TIMEOUT){ // Connection may hold un-drained bytes from the abandoned // response — discard rather than returning it to the pool, // where reuse would desync the next reader. it->second.client.discard(); it = _streams.erase(it); } else { ++it; } } } void _storeStreamState(libhttppp::HttpRequest &req, CheckoutPool<libhttppp::HttpClient>::Handle client, size_t sendSize, int tid){ std::unique_lock lock(_streamMutex); _reapStaleStreamsLocked(); auto &ss = _streams[reinterpret_cast<uintptr_t>(&req)]; ss.client = std::move(client); ss.sendSize = sendSize; ss.produced = 0; ss.tid = tid; ss.last_activity = std::chrono::steady_clock::now(); } StreamState* _getStreamState(libhttppp::HttpRequest &req){ Loading @@ -1850,6 +1877,7 @@ namespace blogi { _streams.erase(it); return nullptr; } ptr->last_activity = std::chrono::steady_clock::now(); return ptr; } Loading Loading
plugins/media/media.cpp +28 −0 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ #include <shared_mutex> #include <condition_variable> #include <atomic> #include <chrono> #include <memory> #include <algorithm> #include <cstdint> Loading Loading @@ -1828,17 +1829,43 @@ namespace blogi { size_t sendSize = 0; size_t produced = 0; int tid = 0; std::chrono::steady_clock::time_point last_activity = std::chrono::steady_clock::now(); }; // Plugins get no callback when the browser-facing connection dies // mid-stream (no Disconnect hook in PluginApi), so a StreamState // whose owning req is abandoned would otherwise sit in _streams // forever — Response() simply stops being called for it, holding // its pooled mediadb connection open (and un-drained) permanently. // Sweep those out opportunistically whenever a new stream starts. static constexpr std::chrono::seconds STREAM_IDLE_TIMEOUT{30}; void _reapStaleStreamsLocked(){ const auto now = std::chrono::steady_clock::now(); for(auto it = _streams.begin(); it != _streams.end();){ if(now - it->second.last_activity > STREAM_IDLE_TIMEOUT){ // Connection may hold un-drained bytes from the abandoned // response — discard rather than returning it to the pool, // where reuse would desync the next reader. it->second.client.discard(); it = _streams.erase(it); } else { ++it; } } } void _storeStreamState(libhttppp::HttpRequest &req, CheckoutPool<libhttppp::HttpClient>::Handle client, size_t sendSize, int tid){ std::unique_lock lock(_streamMutex); _reapStaleStreamsLocked(); auto &ss = _streams[reinterpret_cast<uintptr_t>(&req)]; ss.client = std::move(client); ss.sendSize = sendSize; ss.produced = 0; ss.tid = tid; ss.last_activity = std::chrono::steady_clock::now(); } StreamState* _getStreamState(libhttppp::HttpRequest &req){ Loading @@ -1850,6 +1877,7 @@ namespace blogi { _streams.erase(it); return nullptr; } ptr->last_activity = std::chrono::steady_clock::now(); return ptr; } Loading