idnode: optimize idnodes (split to domains)

This commit is contained in:
Jaroslav Kysela 2014-09-22 16:36:22 +02:00
parent fca35b9d2d
commit df1cf7dffe
13 changed files with 144 additions and 69 deletions

View file

@ -185,7 +185,7 @@ api_idnode_load_by_class
assert(idc);
l = htsmsg_create_list();
if ((is = idnode_find_all(idc))) {
if ((is = idnode_find_all(idc, NULL))) {
for (i = 0; i < is->is_count; i++) {
in = is->is_array[i];
@ -256,10 +256,12 @@ api_idnode_load
/* Multiple */
if (uuids) {
const idnodes_rb_t *domain = NULL;
l = htsmsg_create_list();
HTSMSG_FOREACH(f, uuids) {
if (!(uuid = htsmsg_field_get_str(f))) continue;
if (!(in = idnode_find(uuid, NULL))) continue;
if (!(in = idnode_find(uuid, NULL, domain))) continue;
domain = in->in_domain;
if (idnode_perm(in, perm, NULL)) {
err = EPERM;
continue;
@ -276,7 +278,7 @@ api_idnode_load
/* Single */
} else {
if (!(in = idnode_find(uuid, NULL)))
if (!(in = idnode_find(uuid, NULL, NULL)))
err = ENOENT;
else {
if (idnode_perm(in, perm, NULL)) {
@ -326,7 +328,7 @@ api_idnode_save
if (!msg->hm_islist) {
if (!(uuid = htsmsg_get_str(msg, "uuid")))
goto exit;
if (!(in = idnode_find(uuid, NULL)))
if (!(in = idnode_find(uuid, NULL, NULL)))
goto exit;
if (idnode_perm(in, perm, msg)) {
err = EPERM;
@ -337,13 +339,15 @@ api_idnode_save
/* Multiple */
} else {
const idnodes_rb_t *domain = NULL;
HTSMSG_FOREACH(f, msg) {
if (!(conf = htsmsg_field_get_map(f)))
continue;
if (!(uuid = htsmsg_get_str(conf, "uuid")))
continue;
if (!(in = idnode_find(uuid, NULL)))
if (!(in = idnode_find(uuid, NULL, domain)))
continue;
domain = in->in_domain;
if (idnode_perm(in, perm, conf)) {
err = EPERM;
continue;
@ -389,7 +393,7 @@ api_idnode_tree
pthread_mutex_lock(&global_lock);
if (!isroot || root) {
if (!(node = idnode_find(isroot ? root : uuid, NULL))) {
if (!(node = idnode_find(isroot ? root : uuid, NULL, NULL))) {
pthread_mutex_unlock(&global_lock);
return EINVAL;
}
@ -477,16 +481,18 @@ api_idnode_handler
/* Multiple */
if (uuids) {
const idnodes_rb_t *domain = NULL;
HTSMSG_FOREACH(f, uuids) {
if (!(uuid = htsmsg_field_get_string(f))) continue;
if (!(in = idnode_find(uuid, NULL))) continue;
if (!(in = idnode_find(uuid, NULL, domain))) continue;
domain = in->in_domain;
handler(perm, in);
}
/* Single */
} else {
uuid = htsmsg_field_get_string(f);
if (!(in = idnode_find(uuid, NULL)))
if (!(in = idnode_find(uuid, NULL, NULL)))
err = ENOENT;
else
handler(perm, in);

View file

@ -145,7 +145,7 @@ void channel_delete(channel_t *ch, int delconf);
channel_t *channel_find_by_name(const char *name);
#define channel_find_by_uuid(u)\
(channel_t*)idnode_find(u, &channel_class)
(channel_t*)idnode_find(u, &channel_class, NULL)
channel_t *channel_find_by_id(uint32_t id);
@ -165,7 +165,7 @@ channel_tag_t *channel_tag_find_by_name(const char *name, int create);
channel_tag_t *channel_tag_find_by_identifier(uint32_t id);
static inline channel_tag_t *channel_tag_find_by_uuid(const char *uuid)
{ return (channel_tag_t*)idnode_find(uuid, &channel_tag_class); }
{ return (channel_tag_t*)idnode_find(uuid, &channel_tag_class, NULL); }
void channel_tag_save(channel_tag_t *ct);

View file

@ -1456,7 +1456,7 @@ capmt_thread(void *aux)
int i, n;
extern const idclass_t linuxdvb_adapter_class;
linuxdvb_adapter_t *la;
idnode_set_t *is = idnode_find_all(&linuxdvb_adapter_class);
idnode_set_t *is = idnode_find_all(&linuxdvb_adapter_class, NULL);
for (i = 0; i < is->is_count; i++) {
la = (linuxdvb_adapter_t*)is->is_array[i];
if (!la || !la->la_is_enabled(la)) continue;

View file

@ -344,7 +344,7 @@ dvr_config_t *dvr_config_find_by_name_default(const char *name);
dvr_config_t *dvr_config_create(const char *name, const char *uuid, htsmsg_t *conf);
static inline dvr_config_t *dvr_config_find_by_uuid(const char *uuid)
{ return (dvr_config_t*)idnode_find(uuid, &dvr_config_class); }
{ return (dvr_config_t*)idnode_find(uuid, &dvr_config_class, NULL); }
void dvr_config_delete(const char *name);
@ -431,7 +431,7 @@ void dvr_event_updated(epg_broadcast_t *e);
dvr_entry_t *dvr_entry_find_by_id(int id);
static inline dvr_entry_t *dvr_entry_find_by_uuid(const char *uuid)
{ return (dvr_entry_t*)idnode_find(uuid, &dvr_entry_class); }
{ return (dvr_entry_t*)idnode_find(uuid, &dvr_entry_class, NULL); }
dvr_entry_t *dvr_entry_find_by_event(epg_broadcast_t *e);
@ -490,7 +490,7 @@ void dvr_autorec_changed(dvr_autorec_entry_t *dae, int purge);
static inline dvr_autorec_entry_t *
dvr_autorec_find_by_uuid(const char *uuid)
{ return (dvr_autorec_entry_t*)idnode_find(uuid, &dvr_autorec_entry_class); }
{ return (dvr_autorec_entry_t*)idnode_find(uuid, &dvr_autorec_entry_class, NULL); }
htsmsg_t * dvr_autorec_entry_class_time_list(void *o, const char *null);
@ -526,7 +526,7 @@ dvr_timerec_create(const char *uuid, htsmsg_t *conf);
static inline dvr_timerec_entry_t *
dvr_timerec_find_by_uuid(const char *uuid)
{ return (dvr_timerec_entry_t*)idnode_find(uuid, &dvr_timerec_entry_class); }
{ return (dvr_timerec_entry_t*)idnode_find(uuid, &dvr_timerec_entry_class, NULL); }
void dvr_timerec_save(dvr_timerec_entry_t *dae);

View file

@ -30,14 +30,19 @@
#include "settings.h"
#include "uuid.h"
static const idnodes_rb_t * idnode_domain ( const idclass_t *idc );
static void idclass_root_register ( idnode_t *in );
typedef struct idclass_link
{
const idclass_t *idc;
const idclass_t *idc;
idnodes_rb_t nodes;
RB_ENTRY(idclass_link) link;
} idclass_link_t;
static RB_HEAD(,idnode) idnodes;
static idnodes_rb_t idnodes;
static RB_HEAD(,idclass_link) idclasses;
static RB_HEAD(,idclass_link) idrootclasses;
static pthread_cond_t idnode_cond;
static pthread_mutex_t idnode_mutex;
static htsmsg_t *idnode_queue;
@ -58,6 +63,14 @@ in_cmp(const idnode_t *a, const idnode_t *b)
return memcmp(a->in_uuid, b->in_uuid, sizeof(a->in_uuid));
}
static int
ic_cmp ( const idclass_link_t *a, const idclass_link_t *b )
{
assert(a->idc->ic_class);
assert(b->idc->ic_class);
return strcmp(a->idc->ic_class, b->idc->ic_class);
}
/* **************************************************************************
* Registration
* *************************************************************************/
@ -71,6 +84,9 @@ void
idnode_init(void)
{
idnode_queue = NULL;
RB_INIT(&idnodes);
RB_INIT(&idclasses);
RB_INIT(&idrootclasses);
pthread_mutex_init(&idnode_mutex, NULL);
pthread_cond_init(&idnode_cond, NULL);
tvhthread_create(&idnode_tid, NULL, idnode_thread, NULL);
@ -91,15 +107,16 @@ idnode_done(void)
RB_REMOVE(&idclasses, il, link);
free(il);
}
while ((il = RB_FIRST(&idrootclasses)) != NULL) {
RB_REMOVE(&idrootclasses, il, link);
free(il);
}
SKEL_FREE(idclasses_skel);
}
static const idclass_t *
idnode_root_class(idnode_t *in)
idnode_root_class(const idclass_t *idc)
{
const idclass_t *idc;
idc = in->in_class;
while (idc && idc->ic_super)
idc = idc->ic_super;
return idc;
@ -112,12 +129,13 @@ int
idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class, int flags)
{
idnode_t *c;
lock_assert(&global_lock);
tvh_uuid_t u;
int retries = 5;
uint32_t u32;
const idclass_t *idc;;
lock_assert(&global_lock);
in->in_class = class;
do {
@ -130,9 +148,9 @@ idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class, int flags)
c = NULL;
if (flags & IDNODE_SHORT_UUID) {
u32 = idnode_get_short_uuid(in);
idc = idnode_root_class(in);
idc = idnode_root_class(in->in_class);
RB_FOREACH(c, &idnodes, in_link) {
if (idc != idnode_root_class(c))
if (idc != idnode_root_class(c->in_class))
continue;
if (idnode_get_short_uuid(c) == u32)
break;
@ -153,6 +171,10 @@ idnode_insert(idnode_t *in, const char *uuid, const idclass_t *class, int flags)
/* Register the class */
idclass_register(class); // Note: we never actually unregister
idclass_root_register(in);
assert(in->in_domain);
c = RB_INSERT_SORTED(in->in_domain, in, in_domain_link, in_cmp);
assert(c == NULL);
/* Fire event */
idnode_notify_simple(in);
@ -168,6 +190,7 @@ idnode_unlink(idnode_t *in)
{
lock_assert(&global_lock);
RB_REMOVE(&idnodes, in, in_link);
RB_REMOVE(in->in_domain, in, in_domain_link);
tvhtrace("idnode", "unlink node %s", idnode_uuid_as_str(in));
idnode_notify_simple(in);
}
@ -521,8 +544,24 @@ idnode_get_time
/**
*
*/
static const idnodes_rb_t *
idnode_domain(const idclass_t *idc)
{
if (idc) {
idclass_link_t lskel, *l;
const idclass_t *root = idnode_root_class(idc);
lskel.idc = root;
l = RB_FIND(&idrootclasses, &lskel, link, ic_cmp);
if (l == NULL)
return NULL;
return &l->nodes;
} else {
return NULL;
}
}
void *
idnode_find(const char *uuid, const idclass_t *idc)
idnode_find ( const char *uuid, const idclass_t *idc, const idnodes_rb_t *domain )
{
idnode_t skel, *r;
@ -531,7 +570,12 @@ idnode_find(const char *uuid, const idclass_t *idc)
return NULL;
if(hex2bin(skel.in_uuid, sizeof(skel.in_uuid), uuid))
return NULL;
r = RB_FIND(&idnodes, &skel, in_link, in_cmp);
if (domain == NULL)
domain = idnode_domain(idc);
if (domain == NULL)
r = RB_FIND(&idnodes, &skel, in_link, in_cmp);
else
r = RB_FIND(domain, &skel, in_domain_link, in_cmp);
if(r != NULL && idc != NULL) {
const idclass_t *c = r->in_class;
for(;c != NULL; c = c->ic_super) {
@ -544,21 +588,37 @@ idnode_find(const char *uuid, const idclass_t *idc)
}
idnode_set_t *
idnode_find_all ( const idclass_t *idc )
idnode_find_all ( const idclass_t *idc, const idnodes_rb_t *domain )
{
idnode_t *in;
const idclass_t *ic;
tvhtrace("idnode", "find class %s", idc->ic_class);
idnode_set_t *is = calloc(1, sizeof(idnode_set_t));
RB_FOREACH(in, &idnodes, in_link) {
ic = in->in_class;
while (ic) {
if (ic == idc) {
tvhtrace("idnode", " add node %s", idnode_uuid_as_str(in));
idnode_set_add(is, in, NULL);
break;
if (domain == NULL)
domain = idnode_domain(idc);
if (domain == NULL) {
RB_FOREACH(in, &idnodes, in_link) {
ic = in->in_class;
while (ic) {
if (ic == idc) {
tvhtrace("idnode", " add node %s", idnode_uuid_as_str(in));
idnode_set_add(is, in, NULL);
break;
}
ic = ic->ic_super;
}
}
} else {
RB_FOREACH(in, domain, in_domain_link) {
ic = in->in_class;
while (ic) {
if (ic == idc) {
tvhtrace("idnode", " add node %s", idnode_uuid_as_str(in));
idnode_set_add(is, in, NULL);
break;
}
ic = ic->ic_super;
}
ic = ic->ic_super;
}
}
return is;
@ -1099,14 +1159,6 @@ idclass_get_property_groups (const idclass_t *idc)
return NULL;
}
static int
ic_cmp ( const idclass_link_t *a, const idclass_link_t *b )
{
assert(a->idc->ic_class);
assert(b->idc->ic_class);
return strcmp(a->idc->ic_class, b->idc->ic_class);
}
void
idclass_register(const idclass_t *idc)
{
@ -1115,12 +1167,33 @@ idclass_register(const idclass_t *idc)
idclasses_skel->idc = idc;
if (RB_INSERT_SORTED(&idclasses, idclasses_skel, link, ic_cmp))
break;
RB_INIT(&idclasses_skel->nodes); /* not used, but for sure */
SKEL_USED(idclasses_skel);
tvhtrace("idnode", "register class %s", idc->ic_class);
idc = idc->ic_super;
}
}
static void
idclass_root_register(idnode_t *in)
{
const idclass_t *idc = in->in_class;
idclass_link_t *r;
idc = idnode_root_class(idc);
SKEL_ALLOC(idclasses_skel);
idclasses_skel->idc = idc;
r = RB_INSERT_SORTED(&idrootclasses, idclasses_skel, link, ic_cmp);
if (r) {
in->in_domain = &r->nodes;
return;
}
RB_INIT(&idclasses_skel->nodes);
r = idclasses_skel;
SKEL_USED(idclasses_skel);
tvhtrace("idnode", "register root class %s", idc->ic_class);
in->in_domain = &r->nodes;
}
const idclass_t *
idclass_find ( const char *class )
{
@ -1296,7 +1369,7 @@ idnode_thread ( void *p )
pthread_mutex_lock(&global_lock);
HTSMSG_FOREACH(f, q) {
node = idnode_find(f->hmf_name, NULL);
node = idnode_find(f->hmf_name, NULL, NULL);
event = htsmsg_field_get_str(f);
m = htsmsg_create_map();
htsmsg_add_str(m, "uuid", f->hmf_name);

View file

@ -73,12 +73,17 @@ struct idclass {
int (*ic_perm) (idnode_t *self, struct access *a, htsmsg_t *msg_to_write);
};
typedef RB_HEAD(, idnode) idnodes_rb_t;
/*
* Node definition
*/
struct idnode {
uint8_t in_uuid[UUID_BIN_SIZE]; ///< Unique ID
RB_ENTRY(idnode) in_link; ///< Global hash
RB_ENTRY(idnode) in_domain_link; ///< Root class link (domain)
idnodes_rb_t *in_domain; ///< Domain nodes
const idclass_t *in_class; ///< Class definition
};
@ -149,8 +154,8 @@ void idnode_movedown (idnode_t *in);
void idnode_changed (idnode_t *in);
void *idnode_find (const char *uuid, const idclass_t *idc);
idnode_set_t *idnode_find_all(const idclass_t *idc);
void *idnode_find (const char *uuid, const idclass_t *idc, const idnodes_rb_t *nodes);
idnode_set_t *idnode_find_all(const idclass_t *idc, const idnodes_rb_t *nodes);
void idnode_notify (idnode_t *in, int event);

View file

@ -640,7 +640,8 @@ void mpegts_input_stop_all ( mpegts_input_t *mi );
void mpegts_input_delete ( mpegts_input_t *mi, int delconf );
#define mpegts_input_find(u) idnode_find(u, &mpegts_input_class);
static inline mpegts_input_t *mpegts_input_find(const char *uuid)
{ return idnode_find(uuid, &mpegts_input_class, NULL); }
int mpegts_input_set_networks ( mpegts_input_t *mi, htsmsg_t *msg );
@ -680,8 +681,8 @@ mpegts_network_t *mpegts_network_create0
extern const idclass_t mpegts_network_class;
#define mpegts_network_find(u)\
idnode_find(u, &mpegts_network_class)
static inline mpegts_network_t *mpegts_network_find(const char *uuid)
{ return idnode_find(uuid, &mpegts_network_class, NULL); }
mpegts_mux_t *mpegts_network_find_mux
(mpegts_network_t *mn, uint16_t onid, uint16_t tsid);
@ -706,8 +707,8 @@ mpegts_mux_t *mpegts_mux_create0
mpegts_mux_create0(calloc(1, sizeof(mpegts_mux_t)), &mpegts_mux_class, uuid,\
mn, onid, tsid, conf)
#define mpegts_mux_find(u)\
idnode_find(u, &mpegts_mux_class)
static inline mpegts_mux_t *mpegts_mux_find(const char *uuid)
{ return idnode_find(uuid, &mpegts_mux_class, NULL); }
#define mpegts_mux_delete_by_uuid(u, delconf)\
{ mpegts_mux_t *mm = mpegts_mux_find(u); if (mm) mm->mm_delete(mm, delconf); }
@ -814,8 +815,8 @@ mpegts_service_t *mpegts_service_create0
mpegts_service_t *mpegts_service_find
( mpegts_mux_t *mm, uint16_t sid, uint16_t pmt_pid, int create, int *save );
#define mpegts_service_find_by_uuid(u)\
idnode_find(u, &mpegts_service_class)
static inline mpegts_service_t *mpegts_service_find_by_uuid(const char *uuid)
{ return idnode_find(uuid, &mpegts_service_class, NULL); }
void mpegts_service_delete ( service_t *s, int delconf );

View file

@ -398,7 +398,7 @@ linuxdvb_frontend_network_list ( mpegts_input_t *mi )
else
return NULL;
return idnode_find_all(idc);
return idnode_find_all(idc, NULL);
}
/* **************************************************************************

View file

@ -640,8 +640,7 @@ void dvb_network_done ( void )
dvb_network_t*
dvb_network_find_by_uuid(const char *uuid)
{
idnode_t *in = idnode_find(uuid, &dvb_network_class);
return (dvb_network_t*)in;
return idnode_find(uuid, &dvb_network_class, NULL);
}
int dvb_network_get_orbital_pos

View file

@ -638,7 +638,7 @@ satip_frontend_network_list ( mpegts_input_t *mi )
else
return NULL;
return idnode_find_all(idc);
return idnode_find_all(idc, NULL);
}
/* **************************************************************************

View file

@ -924,7 +924,6 @@ main(int argc, char **argv)
tvhftrace("main", avahi_done);
tvhftrace("main", bonjour_done);
tvhftrace("main", imagecache_done);
tvhftrace("main", idnode_done);
tvhftrace("main", lang_code_done);
tvhftrace("main", api_done);
tvhftrace("main", config_done);
@ -934,6 +933,7 @@ main(int argc, char **argv)
tvhftrace("main", esfilter_done);
tvhftrace("main", intlconv_done);
tvhftrace("main", urlparse_done);
tvhftrace("main", idnode_done);
tvhlog(LOG_NOTICE, "STOP", "Exiting HTS Tvheadend");
tvhlog_end();

View file

@ -861,16 +861,6 @@ service_create0
return t;
}
/**
* Find a service based on the given identifier
*/
service_t *
service_find(const char *identifier)
{
return idnode_find(identifier, &service_class);
}
/**
*
*/

View file

@ -461,7 +461,8 @@ void service_unref(service_t *t);
void service_ref(service_t *t);
service_t *service_find(const char *identifier);
static inline service_t *service_find(const char *identifier)
{ return idnode_find(identifier, &service_class, NULL); }
#define service_find_by_identifier service_find
service_instance_t *service_find_instance(struct service *s,