summaryrefslogtreecommitdiff
path: root/packfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'packfile.c')
-rw-r--r--packfile.c283
1 files changed, 155 insertions, 128 deletions
diff --git a/packfile.c b/packfile.c
index acb680966d..5a7caec292 100644
--- a/packfile.c
+++ b/packfile.c
@@ -278,7 +278,7 @@ static int unuse_one_window(struct packed_git *current)
if (current)
scan_windows(current, &lru_p, &lru_w, &lru_l);
- for (p = current->repo->objects->packed_git; p; p = p->next)
+ for (p = current->repo->objects->packfiles->packs; p; p = p->next)
scan_windows(p, &lru_p, &lru_w, &lru_l);
if (lru_p) {
munmap(lru_w->base, lru_w->len);
@@ -362,13 +362,8 @@ void close_pack(struct packed_git *p)
void close_object_store(struct object_database *o)
{
struct odb_source *source;
- struct packed_git *p;
- for (p = o->packed_git; p; p = p->next)
- if (p->do_not_close)
- BUG("want to close pack marked 'do-not-close'");
- else
- close_pack(p);
+ packfile_store_close(o->packfiles);
for (source = o->sources; source; source = source->next) {
if (source->midx)
@@ -468,7 +463,7 @@ static int close_one_pack(struct repository *r)
struct pack_window *mru_w = NULL;
int accept_windows_inuse = 1;
- for (p = r->objects->packed_git; p; p = p->next) {
+ for (p = r->objects->packfiles->packs; p; p = p->next) {
if (p->pack_fd == -1)
continue;
find_lru_pack(p, &lru_p, &mru_w, &accept_windows_inuse);
@@ -784,16 +779,44 @@ struct packed_git *add_packed_git(struct repository *r, const char *path,
return p;
}
-void install_packed_git(struct repository *r, struct packed_git *pack)
+void packfile_store_add_pack(struct packfile_store *store,
+ struct packed_git *pack)
{
if (pack->pack_fd != -1)
pack_open_fds++;
- pack->next = r->objects->packed_git;
- r->objects->packed_git = pack;
+ pack->next = store->packs;
+ store->packs = pack;
hashmap_entry_init(&pack->packmap_ent, strhash(pack->pack_name));
- hashmap_add(&r->objects->pack_map, &pack->packmap_ent);
+ hashmap_add(&store->map, &pack->packmap_ent);
+}
+
+struct packed_git *packfile_store_load_pack(struct packfile_store *store,
+ const char *idx_path, int local)
+{
+ struct strbuf key = STRBUF_INIT;
+ struct packed_git *p;
+
+ /*
+ * We're being called with the path to the index file, but `pack_map`
+ * holds the path to the packfile itself.
+ */
+ strbuf_addstr(&key, idx_path);
+ strbuf_strip_suffix(&key, ".idx");
+ strbuf_addstr(&key, ".pack");
+
+ p = hashmap_get_entry_from_hash(&store->map, strhash(key.buf), key.buf,
+ struct packed_git, packmap_ent);
+ if (!p) {
+ p = add_packed_git(store->odb->repo, idx_path,
+ strlen(idx_path), local);
+ if (p)
+ packfile_store_add_pack(store, p);
+ }
+
+ strbuf_release(&key);
+ return p;
}
void (*report_garbage)(unsigned seen_bits, const char *path);
@@ -895,23 +918,14 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
const char *file_name, void *_data)
{
struct prepare_pack_data *data = (struct prepare_pack_data *)_data;
- struct packed_git *p;
size_t base_len = full_name_len;
if (strip_suffix_mem(full_name, &base_len, ".idx") &&
!(data->m && midx_contains_pack(data->m, file_name))) {
- struct hashmap_entry hent;
- char *pack_name = xstrfmt("%.*s.pack", (int)base_len, full_name);
- unsigned int hash = strhash(pack_name);
- hashmap_entry_init(&hent, hash);
-
- /* Don't reopen a pack we already have. */
- if (!hashmap_get(&data->r->objects->pack_map, &hent, pack_name)) {
- p = add_packed_git(data->r, full_name, full_name_len, data->local);
- if (p)
- install_packed_git(data->r, p);
- }
- free(pack_name);
+ char *trimmed_path = xstrndup(full_name, full_name_len);
+ packfile_store_load_pack(data->r->objects->packfiles,
+ trimmed_path, data->local);
+ free(trimmed_path);
}
if (!report_garbage)
@@ -951,40 +965,6 @@ static void prepare_packed_git_one(struct odb_source *source)
string_list_clear(data.garbage, 0);
}
-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
- * you should repack because your performance will be awful, or they are
- * all unreachable objects about to be pruned, in which case they're not really
- * interesting as a measure of repo size in the first place.
- */
-unsigned long repo_approximate_object_count(struct repository *r)
-{
- if (!r->objects->approximate_object_count_valid) {
- struct odb_source *source;
- unsigned long count = 0;
- struct packed_git *p;
-
- prepare_packed_git(r);
-
- for (source = r->objects->sources; source; source = source->next) {
- struct multi_pack_index *m = get_multi_pack_index(source);
- if (m)
- count += m->num_objects;
- }
-
- for (p = r->objects->packed_git; p; p = p->next) {
- if (open_pack_index(p))
- continue;
- count += p->num_objects;
- }
- r->objects->approximate_object_count = count;
- r->objects->approximate_object_count_valid = 1;
- }
- return r->objects->approximate_object_count;
-}
-
DEFINE_LIST_SORT(static, sort_packs, struct packed_git, next);
static int sort_pack(const struct packed_git *a, const struct packed_git *b)
@@ -1013,80 +993,51 @@ static int sort_pack(const struct packed_git *a, const struct packed_git *b)
return -1;
}
-static void rearrange_packed_git(struct repository *r)
-{
- sort_packs(&r->objects->packed_git, sort_pack);
-}
-
-static void prepare_packed_git_mru(struct repository *r)
+static void packfile_store_prepare_mru(struct packfile_store *store)
{
struct packed_git *p;
- INIT_LIST_HEAD(&r->objects->packed_git_mru);
+ INIT_LIST_HEAD(&store->mru);
- for (p = r->objects->packed_git; p; p = p->next)
- list_add_tail(&p->mru, &r->objects->packed_git_mru);
+ for (p = store->packs; p; p = p->next)
+ list_add_tail(&p->mru, &store->mru);
}
-static void prepare_packed_git(struct repository *r)
+void packfile_store_prepare(struct packfile_store *store)
{
struct odb_source *source;
- if (r->objects->packed_git_initialized)
+ if (store->initialized)
return;
- odb_prepare_alternates(r->objects);
- for (source = r->objects->sources; source; source = source->next) {
+ odb_prepare_alternates(store->odb);
+ for (source = store->odb->sources; source; source = source->next) {
prepare_multi_pack_index_one(source);
prepare_packed_git_one(source);
}
- rearrange_packed_git(r);
-
- prepare_packed_git_mru(r);
- r->objects->packed_git_initialized = 1;
-}
-
-void reprepare_packed_git(struct repository *r)
-{
- struct odb_source *source;
+ sort_packs(&store->packs, sort_pack);
- obj_read_lock();
-
- /*
- * Reprepare alt odbs, in case the alternates file was modified
- * during the course of this process. This only _adds_ odbs to
- * the linked list, so existing odbs will continue to exist for
- * the lifetime of the process.
- */
- r->objects->loaded_alternates = 0;
- odb_prepare_alternates(r->objects);
-
- for (source = r->objects->sources; source; source = source->next)
- odb_clear_loose_cache(source);
-
- r->objects->approximate_object_count_valid = 0;
- r->objects->packed_git_initialized = 0;
- prepare_packed_git(r);
- obj_read_unlock();
+ packfile_store_prepare_mru(store);
+ store->initialized = true;
}
-struct packed_git *get_packed_git(struct repository *r)
+void packfile_store_reprepare(struct packfile_store *store)
{
- prepare_packed_git(r);
- return r->objects->packed_git;
+ store->initialized = false;
+ packfile_store_prepare(store);
}
-struct multi_pack_index *get_multi_pack_index(struct odb_source *source)
+struct packed_git *packfile_store_get_packs(struct packfile_store *store)
{
- prepare_packed_git(source->odb->repo);
- return source->midx;
+ packfile_store_prepare(store);
+ return store->packs;
}
-struct packed_git *get_all_packs(struct repository *r)
+struct packed_git *packfile_store_get_all_packs(struct packfile_store *store)
{
- prepare_packed_git(r);
+ packfile_store_prepare(store);
- for (struct odb_source *source = r->objects->sources; source; source = source->next) {
+ for (struct odb_source *source = store->odb->sources; source; source = source->next) {
struct multi_pack_index *m = source->midx;
if (!m)
continue;
@@ -1094,13 +1045,46 @@ struct packed_git *get_all_packs(struct repository *r)
prepare_midx_pack(m, i);
}
- return r->objects->packed_git;
+ return store->packs;
}
-struct list_head *get_packed_git_mru(struct repository *r)
+struct list_head *packfile_store_get_packs_mru(struct packfile_store *store)
{
- prepare_packed_git(r);
- return &r->objects->packed_git_mru;
+ packfile_store_prepare(store);
+ return &store->mru;
+}
+
+/*
+ * 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
+ * you should repack because your performance will be awful, or they are
+ * all unreachable objects about to be pruned, in which case they're not really
+ * interesting as a measure of repo size in the first place.
+ */
+unsigned long repo_approximate_object_count(struct repository *r)
+{
+ if (!r->objects->approximate_object_count_valid) {
+ struct odb_source *source;
+ unsigned long count = 0;
+ struct packed_git *p;
+
+ packfile_store_prepare(r->objects->packfiles);
+
+ for (source = r->objects->sources; source; source = source->next) {
+ struct multi_pack_index *m = get_multi_pack_index(source);
+ if (m)
+ count += m->num_objects;
+ }
+
+ for (p = r->objects->packfiles->packs; p; p = p->next) {
+ if (open_pack_index(p))
+ continue;
+ count += p->num_objects;
+ }
+ r->objects->approximate_object_count = count;
+ r->objects->approximate_object_count_valid = 1;
+ }
+ return r->objects->approximate_object_count;
}
unsigned long unpack_object_header_buffer(const unsigned char *buf,
@@ -1155,7 +1139,7 @@ unsigned long get_size_from_delta(struct packed_git *p,
*
* Other worrying sections could be the call to close_pack_fd(),
* which can close packs even with in-use windows, and to
- * reprepare_packed_git(). Regarding the former, mmap doc says:
+ * odb_reprepare(). Regarding the former, mmap doc says:
* "closing the file descriptor does not unmap the region". And
* for the latter, it won't re-open already available packs.
*/
@@ -1219,7 +1203,7 @@ const struct packed_git *has_packed_and_bad(struct repository *r,
{
struct packed_git *p;
- for (p = r->objects->packed_git; p; p = p->next)
+ for (p = r->objects->packfiles->packs; p; p = p->next)
if (oidset_contains(&p->bad_objects, oid))
return p;
return NULL;
@@ -2074,19 +2058,19 @@ int find_pack_entry(struct repository *r, const struct object_id *oid, struct pa
{
struct list_head *pos;
- prepare_packed_git(r);
+ packfile_store_prepare(r->objects->packfiles);
for (struct odb_source *source = r->objects->sources; source; source = source->next)
if (source->midx && fill_midx_entry(source->midx, oid, e))
return 1;
- if (!r->objects->packed_git)
+ if (!r->objects->packfiles->packs)
return 0;
- list_for_each(pos, &r->objects->packed_git_mru) {
+ list_for_each(pos, &r->objects->packfiles->mru) {
struct packed_git *p = list_entry(pos, struct packed_git, mru);
if (!p->multi_pack_index && fill_pack_entry(oid, e, p)) {
- list_move(&p->mru, &r->objects->packed_git_mru);
+ list_move(&p->mru, &r->objects->packfiles->mru);
return 1;
}
}
@@ -2096,19 +2080,19 @@ int find_pack_entry(struct repository *r, const struct object_id *oid, struct pa
static void maybe_invalidate_kept_pack_cache(struct repository *r,
unsigned flags)
{
- if (!r->objects->kept_pack_cache.packs)
+ if (!r->objects->packfiles->kept_cache.packs)
return;
- if (r->objects->kept_pack_cache.flags == flags)
+ if (r->objects->packfiles->kept_cache.flags == flags)
return;
- FREE_AND_NULL(r->objects->kept_pack_cache.packs);
- r->objects->kept_pack_cache.flags = 0;
+ FREE_AND_NULL(r->objects->packfiles->kept_cache.packs);
+ r->objects->packfiles->kept_cache.flags = 0;
}
struct packed_git **kept_pack_cache(struct repository *r, unsigned flags)
{
maybe_invalidate_kept_pack_cache(r, flags);
- if (!r->objects->kept_pack_cache.packs) {
+ if (!r->objects->packfiles->kept_cache.packs) {
struct packed_git **packs = NULL;
size_t nr = 0, alloc = 0;
struct packed_git *p;
@@ -2121,7 +2105,7 @@ struct packed_git **kept_pack_cache(struct repository *r, unsigned flags)
* covers, one kept and one not kept, but the midx returns only
* the non-kept version.
*/
- for (p = get_all_packs(r); p; p = p->next) {
+ for (p = packfile_store_get_all_packs(r->objects->packfiles); p; p = p->next) {
if ((p->pack_keep && (flags & ON_DISK_KEEP_PACKS)) ||
(p->pack_keep_in_core && (flags & IN_CORE_KEEP_PACKS))) {
ALLOC_GROW(packs, nr + 1, alloc);
@@ -2131,11 +2115,11 @@ struct packed_git **kept_pack_cache(struct repository *r, unsigned flags)
ALLOC_GROW(packs, nr + 1, alloc);
packs[nr] = NULL;
- r->objects->kept_pack_cache.packs = packs;
- r->objects->kept_pack_cache.flags = flags;
+ r->objects->packfiles->kept_cache.packs = packs;
+ r->objects->packfiles->kept_cache.flags = flags;
}
- return r->objects->kept_pack_cache.packs;
+ return r->objects->packfiles->kept_cache.packs;
}
int find_kept_pack_entry(struct repository *r,
@@ -2218,7 +2202,7 @@ int for_each_packed_object(struct repository *repo, each_packed_object_fn cb,
int r = 0;
int pack_errors = 0;
- for (p = get_all_packs(repo); p; p = p->next) {
+ for (p = packfile_store_get_all_packs(repo->objects->packfiles); p; p = p->next) {
if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
continue;
if ((flags & FOR_EACH_OBJECT_PROMISOR_ONLY) &&
@@ -2332,3 +2316,46 @@ int parse_pack_header_option(const char *in, unsigned char *out, unsigned int *l
*len = hdr - out;
return 0;
}
+
+static int pack_map_entry_cmp(const void *cmp_data UNUSED,
+ const struct hashmap_entry *entry,
+ const struct hashmap_entry *entry2,
+ const void *keydata)
+{
+ const char *key = keydata;
+ const struct packed_git *pg1, *pg2;
+
+ pg1 = container_of(entry, const struct packed_git, packmap_ent);
+ pg2 = container_of(entry2, const struct packed_git, packmap_ent);
+
+ return strcmp(pg1->pack_name, key ? key : pg2->pack_name);
+}
+
+struct packfile_store *packfile_store_new(struct object_database *odb)
+{
+ struct packfile_store *store;
+ CALLOC_ARRAY(store, 1);
+ store->odb = odb;
+ INIT_LIST_HEAD(&store->mru);
+ hashmap_init(&store->map, pack_map_entry_cmp, NULL, 0);
+ return store;
+}
+
+void packfile_store_free(struct packfile_store *store)
+{
+ for (struct packed_git *p = store->packs, *next; p; p = next) {
+ next = p->next;
+ free(p);
+ }
+ hashmap_clear(&store->map);
+ free(store);
+}
+
+void packfile_store_close(struct packfile_store *store)
+{
+ for (struct packed_git *p = store->packs; p; p = p->next) {
+ if (p->do_not_close)
+ BUG("want to close pack marked 'do-not-close'");
+ close_pack(p);
+ }
+}