Merge branch 'ps/packed-git-in-object-store'
The list of packfiles used in a running Git process is moved from the packed_git structure into the packfile store. * ps/packed-git-in-object-store: packfile: track packs via the MRU list exclusively packfile: always add packfiles to MRU when adding a pack packfile: move list of packs into the packfile store builtin/pack-objects: simplify logic to find kept or nonlocal objects packfile: fix approximation of object counts http: refactor subsystem to use `packfile_list`s packfile: move the MRU list into the packfile store packfile: use a `strmap` to store packs by namemain
commit
7a75e549b2
|
|
@ -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! */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
21
http.c
21
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
5
http.h
5
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 {
|
||||
|
|
|
|||
2
midx.c
2
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) {
|
||||
|
|
|
|||
224
packfile.c
224
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
70
packfile.h
70
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);
|
||||
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue