Periodically check the sizes db and remove obsolete entries
authorSteve McIntyre <steve@einval.com>
Tue, 22 Nov 2011 18:51:18 +0000 (18:51 +0000)
committerSteve McIntyre <steve@einval.com>
Tue, 22 Nov 2011 18:51:18 +0000 (18:51 +0000)
 * Spawn another thread at system startup.
 * Once per hour, that thread will crawl the DB and check for dead
   entries

C/fmdb.c
C/fmdb.h
C/fuse-music.c

index 6cda1af..7dd40ba 100644 (file)
--- a/C/fmdb.c
+++ b/C/fmdb.c
@@ -358,6 +358,58 @@ int db_remove_size_entry(FMDB *dbp, const db_size_entry_t *in)
     return error;
 }
 
+/* Walk the size database, removing any entries for flac files that no longer exist */
+int db_cleanup_sizes(FMDB *dbp, const char *basedir)
+{
+    int error = 0;
+    db_state_t *state = dbp;
+    char *open_error;
+    int result_type = RES_SIZE;
+    char sql_command[2 * PATH_MAX];
+    int removed_db_entries = 0;
+    int num_entries = 0;
+    char flac_file[PATH_MAX];
+    struct stat sb;
+
+    pthread_mutex_lock(&db_mutex);
+    free_results();
+
+    DBLOG0((logfile, "%s: looking for old entries to remove\n", __func__));
+    sprintf(sql_command, "SELECT * FROM sizes;");
+    error = sqlite3_exec(state->db, sql_command, results_callback, &result_type, &open_error);
+    if (error)
+    {
+        DBLOG0((logfile, "%s: Failed to lookup, error %d (%s)\n", __func__, error, open_error));
+        if (open_error)
+            sqlite3_free(open_error);
+        pthread_mutex_unlock(&db_mutex);
+        return error;
+    }
+
+    res_current = res_head;
+    while (res_current)
+    { 
+        db_size_entry_t *entry = &res_current->data.size;
+        /* Now look for entries that don't have a matching
+         * (and correct) flac file on disk */
+        snprintf(flac_file, PATH_MAX, "%s/%s", basedir, entry->flac_path);
+        error = stat(flac_file, &sb);
+        if (error)
+        {
+            DBLOG1((logfile, "%s: can't stat flac file %s, error %d. Deleting DB entry\n",
+                    __func__, flac_file, errno));
+            error = db_remove_size_entry_unlocked(dbp, entry);
+            removed_db_entries++;
+        }
+        num_entries++;
+        res_current = res_current->next;
+    }
+    DBLOG0((logfile, "%s: found %d entries total, removed %d obsolete entries\n",
+            __func__, num_entries, removed_db_entries));
+    pthread_mutex_unlock(&db_mutex);
+    return error;
+}    
+
 /* Needs no locking, internal function called at startup when we're
  * still single threaded */
 static int db_create_cache_table(db_state_t *dbp)
index bb9edaf..cee8970 100644 (file)
--- a/C/fmdb.h
+++ b/C/fmdb.h
@@ -56,6 +56,8 @@ int db_store_size_entry(FMDB *dbp, const db_size_entry_t *in);
 int db_lookup_size_entry(FMDB *dbp, const db_size_entry_t *in, db_size_entry_t *out);
 /* Remove. Needed? */
 int db_remove_size_entry(FMDB *dbp, const db_size_entry_t *in);
+/* Walk the size database, removing any entries for flac files that no longer exist */
+int db_cleanup_sizes(FMDB *dbp, const char *basedir);
 /* Print out the members of a size DB entry */
 void db_dump_size_entry(const db_size_entry_t *entry);
 /* Dump the contents of the DB to the logfile */
index 1d10f32..afa9581 100644 (file)
@@ -74,7 +74,7 @@ format_t formats[] =
 
 static fmt_e format_index = OUTFMT_OGG;
 static long long cachesize_value = CACHE_DEFAULT_SIZE;
-static long num_threads_value = 1;
+static long num_encoder_threads_value = 1;
 char *quality = NULL;
 FMDB *db_state = NULL;
 
@@ -172,6 +172,7 @@ struct
 } dir_state;
 pthread_once_t once_control = PTHREAD_ONCE_INIT;
 void *bg_handler(void *arg);
+void *bg_db_cleanup(void *arg);
 
 static void init_threads(void)
 {
@@ -185,23 +186,26 @@ static void init_threads(void)
     pthread_mutex_init(&dir_state.lock, &attr);
     pthread_mutex_init(&global_work.lock, &attr);
     pthread_cond_init(&global_work.cv, NULL);
-    bg_thread = malloc(num_threads_value * sizeof(pthread_t));
+    /* +1 for the DB cleanup thread */
+    bg_thread = malloc((1 + num_encoder_threads_value) * sizeof(pthread_t));
     if (!bg_thread)
     {
         MAINLOG0((logfile, "%s: Failed to malloc thread space for thread descriptors\n", __func__));
         db_close(db_state);
     }
-    threadcount = malloc(num_threads_value * sizeof(int));
+    threadcount = malloc((1 + num_encoder_threads_value) * sizeof(int));
     if (!threadcount)
     {
         MAINLOG0((logfile, "%s: Failed to malloc thread space for thread numbers\n", __func__));
         db_close(db_state);
     }
-    for (i = 0; i < num_threads_value; i++)
+    for (i = 0; i < num_encoder_threads_value; i++)
     {
         threadcount[i] = i;
         error = pthread_create(&bg_thread[i], NULL, bg_handler, &threadcount[i]);
     }
+    error = pthread_create(&bg_thread[i], NULL, bg_db_cleanup, &threadcount[i]);
+    i++;
 }
 
 static char *str_encode_state(encode_state_e state)
@@ -659,7 +663,7 @@ static int enqueue_encode_file(const char *flac_path, encode_keep_e keep)
 
     pthread_mutex_unlock(&global_work.lock);
 
-    if (num_threads_value > 1)
+    if (num_encoder_threads_value > 1)
     {
         tmp_path = strdup(flac_path);
         current_dir = dirname(tmp_path);
@@ -693,7 +697,7 @@ static int enqueue_encode_file(const char *flac_path, encode_keep_e keep)
         }
         pthread_mutex_unlock(&dir_state.lock);
         free(tmp_path);
-    } /* num_threads_value > 1 */
+    } /* num_encoder_threads_value > 1 */
  
     pthread_mutex_lock(&global_work.lock);
     MAINLOG1((logfile, "%s: signal, %d files in queue\n", dbgname, global_work.num_todo));
@@ -1085,6 +1089,23 @@ void *bg_handler(void *arg)
     }
 }
 
+/* Background thread to periodically clean up old size database entries */
+void *bg_db_cleanup(void *arg)
+{
+    int *tmp = arg;
+    int threadnum = *tmp;
+    char dbgname[64];
+    
+    sprintf(dbgname, "%s:%d (%ld)", __func__, threadnum, (unsigned long)pthread_self());
+    MAINLOG1((logfile, "%s: startup\n", dbgname));
+    
+    while(1)
+    {
+        db_cleanup_sizes(db_state, mo.basedir);
+        sleep(3600); /* Wait an hour */
+    }
+}
+
 /* Deal with:
  *
  * ( )*CONFIG_VAR( )*=( )*value( )*
@@ -1241,7 +1262,7 @@ int main(int argc, char *argv[])
     
     if (mo.num_threads)
     {
-        error = parse_string_to_long(mo.num_threads, &num_threads_value);
+        error = parse_string_to_long(mo.num_threads, &num_encoder_threads_value);
         if (error)
         {
             MAINLOG0((logfile, "Unable to parse num_threads value: %s\n", mo.num_threads));