#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;
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);
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 )
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
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;
}
* 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;
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
/* Unlink */
void epg_channel_unlink ( struct channel *ch );
+/* ************************************************************************
+ * Global config
+ * ***********************************************************************/
+htsmsg_t *epg_config_serialize ( void );
+int epg_config_deserialize ( htsmsg_t *m );
+
/* ************************************************************************
* Querying
* ***********************************************************************/
} 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);
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);
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++;
}
}
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);
}
epggrab_stats_part_t seasons;
epggrab_stats_part_t episodes;
epggrab_stats_part_t broadcasts;
+ epggrab_stats_part_t config;
} epggrab_stats_t;
/* **************************************************************************