static void
handle_sigint (unused (int sig))
{
- ssize_t ignored;
static char msg[] = "Stopping... \n";
- ignored = write(2, msg, sizeof(msg)-1);
+ write(2, msg, sizeof(msg)-1);
interrupted = 1;
}
printf ("%s %d ", action, processed);
if (total) {
- double time_remaining;
-
- time_remaining = ((total - processed) / rate_overall);
- printf ("of %d %s (", total, object);
- notmuch_time_print_formatted_seconds (time_remaining);
- printf (" remaining).\033[K\r");
+ printf ("of %d %s", total, object);
+ if (processed > 0 && elapsed_overall > 0.5) {
+ double time_remaining = ((total - processed) / rate_overall);
+ printf (" (");
+ notmuch_time_print_formatted_seconds (time_remaining);
+ printf (" remaining)");
+ }
} else {
- printf ("%s (%d %s/sec.)\033[K\r", object, (int) rate_overall, object);
+ printf ("%s", object);
+ if (elapsed_overall > 0.5)
+ printf (" (%d %s/sec.)", (int) rate_overall, object);
}
+ printf (".\033[K\r");
fflush (stdout);
}
*
* o Ask the filesystem for files and directories within 'path'
* (via scandir and stored in fs_entries)
- * o Ask the database for files and directories within 'path'
- * (db_files and db_subdirs)
*
* o Pass 1: For each directory in fs_entries, recursively call into
* this same function.
*
- * o Pass 2: If 'fs_mtime' > 'db_mtime', then walk fs_entries
- * simultaneously with db_files and db_subdirs. Look for one of
- * three interesting cases:
+ * o Compare fs_mtime to db_mtime. If they are equivalent, terminate
+ * the algorithm at this point, (this directory has not been
+ * updated in the filesystem since the last database scan of PASS
+ * 2).
+ *
+ * o Ask the database for files and directories within 'path'
+ * (db_files and db_subdirs)
+ *
+ * o Pass 2: Walk fs_entries simultaneously with db_files and
+ * db_subdirs. Look for one of three interesting cases:
*
* 1. Regular file in fs_entries and not in db_files
* This is a new file to add_message into the database.
* information is lost from the database).
*
* o Tell the database to update its time of 'path' to 'fs_mtime'
+ * if fs_mtime isn't the current wall-clock time.
*/
static notmuch_status_t
add_files_recursive (notmuch_database_t *notmuch,
notmuch_directory_t *directory;
notmuch_filenames_t *db_files = NULL;
notmuch_filenames_t *db_subdirs = NULL;
+ time_t stat_time;
struct stat st;
notmuch_bool_t is_maildir, new_directory;
const char **tag;
path, strerror (errno));
return NOTMUCH_STATUS_FILE_ERROR;
}
+ stat_time = time (NULL);
/* This is not an error since we may have recursed based on a
* symlink to a regular file, not a directory, and we don't know
directory = notmuch_database_get_directory (notmuch, path);
db_mtime = notmuch_directory_get_mtime (directory);
- if (db_mtime == 0) {
- new_directory = TRUE;
- db_files = NULL;
- db_subdirs = NULL;
- } else {
- new_directory = FALSE;
- db_files = notmuch_directory_get_child_files (directory);
- db_subdirs = notmuch_directory_get_child_directories (directory);
- }
+ new_directory = db_mtime ? FALSE : TRUE;
+
+ /* XXX This is a temporary workaround. If we don't update the
+ * database mtime until after processing messages in this
+ * directory, then a 0 mtime is *not* sufficient to indicate that
+ * this directory has no messages or subdirs in the database (for
+ * example, if an earlier run skipped the mtime update because
+ * fs_mtime == stat_time, or was interrupted before updating the
+ * mtime at the end). To address this, we record a (bogus)
+ * non-zero value before processing any child messages so that a
+ * later run won't mistake this for a new directory (and, for
+ * example, fail to detect removed files and subdirs).
+ *
+ * A better solution would be for notmuch_database_get_directory
+ * to indicate if it really created a new directory or not, either
+ * by a new out-argument, or by recording this information and
+ * providing an accessor.
+ */
+ if (new_directory)
+ notmuch_directory_set_mtime (directory, -1);
/* If the database knows about this directory, then we sort based
* on strcmp to match the database sorting. Otherwise, we can do
if (fs_mtime == db_mtime)
goto DONE;
+ /* new_directory means a directory that the database has never
+ * seen before. In that case, we can simply leave db_files and
+ * db_subdirs NULL. */
+ if (!new_directory) {
+ db_files = notmuch_directory_get_child_files (directory);
+ db_subdirs = notmuch_directory_get_child_directories (directory);
+ }
+
/* Pass 2: Scan for new files, removed files, and removed directories. */
for (i = 0; i < num_fs_entries; i++)
{
/* If we're looking at a symlink, we only want to add it if it
* links to a regular file, (and not to a directory, say).
*
- * Similarly, if the file is of unknown type (due to filesytem
+ * Similarly, if the file is of unknown type (due to filesystem
* limitations), then we also need to look closer.
*
* In either case, a stat does the trick.
notmuch_filenames_move_to_next (db_subdirs);
}
- if (! interrupted) {
+ /* If the directory's mtime is the same as the wall-clock time
+ * when we stat'ed the directory, we skip updating the mtime in
+ * the database because a message could be delivered later in this
+ * same second. This may lead to unnecessary re-scans, but it
+ * avoids overlooking messages. */
+ if (! interrupted && fs_mtime != stat_time) {
status = notmuch_directory_set_mtime (directory, fs_mtime);
if (status && ret == NOTMUCH_STATUS_SUCCESS)
ret = status;