status: show progress bar if refreshing the index takes too long

Refreshing the index is usually very fast, but it can still take a
long time sometimes. Cold cache is one. Or copying a repo to a new
place (*). It's good to show something to let the user know "git
status" is not hanging, it's just busy doing something.

(*) In this case, all stat info in the index becomes invalid and git
    falls back to rehashing all file content to see if there's any
    difference between updating stat info in the index. This is quite
    expensive. Even with a repo as small as git.git, it takes 3
    seconds.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Nguyễn Thái Ngọc Duy
2018-09-15 19:56:04 +02:00
committed by Junio C Hamano
parent 1d4361b0f3
commit ae9af12287
6 changed files with 72 additions and 11 deletions

View File

@ -5,10 +5,12 @@
#include "pathspec.h"
#include "dir.h"
#include "fsmonitor.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 */
}
@ -25,16 +27,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;
@ -43,6 +52,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++;
@ -58,6 +68,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)))
@ -69,16 +88,25 @@ 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];
uint64_t start = getnanotime();
struct progress_data pd;
if (!core_preload_index)
return;
@ -93,6 +121,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;
@ -100,6 +135,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");
@ -109,15 +146,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_since(start, "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;
}