diff options
Diffstat (limited to 'packfile.c')
-rw-r--r-- | packfile.c | 227 |
1 files changed, 126 insertions, 101 deletions
diff --git a/packfile.c b/packfile.c index 7c1a2519fc..9e7e693fb5 100644 --- a/packfile.c +++ b/packfile.c @@ -1,6 +1,7 @@ #include "cache.h" #include "list.h" #include "pack.h" +#include "repository.h" #include "dir.h" #include "mergesort.h" #include "packfile.h" @@ -13,6 +14,7 @@ #include "tag.h" #include "tree-walk.h" #include "tree.h" +#include "object-store.h" char *odb_pack_name(struct strbuf *buf, const unsigned char *sha1, @@ -44,8 +46,6 @@ 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; -LIST_HEAD(packed_git_mru); #define SZ_FMT PRIuMAX static inline uintmax_t sz_fmt(size_t s) { return s; } @@ -245,7 +245,7 @@ static int unuse_one_window(struct packed_git *current) if (current) scan_windows(current, &lru_p, &lru_w, &lru_l); - for (p = packed_git; p; p = p->next) + for (p = the_repository->objects->packed_git; p; p = p->next) scan_windows(p, &lru_p, &lru_w, &lru_l); if (lru_p) { munmap(lru_w->base, lru_w->len); @@ -304,18 +304,18 @@ void close_pack_index(struct packed_git *p) } } -static void close_pack(struct packed_git *p) +void close_pack(struct packed_git *p) { close_pack_windows(p); close_pack_fd(p); close_pack_index(p); } -void close_all_packs(void) +void close_all_packs(struct raw_object_store *o) { struct packed_git *p; - for (p = packed_git; p; p = p->next) + for (p = o->packed_git; p; p = p->next) if (p->do_not_close) die("BUG: want to close pack marked 'do-not-close'"); else @@ -383,7 +383,7 @@ static int close_one_pack(void) struct pack_window *mru_w = NULL; int accept_windows_inuse = 1; - for (p = packed_git; p; p = p->next) { + for (p = the_repository->objects->packed_git; p; p = p->next) { if (p->pack_fd == -1) continue; find_lru_pack(p, &lru_p, &mru_w, &accept_windows_inuse); @@ -680,13 +680,13 @@ struct packed_git *add_packed_git(const char *path, size_t path_len, int local) return p; } -void install_packed_git(struct packed_git *pack) +void install_packed_git(struct repository *r, struct packed_git *pack) { if (pack->pack_fd != -1) pack_open_fds++; - pack->next = packed_git; - packed_git = pack; + pack->next = r->objects->packed_git; + r->objects->packed_git = pack; } void (*report_garbage)(unsigned seen_bits, const char *path); @@ -735,7 +735,7 @@ static void report_pack_garbage(struct string_list *list) report_helper(list, seen_bits, first, list->nr); } -static void prepare_packed_git_one(char *objdir, int local) +static void prepare_packed_git_one(struct repository *r, char *objdir, int local) { struct strbuf path = STRBUF_INIT; size_t dirnamelen; @@ -768,7 +768,8 @@ static void prepare_packed_git_one(char *objdir, int local) base_len = path.len; if (strip_suffix_mem(path.buf, &base_len, ".idx")) { /* Don't reopen a pack we already have. */ - for (p = packed_git; p; p = p->next) { + for (p = r->objects->packed_git; p; + p = p->next) { size_t len; if (strip_suffix(p->pack_name, ".pack", &len) && len == base_len && @@ -781,7 +782,7 @@ static void prepare_packed_git_one(char *objdir, int local) * corresponding .pack file that we can map. */ (p = add_packed_git(path.buf, path.len, local)) != NULL) - install_packed_git(p); + install_packed_git(r, p); } if (!report_garbage) @@ -802,8 +803,7 @@ static void prepare_packed_git_one(char *objdir, int local) strbuf_release(&path); } -static int approximate_object_count_valid; - +static void prepare_packed_git(struct repository *r); /* * Give a fast, rough count of the number of objects in the repository. This * ignores loose objects completely. If you have a lot of them, then either @@ -813,19 +813,20 @@ static int approximate_object_count_valid; */ unsigned long approximate_object_count(void) { - static unsigned long count; - if (!approximate_object_count_valid) { + if (!the_repository->objects->approximate_object_count_valid) { + unsigned long count; struct packed_git *p; - prepare_packed_git(); + prepare_packed_git(the_repository); count = 0; - for (p = packed_git; p; p = p->next) { + for (p = the_repository->objects->packed_git; p; p = p->next) { if (open_pack_index(p)) continue; count += p->num_objects; } + the_repository->objects->approximate_object_count = count; } - return count; + return the_repository->objects->approximate_object_count; } static void *get_next_packed_git(const void *p) @@ -866,43 +867,55 @@ static int sort_pack(const void *a_, const void *b_) return -1; } -static void rearrange_packed_git(void) +static void rearrange_packed_git(struct repository *r) { - packed_git = llist_mergesort(packed_git, get_next_packed_git, - set_next_packed_git, sort_pack); + r->objects->packed_git = llist_mergesort( + r->objects->packed_git, get_next_packed_git, + set_next_packed_git, sort_pack); } -static void prepare_packed_git_mru(void) +static void prepare_packed_git_mru(struct repository *r) { struct packed_git *p; - INIT_LIST_HEAD(&packed_git_mru); + INIT_LIST_HEAD(&r->objects->packed_git_mru); - for (p = packed_git; p; p = p->next) - list_add_tail(&p->mru, &packed_git_mru); + for (p = r->objects->packed_git; p; p = p->next) + list_add_tail(&p->mru, &r->objects->packed_git_mru); } -static int prepare_packed_git_run_once = 0; -void prepare_packed_git(void) +static void prepare_packed_git(struct repository *r) { struct alternate_object_database *alt; - if (prepare_packed_git_run_once) + if (r->objects->packed_git_initialized) return; - prepare_packed_git_one(get_object_directory(), 1); - prepare_alt_odb(); - for (alt = alt_odb_list; alt; alt = alt->next) - prepare_packed_git_one(alt->path, 0); - rearrange_packed_git(); - prepare_packed_git_mru(); - prepare_packed_git_run_once = 1; + prepare_packed_git_one(r, r->objects->objectdir, 1); + prepare_alt_odb(r); + for (alt = r->objects->alt_odb_list; alt; alt = alt->next) + prepare_packed_git_one(r, alt->path, 0); + rearrange_packed_git(r); + prepare_packed_git_mru(r); + r->objects->packed_git_initialized = 1; +} + +void reprepare_packed_git(struct repository *r) +{ + r->objects->approximate_object_count_valid = 0; + r->objects->packed_git_initialized = 0; + prepare_packed_git(r); +} + +struct packed_git *get_packed_git(struct repository *r) +{ + prepare_packed_git(r); + return r->objects->packed_git; } -void reprepare_packed_git(void) +struct list_head *get_packed_git_mru(struct repository *r) { - approximate_object_count_valid = 0; - prepare_packed_git_run_once = 0; - prepare_packed_git(); + prepare_packed_git(r); + return &r->objects->packed_git_mru; } unsigned long unpack_object_header_buffer(const unsigned char *buf, @@ -1013,7 +1026,7 @@ const struct packed_git *has_packed_and_bad(const unsigned char *sha1) struct packed_git *p; unsigned i; - for (p = packed_git; p; p = p->next) + for (p = the_repository->objects->packed_git; p; p = p->next) for (i = 0; i < p->num_bad_objects; i++) if (!hashcmp(sha1, p->bad_object_sha1 + 20 * i)) return p; @@ -1091,17 +1104,19 @@ static const unsigned char *get_delta_base_sha1(struct packed_git *p, return NULL; } -static int retry_bad_packed_offset(struct packed_git *p, off_t obj_offset) +static int retry_bad_packed_offset(struct repository *r, + struct packed_git *p, + off_t obj_offset) { int type; struct revindex_entry *revidx; - const unsigned char *sha1; + struct object_id oid; revidx = find_pack_revindex(p, obj_offset); if (!revidx) return OBJ_BAD; - sha1 = nth_packed_object_sha1(p, revidx->nr); - mark_bad_packed_object(p, sha1); - type = sha1_object_info(sha1, NULL); + nth_packed_object_oid(&oid, p, revidx->nr); + mark_bad_packed_object(p, oid.hash); + type = oid_object_info(r, &oid, NULL); if (type <= OBJ_NONE) return OBJ_BAD; return type; @@ -1109,7 +1124,8 @@ static int retry_bad_packed_offset(struct packed_git *p, off_t obj_offset) #define POI_STACK_PREALLOC 64 -static enum object_type packed_to_object_type(struct packed_git *p, +static enum object_type packed_to_object_type(struct repository *r, + struct packed_git *p, off_t obj_offset, enum object_type type, struct pack_window **w_curs, @@ -1140,7 +1156,7 @@ static enum object_type packed_to_object_type(struct packed_git *p, if (type <= OBJ_NONE) { /* If getting the base itself fails, we first * retry the base, otherwise unwind */ - type = retry_bad_packed_offset(p, base_offset); + type = retry_bad_packed_offset(r, p, base_offset); if (type > OBJ_NONE) goto out; goto unwind; @@ -1168,7 +1184,7 @@ out: unwind: while (poi_stack_nr) { obj_offset = poi_stack[--poi_stack_nr]; - type = retry_bad_packed_offset(p, obj_offset); + type = retry_bad_packed_offset(r, p, obj_offset); if (type > OBJ_NONE) goto out; } @@ -1255,14 +1271,15 @@ static void detach_delta_base_cache_entry(struct delta_base_cache_entry *ent) free(ent); } -static void *cache_or_unpack_entry(struct packed_git *p, off_t base_offset, - unsigned long *base_size, enum object_type *type) +static void *cache_or_unpack_entry(struct repository *r, struct packed_git *p, + off_t base_offset, unsigned long *base_size, + enum object_type *type) { struct delta_base_cache_entry *ent; ent = get_delta_base_cache_entry(p, base_offset); if (!ent) - return unpack_entry(p, base_offset, type, base_size); + return unpack_entry(r, p, base_offset, type, base_size); if (type) *type = ent->type; @@ -1316,8 +1333,8 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset, hashmap_add(&delta_base_cache, ent); } -int packed_object_info(struct packed_git *p, off_t obj_offset, - struct object_info *oi) +int packed_object_info(struct repository *r, struct packed_git *p, + off_t obj_offset, struct object_info *oi) { struct pack_window *w_curs = NULL; unsigned long size; @@ -1329,7 +1346,7 @@ int packed_object_info(struct packed_git *p, off_t obj_offset, * a "real" type later if the caller is interested. */ if (oi->contentp) { - *oi->contentp = cache_or_unpack_entry(p, obj_offset, oi->sizep, + *oi->contentp = cache_or_unpack_entry(r, p, obj_offset, oi->sizep, &type); if (!*oi->contentp) type = OBJ_BAD; @@ -1363,8 +1380,8 @@ int packed_object_info(struct packed_git *p, off_t obj_offset, if (oi->typep || oi->type_name) { enum object_type ptot; - ptot = packed_to_object_type(p, obj_offset, type, &w_curs, - curpos); + ptot = packed_to_object_type(r, p, obj_offset, + type, &w_curs, curpos); if (oi->typep) *oi->typep = ptot; if (oi->type_name) { @@ -1452,7 +1469,9 @@ struct unpack_entry_stack_ent { unsigned long size; }; -static void *read_object(const unsigned char *sha1, enum object_type *type, +static void *read_object(struct repository *r, + const struct object_id *oid, + enum object_type *type, unsigned long *size) { struct object_info oi = OBJECT_INFO_INIT; @@ -1461,12 +1480,12 @@ static void *read_object(const unsigned char *sha1, enum object_type *type, oi.sizep = size; oi.contentp = &content; - if (sha1_object_info_extended(sha1, &oi, 0) < 0) + if (oid_object_info_extended(r, oid, &oi, 0) < 0) return NULL; return content; } -void *unpack_entry(struct packed_git *p, off_t obj_offset, +void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset, enum object_type *final_type, unsigned long *final_size) { struct pack_window *w_curs = NULL; @@ -1501,11 +1520,11 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset, struct revindex_entry *revidx = find_pack_revindex(p, obj_offset); off_t len = revidx[1].offset - obj_offset; if (check_pack_crc(p, &w_curs, obj_offset, len, revidx->nr)) { - const unsigned char *sha1 = - nth_packed_object_sha1(p, revidx->nr); + struct object_id oid; + nth_packed_object_oid(&oid, p, revidx->nr); error("bad packed object CRC for %s", - sha1_to_hex(sha1)); - mark_bad_packed_object(p, sha1); + oid_to_hex(&oid)); + mark_bad_packed_object(p, oid.hash); data = NULL; goto out; } @@ -1588,16 +1607,16 @@ void *unpack_entry(struct packed_git *p, off_t obj_offset, * of a corrupted pack, and is better than failing outright. */ struct revindex_entry *revidx; - const unsigned char *base_sha1; + struct object_id base_oid; revidx = find_pack_revindex(p, obj_offset); if (revidx) { - base_sha1 = nth_packed_object_sha1(p, revidx->nr); + nth_packed_object_oid(&base_oid, p, revidx->nr); error("failed to read delta base object %s" " at offset %"PRIuMAX" from %s", - sha1_to_hex(base_sha1), (uintmax_t)obj_offset, + oid_to_hex(&base_oid), (uintmax_t)obj_offset, p->pack_name); - mark_bad_packed_object(p, base_sha1); - base = read_object(base_sha1, &type, &base_size); + mark_bad_packed_object(p, base_oid.hash); + base = read_object(r, &base_oid, &type, &base_size); external_base = base; } } @@ -1654,6 +1673,29 @@ out: return data; } +int bsearch_pack(const struct object_id *oid, const struct packed_git *p, uint32_t *result) +{ + const unsigned char *index_fanout = p->index_data; + const unsigned char *index_lookup; + int index_lookup_width; + + if (!index_fanout) + BUG("bsearch_pack called without a valid pack-index"); + + index_lookup = index_fanout + 4 * 256; + if (p->index_version == 1) { + index_lookup_width = 24; + index_lookup += 4; + } else { + index_lookup_width = 20; + index_fanout += 8; + index_lookup += 8; + } + + return bsearch_hash(oid->hash, (const uint32_t*)index_fanout, + index_lookup, index_lookup_width, result); +} + const unsigned char *nth_packed_object_sha1(struct packed_git *p, uint32_t n) { @@ -1720,30 +1762,17 @@ off_t nth_packed_object_offset(const struct packed_git *p, uint32_t n) off_t find_pack_entry_one(const unsigned char *sha1, struct packed_git *p) { - const uint32_t *level1_ofs = p->index_data; const unsigned char *index = p->index_data; - unsigned stride; + struct object_id oid; uint32_t result; if (!index) { if (open_pack_index(p)) return 0; - level1_ofs = p->index_data; - index = p->index_data; - } - if (p->index_version > 1) { - level1_ofs += 2; - index += 8; - } - index += 4 * 256; - if (p->index_version > 1) { - stride = 20; - } else { - stride = 24; - index += 4; } - if (bsearch_hash(sha1, level1_ofs, index, stride, &result)) + hashcpy(oid.hash, sha1); + if (bsearch_pack(&oid, p, &result)) return nth_packed_object_offset(p, result); return 0; } @@ -1814,22 +1843,18 @@ static int fill_pack_entry(const unsigned char *sha1, return 1; } -/* - * Iff a pack file contains the object named by sha1, return true and - * store its location to e. - */ -int find_pack_entry(const unsigned char *sha1, struct pack_entry *e) +int find_pack_entry(struct repository *r, const unsigned char *sha1, struct pack_entry *e) { struct list_head *pos; - prepare_packed_git(); - if (!packed_git) + prepare_packed_git(r); + if (!r->objects->packed_git) return 0; - list_for_each(pos, &packed_git_mru) { + list_for_each(pos, &r->objects->packed_git_mru) { struct packed_git *p = list_entry(pos, struct packed_git, mru); if (fill_pack_entry(sha1, e, p)) { - list_move(&p->mru, &packed_git_mru); + list_move(&p->mru, &r->objects->packed_git_mru); return 1; } } @@ -1839,7 +1864,7 @@ int find_pack_entry(const unsigned char *sha1, struct pack_entry *e) int has_sha1_pack(const unsigned char *sha1) { struct pack_entry e; - return find_pack_entry(sha1, &e); + return find_pack_entry(the_repository, sha1, &e); } int has_pack_index(const unsigned char *sha1) @@ -1850,7 +1875,7 @@ int has_pack_index(const unsigned char *sha1) return 1; } -static int for_each_object_in_pack(struct packed_git *p, each_packed_object_fn cb, void *data) +int for_each_object_in_pack(struct packed_git *p, each_packed_object_fn cb, void *data) { uint32_t i; int r = 0; @@ -1875,8 +1900,8 @@ int for_each_packed_object(each_packed_object_fn cb, void *data, unsigned flags) int r = 0; int pack_errors = 0; - prepare_packed_git(); - for (p = packed_git; p; p = p->next) { + prepare_packed_git(the_repository); + for (p = the_repository->objects->packed_git; p; p = p->next) { if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local) continue; if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) && @@ -1907,7 +1932,7 @@ static int add_promisor_object(const struct object_id *oid, /* * If this is a tree, commit, or tag, the objects it refers - * to are also promisor objects. (Blobs refer to no objects.) + * to are also promisor objects. (Blobs refer to no objects->) */ if (obj->type == OBJ_TREE) { struct tree *tree = (struct tree *)obj; @@ -1925,7 +1950,7 @@ static int add_promisor_object(const struct object_id *oid, struct commit *commit = (struct commit *) obj; struct commit_list *parents = commit->parents; - oidset_insert(set, &commit->tree->object.oid); + oidset_insert(set, get_commit_tree_oid(commit)); for (; parents; parents = parents->next) oidset_insert(set, &parents->item->object.oid); } else if (obj->type == OBJ_TAG) { |