Optimize lookups by CID and nick.

This used to be a linear search O(n), but is now done
as a red-black tree O(log n) instead.

These operations can be further opimized with a hash-table
which would acheive near constant time lookups.
This commit is contained in:
Jan Vidar Krey 2013-03-23 22:11:05 +01:00
parent 52211a6bac
commit cd5c4ee622
4 changed files with 28 additions and 23 deletions

View File

@ -38,6 +38,11 @@ static void clear_user_list_callback(void* ptr)
} }
} }
static int uman_map_compare(const void* a, const void* b)
{
return strcmp((const char*) a, (const char*) b);
}
struct hub_user_manager* uman_init() struct hub_user_manager* uman_init()
{ {
@ -46,15 +51,10 @@ struct hub_user_manager* uman_init()
return NULL; return NULL;
users->list = list_create(); users->list = list_create();
users->nickmap = rb_tree_create(uman_map_compare, NULL, NULL);
users->cidmap = rb_tree_create(uman_map_compare, NULL, NULL);
users->sids = sid_pool_create(net_get_max_sockets()); users->sids = sid_pool_create(net_get_max_sockets());
if (!users->list)
{
list_destroy(users->list);
hub_free(users);
return NULL;
}
return users; return users;
} }
@ -64,11 +64,18 @@ int uman_shutdown(struct hub_user_manager* users)
if (!users) if (!users)
return -1; return -1;
if (users->nickmap)
rb_tree_destroy(users->nickmap);
if (users->cidmap)
rb_tree_destroy(users->cidmap);
if (users->list) if (users->list)
{ {
list_clear(users->list, &clear_user_list_callback); list_clear(users->list, &clear_user_list_callback);
list_destroy(users->list); list_destroy(users->list);
} }
sid_pool_destroy(users->sids); sid_pool_destroy(users->sids);
hub_free(users); hub_free(users);
@ -81,6 +88,9 @@ int uman_add(struct hub_user_manager* users, struct hub_user* user)
if (!users || !user) if (!users || !user)
return -1; return -1;
rb_tree_insert(users->nickmap, user->id.nick, user);
rb_tree_insert(users->cidmap, user->id.cid, user);
list_append(users->list, user); list_append(users->list, user);
users->count++; users->count++;
users->count_peak = MAX(users->count, users->count_peak); users->count_peak = MAX(users->count, users->count_peak);
@ -96,6 +106,8 @@ int uman_remove(struct hub_user_manager* users, struct hub_user* user)
return -1; return -1;
list_remove(users->list, user); list_remove(users->list, user);
rb_tree_remove(users->nickmap, user->id.nick);
rb_tree_remove(users->cidmap, user->id.cid);
if (users->count > 0) if (users->count > 0)
{ {
@ -120,25 +132,15 @@ struct hub_user* uman_get_user_by_sid(struct hub_user_manager* users, sid_t sid)
struct hub_user* uman_get_user_by_cid(struct hub_user_manager* users, const char* cid) struct hub_user* uman_get_user_by_cid(struct hub_user_manager* users, const char* cid)
{ {
struct hub_user* user; struct hub_user* user = (struct hub_user*) rb_tree_get(users->cidmap, (const void*) cid);
LIST_FOREACH(struct hub_user*, user, users->list, return user;
{
if (strcmp(user->id.cid, cid) == 0)
return user;
});
return NULL;
} }
struct hub_user* uman_get_user_by_nick(struct hub_user_manager* users, const char* nick) struct hub_user* uman_get_user_by_nick(struct hub_user_manager* users, const char* nick)
{ {
struct hub_user* user; struct hub_user* user = (struct hub_user*) rb_tree_get(users->nickmap, nick);
LIST_FOREACH(struct hub_user*, user, users->list, return user;
{
if (strcmp(user->id.nick, nick) == 0)
return user;
});
return NULL;
} }
size_t uman_get_user_by_addr(struct hub_user_manager* users, struct linked_list* target, struct ip_range* range) size_t uman_get_user_by_addr(struct hub_user_manager* users, struct linked_list* target, struct ip_range* range)

View File

@ -24,10 +24,12 @@ struct hub_user_manager
{ {
size_t count; /**<< "Number of all fully connected and logged in users" */ size_t count; /**<< "Number of all fully connected and logged in users" */
size_t count_peak; /**<< "Peak number of users" */ size_t count_peak; /**<< "Peak number of users" */
struct sid_pool* sids;
uint64_t shared_size; /**<< "The total number of shared bytes among fully connected users." */ uint64_t shared_size; /**<< "The total number of shared bytes among fully connected users." */
uint64_t shared_files; /**<< "The total number of shared files among fully connected users." */ uint64_t shared_files; /**<< "The total number of shared files among fully connected users." */
struct sid_pool* sids; /**<< "Maps SIDs to users (constant time)" */
struct linked_list* list; /**<< "Contains all logged in users" */ struct linked_list* list; /**<< "Contains all logged in users" */
struct rb_tree* nickmap; /**<< "Maps nicknames to users (red black tree)" */
struct rb_tree* cidmap; /**<< "Maps CIDs to users (red black tree)" */
}; };
/** /**

View File

@ -69,6 +69,7 @@ extern "C" {
#include "util/misc.h" #include "util/misc.h"
#include "util/tiger.h" #include "util/tiger.h"
#include "util/threads.h" #include "util/threads.h"
#include "util/rbtree.h"
#include "adc/sid.h" #include "adc/sid.h"
#include "adc/message.h" #include "adc/message.h"

View File

@ -157,7 +157,7 @@ static struct rb_node* rb_tree_insert_r(struct rb_tree* tree, struct rb_node* no
struct rb_tree* rb_tree_create(rb_tree_compare compare, rb_tree_alloc a, rb_tree_free f) struct rb_tree* rb_tree_create(rb_tree_compare compare, rb_tree_alloc a, rb_tree_free f)
{ {
struct rb_tree* tree = a(sizeof(struct rb_tree)); struct rb_tree* tree = a ? a(sizeof(struct rb_tree)) : hub_malloc(sizeof(struct rb_tree));
tree->compare = compare; tree->compare = compare;
tree->alloc = a ? a : hub_malloc; tree->alloc = a ? a : hub_malloc;
tree->free = f ? f : hub_free; tree->free = f ? f : hub_free;