summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/fast-import.c4
-rw-r--r--builtin/pack-objects.c37
-rw-r--r--http-push.c6
-rw-r--r--http-walker.c26
-rw-r--r--http.c21
-rw-r--r--http.h5
-rw-r--r--midx.c2
-rw-r--r--packfile.c224
-rw-r--r--packfile.h70
9 files changed, 223 insertions, 172 deletions
diff --git a/builtin/fast-import.c b/builtin/fast-import.c
index 7c194e71cb..4cd0b079b6 100644
--- a/builtin/fast-import.c
+++ b/builtin/fast-import.c
@@ -979,7 +979,7 @@ static int store_object(
if (e->idx.offset) {
duplicate_count_by_type[type]++;
return 1;
- } else if (find_oid_pack(&oid, packfile_store_get_packs(packs))) {
+ } else if (packfile_list_find_oid(packfile_store_get_packs(packs), &oid)) {
e->type = type;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
@@ -1180,7 +1180,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
duplicate_count_by_type[OBJ_BLOB]++;
truncate_pack(&checkpoint);
- } else if (find_oid_pack(&oid, packfile_store_get_packs(packs))) {
+ } else if (packfile_list_find_oid(packfile_store_get_packs(packs), &oid)) {
e->type = OBJ_BLOB;
e->pack_id = MAX_PACK_ID;
e->idx.offset = 1; /* just not zero! */
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index b5454e5df1..0e4e9f8068 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -1706,8 +1706,8 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
uint32_t found_mtime)
{
int want;
+ struct packfile_list_entry *e;
struct odb_source *source;
- struct list_head *pos;
if (!exclude && local) {
/*
@@ -1748,12 +1748,11 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
}
}
- list_for_each(pos, packfile_store_get_packs_mru(the_repository->objects->packfiles)) {
- struct packed_git *p = list_entry(pos, struct packed_git, mru);
+ for (e = the_repository->objects->packfiles->packs.head; e; e = e->next) {
+ struct packed_git *p = e->pack;
want = want_object_in_pack_one(p, oid, exclude, found_pack, found_offset, found_mtime);
if (!exclude && want > 0)
- list_move(&p->mru,
- packfile_store_get_packs_mru(the_repository->objects->packfiles));
+ packfile_list_prepend(&the_repository->objects->packfiles->packs, p);
if (want != -1)
return want;
}
@@ -4389,27 +4388,27 @@ static void add_unreachable_loose_objects(struct rev_info *revs)
static int has_sha1_pack_kept_or_nonlocal(const struct object_id *oid)
{
- struct packfile_store *packs = the_repository->objects->packfiles;
- static struct packed_git *last_found = (void *)1;
+ static struct packed_git *last_found = NULL;
struct packed_git *p;
- p = (last_found != (void *)1) ? last_found :
- packfile_store_get_packs(packs);
+ if (last_found && find_pack_entry_one(oid, last_found))
+ return 1;
- while (p) {
- if ((!p->pack_local || p->pack_keep ||
- p->pack_keep_in_core) &&
- find_pack_entry_one(oid, p)) {
+ repo_for_each_pack(the_repository, p) {
+ /*
+ * We have already checked `last_found`, so there is no need to
+ * re-check here.
+ */
+ if (p == last_found)
+ continue;
+
+ if ((!p->pack_local || p->pack_keep || p->pack_keep_in_core) &&
+ find_pack_entry_one(oid, p)) {
last_found = p;
return 1;
}
- if (p == last_found)
- p = packfile_store_get_packs(packs);
- else
- p = p->next;
- if (p == last_found)
- p = p->next;
}
+
return 0;
}
diff --git a/http-push.c b/http-push.c
index a1c01e3b9b..d86ce77119 100644
--- a/http-push.c
+++ b/http-push.c
@@ -104,7 +104,7 @@ struct repo {
int has_info_refs;
int can_update_info_refs;
int has_info_packs;
- struct packed_git *packs;
+ struct packfile_list packs;
struct remote_lock *locks;
};
@@ -311,7 +311,7 @@ static void start_fetch_packed(struct transfer_request *request)
struct transfer_request *check_request = request_queue_head;
struct http_pack_request *preq;
- target = find_oid_pack(&request->obj->oid, repo->packs);
+ target = packfile_list_find_oid(repo->packs.head, &request->obj->oid);
if (!target) {
fprintf(stderr, "Unable to fetch %s, will not be able to update server info refs\n", oid_to_hex(&request->obj->oid));
repo->can_update_info_refs = 0;
@@ -683,7 +683,7 @@ static int add_send_request(struct object *obj, struct remote_lock *lock)
get_remote_object_list(obj->oid.hash[0]);
if (obj->flags & (REMOTE | PUSHING))
return 0;
- target = find_oid_pack(&obj->oid, repo->packs);
+ target = packfile_list_find_oid(repo->packs.head, &obj->oid);
if (target) {
obj->flags |= REMOTE;
return 0;
diff --git a/http-walker.c b/http-walker.c
index 0f7ae46d7f..e886e64866 100644
--- a/http-walker.c
+++ b/http-walker.c
@@ -15,7 +15,7 @@
struct alt_base {
char *base;
int got_indices;
- struct packed_git *packs;
+ struct packfile_list packs;
struct alt_base *next;
};
@@ -324,11 +324,8 @@ static void process_alternates_response(void *callback_data)
} else if (is_alternate_allowed(target.buf)) {
warning("adding alternate object store: %s",
target.buf);
- newalt = xmalloc(sizeof(*newalt));
- newalt->next = NULL;
+ CALLOC_ARRAY(newalt, 1);
newalt->base = strbuf_detach(&target, NULL);
- newalt->got_indices = 0;
- newalt->packs = NULL;
while (tail->next != NULL)
tail = tail->next;
@@ -435,7 +432,7 @@ static int http_fetch_pack(struct walker *walker, struct alt_base *repo,
if (fetch_indices(walker, repo))
return -1;
- target = find_oid_pack(oid, repo->packs);
+ target = packfile_list_find_oid(repo->packs.head, oid);
if (!target)
return -1;
close_pack_index(target);
@@ -584,17 +581,15 @@ static void cleanup(struct walker *walker)
if (data) {
alt = data->alt;
while (alt) {
- struct packed_git *pack;
+ struct packfile_list_entry *e;
alt_next = alt->next;
- pack = alt->packs;
- while (pack) {
- struct packed_git *pack_next = pack->next;
- close_pack(pack);
- free(pack);
- pack = pack_next;
+ for (e = alt->packs.head; e; e = e->next) {
+ close_pack(e->pack);
+ free(e->pack);
}
+ packfile_list_clear(&alt->packs);
free(alt->base);
free(alt);
@@ -612,14 +607,11 @@ struct walker *get_http_walker(const char *url)
struct walker_data *data = xmalloc(sizeof(struct walker_data));
struct walker *walker = xmalloc(sizeof(struct walker));
- data->alt = xmalloc(sizeof(*data->alt));
+ CALLOC_ARRAY(data->alt, 1);
data->alt->base = xstrdup(url);
for (s = data->alt->base + strlen(data->alt->base) - 1; *s == '/'; --s)
*s = 0;
- data->alt->got_indices = 0;
- data->alt->packs = NULL;
- data->alt->next = NULL;
data->got_alternates = -1;
walker->corrupt_object_found = 0;
diff --git a/http.c b/http.c
index 17130823f0..41f850db16 100644
--- a/http.c
+++ b/http.c
@@ -2413,8 +2413,9 @@ static char *fetch_pack_index(unsigned char *hash, const char *base_url)
return tmp;
}
-static int fetch_and_setup_pack_index(struct packed_git **packs_head,
- unsigned char *sha1, const char *base_url)
+static int fetch_and_setup_pack_index(struct packfile_list *packs,
+ unsigned char *sha1,
+ const char *base_url)
{
struct packed_git *new_pack, *p;
char *tmp_idx = NULL;
@@ -2448,12 +2449,11 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
if (ret)
return -1;
- new_pack->next = *packs_head;
- *packs_head = new_pack;
+ packfile_list_prepend(packs, new_pack);
return 0;
}
-int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
+int http_get_info_packs(const char *base_url, struct packfile_list *packs)
{
struct http_get_options options = {0};
int ret = 0;
@@ -2477,7 +2477,7 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
!parse_oid_hex(data, &oid, &data) &&
skip_prefix(data, ".pack", &data) &&
(*data == '\n' || *data == '\0')) {
- fetch_and_setup_pack_index(packs_head, oid.hash, base_url);
+ fetch_and_setup_pack_index(packs, oid.hash, base_url);
} else {
data = strchrnul(data, '\n');
}
@@ -2541,14 +2541,9 @@ cleanup:
}
void http_install_packfile(struct packed_git *p,
- struct packed_git **list_to_remove_from)
+ struct packfile_list *list_to_remove_from)
{
- struct packed_git **lst = list_to_remove_from;
-
- while (*lst != p)
- lst = &((*lst)->next);
- *lst = (*lst)->next;
-
+ packfile_list_remove(list_to_remove_from, p);
packfile_store_add_pack(the_repository->objects->packfiles, p);
}
diff --git a/http.h b/http.h
index 553e16205c..f9d4593404 100644
--- a/http.h
+++ b/http.h
@@ -2,6 +2,7 @@
#define HTTP_H
struct packed_git;
+struct packfile_list;
#include "git-zlib.h"
@@ -190,7 +191,7 @@ struct curl_slist *http_append_auth_header(const struct credential *c,
/* Helpers for fetching packs */
int http_get_info_packs(const char *base_url,
- struct packed_git **packs_head);
+ struct packfile_list *packs);
/* Helper for getting Accept-Language header */
const char *http_get_accept_language_header(void);
@@ -226,7 +227,7 @@ void release_http_pack_request(struct http_pack_request *preq);
* from http_get_info_packs() and have chosen a specific pack to fetch.
*/
void http_install_packfile(struct packed_git *p,
- struct packed_git **list_to_remove_from);
+ struct packfile_list *list_to_remove_from);
/* Helpers for fetching object */
struct http_object_request {
diff --git a/midx.c b/midx.c
index 1d6269f957..24e1e72175 100644
--- a/midx.c
+++ b/midx.c
@@ -462,8 +462,6 @@ int prepare_midx_pack(struct multi_pack_index *m,
m->pack_names[pack_int_id]);
p = packfile_store_load_pack(r->objects->packfiles,
pack_name.buf, m->source->local);
- if (p)
- list_add_tail(&p->mru, &r->objects->packfiles->mru);
strbuf_release(&pack_name);
if (!p) {
diff --git a/packfile.c b/packfile.c
index 1ae2b2fe1e..378b0b1920 100644
--- a/packfile.c
+++ b/packfile.c
@@ -47,6 +47,89 @@ static size_t pack_mapped;
#define SZ_FMT PRIuMAX
static inline uintmax_t sz_fmt(size_t s) { return s; }
+void packfile_list_clear(struct packfile_list *list)
+{
+ struct packfile_list_entry *e, *next;
+
+ for (e = list->head; e; e = next) {
+ next = e->next;
+ free(e);
+ }
+
+ list->head = list->tail = NULL;
+}
+
+static struct packfile_list_entry *packfile_list_remove_internal(struct packfile_list *list,
+ struct packed_git *pack)
+{
+ struct packfile_list_entry *e, *prev;
+
+ for (e = list->head, prev = NULL; e; prev = e, e = e->next) {
+ if (e->pack != pack)
+ continue;
+
+ if (prev)
+ prev->next = e->next;
+ if (list->head == e)
+ list->head = e->next;
+ if (list->tail == e)
+ list->tail = prev;
+
+ return e;
+ }
+
+ return NULL;
+}
+
+void packfile_list_remove(struct packfile_list *list, struct packed_git *pack)
+{
+ free(packfile_list_remove_internal(list, pack));
+}
+
+void packfile_list_prepend(struct packfile_list *list, struct packed_git *pack)
+{
+ struct packfile_list_entry *entry;
+
+ entry = packfile_list_remove_internal(list, pack);
+ if (!entry) {
+ entry = xmalloc(sizeof(*entry));
+ entry->pack = pack;
+ }
+ entry->next = list->head;
+
+ list->head = entry;
+ if (!list->tail)
+ list->tail = entry;
+}
+
+void packfile_list_append(struct packfile_list *list, struct packed_git *pack)
+{
+ struct packfile_list_entry *entry;
+
+ entry = packfile_list_remove_internal(list, pack);
+ if (!entry) {
+ entry = xmalloc(sizeof(*entry));
+ entry->pack = pack;
+ }
+ entry->next = NULL;
+
+ if (list->tail) {
+ list->tail->next = entry;
+ list->tail = entry;
+ } else {
+ list->head = list->tail = entry;
+ }
+}
+
+struct packed_git *packfile_list_find_oid(struct packfile_list_entry *packs,
+ const struct object_id *oid)
+{
+ for (; packs; packs = packs->next)
+ if (find_pack_entry_one(oid, packs->pack))
+ return packs->pack;
+ return NULL;
+}
+
void pack_report(struct repository *repo)
{
fprintf(stderr,
@@ -273,13 +356,14 @@ static void scan_windows(struct packed_git *p,
static int unuse_one_window(struct packed_git *current)
{
- struct packed_git *p, *lru_p = NULL;
+ struct packfile_list_entry *e;
+ struct packed_git *lru_p = NULL;
struct pack_window *lru_w = NULL, *lru_l = NULL;
if (current)
scan_windows(current, &lru_p, &lru_w, &lru_l);
- for (p = current->repo->objects->packfiles->packs; p; p = p->next)
- scan_windows(p, &lru_p, &lru_w, &lru_l);
+ for (e = current->repo->objects->packfiles->packs.head; e; e = e->next)
+ scan_windows(e->pack, &lru_p, &lru_w, &lru_l);
if (lru_p) {
munmap(lru_w->base, lru_w->len);
pack_mapped -= lru_w->len;
@@ -459,14 +543,15 @@ static void find_lru_pack(struct packed_git *p, struct packed_git **lru_p, struc
static int close_one_pack(struct repository *r)
{
- struct packed_git *p, *lru_p = NULL;
+ struct packfile_list_entry *e;
+ struct packed_git *lru_p = NULL;
struct pack_window *mru_w = NULL;
int accept_windows_inuse = 1;
- for (p = r->objects->packfiles->packs; p; p = p->next) {
- if (p->pack_fd == -1)
+ for (e = r->objects->packfiles->packs.head; e; e = e->next) {
+ if (e->pack->pack_fd == -1)
continue;
- find_lru_pack(p, &lru_p, &mru_w, &accept_windows_inuse);
+ find_lru_pack(e->pack, &lru_p, &mru_w, &accept_windows_inuse);
}
if (lru_p)
@@ -785,11 +870,8 @@ void packfile_store_add_pack(struct packfile_store *store,
if (pack->pack_fd != -1)
pack_open_fds++;
- pack->next = store->packs;
- store->packs = pack;
-
- hashmap_entry_init(&pack->packmap_ent, strhash(pack->pack_name));
- hashmap_add(&store->map, &pack->packmap_ent);
+ packfile_list_append(&store->packs, pack);
+ strmap_put(&store->packs_by_path, pack->pack_name, pack);
}
struct packed_git *packfile_store_load_pack(struct packfile_store *store,
@@ -806,8 +888,7 @@ struct packed_git *packfile_store_load_pack(struct packfile_store *store,
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);
+ p = strmap_get(&store->packs_by_path, key.buf);
if (!p) {
p = add_packed_git(store->odb->repo, idx_path,
strlen(idx_path), local);
@@ -965,9 +1046,10 @@ static void prepare_packed_git_one(struct odb_source *source)
string_list_clear(data.garbage, 0);
}
-DEFINE_LIST_SORT(static, sort_packs, struct packed_git, next);
+DEFINE_LIST_SORT(static, sort_packs, struct packfile_list_entry, next);
-static int sort_pack(const struct packed_git *a, const struct packed_git *b)
+static int sort_pack(const struct packfile_list_entry *a,
+ const struct packfile_list_entry *b)
{
int st;
@@ -977,7 +1059,7 @@ static int sort_pack(const struct packed_git *a, const struct packed_git *b)
* remote ones could be on a network mounted filesystem.
* Favor local ones for these reasons.
*/
- st = a->pack_local - b->pack_local;
+ st = a->pack->pack_local - b->pack->pack_local;
if (st)
return -st;
@@ -986,23 +1068,13 @@ static int sort_pack(const struct packed_git *a, const struct packed_git *b)
* and more recent objects tend to get accessed more
* often.
*/
- if (a->mtime < b->mtime)
+ if (a->pack->mtime < b->pack->mtime)
return 1;
- else if (a->mtime == b->mtime)
+ else if (a->pack->mtime == b->pack->mtime)
return 0;
return -1;
}
-static void packfile_store_prepare_mru(struct packfile_store *store)
-{
- struct packed_git *p;
-
- INIT_LIST_HEAD(&store->mru);
-
- for (p = store->packs; p; p = p->next)
- list_add_tail(&p->mru, &store->mru);
-}
-
void packfile_store_prepare(struct packfile_store *store)
{
struct odb_source *source;
@@ -1015,9 +1087,12 @@ void packfile_store_prepare(struct packfile_store *store)
prepare_multi_pack_index_one(source);
prepare_packed_git_one(source);
}
- sort_packs(&store->packs, sort_pack);
- packfile_store_prepare_mru(store);
+ sort_packs(&store->packs.head, sort_pack);
+ for (struct packfile_list_entry *e = store->packs.head; e; e = e->next)
+ if (!e->next)
+ store->packs.tail = e;
+
store->initialized = true;
}
@@ -1027,7 +1102,7 @@ void packfile_store_reprepare(struct packfile_store *store)
packfile_store_prepare(store);
}
-struct packed_git *packfile_store_get_packs(struct packfile_store *store)
+struct packfile_list_entry *packfile_store_get_packs(struct packfile_store *store)
{
packfile_store_prepare(store);
@@ -1039,13 +1114,7 @@ struct packed_git *packfile_store_get_packs(struct packfile_store *store)
prepare_midx_pack(m, i);
}
- return store->packs;
-}
-
-struct list_head *packfile_store_get_packs_mru(struct packfile_store *store)
-{
- packfile_store_prepare(store);
- return &store->mru;
+ return store->packs.head;
}
/*
@@ -1062,16 +1131,16 @@ unsigned long repo_approximate_object_count(struct repository *r)
unsigned long count = 0;
struct packed_git *p;
- packfile_store_prepare(r->objects->packfiles);
+ odb_prepare_alternates(r->objects);
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;
+ count += m->num_objects + m->num_objects_in_base;
}
- for (p = r->objects->packfiles->packs; p; p = p->next) {
- if (open_pack_index(p))
+ repo_for_each_pack(r, p) {
+ if (p->multi_pack_index || open_pack_index(p))
continue;
count += p->num_objects;
}
@@ -1195,11 +1264,11 @@ void mark_bad_packed_object(struct packed_git *p, const struct object_id *oid)
const struct packed_git *has_packed_and_bad(struct repository *r,
const struct object_id *oid)
{
- struct packed_git *p;
+ struct packfile_list_entry *e;
- for (p = r->objects->packfiles->packs; p; p = p->next)
- if (oidset_contains(&p->bad_objects, oid))
- return p;
+ for (e = r->objects->packfiles->packs.head; e; e = e->next)
+ if (oidset_contains(&e->pack->bad_objects, oid))
+ return e->pack;
return NULL;
}
@@ -2007,19 +2076,6 @@ int is_pack_valid(struct packed_git *p)
return !open_packed_git(p);
}
-struct packed_git *find_oid_pack(const struct object_id *oid,
- struct packed_git *packs)
-{
- struct packed_git *p;
-
- for (p = packs; p; p = p->next) {
- if (find_pack_entry_one(oid, p))
- return p;
- }
- return NULL;
-
-}
-
static int fill_pack_entry(const struct object_id *oid,
struct pack_entry *e,
struct packed_git *p)
@@ -2050,7 +2106,7 @@ static int fill_pack_entry(const struct object_id *oid,
int find_pack_entry(struct repository *r, const struct object_id *oid, struct pack_entry *e)
{
- struct list_head *pos;
+ struct packfile_list_entry *l;
packfile_store_prepare(r->objects->packfiles);
@@ -2058,13 +2114,15 @@ int find_pack_entry(struct repository *r, const struct object_id *oid, struct pa
if (source->midx && fill_midx_entry(source->midx, oid, e))
return 1;
- if (!r->objects->packfiles->packs)
+ if (!r->objects->packfiles->packs.head)
return 0;
- list_for_each(pos, &r->objects->packfiles->mru) {
- struct packed_git *p = list_entry(pos, struct packed_git, mru);
+ for (l = r->objects->packfiles->packs.head; l; l = l->next) {
+ struct packed_git *p = l->pack;
+
if (!p->multi_pack_index && fill_pack_entry(oid, e, p)) {
- list_move(&p->mru, &r->objects->packfiles->mru);
+ if (!r->objects->packfiles->skip_mru_updates)
+ packfile_list_prepend(&r->objects->packfiles->packs, p);
return 1;
}
}
@@ -2196,6 +2254,7 @@ int for_each_packed_object(struct repository *repo, each_packed_object_fn cb,
int r = 0;
int pack_errors = 0;
+ repo->objects->packfiles->skip_mru_updates = true;
repo_for_each_pack(repo, p) {
if ((flags & FOR_EACH_OBJECT_LOCAL_ONLY) && !p->pack_local)
continue;
@@ -2216,6 +2275,8 @@ int for_each_packed_object(struct repository *repo, each_packed_object_fn cb,
if (r)
break;
}
+ repo->objects->packfiles->skip_mru_updates = false;
+
return r ? r : pack_errors;
}
@@ -2311,45 +2372,30 @@ int parse_pack_header_option(const char *in, unsigned char *out, unsigned int *l
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);
+ strmap_init(&store->packs_by_path);
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);
+ for (struct packfile_list_entry *e = store->packs.head; e; e = e->next)
+ free(e->pack);
+ packfile_list_clear(&store->packs);
+
+ strmap_clear(&store->packs_by_path, 0);
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)
+ for (struct packfile_list_entry *e = store->packs.head; e; e = e->next) {
+ if (e->pack->do_not_close)
BUG("want to close pack marked 'do-not-close'");
- close_pack(p);
+ close_pack(e->pack);
}
}
diff --git a/packfile.h b/packfile.h
index c9d0b93446..27ba607e7c 100644
--- a/packfile.h
+++ b/packfile.h
@@ -5,14 +5,12 @@
#include "object.h"
#include "odb.h"
#include "oidset.h"
+#include "strmap.h"
/* in odb.h */
struct object_info;
struct packed_git {
- struct hashmap_entry packmap_ent;
- struct packed_git *next;
- struct list_head mru;
struct pack_window *windows;
off_t pack_size;
const void *index_data;
@@ -52,6 +50,28 @@ struct packed_git {
char pack_name[FLEX_ARRAY]; /* more */
};
+struct packfile_list {
+ struct packfile_list_entry *head, *tail;
+};
+
+struct packfile_list_entry {
+ struct packfile_list_entry *next;
+ struct packed_git *pack;
+};
+
+void packfile_list_clear(struct packfile_list *list);
+void packfile_list_remove(struct packfile_list *list, struct packed_git *pack);
+void packfile_list_prepend(struct packfile_list *list, struct packed_git *pack);
+void packfile_list_append(struct packfile_list *list, struct packed_git *pack);
+
+/*
+ * Find the pack within the "packs" list whose index contains the object
+ * "oid". For general object lookups, you probably don't want this; use
+ * find_pack_entry() instead.
+ */
+struct packed_git *packfile_list_find_oid(struct packfile_list_entry *packs,
+ const struct object_id *oid);
+
/*
* A store that manages packfiles for a given object database.
*/
@@ -59,10 +79,10 @@ struct packfile_store {
struct object_database *odb;
/*
- * The list of packfiles in the order in which they are being added to
- * the store.
+ * The list of packfiles in the order in which they have been most
+ * recently used.
*/
- struct packed_git *packs;
+ struct packfile_list packs;
/*
* Cache of packfiles which are marked as "kept", either because there
@@ -78,20 +98,32 @@ struct packfile_store {
unsigned flags;
} kept_cache;
- /* A most-recently-used ordered version of the packs list. */
- struct list_head mru;
-
/*
* A map of packfile names to packed_git structs for tracking which
* packs have been loaded already.
*/
- struct hashmap map;
+ struct strmap packs_by_path;
/*
* Whether packfiles have already been populated with this store's
* packs.
*/
bool initialized;
+
+ /*
+ * Usually, packfiles will be reordered to the front of the `packs`
+ * list whenever an object is looked up via them. This has the effect
+ * that packs that contain a lot of accessed objects will be located
+ * towards the front.
+ *
+ * This is usually desireable, but there are exceptions. One exception
+ * is when the looking up multiple objects in a loop for each packfile.
+ * In that case, we may easily end up with an infinite loop as the
+ * packfiles get reordered to the front repeatedly.
+ *
+ * Setting this field to `true` thus disables these reorderings.
+ */
+ bool skip_mru_updates;
};
/*
@@ -142,18 +174,14 @@ void packfile_store_add_pack(struct packfile_store *store,
* repository.
*/
#define repo_for_each_pack(repo, p) \
- for (p = packfile_store_get_packs(repo->objects->packfiles); p; p = p->next)
+ for (struct packfile_list_entry *e = packfile_store_get_packs(repo->objects->packfiles); \
+ ((p) = (e ? e->pack : NULL)); e = e->next)
/*
* Get all packs managed by the given store, including packfiles that are
* referenced by multi-pack indices.
*/
-struct packed_git *packfile_store_get_packs(struct packfile_store *store);
-
-/*
- * Get all packs in most-recently-used order.
- */
-struct list_head *packfile_store_get_packs_mru(struct packfile_store *store);
+struct packfile_list_entry *packfile_store_get_packs(struct packfile_store *store);
/*
* Open the packfile and add it to the store if it isn't yet known. Returns
@@ -245,14 +273,6 @@ extern void (*report_garbage)(unsigned seen_bits, const char *path);
*/
unsigned long repo_approximate_object_count(struct repository *r);
-/*
- * Find the pack within the "packs" list whose index contains the object "oid".
- * For general object lookups, you probably don't want this; use
- * find_pack_entry() instead.
- */
-struct packed_git *find_oid_pack(const struct object_id *oid,
- struct packed_git *packs);
-
void pack_report(struct repository *repo);
/*