From df1cf7dffe21d7f61b516c962127be855dd020aa Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Mon, 22 Sep 2014 16:36:22 +0200 Subject: [PATCH] idnode: optimize idnodes (split to domains) --- src/api/api_idnode.c | 22 +-- src/channels.h | 4 +- src/descrambler/capmt.c | 2 +- src/dvr/dvr.h | 8 +- src/idnode.c | 131 ++++++++++++++---- src/idnode.h | 9 +- src/input/mpegts.h | 15 +- src/input/mpegts/linuxdvb/linuxdvb_frontend.c | 2 +- src/input/mpegts/mpegts_network_dvb.c | 3 +- src/input/mpegts/satip/satip_frontend.c | 2 +- src/main.c | 2 +- src/service.c | 10 -- src/service.h | 3 +- 13 files changed, 144 insertions(+), 69 deletions(-) diff --git a/src/api/api_idnode.c b/src/api/api_idnode.c index 997b8742..4cf0bf1c 100644 --- a/src/api/api_idnode.c +++ b/src/api/api_idnode.c @@ -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); diff --git a/src/channels.h b/src/channels.h index cb5b717d..3993c436 100644 --- a/src/channels.h +++ b/src/channels.h @@ -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); diff --git a/src/descrambler/capmt.c b/src/descrambler/capmt.c index eabe16a7..6e312264 100644 --- a/src/descrambler/capmt.c +++ b/src/descrambler/capmt.c @@ -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; diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index 0bc37067..eccace43 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -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); diff --git a/src/idnode.c b/src/idnode.c index 6764d589..27b65e32 100644 --- a/src/idnode.c +++ b/src/idnode.c @@ -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); diff --git a/src/idnode.h b/src/idnode.h index f3d03387..12693533 100644 --- a/src/idnode.h +++ b/src/idnode.h @@ -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); diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 2bb75b4a..b6a0e24a 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -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 ); diff --git a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c index be3cb32c..8de4f471 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_frontend.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_frontend.c @@ -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); } /* ************************************************************************** diff --git a/src/input/mpegts/mpegts_network_dvb.c b/src/input/mpegts/mpegts_network_dvb.c index 12916f57..f2237218 100644 --- a/src/input/mpegts/mpegts_network_dvb.c +++ b/src/input/mpegts/mpegts_network_dvb.c @@ -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 diff --git a/src/input/mpegts/satip/satip_frontend.c b/src/input/mpegts/satip/satip_frontend.c index 763280d5..686ca576 100644 --- a/src/input/mpegts/satip/satip_frontend.c +++ b/src/input/mpegts/satip/satip_frontend.c @@ -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); } /* ************************************************************************** diff --git a/src/main.c b/src/main.c index 9bc86856..2e77000e 100644 --- a/src/main.c +++ b/src/main.c @@ -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(); diff --git a/src/service.c b/src/service.c index 68f4f87e..8de4dfb3 100644 --- a/src/service.c +++ b/src/service.c @@ -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); -} - - /** * */ diff --git a/src/service.h b/src/service.h index d7706e4f..b6d56ac3 100644 --- a/src/service.h +++ b/src/service.h @@ -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,