This requires any threads (including the main one) to call init_pack_context() first. All pack data is per thread. Original patch is written by Thomas Rast <trast@xxxxxxxxxxxxxxx> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- cache.h | 1 + git.c | 1 + sha1_file.c | 251 +++++++++++++++++++++++++++++++++++------------------------ 3 files changed, 152 insertions(+), 101 deletions(-) diff --git a/cache.h b/cache.h index 26d14b4..868ef48 100644 --- a/cache.h +++ b/cache.h @@ -997,6 +997,7 @@ struct packed_git { extern struct packed_git *get_packed_git(void); extern void set_packed_git(struct packed_git *); +extern void init_pack_context(void); struct pack_entry { off_t offset; diff --git a/git.c b/git.c index 3805616..7eee270 100644 --- a/git.c +++ b/git.c @@ -533,6 +533,7 @@ int main(int argc, const char **argv) const char *cmd; startup_info = &git_startup_info; + init_pack_context(); cmd = git_extract_argv0_path(argv[0]); if (!cmd) diff --git a/sha1_file.c b/sha1_file.c index 4fd4e2c..170c0b1 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -33,16 +33,79 @@ static inline uintmax_t sz_fmt(size_t s) { return s; } const unsigned char null_sha1[20]; -static struct packed_git *packed_git_; +#define MAX_DELTA_CACHE (256) + +struct delta_base_cache_lru_list { + struct delta_base_cache_lru_list *prev; + struct delta_base_cache_lru_list *next; +}; + +struct delta_base_cache_entry { + struct delta_base_cache_lru_list lru; + void *data; + struct packed_git *p; + off_t base_offset; + unsigned long size; + enum object_type type; +}; + +struct pack_context { + size_t delta_base_cached; + struct delta_base_cache_entry *delta_base_cache; + struct delta_base_cache_lru_list *delta_base_cache_lru; + struct packed_git *last_found_pack; + + unsigned int pack_used_ctr; + unsigned int pack_mmap_calls; + unsigned int peak_pack_open_windows; + unsigned int pack_open_windows; + unsigned int pack_open_fds; + unsigned int pack_max_fds; + size_t peak_pack_mapped; + size_t pack_mapped; + struct packed_git *packed_git; + int prepare_packed_git_run_once; + + char sha1_file_name_buf[PATH_MAX]; + char *sha1_pack_name, *sha1_pack_base; + char *sha1_pack_index_name, *sha1_pack_index_base; +}; + +static pthread_key_t pack_key; +struct pack_context *get_thread_pack_context(void) +{ + return pthread_getspecific(pack_key); +} + struct packed_git *get_packed_git(void) { - return packed_git_; + return get_thread_pack_context()->packed_git; } void set_packed_git(struct packed_git *p) { - packed_git_ = p; + get_thread_pack_context()->packed_git = p; } +void init_pack_context(void) +{ + static int initialized = 0; + struct pack_context *ctx = xmalloc(sizeof(struct pack_context)); + + if (!initialized) { + pthread_key_create(&pack_key, NULL); + initialized = 1; + } + + memset(ctx, 0, sizeof(*ctx)); + ctx->delta_base_cached = 0; + ctx->delta_base_cache_lru = xmalloc(sizeof(struct delta_base_cache_lru_list)); + ctx->delta_base_cache_lru->prev = ctx->delta_base_cache_lru; + ctx->delta_base_cache_lru->next = ctx->delta_base_cache_lru; + ctx->delta_base_cache = xcalloc(MAX_DELTA_CACHE, sizeof(struct delta_base_cache_entry)); + ctx->last_found_pack = NULL; + ctx->packed_git = NULL; + pthread_setspecific(pack_key, ctx); +} /* * This is meant to hold a *small* number of objects that you would @@ -65,8 +128,6 @@ static struct cached_object empty_tree = { 0 }; -static struct packed_git *last_found_pack; - static struct cached_object *find_cached_object(const unsigned char *sha1) { int i; @@ -177,7 +238,7 @@ static void fill_sha1_path(char *pathbuf, const unsigned char *sha1) */ char *sha1_file_name(const unsigned char *sha1) { - static char buf[PATH_MAX]; + char *buf = get_thread_pack_context()->sha1_file_name_buf; const char *objdir; int len; @@ -224,16 +285,14 @@ static char *sha1_get_pack_name(const unsigned char *sha1, char *sha1_pack_name(const unsigned char *sha1) { - static char *name, *base; - - return sha1_get_pack_name(sha1, &name, &base, "pack"); + struct pack_context *ctx = get_thread_pack_context(); + return sha1_get_pack_name(sha1, &ctx->sha1_pack_name, &ctx->sha1_pack_base, "pack"); } char *sha1_pack_index_name(const unsigned char *sha1) { - static char *name, *base; - - return sha1_get_pack_name(sha1, &name, &base, "idx"); + struct pack_context *ctx = get_thread_pack_context(); + return sha1_get_pack_name(sha1, &ctx->sha1_pack_index_name, &ctx->sha1_pack_index_base, "idx"); } struct alternate_object_database *alt_odb_list; @@ -455,18 +514,10 @@ static int has_loose_object(const unsigned char *sha1) has_loose_object_nonlocal(sha1); } -static unsigned int pack_used_ctr; -static unsigned int pack_mmap_calls; -static unsigned int peak_pack_open_windows; -static unsigned int pack_open_windows; -static unsigned int pack_open_fds; -static unsigned int pack_max_fds; -static size_t peak_pack_mapped; -static size_t pack_mapped; -struct packed_git *packed_git; - -void pack_report(void) +void pack_report() { + struct pack_context *ctx = get_thread_pack_context(); + fprintf(stderr, "pack_report: getpagesize() = %10" SZ_FMT "\n" "pack_report: core.packedGitWindowSize = %10" SZ_FMT "\n" @@ -480,10 +531,10 @@ void pack_report(void) "pack_report: pack_open_windows = %10u / %10u\n" "pack_report: pack_mapped = " "%10" SZ_FMT " / %10" SZ_FMT "\n", - pack_used_ctr, - pack_mmap_calls, - pack_open_windows, peak_pack_open_windows, - sz_fmt(pack_mapped), sz_fmt(peak_pack_mapped)); + ctx->pack_used_ctr, + ctx->pack_mmap_calls, + ctx->pack_open_windows, ctx->peak_pack_open_windows, + sz_fmt(ctx->pack_mapped), sz_fmt(ctx->peak_pack_mapped)); } static int check_packed_git_idx(const char *path, struct packed_git *p) @@ -624,6 +675,7 @@ static void scan_windows(struct packed_git *p, static int unuse_one_window(struct packed_git *current, int keep_fd) { + struct pack_context *ctx = get_thread_pack_context(); struct packed_git *p, *lru_p = NULL; struct pack_window *lru_w = NULL, *lru_l = NULL; @@ -633,7 +685,7 @@ static int unuse_one_window(struct packed_git *current, int keep_fd) scan_windows(p, &lru_p, &lru_w, &lru_l); if (lru_p) { munmap(lru_w->base, lru_w->len); - pack_mapped -= lru_w->len; + ctx->pack_mapped -= lru_w->len; if (lru_l) lru_l->next = lru_w->next; else { @@ -641,12 +693,12 @@ static int unuse_one_window(struct packed_git *current, int keep_fd) if (!lru_p->windows && lru_p->pack_fd != -1 && lru_p->pack_fd != keep_fd) { close(lru_p->pack_fd); - pack_open_fds--; + ctx->pack_open_fds--; lru_p->pack_fd = -1; } } free(lru_w); - pack_open_windows--; + ctx->pack_open_windows--; return 1; } return 0; @@ -654,8 +706,9 @@ static int unuse_one_window(struct packed_git *current, int keep_fd) void release_pack_memory(size_t need, int fd) { - size_t cur = pack_mapped; - while (need >= (cur - pack_mapped) && unuse_one_window(NULL, fd)) + struct pack_context *ctx = get_thread_pack_context(); + size_t cur = ctx->pack_mapped; + while (need >= (cur - ctx->pack_mapped) && unuse_one_window(NULL, fd)) ; /* nothing */ } @@ -676,6 +729,7 @@ void *xmmap(void *start, size_t length, void close_pack_windows(struct packed_git *p) { + struct pack_context *ctx = get_thread_pack_context(); while (p->windows) { struct pack_window *w = p->windows; @@ -683,8 +737,8 @@ void close_pack_windows(struct packed_git *p) die("pack '%s' still has open windows to it", p->pack_name); munmap(w->base, w->len); - pack_mapped -= w->len; - pack_open_windows--; + ctx->pack_mapped -= w->len; + ctx->pack_open_windows--; p->windows = w->next; free(w); } @@ -719,7 +773,8 @@ void close_pack_index(struct packed_git *p) */ void free_pack_by_name(const char *pack_name) { - struct packed_git *p, **pp = &packed_git_; + struct pack_context *ctx = get_thread_pack_context(); + struct packed_git *p, **pp = &ctx->packed_git; while (*pp) { p = *pp; @@ -728,13 +783,13 @@ void free_pack_by_name(const char *pack_name) close_pack_windows(p); if (p->pack_fd != -1) { close(p->pack_fd); - pack_open_fds--; + ctx->pack_open_fds--; } close_pack_index(p); free(p->bad_object_sha1); *pp = p->next; - if (last_found_pack == p) - last_found_pack = NULL; + if (ctx->last_found_pack == p) + ctx->last_found_pack = NULL; free(p); return; } @@ -748,6 +803,7 @@ void free_pack_by_name(const char *pack_name) */ static int open_packed_git_1(struct packed_git *p) { + struct pack_context *ctx = get_thread_pack_context(); struct stat st; struct pack_header hdr; unsigned char sha1[20]; @@ -757,7 +813,7 @@ static int open_packed_git_1(struct packed_git *p) if (!p->index_data && open_pack_index(p)) return error("packfile %s index unavailable", p->pack_name); - if (!pack_max_fds) { + if (!ctx->pack_max_fds) { struct rlimit lim; unsigned int max_fds; @@ -768,18 +824,18 @@ static int open_packed_git_1(struct packed_git *p) /* Save 3 for stdin/stdout/stderr, 22 for work */ if (25 < max_fds) - pack_max_fds = max_fds - 25; + ctx->pack_max_fds = max_fds - 25; else - pack_max_fds = 1; + ctx->pack_max_fds = 1; } - while (pack_max_fds <= pack_open_fds && unuse_one_window(NULL, -1)) + while (ctx->pack_max_fds <= ctx->pack_open_fds && unuse_one_window(NULL, -1)) ; /* nothing */ p->pack_fd = git_open_noatime(p->pack_name); if (p->pack_fd < 0 || fstat(p->pack_fd, &st)) return -1; - pack_open_fds++; + ctx->pack_open_fds++; /* If we created the struct before we had the pack we lack size. */ if (!p->pack_size) { @@ -827,11 +883,12 @@ static int open_packed_git_1(struct packed_git *p) static int open_packed_git(struct packed_git *p) { + struct pack_context *ctx = get_thread_pack_context(); if (!open_packed_git_1(p)) return 0; if (p->pack_fd != -1) { close(p->pack_fd); - pack_open_fds--; + ctx->pack_open_fds--; p->pack_fd = -1; } return -1; @@ -855,6 +912,7 @@ unsigned char *use_pack(struct packed_git *p, off_t offset, unsigned long *left) { + struct pack_context *ctx = get_thread_pack_context(); struct pack_window *win = *w_cursor; /* Since packfiles end in a hash of their content and it's @@ -887,8 +945,8 @@ unsigned char *use_pack(struct packed_git *p, if (len > packed_git_window_size) len = packed_git_window_size; win->len = (size_t)len; - pack_mapped += win->len; - while (packed_git_limit < pack_mapped + ctx->pack_mapped += win->len; + while (packed_git_limit < ctx->pack_mapped && unuse_one_window(p, p->pack_fd)) ; /* nothing */ win->base = xmmap(NULL, win->len, @@ -901,21 +959,21 @@ unsigned char *use_pack(struct packed_git *p, if (!win->offset && win->len == p->pack_size && !p->do_not_close) { close(p->pack_fd); - pack_open_fds--; + ctx->pack_open_fds--; p->pack_fd = -1; } - pack_mmap_calls++; - pack_open_windows++; - if (pack_mapped > peak_pack_mapped) - peak_pack_mapped = pack_mapped; - if (pack_open_windows > peak_pack_open_windows) - peak_pack_open_windows = pack_open_windows; + ctx->pack_mmap_calls++; + ctx->pack_open_windows++; + if (ctx->pack_mapped > ctx->peak_pack_mapped) + ctx->peak_pack_mapped = ctx->pack_mapped; + if (ctx->pack_open_windows > ctx->peak_pack_open_windows) + ctx->peak_pack_open_windows = ctx->pack_open_windows; win->next = p->windows; p->windows = win; } } if (win != *w_cursor) { - win->last_used = pack_used_ctr++; + win->last_used = ctx->pack_used_ctr++; win->inuse_cnt++; *w_cursor = win; } @@ -998,8 +1056,9 @@ struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path) void install_packed_git(struct packed_git *pack) { + struct pack_context *ctx = get_thread_pack_context(); if (pack->pack_fd != -1) - pack_open_fds++; + ctx->pack_open_fds++; pack->next = get_packed_git(); set_packed_git(pack); @@ -1108,12 +1167,12 @@ static void rearrange_packed_git(void) free(ary); } -static int prepare_packed_git_run_once = 0; void prepare_packed_git(void) { struct alternate_object_database *alt; + struct pack_context *ctx = get_thread_pack_context(); - if (prepare_packed_git_run_once) + if (ctx->prepare_packed_git_run_once) return; prepare_packed_git_one(get_object_directory(), 1); prepare_alt_odb(); @@ -1123,13 +1182,14 @@ void prepare_packed_git(void) alt->name[-1] = '/'; } rearrange_packed_git(); - prepare_packed_git_run_once = 1; + ctx->prepare_packed_git_run_once = 1; } void reprepare_packed_git(void) { + struct pack_context *ctx = get_thread_pack_context(); discard_revindex(); - prepare_packed_git_run_once = 0; + ctx->prepare_packed_git_run_once = 0; prepare_packed_git(); } @@ -1664,24 +1724,6 @@ static void *unpack_compressed_entry(struct packed_git *p, return buffer; } -#define MAX_DELTA_CACHE (256) - -static size_t delta_base_cached; - -static struct delta_base_cache_lru_list { - struct delta_base_cache_lru_list *prev; - struct delta_base_cache_lru_list *next; -} delta_base_cache_lru = { &delta_base_cache_lru, &delta_base_cache_lru }; - -static struct delta_base_cache_entry { - struct delta_base_cache_lru_list lru; - void *data; - struct packed_git *p; - off_t base_offset; - unsigned long size; - enum object_type type; -} delta_base_cache[MAX_DELTA_CACHE]; - static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset) { unsigned long hash; @@ -1694,7 +1736,8 @@ static unsigned long pack_entry_hash(struct packed_git *p, off_t base_offset) static int in_delta_base_cache(struct packed_git *p, off_t base_offset) { unsigned long hash = pack_entry_hash(p, base_offset); - struct delta_base_cache_entry *ent = delta_base_cache + hash; + struct delta_base_cache_entry *ent + = get_thread_pack_context()->delta_base_cache + hash; return (ent->data && ent->p == p && ent->base_offset == base_offset); } @@ -1703,7 +1746,8 @@ static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset, { void *ret; unsigned long hash = pack_entry_hash(p, base_offset); - struct delta_base_cache_entry *ent = delta_base_cache + hash; + struct pack_context *ctx = get_thread_pack_context(); + struct delta_base_cache_entry *ent = ctx->delta_base_cache + hash; ret = ent->data; if (!ret || ent->p != p || ent->base_offset != base_offset) @@ -1713,7 +1757,7 @@ static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset, ent->data = NULL; ent->lru.next->prev = ent->lru.prev; ent->lru.prev->next = ent->lru.next; - delta_base_cached -= ent->size; + ctx->delta_base_cached -= ent->size; } else { ret = xmemdupz(ent->data, ent->size); } @@ -1722,48 +1766,52 @@ static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset, return ret; } -static inline void release_delta_base_cache(struct delta_base_cache_entry *ent) +static inline void release_delta_base_cache(struct pack_context *ctx, + struct delta_base_cache_entry *ent) { if (ent->data) { free(ent->data); ent->data = NULL; ent->lru.next->prev = ent->lru.prev; ent->lru.prev->next = ent->lru.next; - delta_base_cached -= ent->size; + ctx->delta_base_cached -= ent->size; } } void clear_delta_base_cache(void) { unsigned long p; + struct pack_context *ctx = get_thread_pack_context(); + struct delta_base_cache_entry *delta_base_cache = ctx->delta_base_cache; for (p = 0; p < MAX_DELTA_CACHE; p++) - release_delta_base_cache(&delta_base_cache[p]); + release_delta_base_cache(ctx, &delta_base_cache[p]); } static void add_delta_base_cache(struct packed_git *p, off_t base_offset, void *base, unsigned long base_size, enum object_type type) { unsigned long hash = pack_entry_hash(p, base_offset); - struct delta_base_cache_entry *ent = delta_base_cache + hash; + struct pack_context *ctx = get_thread_pack_context(); + struct delta_base_cache_entry *ent = ctx->delta_base_cache + hash; struct delta_base_cache_lru_list *lru; - release_delta_base_cache(ent); - delta_base_cached += base_size; + release_delta_base_cache(ctx, ent); + ctx->delta_base_cached += base_size; - for (lru = delta_base_cache_lru.next; - delta_base_cached > delta_base_cache_limit - && lru != &delta_base_cache_lru; + for (lru = ctx->delta_base_cache_lru->next; + ctx->delta_base_cached > delta_base_cache_limit + && lru != ctx->delta_base_cache_lru; lru = lru->next) { struct delta_base_cache_entry *f = (void *)lru; if (f->type == OBJ_BLOB) - release_delta_base_cache(f); + release_delta_base_cache(ctx, f); } - for (lru = delta_base_cache_lru.next; - delta_base_cached > delta_base_cache_limit - && lru != &delta_base_cache_lru; + for (lru = ctx->delta_base_cache_lru->next; + ctx->delta_base_cached > delta_base_cache_limit + && lru != ctx->delta_base_cache_lru; lru = lru->next) { struct delta_base_cache_entry *f = (void *)lru; - release_delta_base_cache(f); + release_delta_base_cache(ctx, f); } ent->p = p; @@ -1771,10 +1819,10 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset, ent->type = type; ent->data = base; ent->size = base_size; - ent->lru.next = &delta_base_cache_lru; - ent->lru.prev = delta_base_cache_lru.prev; - delta_base_cache_lru.prev->next = &ent->lru; - delta_base_cache_lru.prev = &ent->lru; + ent->lru.next = ctx->delta_base_cache_lru; + ent->lru.prev = ctx->delta_base_cache_lru->prev; + ctx->delta_base_cache_lru->prev->next = &ent->lru; + ctx->delta_base_cache_lru->prev = &ent->lru; } static void *read_object(const unsigned char *sha1, enum object_type *type, @@ -2066,20 +2114,21 @@ static int fill_pack_entry(const unsigned char *sha1, static int find_pack_entry(const unsigned char *sha1, struct pack_entry *e) { + struct pack_context *ctx = get_thread_pack_context(); struct packed_git *p; prepare_packed_git(); if (!get_packed_git()) return 0; - if (last_found_pack && fill_pack_entry(sha1, e, last_found_pack)) + if (ctx->last_found_pack && fill_pack_entry(sha1, e, ctx->last_found_pack)) return 1; for (p = get_packed_git(); p; p = p->next) { - if (p == last_found_pack || !fill_pack_entry(sha1, e, p)) + if (p == ctx->last_found_pack || !fill_pack_entry(sha1, e, p)) continue; - last_found_pack = p; + ctx->last_found_pack = p; return 1; } return 0; -- 1.7.8.36.g69ee2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html