Expand the directory-tracking pre-coding logic master
authorSteve McIntyre <steve@einval.com>
Sat, 1 Jun 2013 18:55:22 +0000 (19:55 +0100)
committerSteve McIntyre <steve@einval.com>
Sat, 1 Jun 2013 18:55:22 +0000 (19:55 +0100)
The old code used to just track the single previous directory. This
would be thrown by multiple users reading files from different
directories, stopping parallelism from happening. Now, track the last
10 directories accessed all the time, and trigger if there are
sufficient matches in any of those positions. Much faster.

C/fuse-music.c

index 777c89b..4f8f5bd 100644 (file)
@@ -70,6 +70,7 @@ format_t formats[] =
 
 #define CACHE_MIN_SIZE (100ULL * MiB)
 #define CACHE_DEFAULT_SIZE (10ULL * GiB)
+#define NUM_LRU_DIRS 10
 #define DIR_TRIGGER 2
 
 static fmt_e format_index = OUTFMT_OGG;
@@ -167,8 +168,7 @@ static const struct config_opt config_opts[] = {
 struct
 {
     pthread_mutex_t lock;
-    char last[PATH_MAX];
-    int  num;
+    char *lru_dirs[NUM_LRU_DIRS];
 } dir_state;
 pthread_once_t once_control = PTHREAD_ONCE_INIT;
 void *bg_handler(void *arg);
@@ -177,7 +177,6 @@ void *bg_db_cleanup(void *arg);
 static void init_threads(void)
 {
     intptr_t i = 0;
-    int error = 0;
     int *threadcount;
     pthread_mutexattr_t attr;
     pthread_mutexattr_init(&attr);
@@ -202,9 +201,9 @@ static void init_threads(void)
     for (i = 0; i < num_encoder_threads_value; i++)
     {
         threadcount[i] = i;
-        error = pthread_create(&bg_thread[i], NULL, bg_handler, &threadcount[i]);
+        (void)pthread_create(&bg_thread[i], NULL, bg_handler, &threadcount[i]);
     }
-    error = pthread_create(&bg_thread[i], NULL, bg_db_cleanup, &threadcount[i]);
+    (void)pthread_create(&bg_thread[i], NULL, bg_db_cleanup, &threadcount[i]);
     i++;
 }
 
@@ -644,6 +643,49 @@ static int add_todo_entry_dir(const char *flac_dir, int keep)
     return 0;
 }
 
+/* Add the current directory to the LRU state at the beginning;
+ * shuffle all the other entries down one. Pass back the number of
+ * entries that match the new one (including that new one, so will
+ * always be 1 or more!). */
+static int update_dir_state(char *current_dir, int *num_matches)
+{
+    int i = 0;
+    int matches = 0;
+    char dbgname[64];
+    sprintf(dbgname, "%s(%ld):", __func__, (unsigned long)pthread_self());
+
+    pthread_mutex_lock(&dir_state.lock);
+
+    /* Free the last one on the current list */
+    free (dir_state.lru_dirs[NUM_LRU_DIRS - 1]);
+
+    /* Shuffle the others down, checking for matches as we go */
+    for (i = NUM_LRU_DIRS - 1; i >= 1; i--)
+    {
+        dir_state.lru_dirs[i] = dir_state.lru_dirs[i-1];
+        if ((NULL != dir_state.lru_dirs[i]) && 
+           (!strcmp(current_dir, dir_state.lru_dirs[i])))
+            matches++;
+    }
+
+    /* Copy the new one into place */
+    dir_state.lru_dirs[0] = strdup(current_dir);
+    if (NULL == dir_state.lru_dirs[0])
+    {
+        pthread_mutex_unlock(&dir_state.lock);
+        return ENOMEM;
+    }
+
+    /* Add 1 for the one we just added */
+    matches++;    
+
+    MAINLOG1((logfile, "%s: added saved dir %s, now called %d times in recent history (last %d)\n",
+              dbgname, current_dir, matches, NUM_LRU_DIRS));
+    *num_matches = matches;
+    pthread_mutex_unlock(&dir_state.lock);
+    return 0;
+}    
+
 static int enqueue_encode_file(const char *flac_path, encode_keep_e keep)
 {
     int error = 0;
@@ -665,37 +707,33 @@ static int enqueue_encode_file(const char *flac_path, encode_keep_e keep)
 
     if (num_encoder_threads_value > 1)
     {
+        int num_matches = 0;
+
         tmp_path = strdup(flac_path);
         current_dir = dirname(tmp_path);
-        pthread_mutex_lock(&dir_state.lock);
-        if (!strcmp(current_dir, dir_state.last))
-        {
-            dir_state.num++;
-            MAINLOG1((logfile, "%s: triggered again on dir %s, now called %d times in succession\n",
-                      dbgname, dir_state.last, dir_state.num));
-        }
-        else
+
+       error = update_dir_state(current_dir, &num_matches);
+        if (error)
         {
-            strcpy(dir_state.last, current_dir);
-            dir_state.num = 1;
-            MAINLOG1((logfile, "%s: new dir %s\n", dbgname, dir_state.last));
+            free(tmp_path);
+            pthread_mutex_unlock(&global_work.lock);
+            MAINLOG0((logfile, "%s: update_dir_state failed, error %d\n",
+                      dbgname, error));
+            return error;
         }
 
-        if (dir_state.num >= DIR_TRIGGER)
+        if (num_matches >= DIR_TRIGGER)
         {
             error = add_todo_entry_dir(tmp_path, keep);
             if (error)
             {
-                pthread_mutex_unlock(&dir_state.lock);
                 free(tmp_path);
                 pthread_mutex_unlock(&global_work.lock);
                 MAINLOG0((logfile, "%s: add_todo_entry_dir failed, error %d\n",
                           dbgname, error));
                 return error;
             }
-            dir_state.num = 0;
         }
-        pthread_mutex_unlock(&dir_state.lock);
         free(tmp_path);
     } /* num_encoder_threads_value > 1 */
  
@@ -1320,8 +1358,8 @@ int main(int argc, char *argv[])
         return 1;
     }
 
-    strcpy(dir_state.last, "");
-    dir_state.num = 0;
+    for (i = 0; i < NUM_LRU_DIRS; i++)
+        dir_state.lru_dirs[i] = NULL;
 
     error = fuse_main(args.argc, args.argv, &fm_oper, NULL);
     if (error)