]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
Store EPG on disk (using a binary format)
authorAndreas Öman <andreas@lonelycoder.com>
Sat, 8 Jan 2011 12:37:29 +0000 (13:37 +0100)
committerAndreas Öman <andreas@lonelycoder.com>
Sat, 8 Jan 2011 12:37:29 +0000 (13:37 +0100)
Based on work by Jörg Dembski

src/epg.c
src/epg.h

index 336609b20e381edf743d9512500a615b16cf0268..24bf59d2b1c4f54be126e06d2309277a87ffc372 100644 (file)
--- a/src/epg.c
+++ b/src/epg.c
@@ -16,6 +16,8 @@
  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <sys/mman.h>
+#include <sys/stat.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
@@ -29,6 +31,7 @@
 #include "epg.h"
 #include "dvr/dvr.h"
 #include "htsp.h"
+#include "htsmsg_binary.h"
 
 #define EPG_MAX_AGE 86400
 
@@ -528,119 +531,187 @@ epg_content_group_find_by_name(const char *name)
 }
 
 
-/*
+/**
  *
  */
-void
-epg_init(void)
+static int
+epg_event_create_by_msg(htsmsg_t *c, time_t now)
 {
-  event_t *e;
-  int injected = 0;
-  int created = 0;
-  uint32_t id = 0;
+ channel_t *ch;
+  event_t *e = NULL;
+  uint32_t ch_id = 0;
+  uint32_t e_start = 0;
+  uint32_t e_stop = 0;
+  int e_dvb_id = 0, v;
+  const char *s;
 
-  htsmsg_t *l, *c;
-  htsmsg_field_t *f;
+  // Now create the event
+  if(htsmsg_get_u32(c, "ch_id", &ch_id))
+    return 0;
 
-  if((l = hts_settings_load("epg")) == NULL)
-    return;
-  HTSMSG_FOREACH(f, l) {
-    if((c = htsmsg_get_map_by_field(f)) == NULL)
-      continue;
+  if((ch = channel_find_by_identifier(ch_id)) == NULL)
+    return 0;
 
-    e = epg_event_create_by_msg(c, &created);
-    htsmsg_get_u32(c, "id", &id);
+  if(htsmsg_get_u32(c, "start", &e_start))
+    return 0;
 
-    hts_settings_remove("epg/%d", id);
+  if(htsmsg_get_u32(c, "stop", &e_stop))
+    return 0;
 
-    if(created)
-      injected++;
-  }
-  htsmsg_destroy(l);
+  if(e_stop < now)
+    return 0;
 
-  tvhlog(LOG_INFO, "epg", "Injected %d epg events.", injected);
-} 
+  if(htsmsg_get_s32(c, "dvb_id", &e_dvb_id))
+    e_dvb_id = -1;
 
-/*
+  e = epg_event_create(ch, e_start, e_stop, e_dvb_id, NULL);
+
+  if((s = htsmsg_get_str(c, "title")) != NULL)
+    epg_event_set_title(e, s);
+
+  if((s = htsmsg_get_str(c, "desc")) != NULL)
+    epg_event_set_desc(e, s);
+
+  if(!htsmsg_get_s32(c, "season", &v))
+    e->e_episode.ee_season = v;
+
+  if(!htsmsg_get_s32(c, "episode", &v))
+    e->e_episode.ee_episode = v;
+
+  if(!htsmsg_get_s32(c, "part", &v))
+    e->e_episode.ee_part = v;
+
+  if((s = htsmsg_get_str(c, "epname")) != NULL)
+    tvh_str_set(&e->e_episode.ee_onscreen, s);
+
+  return 1;
+}
+
+
+/**
  *
  */
-event_t *
-epg_event_create_by_msg(htsmsg_t *c, int *created) 
+static void
+epg_load(void)
 {
- channel_t *ch;
-  event_t *e = NULL;
-  uint32_t ch_id = 0;
-  uint32_t e_start = 0;
-  uint32_t e_stop = 0;
-  int e_dvb_id = 0;
-  const char *e_title, *e_desc;
+  struct stat st;
+  int fd = hts_settings_open_file(0, "epgdb");
+  time_t now;
+  int created = 0;
 
-  if (created != NULL)
-    *created = 0;
+  time(&now);
 
-    // Now create the event
-    htsmsg_get_u32(c, "ch_id", &ch_id);
-    ch = channel_find_by_identifier(ch_id);
-    if (ch == NULL)
-      tvhlog(LOG_DEBUG, "epg", "Cannot find this channel, skipping...");
-    else {
-      htsmsg_get_u32(c, "start", &e_start);
-      htsmsg_get_u32(c, "stop", &e_stop);
-      htsmsg_get_s32(c, "dvb_id", &e_dvb_id);
+  if(fd == -1)
+    return;
 
-      e = epg_event_create(ch, e_start, e_stop, e_dvb_id, created);
+  if(fstat(fd, &st)) {
+    close(fd);
+    return;
+  }
+  uint8_t *mem = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+  if(mem == MAP_FAILED) {
+    close(fd);
+    return;
+  }
+  const uint8_t *rp = mem;
+  size_t remain = st.st_size;
 
-      int changed = 0;
+  while(remain > 4) {
+    int msglen = (rp[0] << 24) | (rp[1] << 16) | (rp[2] << 8) | rp[3];
+    remain -= 4;
+    rp += 4;
 
-      e_title = htsmsg_get_str(c, "title");
-      if (e_title != NULL)
-        changed |= epg_event_set_title(e, e_title);
+    if(msglen > remain) {
+      tvhlog(LOG_ERR, "EPG", "Malformed EPG database, skipping some data");
+      break;
+    }
+    htsmsg_t *m = htsmsg_binary_deserialize(rp, msglen, NULL);
 
-      e_desc = htsmsg_get_str(c, "title");
-      if (e_desc != NULL)
-        changed |= epg_event_set_title(e, e_desc);
+    created += epg_event_create_by_msg(m, now);
 
-      if(changed)
-        epg_event_updated(e);
-    }
+    htsmsg_destroy(m);
+    rp += msglen;
+    remain -= msglen;
+  }
 
-  return e;
+  munmap(mem, st.st_size);
+  close(fd);
+  tvhlog(LOG_NOTICE, "EPG", "Injected %d event from disk database", created);
 }
 
-/*
+/**
+ *
+ */
+void
+epg_init(void)
+{
+  epg_load();
+}
+
+
+/**
  * Save the epg on disk
  */ 
 void
 epg_save(void)
 {
   event_t *e;
-  int saved = 0;
-
+  int num_saved = 0;
+  size_t msglen;
+  void *msgdata;
   channel_t *ch;
 
+  int fd = hts_settings_open_file(1, "epgdb");
+
   RB_FOREACH(ch, &channel_name_tree, ch_name_link) {
     RB_FOREACH(e, &ch->ch_epg_events, e_channel_link) {
-      if((e->e_start) && (e->e_stop)) {
-        htsmsg_t *m = htsmsg_create_map();
-        htsmsg_add_u32(m, "id", saved);
-        htsmsg_add_u32(m, "start", e->e_start);
-        htsmsg_add_u32(m, "stop", e->e_stop);
-        if (e->e_title != NULL)
-          htsmsg_add_str(m, "title", e->e_title);
-
-        if (e->e_desc != NULL)
-          htsmsg_add_str(m, "desc", e->e_desc);
-        htsmsg_add_u32(m, "ch_id", ch->ch_id);
-        htsmsg_add_s32(m, "dvb_id", e->e_dvb_id);
-
-        hts_settings_save(m, "epg/%d", saved);
-
-        saved++;
+      if(!e->e_start || !e->e_stop)
+       continue;
+
+      htsmsg_t *m = htsmsg_create_map();
+      htsmsg_add_u32(m, "ch_id", ch->ch_id);
+      htsmsg_add_u32(m, "start", e->e_start);
+      htsmsg_add_u32(m, "stop", e->e_stop);
+      if(e->e_title != NULL)
+       htsmsg_add_str(m, "title", e->e_title);
+      if(e->e_desc != NULL)
+       htsmsg_add_str(m, "desc", e->e_desc);
+      if(e->e_dvb_id)
+       htsmsg_add_u32(m, "dvb_id", e->e_dvb_id);
+
+      if(e->e_episode.ee_season)
+       htsmsg_add_u32(m, "season", e->e_episode.ee_season);
+
+      if(e->e_episode.ee_episode)
+       htsmsg_add_u32(m, "episode", e->e_episode.ee_episode);
+
+      if(e->e_episode.ee_part)
+       htsmsg_add_u32(m, "part", e->e_episode.ee_part);
+
+      if(e->e_episode.ee_onscreen)
+       htsmsg_add_str(m, "epname", e->e_episode.ee_onscreen);
+
+
+      int r = htsmsg_binary_serialize(m, &msgdata, &msglen, 0x10000);
+      htsmsg_destroy(m);
+
+      if(!r) {
+       ssize_t written = write(fd, msgdata, msglen);
+       int err = errno;
+       free(msgdata);
+       if(written != msglen) {
+         tvhlog(LOG_DEBUG, "epg", "Failed to store EPG on disk -- %s",
+                strerror(err));
+         close(fd);
+         hts_settings_remove("epgdb");
+         return;
+       }
       }
+      num_saved++;
     }
   }
-  tvhlog(LOG_DEBUG, "epg", "Wrote epg data for %d events", saved);
+  close(fd);
+  tvhlog(LOG_DEBUG, "EPG", "Stored EPG data for %d events on disk", num_saved);
 }
 
 
index 0046dbf4d1a928e66951aa9212055395d38d12c8..ebd7b0c96ef8f2e95fc88c1e4f5cfe831b36636c 100644 (file)
--- a/src/epg.h
+++ b/src/epg.h
@@ -82,11 +82,9 @@ void epg_save(void);
  * can combine multiple set()'s into one update
  *
  */
-int epg_event_set_title(event_t *e, const char *title)
-       __attribute__ ((warn_unused_result));
+int epg_event_set_title(event_t *e, const char *title);
 
-int epg_event_set_desc(event_t *e, const char *desc)
-       __attribute__ ((warn_unused_result));
+int epg_event_set_desc(event_t *e, const char *desc);
 
 int epg_event_set_ext_desc(event_t *e, int ext_dn, const char *desc)
        __attribute__ ((warn_unused_result));
@@ -108,8 +106,6 @@ void epg_event_updated(event_t *e);
 event_t *epg_event_create(channel_t *ch, time_t start, time_t stop,
                          int dvb_id, int *created);
 
-event_t *epg_event_create_by_msg(htsmsg_t *c, int *created);
-
 event_t *epg_event_find_by_time(channel_t *ch, time_t t);
 
 event_t *epg_event_find_by_id(int eventid);