Skip to content

Commit

Permalink
Refactor packed_git to prepare for sliding mmap windows.
Browse files Browse the repository at this point in the history
The idea behind the sliding mmap window pack reader implementation
is to have multiple mmap regions active against the same pack file,
thereby allowing the process to mmap in only the active/hot sections
of the pack and reduce overall virtual address space usage.

To implement this we need to refactor the mmap related data
(pack_base, pack_use_cnt) out of struct packed_git and move them
into a new struct pack_window.

We are refactoring the code to support a single struct pack_window
per packfile, thereby emulating the prior behavior of mmap'ing the
entire pack file.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
  • Loading branch information
Shawn O. Pearce authored and Junio C Hamano committed Dec 29, 2006
1 parent 77ccc5b commit c41ee58
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 34 deletions.
4 changes: 2 additions & 2 deletions builtin-pack-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -438,7 +438,7 @@ static unsigned long write_object(struct sha1file *f,
}

use_packed_git(p);
buf = (char *) p->pack_base
buf = p->windows->base
+ entry->in_pack_offset
+ entry->in_pack_header_size;
datalen = find_packed_object_size(p, entry->in_pack_offset)
Expand Down Expand Up @@ -943,7 +943,7 @@ static void check_object(struct object_entry *entry)
struct object_entry *base_entry = NULL;

use_packed_git(p);
buf = p->pack_base;
buf = p->windows->base;
buf += entry->in_pack_offset;

/* We want in_pack_type even if we do not reuse delta.
Expand Down
13 changes: 10 additions & 3 deletions cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,14 +336,21 @@ extern struct alternate_object_database {
} *alt_odb_list;
extern void prepare_alt_odb(void);

struct pack_window {
struct pack_window *next;
unsigned char *base;
off_t offset;
size_t len;
unsigned int last_used;
unsigned int inuse_cnt;
};

extern struct packed_git {
struct packed_git *next;
unsigned long index_size;
unsigned long pack_size;
struct pack_window *windows;
unsigned int *index_base;
void *pack_base;
unsigned int pack_last_used;
unsigned int pack_use_cnt;
int pack_local;
unsigned char sha1[20];
/* something like ".git/objects/pack/xxxxx.pack" */
Expand Down
6 changes: 3 additions & 3 deletions pack-check.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ static int verify_packfile(struct packed_git *p)
int nr_objects, err, i;

/* Header consistency check */
hdr = p->pack_base;
pack_base = p->windows->base;
hdr = (struct pack_header*)pack_base;
if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
return error("Packfile %s signature mismatch", p->pack_name);
if (!pack_version_ok(hdr->hdr_version))
Expand All @@ -26,7 +27,6 @@ static int verify_packfile(struct packed_git *p)
num_packed_objects(p));

SHA1_Init(&ctx);
pack_base = p->pack_base;
SHA1_Update(&ctx, pack_base, pack_size - 20);
SHA1_Final(sha1, &ctx);
if (hashcmp(sha1, (unsigned char *)pack_base + pack_size - 20))
Expand Down Expand Up @@ -78,7 +78,7 @@ static void show_pack_info(struct packed_git *p)
int nr_objects, i;
unsigned int chain_histogram[MAX_CHAIN];

hdr = p->pack_base;
hdr = (struct pack_header*)p->windows->base;
nr_objects = ntohl(hdr->hdr_entries);
memset(chain_histogram, 0, sizeof(chain_histogram));

Expand Down
51 changes: 25 additions & 26 deletions sha1_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -455,21 +455,23 @@ static int unuse_one_packed_git(void)
struct packed_git *p, *lru = NULL;

for (p = packed_git; p; p = p->next) {
if (p->pack_use_cnt || !p->pack_base)
if (!p->windows || p->windows->inuse_cnt)
continue;
if (!lru || p->pack_last_used < lru->pack_last_used)
if (!lru || p->windows->last_used < lru->windows->last_used)
lru = p;
}
if (!lru)
return 0;
munmap(lru->pack_base, lru->pack_size);
lru->pack_base = NULL;
munmap(lru->windows->base, lru->windows->len);
free(lru->windows);
lru->windows = NULL;
return 1;
}

void unuse_packed_git(struct packed_git *p)
{
p->pack_use_cnt--;
if (p->windows)
p->windows->inuse_cnt--;
}

int use_packed_git(struct packed_git *p)
Expand All @@ -482,10 +484,10 @@ int use_packed_git(struct packed_git *p)
die("packfile %s not a regular file", p->pack_name);
p->pack_size = st.st_size;
}
if (!p->pack_base) {
if (!p->windows) {
int fd;
struct stat st;
void *map;
struct pack_window *win;
struct pack_header *hdr;

pack_mapped += p->pack_size;
Expand All @@ -500,16 +502,18 @@ int use_packed_git(struct packed_git *p)
}
if (st.st_size != p->pack_size)
die("packfile %s size mismatch.", p->pack_name);
map = mmap(NULL, p->pack_size, PROT_READ, MAP_PRIVATE, fd, 0);
win = xcalloc(1, sizeof(*win));
win->len = p->pack_size;
win->base = mmap(NULL, p->pack_size, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd);
if (map == MAP_FAILED)
if (win->base == MAP_FAILED)
die("packfile %s cannot be mapped.", p->pack_name);
p->pack_base = map;
p->windows = win;

/* Check if we understand this pack file. If we don't we're
* likely too old to handle it.
*/
hdr = map;
hdr = (struct pack_header*)win->base;
if (hdr->hdr_signature != htonl(PACK_SIGNATURE))
die("packfile %s isn't actually a pack.", p->pack_name);
if (!pack_version_ok(hdr->hdr_version))
Expand All @@ -522,13 +526,13 @@ int use_packed_git(struct packed_git *p)
*/
if (hashcmp((unsigned char *)(p->index_base) +
p->index_size - 40,
(unsigned char *)p->pack_base +
p->windows->base +
p->pack_size - 20)) {
die("packfile %s does not match index.", p->pack_name);
}
}
p->pack_last_used = pack_used_ctr++;
p->pack_use_cnt++;
p->windows->last_used = pack_used_ctr++;
p->windows->inuse_cnt++;
return 0;
}

Expand Down Expand Up @@ -558,9 +562,7 @@ struct packed_git *add_packed_git(char *path, int path_len, int local)
p->pack_size = st.st_size;
p->index_base = idx_map;
p->next = NULL;
p->pack_base = NULL;
p->pack_last_used = 0;
p->pack_use_cnt = 0;
p->windows = NULL;
p->pack_local = local;
if ((path_len > 44) && !get_sha1_hex(path + path_len - 44, sha1))
hashcpy(p->sha1, sha1);
Expand Down Expand Up @@ -591,9 +593,7 @@ struct packed_git *parse_pack_index_file(const unsigned char *sha1, char *idx_pa
p->pack_size = 0;
p->index_base = idx_map;
p->next = NULL;
p->pack_base = NULL;
p->pack_last_used = 0;
p->pack_use_cnt = 0;
p->windows = NULL;
hashcpy(p->sha1, sha1);
return p;
}
Expand Down Expand Up @@ -882,7 +882,7 @@ static unsigned long get_delta_base(struct packed_git *p,
unsigned long delta_obj_offset,
unsigned long *base_obj_offset)
{
unsigned char *base_info = (unsigned char *) p->pack_base + offset;
unsigned char *base_info = p->windows->base + offset;
unsigned long base_offset;

/* there must be at least 20 bytes left regardless of delta type */
Expand Down Expand Up @@ -949,7 +949,7 @@ static int packed_delta_info(struct packed_git *p,

memset(&stream, 0, sizeof(stream));

stream.next_in = (unsigned char *) p->pack_base + offset;
stream.next_in = p->windows->base + offset;
stream.avail_in = p->pack_size - offset;
stream.next_out = delta_head;
stream.avail_out = sizeof(delta_head);
Expand Down Expand Up @@ -984,8 +984,7 @@ static unsigned long unpack_object_header(struct packed_git *p, unsigned long of
if (p->pack_size <= offset)
die("object offset outside of pack file");

used = unpack_object_header_gently((unsigned char *)p->pack_base +
offset,
used = unpack_object_header_gently(p->windows->base + offset,
p->pack_size - offset, type, sizep);
if (!used)
die("object offset outside of pack file");
Expand Down Expand Up @@ -1031,7 +1030,7 @@ void packed_object_info_detail(struct packed_git *p,
if (p->pack_size <= offset + 20)
die("pack file %s records an incomplete delta base",
p->pack_name);
next_sha1 = (unsigned char *) p->pack_base + offset;
next_sha1 = p->windows->base + offset;
if (*delta_chain_length == 0)
hashcpy(base_sha1, next_sha1);
offset = find_pack_entry_one(next_sha1, p);
Expand Down Expand Up @@ -1081,7 +1080,7 @@ static void *unpack_compressed_entry(struct packed_git *p,
buffer = xmalloc(size + 1);
buffer[size] = 0;
memset(&stream, 0, sizeof(stream));
stream.next_in = (unsigned char*)p->pack_base + offset;
stream.next_in = p->windows->base + offset;
stream.avail_in = p->pack_size - offset;
stream.next_out = buffer;
stream.avail_out = size;
Expand Down

0 comments on commit c41ee58

Please sign in to comment.