Merge branch 'nd/status-refresh-progress'
authorJunio C Hamano <gitster@pobox.com>
Fri, 19 Oct 2018 04:34:03 +0000 (13:34 +0900)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Oct 2018 04:34:03 +0000 (13:34 +0900)
"git status" learns to show progress bar when refreshing the index
takes a long time.

* nd/status-refresh-progress:
status: show progress bar if refreshing the index takes too long

builtin/am.c
builtin/commit.c
cache.h
preload-index.c
read-cache.c
sequencer.c
index d79f092a96f8e9aab59c6d6c623c8fd7fbcb677d..3ee9a9d2a92aaa0e9716719640deaec7e260c811 100644 (file)
@@ -2328,7 +2328,7 @@ int cmd_am(int argc, const char **argv, const char *prefix)
        /* Ensure a valid committer ident can be constructed */
        git_committer_info(IDENT_STRICT);
 
-       if (read_index_preload(&the_index, NULL) < 0)
+       if (read_index_preload(&the_index, NULL, 0) < 0)
                die(_("failed to read the index"));
 
        if (in_progress) {
index 31b44e5d629db82781ee1bd1afc45a47c8936ba9..074bd9a55160a8efcaa1c108afcf6bd6bc360626 100644 (file)
@@ -1299,6 +1299,7 @@ int cmd_status(int argc, const char **argv, const char *prefix)
        static int no_renames = -1;
        static const char *rename_score_arg = (const char *)-1;
        static struct wt_status s;
+       unsigned int progress_flag = 0;
        int fd;
        struct object_id oid;
        static struct option builtin_status_options[] = {
@@ -1359,8 +1360,13 @@ int cmd_status(int argc, const char **argv, const char *prefix)
                       PATHSPEC_PREFER_FULL,
                       prefix, argv);
 
-       read_cache_preload(&s.pathspec);
-       refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED, &s.pathspec, NULL, NULL);
+       if (status_format != STATUS_FORMAT_PORCELAIN &&
+           status_format != STATUS_FORMAT_PORCELAIN_V2)
+               progress_flag = REFRESH_PROGRESS;
+       read_index_preload(&the_index, &s.pathspec, progress_flag);
+       refresh_index(&the_index,
+                     REFRESH_QUIET|REFRESH_UNMERGED|progress_flag,
+                     &s.pathspec, NULL, NULL);
 
        if (use_optional_locks())
                fd = hold_locked_index(&index_lock, 0);
diff --git a/cache.h b/cache.h
index 1d749abf6916831fe81ea6e256e515ae8fcd149b..59c8a930466d034ea2ce84b362e464803e19a100 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -410,7 +410,7 @@ void validate_cache_entries(const struct index_state *istate);
 
 #define read_cache() read_index(&the_index)
 #define read_cache_from(path) read_index_from(&the_index, (path), (get_git_dir()))
-#define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec))
+#define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec), 0)
 #define is_cache_unborn() is_index_unborn(&the_index)
 #define read_cache_unmerged() read_index_unmerged(&the_index)
 #define discard_cache() discard_index(&the_index)
@@ -659,7 +659,9 @@ extern int daemonize(void);
 /* Initialize and use the cache information */
 struct lock_file;
 extern int read_index(struct index_state *);
-extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);
+extern int read_index_preload(struct index_state *,
+                             const struct pathspec *pathspec,
+                             unsigned int refresh_flags);
 extern int do_read_index(struct index_state *istate, const char *path,
                         int must_exist); /* for testting only! */
 extern int read_index_from(struct index_state *, const char *path,
@@ -814,6 +816,7 @@ extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);
 #define REFRESH_IGNORE_MISSING 0x0008  /* ignore non-existent */
 #define REFRESH_IGNORE_SUBMODULES      0x0010  /* ignore submodules */
 #define REFRESH_IN_PORCELAIN   0x0020  /* user friendly output, not "needs update" */
+#define REFRESH_PROGRESS       0x0040  /* show progress bar if stderr is tty */
 extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
 extern struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int);
 
index 16dc5ad868ff0d69a49a30d9130779997267c63b..9e7152ab14d9359d0a48da8b25cd58253a13fc0c 100644 (file)
@@ -6,10 +6,12 @@
 #include "dir.h"
 #include "fsmonitor.h"
 #include "config.h"
+#include "progress.h"
 
 #ifdef NO_PTHREADS
 static void preload_index(struct index_state *index,
-                         const struct pathspec *pathspec)
+                         const struct pathspec *pathspec,
+                         unsigned int refresh_flags)
 {
        ; /* nothing */
 }
@@ -26,16 +28,23 @@ static void preload_index(struct index_state *index,
 #define MAX_PARALLEL (20)
 #define THREAD_COST (500)
 
+struct progress_data {
+       unsigned long n;
+       struct progress *progress;
+       pthread_mutex_t mutex;
+};
+
 struct thread_data {
        pthread_t pthread;
        struct index_state *index;
        struct pathspec pathspec;
+       struct progress_data *progress;
        int offset, nr;
 };
 
 static void *preload_thread(void *_data)
 {
-       int nr;
+       int nr, last_nr;
        struct thread_data *p = _data;
        struct index_state *index = p->index;
        struct cache_entry **cep = index->cache + p->offset;
@@ -44,6 +53,7 @@ static void *preload_thread(void *_data)
        nr = p->nr;
        if (nr + p->offset > index->cache_nr)
                nr = index->cache_nr - p->offset;
+       last_nr = nr;
 
        do {
                struct cache_entry *ce = *cep++;
@@ -59,6 +69,15 @@ static void *preload_thread(void *_data)
                        continue;
                if (ce->ce_flags & CE_FSMONITOR_VALID)
                        continue;
+               if (p->progress && !(nr & 31)) {
+                       struct progress_data *pd = p->progress;
+
+                       pthread_mutex_lock(&pd->mutex);
+                       pd->n += last_nr - nr;
+                       display_progress(pd->progress, pd->n);
+                       pthread_mutex_unlock(&pd->mutex);
+                       last_nr = nr;
+               }
                if (!ce_path_match(index, ce, &p->pathspec, NULL))
                        continue;
                if (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))
@@ -70,15 +89,24 @@ static void *preload_thread(void *_data)
                ce_mark_uptodate(ce);
                mark_fsmonitor_valid(ce);
        } while (--nr > 0);
+       if (p->progress) {
+               struct progress_data *pd = p->progress;
+
+               pthread_mutex_lock(&pd->mutex);
+               display_progress(pd->progress, pd->n + last_nr);
+               pthread_mutex_unlock(&pd->mutex);
+       }
        cache_def_clear(&cache);
        return NULL;
 }
 
 static void preload_index(struct index_state *index,
-                         const struct pathspec *pathspec)
+                         const struct pathspec *pathspec,
+                         unsigned int refresh_flags)
 {
        int threads, i, work, offset;
        struct thread_data data[MAX_PARALLEL];
+       struct progress_data pd;
 
        if (!core_preload_index)
                return;
@@ -94,6 +122,13 @@ static void preload_index(struct index_state *index,
        offset = 0;
        work = DIV_ROUND_UP(index->cache_nr, threads);
        memset(&data, 0, sizeof(data));
+
+       memset(&pd, 0, sizeof(pd));
+       if (refresh_flags & REFRESH_PROGRESS && isatty(2)) {
+               pd.progress = start_delayed_progress(_("Refreshing index"), index->cache_nr);
+               pthread_mutex_init(&pd.mutex, NULL);
+       }
+
        for (i = 0; i < threads; i++) {
                struct thread_data *p = data+i;
                p->index = index;
@@ -101,6 +136,8 @@ static void preload_index(struct index_state *index,
                        copy_pathspec(&p->pathspec, pathspec);
                p->offset = offset;
                p->nr = work;
+               if (pd.progress)
+                       p->progress = &pd;
                offset += work;
                if (pthread_create(&p->pthread, NULL, preload_thread, p))
                        die("unable to create threaded lstat");
@@ -110,15 +147,18 @@ static void preload_index(struct index_state *index,
                if (pthread_join(p->pthread, NULL))
                        die("unable to join threaded lstat");
        }
+       stop_progress(&pd.progress);
+
        trace_performance_leave("preload index");
 }
 #endif
 
 int read_index_preload(struct index_state *index,
-                      const struct pathspec *pathspec)
+                      const struct pathspec *pathspec,
+                      unsigned int refresh_flags)
 {
        int retval = read_index(index);
 
-       preload_index(index, pathspec);
+       preload_index(index, pathspec, refresh_flags);
        return retval;
 }
index 4c994e4b65cc820351117ccc90647d4534cde415..1df5c16dbc31d444b98478bc892821bf1e2dda85 100644 (file)
@@ -24,6 +24,7 @@
 #include "utf8.h"
 #include "fsmonitor.h"
 #include "thread-utils.h"
+#include "progress.h"
 
 /* Mask for the name length in ce_flags in the on-disk index */
 
@@ -1483,6 +1484,11 @@ int refresh_index(struct index_state *istate, unsigned int flags,
        const char *typechange_fmt;
        const char *added_fmt;
        const char *unmerged_fmt;
+       struct progress *progress = NULL;
+
+       if (flags & REFRESH_PROGRESS && isatty(2))
+               progress = start_delayed_progress(_("Refresh index"),
+                                                 istate->cache_nr);
 
        trace_performance_enter();
        modified_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
@@ -1523,6 +1529,8 @@ int refresh_index(struct index_state *istate, unsigned int flags,
                new_entry = refresh_cache_ent(istate, ce, options, &cache_errno, &changed);
                if (new_entry == ce)
                        continue;
+               if (progress)
+                       display_progress(progress, i);
                if (!new_entry) {
                        const char *fmt;
 
@@ -1554,6 +1562,10 @@ int refresh_index(struct index_state *istate, unsigned int flags,
 
                replace_index_entry(istate, i, new_entry);
        }
+       if (progress) {
+               display_progress(progress, istate->cache_nr);
+               stop_progress(&progress);
+       }
        trace_performance_leave("refresh index");
        return has_errors;
 }
index 83f17721d4fc44cd5da211878c335f4e0e07cde9..0c164d5f98f152156ef21a79159f6348fecb0273 100644 (file)
@@ -1913,7 +1913,7 @@ static int read_and_refresh_cache(struct replay_opts *opts)
 {
        struct lock_file index_lock = LOCK_INIT;
        int index_fd = hold_locked_index(&index_lock, 0);
-       if (read_index_preload(&the_index, NULL) < 0) {
+       if (read_index_preload(&the_index, NULL, 0) < 0) {
                rollback_lock_file(&index_lock);
                return error(_("git %s: failed to read the index"),
                        _(action_name(opts)));