From 927dd473ebab7880b5dcda7d200e21b116b96aaa Mon Sep 17 00:00:00 2001 From: winlin Date: Fri, 30 Sep 2022 18:33:29 +0800 Subject: [PATCH] Kernel: Support lazy sweeping simple GC. v5.0.69 --- trunk/doc/CHANGELOG.md | 1 + trunk/src/app/srs_app_conn.cpp | 22 ++++++ trunk/src/app/srs_app_conn.hpp | 89 +++++++++++++++++++++++- trunk/src/core/srs_core_version5.hpp | 2 +- trunk/src/protocol/srs_protocol_conn.cpp | 64 +++++++++++++++++ trunk/src/protocol/srs_protocol_conn.hpp | 46 ++++++++++++ 6 files changed, 221 insertions(+), 3 deletions(-) diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md index 9dcdb918e..a8d5d78c6 100644 --- a/trunk/doc/CHANGELOG.md +++ b/trunk/doc/CHANGELOG.md @@ -7,6 +7,7 @@ The changelog for SRS. ## SRS 5.0 Changelog +* v5.0, 2022-09-30, Kernel: Support lazy sweeping simple GC. v5.0.69 * v5.0, 2022-09-30, HTTP: Support HTTP header in creating order. v5.0.68 * v5.0, 2022-09-27, For [#2899](https://github.com/ossrs/srs/issues/2899): API: Support exporter for Prometheus. v5.0.67 * v5.0, 2022-09-27, For [#3167](https://github.com/ossrs/srs/issues/3167): WebRTC: Refine sequence jitter algorithm. v5.0.66 diff --git a/trunk/src/app/srs_app_conn.cpp b/trunk/src/app/srs_app_conn.cpp index 6743acdc5..afec3d097 100644 --- a/trunk/src/app/srs_app_conn.cpp +++ b/trunk/src/app/srs_app_conn.cpp @@ -406,6 +406,28 @@ void SrsResourceManager::dispose(ISrsResource* c) } } +SrsSweepGc::SrsSweepGc() +{ +} + +SrsSweepGc::~SrsSweepGc() +{ +} + +srs_error_t SrsSweepGc::start() +{ + srs_error_t err = srs_success; + return err; +} + +void SrsSweepGc::remove(ISrsLazyResource* c) +{ + // TODO: FIXME: MUST lazy sweep. + srs_freep(c); +} + +ISrsLazyGc* _srs_gc = NULL; + ISrsExpire::ISrsExpire() { } diff --git a/trunk/src/app/srs_app_conn.hpp b/trunk/src/app/srs_app_conn.hpp index d2e3b4433..a8d0b87c6 100644 --- a/trunk/src/app/srs_app_conn.hpp +++ b/trunk/src/app/srs_app_conn.hpp @@ -124,8 +124,93 @@ private: void dispose(ISrsResource* c); }; -// If a connection is able to be expired, -// user can use HTTP-API to kick-off it. +// A simple lazy-sweep GC, just wait for a long time to delete the disposable resources. +class SrsSweepGc : public ISrsLazyGc +{ +public: + SrsSweepGc(); + virtual ~SrsSweepGc(); +public: + virtual srs_error_t start(); + virtual void remove(ISrsLazyResource* c); +}; + +extern ISrsLazyGc* _srs_gc; + +// A wrapper template for lazy-sweep resource. +// See https://github.com/ossrs/srs/issues/3176#lazy-sweep +template +class SrsLazyResourceWrapper : public ISrsResource +{ +private: + T* resource_; + ISrsResource* wrapper_; + bool is_root_; +public: + SrsLazyResourceWrapper(T* resource = NULL, ISrsResource* wrapper = NULL) { + wrapper_ = wrapper ? wrapper : this; + resource_ = resource ? resource : new T(); + resource_->gc_use(wrapper_); + + is_root_ = !resource; + if (!resource) { + resource_->gc_set_creator_wrapper(wrapper_); + } + } + virtual ~SrsLazyResourceWrapper() { + resource_->gc_dispose(wrapper_); + + if (is_root_) { + resource_->gc_set_creator_wrapper(NULL); + } + + if (resource_->gc_ref() == 0) { + _srs_gc->remove(resource_); + } + } +public: + SrsLazyResourceWrapper* copy() { + return new SrsLazyResourceWrapper(resource_); + } + T* resource() { + return resource_; + } +// Interface ISrsResource +public: + virtual const SrsContextId& get_id() { + return resource_->get_id(); + } + virtual std::string desc() { + return resource_->desc(); + } +}; + +// Use macro to generate a wrapper class, because typedef will cause IDE incorrect tips. +// See https://github.com/ossrs/srs/issues/3176#lazy-sweep +#define SRS_LAZY_WRAPPER_GENERATOR(Resource, IWrapper, IResource) \ + private: \ + SrsLazyResourceWrapper impl_; \ + public: \ + Resource##Wrapper(Resource* resource = NULL) : impl_(resource, this) { \ + } \ + virtual ~Resource##Wrapper() { \ + } \ + public: \ + IWrapper* copy() { \ + return new Resource##Wrapper(impl_.resource()); \ + } \ + IResource* resource() { \ + return impl_.resource(); \ + } \ + public: \ + virtual const SrsContextId& get_id() { \ + return impl_.get_id(); \ + } \ + virtual std::string desc() { \ + return impl_.desc(); \ + } \ + +// If a connection is able be expired, user can use HTTP-API to kick-off it. class ISrsExpire { public: diff --git a/trunk/src/core/srs_core_version5.hpp b/trunk/src/core/srs_core_version5.hpp index beb8e6eb3..ca787cc1d 100644 --- a/trunk/src/core/srs_core_version5.hpp +++ b/trunk/src/core/srs_core_version5.hpp @@ -9,6 +9,6 @@ #define VERSION_MAJOR 5 #define VERSION_MINOR 0 -#define VERSION_REVISION 68 +#define VERSION_REVISION 69 #endif diff --git a/trunk/src/protocol/srs_protocol_conn.cpp b/trunk/src/protocol/srs_protocol_conn.cpp index 1fe717e7b..8ebaffb72 100644 --- a/trunk/src/protocol/srs_protocol_conn.cpp +++ b/trunk/src/protocol/srs_protocol_conn.cpp @@ -6,6 +6,9 @@ #include +#include +using namespace std; + ISrsResource::ISrsResource() { } @@ -35,3 +38,64 @@ ISrsConnection::~ISrsConnection() { } +ISrsLazyResource::ISrsLazyResource() +{ + gc_ref_ = 0; + gc_creator_wrapper_ = NULL; +} + +ISrsLazyResource::~ISrsLazyResource() +{ +} + +ISrsLazyResource* ISrsLazyResource::gc_use(ISrsResource* wrapper) +{ + srs_assert(wrapper); + if (std::find(gc_wrappers_.begin(), gc_wrappers_.end(), wrapper) == gc_wrappers_.end()) { + gc_wrappers_.push_back(wrapper); + } + + gc_ref_++; + return this; +} + +ISrsLazyResource* ISrsLazyResource::gc_dispose(ISrsResource* wrapper) +{ + srs_assert(wrapper); + vector::iterator it = std::find(gc_wrappers_.begin(), gc_wrappers_.end(), wrapper); + if (it != gc_wrappers_.end()) { + it = gc_wrappers_.erase(it); + } + + gc_ref_--; + return this; +} + +int32_t ISrsLazyResource::gc_ref() +{ + return gc_ref_; +} + +void ISrsLazyResource::gc_set_creator_wrapper(ISrsResource* wrapper) +{ + gc_creator_wrapper_ = wrapper; +} + +ISrsResource* ISrsLazyResource::gc_creator_wrapper() +{ + return gc_creator_wrapper_; +} + +ISrsResource* ISrsLazyResource::gc_available_wrapper() +{ + return gc_wrappers_.empty() ? NULL : gc_wrappers_.front(); +} + +ISrsLazyGc::ISrsLazyGc() +{ +} + +ISrsLazyGc::~ISrsLazyGc() +{ +} + diff --git a/trunk/src/protocol/srs_protocol_conn.hpp b/trunk/src/protocol/srs_protocol_conn.hpp index 2c3918dde..35fb37882 100644 --- a/trunk/src/protocol/srs_protocol_conn.hpp +++ b/trunk/src/protocol/srs_protocol_conn.hpp @@ -10,6 +10,7 @@ #include #include +#include // The resource managed by ISrsResourceManager. class ISrsResource @@ -20,6 +21,7 @@ public: public: // Get the context id of connection. virtual const SrsContextId& get_id() = 0; +public: // The resource description, optional. virtual std::string desc(); }; @@ -46,5 +48,49 @@ public: virtual std::string remote_ip() = 0; }; +// Lazy-sweep resource, never sweep util all wrappers are freed. +// See https://github.com/ossrs/srs/issues/3176#lazy-sweep +class ISrsLazyResource : public ISrsResource +{ +private: + // The reference count of resource, 0 is no wrapper and safe to sweep. + int32_t gc_ref_; + // The creator wrapper, which created this resource. Note that it might be disposed and the pointer is NULL, so be + // careful and make sure to check it before use it. + ISrsResource* gc_creator_wrapper_; + // All available wrappers. + std::vector gc_wrappers_; +public: + ISrsLazyResource(); + virtual ~ISrsLazyResource(); +public: + // For wrapper to use this resource. + virtual ISrsLazyResource* gc_use(ISrsResource* wrapper); + // For wrapper to dispose this resource. + virtual ISrsLazyResource* gc_dispose(ISrsResource* wrapper); + // The current reference count of resource. + virtual int32_t gc_ref(); +public: + // Set the creator wrapper, from which resource clone wrapper. + virtual void gc_set_creator_wrapper(ISrsResource* wrapper); + // Get the first available wrapper. NULL if the creator wrapper disposed. + virtual ISrsResource* gc_creator_wrapper(); + // Get the first available wrapper. NULL if all wrappers disposed. + // It should be equal to the gc_creator_wrapper() if creator wrapper not disposed. + virtual ISrsResource* gc_available_wrapper(); +}; + +// The lazy-sweep GC, wait for a long time to dispose resource even when resource is disposable. +// See https://github.com/ossrs/srs/issues/3176#lazy-sweep +class ISrsLazyGc +{ +public: + ISrsLazyGc(); + virtual ~ISrsLazyGc(); +public: + // Remove then free the specified resource. + virtual void remove(ISrsLazyResource* c) = 0; +}; + #endif