diff --git a/src/epg.c b/src/epg.c index ad1a5edd..38d63797 100644 --- a/src/epg.c +++ b/src/epg.c @@ -39,6 +39,9 @@ #define EPG_HASH_WIDTH 1024 #define EPG_HASH_MASK (EPG_HASH_WIDTH - 1) +/* Objects tree */ +epg_object_tree_t epg_objects[EPG_HASH_WIDTH]; + /* URI lists */ epg_object_tree_t epg_brands; epg_object_tree_t epg_seasons; @@ -46,17 +49,29 @@ epg_object_tree_t epg_episodes; epg_object_tree_t epg_serieslinks; /* Other special case lists */ -epg_object_list_t epg_objects[EPG_HASH_WIDTH]; epg_object_list_t epg_object_unref; epg_object_list_t epg_object_updated; /* Global counter */ static uint32_t _epg_object_idx = 0; +/* + * + */ +static inline epg_object_tree_t *epg_id_tree( epg_object_t *eo ) +{ + return &epg_objects[eo->id & EPG_HASH_MASK]; +} + /* ************************************************************************** * Comparators / Ordering * *************************************************************************/ +static int _id_cmp ( const void *a, const void *b ) +{ + return ((epg_object_t*)a)->id - ((epg_object_t*)b)->id; +} + static int _uri_cmp ( const void *a, const void *b ) { return strcmp(((epg_object_t*)a)->uri, ((epg_object_t*)b)->uri); @@ -132,7 +147,7 @@ static void _epg_object_destroy if (eo->uri) free(eo->uri); if (tree) RB_REMOVE(tree, eo, uri_link); if (eo->_updated) LIST_REMOVE(eo, up_link); - LIST_REMOVE(eo, id_link); + RB_REMOVE(epg_id_tree(eo), eo, id_link); } static void _epg_object_getref ( void *o ) @@ -169,15 +184,25 @@ static void _epg_object_set_updated ( void *o ) static void _epg_object_create ( void *o ) { epg_object_t *eo = o; + uint32_t id = eo->id; + if (!id) eo->id = ++_epg_object_idx; if (!eo->id) eo->id = ++_epg_object_idx; - else if (eo->id > _epg_object_idx) _epg_object_idx = eo->id; if (!eo->getref) eo->getref = _epg_object_getref; if (!eo->putref) eo->putref = _epg_object_putref; tvhtrace("epg", "eo [%p, %u, %d, %s] created", eo, eo->id, eo->type, eo->uri); _epg_object_set_updated(eo); LIST_INSERT_HEAD(&epg_object_unref, eo, un_link); - LIST_INSERT_HEAD(&epg_objects[eo->id & EPG_HASH_MASK], eo, id_link); + while (1) { + if (!RB_INSERT_SORTED(epg_id_tree(eo), eo, id_link, _id_cmp)) + break; + if (id) { + tvherror("epg", "fatal error, duplicate EPG ID"); + abort(); + } + eo->id = ++_epg_object_idx; + if (!eo->id) eo->id = ++_epg_object_idx; + } } static epg_object_t *_epg_object_find_by_uri @@ -211,11 +236,11 @@ static epg_object_t *_epg_object_find_by_uri epg_object_t *epg_object_find_by_id ( uint32_t id, epg_object_type_t type ) { - epg_object_t *eo; - LIST_FOREACH(eo, &epg_objects[id & EPG_HASH_MASK], id_link) { - if (eo->id == id) - return ((type == EPG_UNDEF) || (eo->type == type)) ? eo : NULL; - } + epg_object_t *eo, temp; + temp.id = id; + eo = RB_FIND(epg_id_tree(&temp), &temp, id_link, _id_cmp); + if (eo && eo->type == type) + return eo; return NULL; } @@ -2603,6 +2628,20 @@ void epg_query_free(epg_query_t *eq) * Miscellaneous * *************************************************************************/ +htsmsg_t *epg_config_serialize( void ) +{ + htsmsg_t *m = htsmsg_create_map(); + htsmsg_add_u32(m, "last_id", _epg_object_idx); + return m; +} + +int epg_config_deserialize( htsmsg_t *m ) +{ + if (htsmsg_get_u32(m, "last_id", &_epg_object_idx)) + return 0; + return 1; /* ok */ +} + void epg_skel_done(void) { epg_object_t **skel; diff --git a/src/epg.h b/src/epg.h index fd17e5da..340a23f4 100644 --- a/src/epg.h +++ b/src/epg.h @@ -104,7 +104,7 @@ typedef enum epg_object_type struct epg_object { RB_ENTRY(epg_object) uri_link; ///< Global URI link - LIST_ENTRY(epg_object) id_link; ///< Global (ID) link + RB_ENTRY(epg_object) id_link; ///< Global (ID) link LIST_ENTRY(epg_object) un_link; ///< Global unref'd link LIST_ENTRY(epg_object) up_link; ///< Global updated link @@ -527,6 +527,12 @@ epg_broadcast_t *epg_broadcast_deserialize /* Unlink */ void epg_channel_unlink ( struct channel *ch ); +/* ************************************************************************ + * Global config + * ***********************************************************************/ +htsmsg_t *epg_config_serialize ( void ); +int epg_config_deserialize ( htsmsg_t *m ); + /* ************************************************************************ * Querying * ***********************************************************************/ diff --git a/src/epgdb.c b/src/epgdb.c index 32d9adb1..1ba29ac6 100644 --- a/src/epgdb.c +++ b/src/epgdb.c @@ -131,6 +131,10 @@ _epgdb_v2_process( char **sect, htsmsg_t *m, epggrab_stats_t *stats ) } else if ( !strcmp(*sect, "broadcasts") ) { if (epg_broadcast_deserialize(m, 1, &save)) stats->broadcasts.total++; + /* Global config */ + } else if ( !strcmp(*sect, "config") ) { + if (epg_config_deserialize(m)) stats->config.total++; + /* Unknown */ } else { tvhlog(LOG_DEBUG, "epgdb", "malformed database section [%s]", *sect); @@ -220,8 +224,17 @@ void epg_init ( void ) free(sect); + if (!stats.config.total) { + htsmsg_t *m = htsmsg_create_map(); + /* it's not correct, but at least something */ + htsmsg_add_u32(m, "last_id", 64 * 1024 * 1024); + if (!epg_config_deserialize(m)) + assert(0); + } + /* Stats */ tvhlog(LOG_INFO, "epgdb", "loaded v%d", ver); + tvhlog(LOG_INFO, "epgdb", " config %d", stats.config.total); tvhlog(LOG_INFO, "epgdb", " channels %d", stats.channels.total); tvhlog(LOG_INFO, "epgdb", " brands %d", stats.brands.total); tvhlog(LOG_INFO, "epgdb", " seasons %d", stats.seasons.total); @@ -300,31 +313,32 @@ void epg_save ( void ) return; memset(&stats, 0, sizeof(stats)); - if ( _epg_write_sect(fd, "brands") ) return; + if ( _epg_write_sect(fd, "config") ) goto fin; + if (_epg_write(fd, epg_config_serialize())) goto fin; + if ( _epg_write_sect(fd, "brands") ) goto fin; RB_FOREACH(eo, &epg_brands, uri_link) { - if (_epg_write(fd, epg_brand_serialize((epg_brand_t*)eo))) return; + if (_epg_write(fd, epg_brand_serialize((epg_brand_t*)eo))) goto fin; stats.brands.total++; } - if ( _epg_write_sect(fd, "seasons") ) return; + if ( _epg_write_sect(fd, "seasons") ) goto fin; RB_FOREACH(eo, &epg_seasons, uri_link) { - if (_epg_write(fd, epg_season_serialize((epg_season_t*)eo))) return; + if (_epg_write(fd, epg_season_serialize((epg_season_t*)eo))) goto fin; stats.seasons.total++; } - if ( _epg_write_sect(fd, "episodes") ) return; + if ( _epg_write_sect(fd, "episodes") ) goto fin; RB_FOREACH(eo, &epg_episodes, uri_link) { - if (_epg_write(fd, epg_episode_serialize((epg_episode_t*)eo))) return; + if (_epg_write(fd, epg_episode_serialize((epg_episode_t*)eo))) goto fin; stats.episodes.total++; } - if ( _epg_write_sect(fd, "serieslinks") ) return; + if ( _epg_write_sect(fd, "serieslinks") ) goto fin; RB_FOREACH(eo, &epg_serieslinks, uri_link) { - if (_epg_write(fd, epg_serieslink_serialize((epg_serieslink_t*)eo))) - return; + if (_epg_write(fd, epg_serieslink_serialize((epg_serieslink_t*)eo))) goto fin; stats.seasons.total++; } - if ( _epg_write_sect(fd, "broadcasts") ) return; + if ( _epg_write_sect(fd, "broadcasts") ) goto fin; CHANNEL_FOREACH(ch) { RB_FOREACH(ebc, &ch->ch_epg_schedule, sched_link) { - if (_epg_write(fd, epg_broadcast_serialize(ebc))) return; + if (_epg_write(fd, epg_broadcast_serialize(ebc))) goto fin; stats.broadcasts.total++; } } @@ -335,4 +349,7 @@ void epg_save ( void ) tvhlog(LOG_INFO, "epgdb", " seasons %d", stats.seasons.total); tvhlog(LOG_INFO, "epgdb", " episodes %d", stats.episodes.total); tvhlog(LOG_INFO, "epgdb", " broadcasts %d", stats.broadcasts.total); + +fin: + close(fd); } diff --git a/src/epggrab.h b/src/epggrab.h index 79358304..518dcb4c 100644 --- a/src/epggrab.h +++ b/src/epggrab.h @@ -58,6 +58,7 @@ typedef struct epggrab_stats epggrab_stats_part_t seasons; epggrab_stats_part_t episodes; epggrab_stats_part_t broadcasts; + epggrab_stats_part_t config; } epggrab_stats_t; /* **************************************************************************