Partial revert of previous multi-key update. I have decided to leave it to the upstream data providers to fix this (which still makes it my problem) but I have kept some of the simplifications added as part of the previous update.

This commit is contained in:
Adam Sutton 2012-06-12 13:05:39 +01:00
parent 2355e45160
commit b09b493fdc
3 changed files with 53 additions and 93 deletions

114
src/epg.c
View file

@ -40,14 +40,14 @@
#define EPG_HASH_MASK (EPG_HASH_WIDTH - 1)
/* URI lists */
epg_object_key_tree_t epg_brands;
epg_object_key_tree_t epg_seasons;
epg_object_key_tree_t epg_episodes;
epg_object_tree_t epg_brands;
epg_object_tree_t epg_seasons;
epg_object_tree_t epg_episodes;
/* 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;
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 uint64_t _epg_object_idx = 0;
@ -61,11 +61,6 @@ static int _uri_cmp ( const void *a, const void *b )
return strcmp(((epg_object_t*)a)->uri, ((epg_object_t*)b)->uri);
}
static int _key_cmp ( const void *a, const void *b )
{
return _uri_cmp(((epg_object_key_t*)a)->obj, ((epg_object_key_t*)b)->obj);
}
static int _ebc_start_cmp ( const void *a, const void *b )
{
return ((epg_broadcast_t*)a)->start - ((epg_broadcast_t*)b)->start;
@ -99,44 +94,46 @@ static int _epg_write ( int fd, htsmsg_t *m )
return ret;
}
#define _epg_write_sect(_fd, _total, _sect, _type, _type2, _pack)\
{\
int i;\
epg_object_t *eo;\
htsmsg_t *m = htsmsg_create_map();\
htsmsg_add_str(m, "__section__", _sect);\
if (_epg_write(_fd, m)) return;\
for ( i = 0; i < EPG_HASH_WIDTH; i++ ) {\
LIST_FOREACH(eo, &epg_objects[i], hlink) {\
if (eo->type == _type) {\
if (_epg_write(_fd, _pack((_type2*)eo))) return;\
_total++;\
}\
}\
}\
static int _epg_write_sect ( int fd, const char *sect )
{
htsmsg_t *m = htsmsg_create_map();
htsmsg_add_str(m, "__section__", sect);
return _epg_write(fd, m);
}
void epg_save ( void )
{
int fd;
epg_object_t *eo;
epg_broadcast_t *ebc;
channel_t *ch;
epggrab_stats_t stats;
fd = hts_settings_open_file(1, "epgdb");
memset(&stats, 0, sizeof(stats));
/* Write each object type:
* Note: this is slightly inefficient (due to excessive looping)
* but should be ok */
_epg_write_sect(fd, stats.brands.total, "brands", EPG_BRAND,
epg_brand_t, epg_brand_serialize);
_epg_write_sect(fd, stats.seasons.total, "seasons", EPG_SEASON,
epg_season_t, epg_season_serialize);
_epg_write_sect(fd, stats.episodes.total, "episodes", EPG_EPISODE,
epg_episode_t, epg_episode_serialize);
_epg_write_sect(fd, stats.broadcasts.total, "broadcasts", EPG_BROADCAST,
epg_broadcast_t, epg_broadcast_serialize);
// TODO: as I include the URI in the object I could use that to allow
// me to only loop over the type lists
memset(&stats, 0, sizeof(stats));
if ( _epg_write_sect(fd, "brands") ) return;
RB_FOREACH(eo, &epg_brands, glink) {
if (_epg_write(fd, epg_brand_serialize((epg_brand_t*)eo))) return;
stats.brands.total++;
}
if ( _epg_write_sect(fd, "seasons") ) return;
RB_FOREACH(eo, &epg_seasons, glink) {
if (_epg_write(fd, epg_season_serialize((epg_season_t*)eo))) return;
stats.seasons.total++;
}
if ( _epg_write_sect(fd, "episodes") ) return;
RB_FOREACH(eo, &epg_episodes, glink) {
if (_epg_write(fd, epg_episode_serialize((epg_episode_t*)eo))) return;
stats.episodes.total++;
}
if ( _epg_write_sect(fd, "broadcasts") ) return;
RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
RB_FOREACH(ebc, &ch->ch_epg_schedule, glink) {
if (_epg_write(fd, epg_broadcast_serialize(ebc))) return;
stats.broadcasts.total++;
}
}
/* Stats */
tvhlog(LOG_INFO, "epg", "database saved");
@ -274,16 +271,11 @@ void epg_updated ( void )
* *************************************************************************/
static void _epg_object_destroy
( epg_object_t *eo, epg_object_key_tree_t *tree )
( epg_object_t *eo, epg_object_tree_t *tree )
{
epg_object_key_t *ek;
assert(eo->refcount == 0);
if (eo->uri) free(eo->uri);
if (tree) {
LIST_FOREACH(ek, &eo->aliases, olink) {
RB_REMOVE(tree, ek, glink);
}
}
if (tree) RB_REMOVE(tree, eo, glink);
if (eo->_updated) LIST_REMOVE(eo, uplink);
LIST_REMOVE(eo, hlink);
}
@ -322,37 +314,31 @@ static void _epg_object_create ( epg_object_t *eo )
static epg_object_t *_epg_object_find_by_uri
( const char *uri, int create, int *save,
epg_object_key_tree_t *tree, epg_object_t **skel )
epg_object_tree_t *tree, epg_object_t **skel )
{
static epg_object_key_t *ekskel = NULL;
epg_object_key_t *ek;
epg_object_t *eo;
assert(skel != NULL);
lock_assert(&global_lock);
if (!ekskel) ekskel = calloc(1, sizeof(epg_object_key_t));
ekskel->uri = (char*)uri;
(*skel)->uri = (char*)uri;
/* Find only */
if ( !create ) {
ek = RB_FIND(tree, ekskel, glink, _key_cmp);
eo = RB_FIND(tree, *skel, glink, _uri_cmp);
/* Find/create */
} else {
ek = RB_INSERT_SORTED(tree, ekskel, glink, _key_cmp);
if ( !ek ) {
eo = RB_INSERT_SORTED(tree, *skel, glink, _uri_cmp);
if ( !eo ) {
*save = 1;
ek = ekskel;
ek->uri = strdup(uri);
ek->obj = *skel;
ek->obj->uri = strdup(uri); // TODO: could not dup this!
LIST_INSERT_HEAD(&ek->obj->aliases, ek, olink);
_epg_object_create(ek->obj);
eo = *skel;
*skel = NULL;
ekskel = NULL;
eo->uri = strdup(uri);
_epg_object_create(eo);
}
}
return ek ? ek->obj : NULL;
return eo;
}
static epg_object_t *_epg_object_find_by_id ( uint64_t id )

View file

@ -31,8 +31,7 @@ struct channel_tag;
* Map types
*/
LIST_HEAD(epg_object_list, epg_object);
LIST_HEAD(epg_object_key_list, epg_object_key);
RB_HEAD (epg_object_key_tree, epg_object_key);
RB_HEAD (epg_object_tree, epg_object);
LIST_HEAD(epg_brand_list, epg_brand);
LIST_HEAD(epg_season_list, epg_season);
LIST_HEAD(epg_episode_list, epg_episode);
@ -43,7 +42,6 @@ RB_HEAD (epg_broadcast_tree, epg_broadcast);
* Typedefs (most are redundant!)
*/
typedef struct epg_object epg_object_t;
typedef struct epg_object_key epg_object_key_t;
typedef struct epg_brand epg_brand_t;
typedef struct epg_season epg_season_t;
typedef struct epg_episode epg_episode_t;
@ -53,25 +51,13 @@ typedef struct epg_episode_list epg_episode_list_t;
typedef struct epg_broadcast_list epg_broadcast_list_t;
typedef struct epg_broadcast_tree epg_broadcast_tree_t;
typedef struct epg_object_list epg_object_list_t;
typedef struct epg_object_key_tree epg_object_key_tree_t;
typedef struct epg_object_key_list epg_object_key_list_t;
typedef struct epg_object_tree epg_object_tree_t;
/* ************************************************************************
* Generic Object
* ***********************************************************************/
/* Used to allow multiple keys per object */
typedef struct epg_object_key
{
LIST_ENTRY(epg_object_key) olink; ///< Link to object's list
RB_ENTRY(epg_object_key) glink; ///< Link to global list
epg_object_t *obj; ///< Object we're wrapping
const char *uri; ///< Object URI
// TODO: could make this union?
} epg_object_key_t;
/* Object type */
typedef enum epg_object_type
{
@ -85,6 +71,7 @@ typedef enum epg_object_type
/* Object */
struct epg_object
{
RB_ENTRY(epg_object) glink; ///< Global URI link
LIST_ENTRY(epg_object) hlink; ///< Global (ID) link
LIST_ENTRY(epg_object) ulink; ///< Global unref'd link
LIST_ENTRY(epg_object) uplink; ///< Global updated link
@ -92,7 +79,6 @@ struct epg_object
epg_object_type_t type; ///< Specific object type
uint64_t id; ///< Internal ID
char *uri; ///< Unique ID (from grabber)
epg_object_key_list_t aliases; ///< URI aliases (inc primary)
int _updated; ///< Flag to indicate updated
int refcount; ///< Reference counting

View file

@ -111,18 +111,6 @@
} \
} while(0)
#define LIST_FIND(head, skel, field, cmpfunc)\
({\
typeof(skel) a, b = NULL;\
LIST_FOREACH(a, head, field) {\
if (!cmpfunc(skel, a)) {\
b = a;\
break;\
}\
}\
b;\
})
#define TAILQ_INSERT_SORTED(head, elm, field, cmpfunc) do { \
if(TAILQ_FIRST(head) == NULL) { \
TAILQ_INSERT_HEAD(head, elm, field); \