]> git.notmuchmail.org Git - notmuch/blobdiff - notmuch-new.c
Accumulated news for Austin's changes
[notmuch] / notmuch-new.c
index 491541801f5fc5bab63180474c09398a01bf7361..ba05cb41e10f2d124681acc7399a9428a2de4a5c 100644 (file)
@@ -323,6 +323,35 @@ add_files (notmuch_database_t *notmuch,
     }
     db_mtime = directory ? notmuch_directory_get_mtime (directory) : 0;
 
+    /* If the directory is unchanged from our last scan and has no
+     * sub-directories, then return without scanning it at all.  In
+     * some situations, skipping the scan can substantially reduce the
+     * cost of notmuch new, especially since the huge numbers of files
+     * in Maildirs make scans expensive, but all files live in leaf
+     * directories.
+     *
+     * To check for sub-directories, we borrow a trick from find,
+     * kpathsea, and many other UNIX tools: since a directory's link
+     * count is the number of sub-directories (specifically, their
+     * '..' entries) plus 2 (the link from the parent and the link for
+     * '.').  This check is safe even on weird file systems, since
+     * file systems that can't compute this will return 0 or 1.  This
+     * is safe even on *really* weird file systems like HFS+ that
+     * mistakenly return the total number of directory entries, since
+     * that only inflates the count beyond 2.
+     */
+    if (directory && fs_mtime == db_mtime && st.st_nlink == 2) {
+       /* There's one catch: pass 1 below considers symlinks to
+        * directories to be directories, but these don't increase the
+        * file system link count.  So, only bail early if the
+        * database agrees that there are no sub-directories. */
+       db_subdirs = notmuch_directory_get_child_directories (directory);
+       if (!notmuch_filenames_valid (db_subdirs))
+           goto DONE;
+       notmuch_filenames_destroy (db_subdirs);
+       db_subdirs = NULL;
+    }
+
     /* If the database knows about this directory, then we sort based
      * on strcmp to match the database sorting. Otherwise, we can do
      * inode-based sorting for faster filesystem operation. */
@@ -840,9 +869,8 @@ _remove_directory (void *ctx,
 }
 
 int
-notmuch_new_command (void *ctx, int argc, char *argv[])
+notmuch_new_command (notmuch_config_t *config, int argc, char *argv[])
 {
-    notmuch_config_t *config;
     notmuch_database_t *notmuch;
     add_files_state_t add_files_state;
     double elapsed;
@@ -875,10 +903,6 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
        return 1;
     }
 
-    config = notmuch_config_open (ctx, NULL, FALSE);
-    if (config == NULL)
-       return 1;
-
     add_files_state.new_tags = notmuch_config_get_new_tags (config, &add_files_state.new_tags_length);
     add_files_state.new_ignore = notmuch_config_get_new_ignore (config, &add_files_state.new_ignore_length);
     add_files_state.synchronize_flags = notmuch_config_get_maildir_synchronize_flags (config);
@@ -890,7 +914,7 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
            return ret;
     }
 
-    dot_notmuch_path = talloc_asprintf (ctx, "%s/%s", db_path, ".notmuch");
+    dot_notmuch_path = talloc_asprintf (config, "%s/%s", db_path, ".notmuch");
 
     if (stat (dot_notmuch_path, &st)) {
        int count;
@@ -941,9 +965,9 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
     add_files_state.removed_messages = add_files_state.renamed_messages = 0;
     gettimeofday (&add_files_state.tv_start, NULL);
 
-    add_files_state.removed_files = _filename_list_create (ctx);
-    add_files_state.removed_directories = _filename_list_create (ctx);
-    add_files_state.directory_mtimes = _filename_list_create (ctx);
+    add_files_state.removed_files = _filename_list_create (config);
+    add_files_state.removed_directories = _filename_list_create (config);
+    add_files_state.directory_mtimes = _filename_list_create (config);
 
     if (! debugger_is_active () && add_files_state.output_is_a_tty
        && ! add_files_state.verbose) {
@@ -970,7 +994,7 @@ notmuch_new_command (void *ctx, int argc, char *argv[])
 
     gettimeofday (&tv_start, NULL);
     for (f = add_files_state.removed_directories->head, i = 0; f && !interrupted; f = f->next, i++) {
-       ret = _remove_directory (ctx, notmuch, f->filename, &add_files_state);
+       ret = _remove_directory (config, notmuch, f->filename, &add_files_state);
        if (ret)
            goto DONE;
        if (do_print_progress) {