mirror of
https://github.com/ossrs/srs.git
synced 2025-03-09 15:49:59 +00:00
RTC: Use vector for fast search fast-id
This commit is contained in:
parent
ef279a8b1e
commit
95193979f4
3 changed files with 190 additions and 3 deletions
|
@ -52,6 +52,9 @@ SrsResourceManager::SrsResourceManager(const std::string& label, bool verbose)
|
||||||
trd = NULL;
|
trd = NULL;
|
||||||
p_disposing_ = NULL;
|
p_disposing_ = NULL;
|
||||||
removing_ = false;
|
removing_ = false;
|
||||||
|
|
||||||
|
nn_level0_cache_ = 100000;
|
||||||
|
conns_level0_cache_ = new SrsResourceFastIdItem[nn_level0_cache_];
|
||||||
}
|
}
|
||||||
|
|
||||||
SrsResourceManager::~SrsResourceManager()
|
SrsResourceManager::~SrsResourceManager()
|
||||||
|
@ -65,6 +68,8 @@ SrsResourceManager::~SrsResourceManager()
|
||||||
}
|
}
|
||||||
|
|
||||||
clear();
|
clear();
|
||||||
|
|
||||||
|
srs_freepa(conns_level0_cache_);
|
||||||
}
|
}
|
||||||
|
|
||||||
srs_error_t SrsResourceManager::start()
|
srs_error_t SrsResourceManager::start()
|
||||||
|
@ -114,10 +119,14 @@ srs_error_t SrsResourceManager::cycle()
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsResourceManager::add(ISrsResource* conn)
|
void SrsResourceManager::add(ISrsResource* conn, bool* exists)
|
||||||
{
|
{
|
||||||
if (std::find(conns_.begin(), conns_.end(), conn) == conns_.end()) {
|
if (std::find(conns_.begin(), conns_.end(), conn) == conns_.end()) {
|
||||||
conns_.push_back(conn);
|
conns_.push_back(conn);
|
||||||
|
} else {
|
||||||
|
if (exists) {
|
||||||
|
*exists = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,8 +138,35 @@ void SrsResourceManager::add_with_id(const std::string& id, ISrsResource* conn)
|
||||||
|
|
||||||
void SrsResourceManager::add_with_fast_id(uint64_t id, ISrsResource* conn)
|
void SrsResourceManager::add_with_fast_id(uint64_t id, ISrsResource* conn)
|
||||||
{
|
{
|
||||||
add(conn);
|
bool exists = false;
|
||||||
|
add(conn, &exists);
|
||||||
conns_fast_id_[id] = conn;
|
conns_fast_id_[id] = conn;
|
||||||
|
|
||||||
|
if (exists) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For new resource, build the level-0 cache for fast-id.
|
||||||
|
SrsResourceFastIdItem* item = &conns_level0_cache_[(id | id>>32) % nn_level0_cache_];
|
||||||
|
|
||||||
|
// Ignore if exits item.
|
||||||
|
if (item->fast_id && item->fast_id == id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fresh one, create the item.
|
||||||
|
if (!item->fast_id) {
|
||||||
|
item->fast_id = id;
|
||||||
|
item->impl = conn;
|
||||||
|
item->nn_collisions = 1;
|
||||||
|
item->available = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collision, increase the collisions.
|
||||||
|
if (item->fast_id != id) {
|
||||||
|
item->nn_collisions++;
|
||||||
|
item->available = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SrsResourceManager::add_with_name(const std::string& name, ISrsResource* conn)
|
void SrsResourceManager::add_with_name(const std::string& name, ISrsResource* conn)
|
||||||
|
@ -152,6 +188,11 @@ ISrsResource* SrsResourceManager::find_by_id(std::string id)
|
||||||
|
|
||||||
ISrsResource* SrsResourceManager::find_by_fast_id(uint64_t id)
|
ISrsResource* SrsResourceManager::find_by_fast_id(uint64_t id)
|
||||||
{
|
{
|
||||||
|
SrsResourceFastIdItem* item = &conns_level0_cache_[(id | id>>32) % nn_level0_cache_];
|
||||||
|
if (item->available && item->fast_id == id) {
|
||||||
|
return item->impl;
|
||||||
|
}
|
||||||
|
|
||||||
map<uint64_t, ISrsResource*>::iterator it = conns_fast_id_.find(id);
|
map<uint64_t, ISrsResource*>::iterator it = conns_fast_id_.find(id);
|
||||||
return (it != conns_fast_id_.end())? it->second : NULL;
|
return (it != conns_fast_id_.end())? it->second : NULL;
|
||||||
}
|
}
|
||||||
|
@ -332,6 +373,15 @@ void SrsResourceManager::dispose(ISrsResource* c)
|
||||||
if (c != it->second) {
|
if (c != it->second) {
|
||||||
++it;
|
++it;
|
||||||
} else {
|
} else {
|
||||||
|
// Update the level-0 cache for fast-id.
|
||||||
|
uint64_t id = it->first;
|
||||||
|
SrsResourceFastIdItem* item = &conns_level0_cache_[(id | id>>32) % nn_level0_cache_];
|
||||||
|
item->nn_collisions--;
|
||||||
|
if (!item->nn_collisions) {
|
||||||
|
item->fast_id = 0;
|
||||||
|
item->available = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Use C++98 style: https://stackoverflow.com/a/4636230
|
// Use C++98 style: https://stackoverflow.com/a/4636230
|
||||||
conns_fast_id_.erase(it++);
|
conns_fast_id_.erase(it++);
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,27 @@ public:
|
||||||
virtual void on_disposing(ISrsResource* c) = 0;
|
virtual void on_disposing(ISrsResource* c) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The item to identify the fast id object.
|
||||||
|
class SrsResourceFastIdItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// If available, use the resource in item.
|
||||||
|
bool available;
|
||||||
|
// How many resource have the same fast-id, which contribute a collision.
|
||||||
|
int nn_collisions;
|
||||||
|
// The first fast-id of resources.
|
||||||
|
uint64_t fast_id;
|
||||||
|
// The first resource object.
|
||||||
|
ISrsResource* impl;
|
||||||
|
public:
|
||||||
|
SrsResourceFastIdItem() {
|
||||||
|
available = false;
|
||||||
|
nn_collisions = 0;
|
||||||
|
fast_id = 0;
|
||||||
|
impl = NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// The resource manager remove resource and delete it asynchronously.
|
// The resource manager remove resource and delete it asynchronously.
|
||||||
class SrsResourceManager : virtual public ISrsCoroutineHandler, virtual public ISrsResourceManager
|
class SrsResourceManager : virtual public ISrsCoroutineHandler, virtual public ISrsResourceManager
|
||||||
{
|
{
|
||||||
|
@ -78,6 +99,9 @@ private:
|
||||||
std::map<std::string, ISrsResource*> conns_id_;
|
std::map<std::string, ISrsResource*> conns_id_;
|
||||||
// The connections with resource fast(int) id.
|
// The connections with resource fast(int) id.
|
||||||
std::map<uint64_t, ISrsResource*> conns_fast_id_;
|
std::map<uint64_t, ISrsResource*> conns_fast_id_;
|
||||||
|
// The level-0 fast cache for fast id.
|
||||||
|
int nn_level0_cache_;
|
||||||
|
SrsResourceFastIdItem* conns_level0_cache_;
|
||||||
// The connections with resource name.
|
// The connections with resource name.
|
||||||
std::map<std::string, ISrsResource*> conns_name_;
|
std::map<std::string, ISrsResource*> conns_name_;
|
||||||
public:
|
public:
|
||||||
|
@ -91,7 +115,7 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual srs_error_t cycle();
|
virtual srs_error_t cycle();
|
||||||
public:
|
public:
|
||||||
void add(ISrsResource* conn);
|
void add(ISrsResource* conn, bool* exists = NULL);
|
||||||
void add_with_id(const std::string& id, ISrsResource* conn);
|
void add_with_id(const std::string& id, ISrsResource* conn);
|
||||||
void add_with_fast_id(uint64_t id, ISrsResource* conn);
|
void add_with_fast_id(uint64_t id, ISrsResource* conn);
|
||||||
void add_with_name(const std::string& name, ISrsResource* conn);
|
void add_with_name(const std::string& name, ISrsResource* conn);
|
||||||
|
|
|
@ -30,6 +30,119 @@ using namespace std;
|
||||||
#include <srs_app_config.hpp>
|
#include <srs_app_config.hpp>
|
||||||
|
|
||||||
#include <srs_app_st.hpp>
|
#include <srs_app_st.hpp>
|
||||||
|
#include <srs_service_conn.hpp>
|
||||||
|
#include <srs_app_conn.hpp>
|
||||||
|
|
||||||
|
class MockIDResource : public ISrsResource
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int id;
|
||||||
|
MockIDResource(int v) {
|
||||||
|
id = v;
|
||||||
|
}
|
||||||
|
virtual ~MockIDResource() {
|
||||||
|
}
|
||||||
|
virtual const SrsContextId& get_id() {
|
||||||
|
return _srs_context->get_id();
|
||||||
|
}
|
||||||
|
virtual std::string desc() {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
VOID TEST(AppResourceManagerTest, FindByFastID)
|
||||||
|
{
|
||||||
|
srs_error_t err = srs_success;
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsResourceManager m("test");
|
||||||
|
HELPER_EXPECT_SUCCESS(m.start());
|
||||||
|
|
||||||
|
m.add_with_fast_id(101, new MockIDResource(1));
|
||||||
|
m.add_with_fast_id(102, new MockIDResource(2));
|
||||||
|
m.add_with_fast_id(103, new MockIDResource(3));
|
||||||
|
EXPECT_EQ(1, ((MockIDResource*)m.find_by_fast_id(101))->id);
|
||||||
|
EXPECT_EQ(2, ((MockIDResource*)m.find_by_fast_id(102))->id);
|
||||||
|
EXPECT_EQ(3, ((MockIDResource*)m.find_by_fast_id(103))->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsResourceManager m("test");
|
||||||
|
HELPER_EXPECT_SUCCESS(m.start());
|
||||||
|
|
||||||
|
MockIDResource* r1 = new MockIDResource(1);
|
||||||
|
MockIDResource* r2 = new MockIDResource(2);
|
||||||
|
MockIDResource* r3 = new MockIDResource(3);
|
||||||
|
m.add_with_fast_id(101, r1);
|
||||||
|
m.add_with_fast_id(102, r2);
|
||||||
|
m.add_with_fast_id(103, r3);
|
||||||
|
EXPECT_EQ(1, ((MockIDResource*)m.find_by_fast_id(101))->id);
|
||||||
|
EXPECT_EQ(2, ((MockIDResource*)m.find_by_fast_id(102))->id);
|
||||||
|
EXPECT_EQ(3, ((MockIDResource*)m.find_by_fast_id(103))->id);
|
||||||
|
|
||||||
|
m.remove(r2); srs_usleep(0);
|
||||||
|
EXPECT_TRUE(m.find_by_fast_id(102) == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsResourceManager m("test");
|
||||||
|
HELPER_EXPECT_SUCCESS(m.start());
|
||||||
|
|
||||||
|
MockIDResource* r1 = new MockIDResource(1);
|
||||||
|
MockIDResource* r2 = new MockIDResource(2);
|
||||||
|
MockIDResource* r3 = new MockIDResource(3);
|
||||||
|
m.add_with_fast_id(1, r1);
|
||||||
|
m.add_with_fast_id(100001, r2);
|
||||||
|
m.add_with_fast_id(1000001, r3);
|
||||||
|
EXPECT_EQ(1, ((MockIDResource*)m.find_by_fast_id(1))->id);
|
||||||
|
EXPECT_EQ(2, ((MockIDResource*)m.find_by_fast_id(100001))->id);
|
||||||
|
EXPECT_EQ(3, ((MockIDResource*)m.find_by_fast_id(1000001))->id);
|
||||||
|
|
||||||
|
m.remove(r2); srs_usleep(0);
|
||||||
|
EXPECT_TRUE(m.find_by_fast_id(100001) == NULL);
|
||||||
|
|
||||||
|
m.remove(r3); srs_usleep(0);
|
||||||
|
EXPECT_TRUE(m.find_by_fast_id(1000001) == NULL);
|
||||||
|
|
||||||
|
m.remove(r1); srs_usleep(0);
|
||||||
|
EXPECT_TRUE(m.find_by_fast_id(1) == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsResourceManager m("test");
|
||||||
|
HELPER_EXPECT_SUCCESS(m.start());
|
||||||
|
|
||||||
|
m.add_with_fast_id(101, new MockIDResource(1));
|
||||||
|
m.add_with_fast_id(10101, new MockIDResource(2));
|
||||||
|
m.add_with_fast_id(1010101, new MockIDResource(3));
|
||||||
|
m.add_with_fast_id(101010101, new MockIDResource(4));
|
||||||
|
m.add_with_fast_id(10101010101LL, new MockIDResource(5));
|
||||||
|
m.add_with_fast_id(1010101010101LL, new MockIDResource(6));
|
||||||
|
m.add_with_fast_id(101010101010101LL, new MockIDResource(7));
|
||||||
|
m.add_with_fast_id(10101010101010101LL, new MockIDResource(8));
|
||||||
|
m.add_with_fast_id(1010101010101010101ULL, new MockIDResource(9));
|
||||||
|
m.add_with_fast_id(11010101010101010101ULL, new MockIDResource(10));
|
||||||
|
EXPECT_EQ(1, ((MockIDResource*)m.find_by_fast_id(101))->id);
|
||||||
|
EXPECT_EQ(2, ((MockIDResource*)m.find_by_fast_id(10101))->id);
|
||||||
|
EXPECT_EQ(3, ((MockIDResource*)m.find_by_fast_id(1010101))->id);
|
||||||
|
EXPECT_EQ(4, ((MockIDResource*)m.find_by_fast_id(101010101))->id);
|
||||||
|
EXPECT_EQ(5, ((MockIDResource*)m.find_by_fast_id(10101010101LL))->id);
|
||||||
|
EXPECT_EQ(6, ((MockIDResource*)m.find_by_fast_id(1010101010101LL))->id);
|
||||||
|
EXPECT_EQ(7, ((MockIDResource*)m.find_by_fast_id(101010101010101LL))->id);
|
||||||
|
EXPECT_EQ(8, ((MockIDResource*)m.find_by_fast_id(10101010101010101LL))->id);
|
||||||
|
EXPECT_EQ(9, ((MockIDResource*)m.find_by_fast_id(1010101010101010101ULL))->id);
|
||||||
|
EXPECT_EQ(10, ((MockIDResource*)m.find_by_fast_id(11010101010101010101ULL))->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SrsResourceManager m("test");
|
||||||
|
HELPER_EXPECT_SUCCESS(m.start());
|
||||||
|
|
||||||
|
m.add_with_fast_id(101, new MockIDResource(1));
|
||||||
|
m.add_with_fast_id(101, new MockIDResource(4));
|
||||||
|
EXPECT_EQ(1, ((MockIDResource*)m.find_by_fast_id(101))->id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VOID TEST(AppCoroutineTest, Dummy)
|
VOID TEST(AppCoroutineTest, Dummy)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue