summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRené Scharfe <rene.scharfe@lsrfire.ath.cx>2011-10-24 21:59:14 (GMT)
committerJunio C Hamano <gitster@pobox.com>2011-10-26 22:25:59 (GMT)
commitdebed2a6291a29fd7b0e96f63fbf0142ed3280eb (patch)
tree89aac247843d0ca266dcf854bf656976189281f8
parent10b2a48113b8ab6b8f48229eb40fc3637ce025ae (diff)
downloadgit-debed2a6291a29fd7b0e96f63fbf0142ed3280eb.zip
git-debed2a6291a29fd7b0e96f63fbf0142ed3280eb.tar.gz
git-debed2a6291a29fd7b0e96f63fbf0142ed3280eb.tar.bz2
read-cache.c: allocate index entries individually
The code to estimate the in-memory size of the index based on its on-disk representation is subtly wrong for certain architecture-dependent struct layouts. Instead of fixing it, replace the code to keep the index entries in a single large block of memory and allocate each entry separately instead. This is both simpler and more flexible, as individual entries can now be freed. Actually using that added flexibility is left for a later patch. Suggested-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--cache.h1
-rw-r--r--read-cache.c81
2 files changed, 31 insertions, 51 deletions
diff --git a/cache.h b/cache.h
index 2e6ad36..59840a4 100644
--- a/cache.h
+++ b/cache.h
@@ -316,7 +316,6 @@ struct index_state {
struct string_list *resolve_undo;
struct cache_tree *cache_tree;
struct cache_time timestamp;
- void *alloc;
unsigned name_hash_initialized : 1,
initialized : 1;
struct hash_table name_hash;
diff --git a/read-cache.c b/read-cache.c
index 01a0e25..dea7cd8 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -1202,29 +1202,18 @@ int read_index(struct index_state *istate)
return read_index_from(istate, get_index_file());
}
-static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_entry *ce)
+static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk)
{
+ struct cache_entry *ce;
size_t len;
const char *name;
+ unsigned int flags;
- ce->ce_ctime.sec = ntohl(ondisk->ctime.sec);
- ce->ce_mtime.sec = ntohl(ondisk->mtime.sec);
- ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec);
- ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec);
- ce->ce_dev = ntohl(ondisk->dev);
- ce->ce_ino = ntohl(ondisk->ino);
- ce->ce_mode = ntohl(ondisk->mode);
- ce->ce_uid = ntohl(ondisk->uid);
- ce->ce_gid = ntohl(ondisk->gid);
- ce->ce_size = ntohl(ondisk->size);
/* On-disk flags are just 16 bits */
- ce->ce_flags = ntohs(ondisk->flags);
-
- hashcpy(ce->sha1, ondisk->sha1);
+ flags = ntohs(ondisk->flags);
+ len = flags & CE_NAMEMASK;
- len = ce->ce_flags & CE_NAMEMASK;
-
- if (ce->ce_flags & CE_EXTENDED) {
+ if (flags & CE_EXTENDED) {
struct ondisk_cache_entry_extended *ondisk2;
int extended_flags;
ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
@@ -1232,7 +1221,7 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
/* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
if (extended_flags & ~CE_EXTENDED_FLAGS)
die("Unknown index entry format %08x", extended_flags);
- ce->ce_flags |= extended_flags;
+ flags |= extended_flags;
name = ondisk2->name;
}
else
@@ -1240,25 +1229,26 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
if (len == CE_NAMEMASK)
len = strlen(name);
- /*
- * NEEDSWORK: If the original index is crafted, this copy could
- * go unchecked.
- */
- memcpy(ce->name, name, len + 1);
-}
-static inline size_t estimate_cache_size(size_t ondisk_size, unsigned int entries)
-{
- long per_entry;
+ ce = xmalloc(cache_entry_size(len));
- per_entry = sizeof(struct cache_entry) - sizeof(struct ondisk_cache_entry);
+ ce->ce_ctime.sec = ntohl(ondisk->ctime.sec);
+ ce->ce_mtime.sec = ntohl(ondisk->mtime.sec);
+ ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec);
+ ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec);
+ ce->ce_dev = ntohl(ondisk->dev);
+ ce->ce_ino = ntohl(ondisk->ino);
+ ce->ce_mode = ntohl(ondisk->mode);
+ ce->ce_uid = ntohl(ondisk->uid);
+ ce->ce_gid = ntohl(ondisk->gid);
+ ce->ce_size = ntohl(ondisk->size);
+ ce->ce_flags = flags;
- /*
- * Alignment can cause differences. This should be "alignof", but
- * since that's a gcc'ism, just use the size of a pointer.
- */
- per_entry += sizeof(void *);
- return ondisk_size + entries*per_entry;
+ hashcpy(ce->sha1, ondisk->sha1);
+
+ memcpy(ce->name, name, len);
+ ce->name[len] = '\0';
+ return ce;
}
/* remember to discard_cache() before reading a different cache! */
@@ -1266,7 +1256,7 @@ int read_index_from(struct index_state *istate, const char *path)
{
int fd, i;
struct stat st;
- unsigned long src_offset, dst_offset;
+ unsigned long src_offset;
struct cache_header *hdr;
void *mmap;
size_t mmap_size;
@@ -1305,29 +1295,18 @@ int read_index_from(struct index_state *istate, const char *path)
istate->cache_nr = ntohl(hdr->hdr_entries);
istate->cache_alloc = alloc_nr(istate->cache_nr);
istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *));
-
- /*
- * The disk format is actually larger than the in-memory format,
- * due to space for nsec etc, so even though the in-memory one
- * has room for a few more flags, we can allocate using the same
- * index size
- */
- istate->alloc = xmalloc(estimate_cache_size(mmap_size, istate->cache_nr));
istate->initialized = 1;
src_offset = sizeof(*hdr);
- dst_offset = 0;
for (i = 0; i < istate->cache_nr; i++) {
struct ondisk_cache_entry *disk_ce;
struct cache_entry *ce;
disk_ce = (struct ondisk_cache_entry *)((char *)mmap + src_offset);
- ce = (struct cache_entry *)((char *)istate->alloc + dst_offset);
- convert_from_disk(disk_ce, ce);
+ ce = create_from_disk(disk_ce);
set_index_entry(istate, i, ce);
src_offset += ondisk_ce_size(ce);
- dst_offset += ce_size(ce);
}
istate->timestamp.sec = st.st_mtime;
istate->timestamp.nsec = ST_MTIME_NSEC(st);
@@ -1361,11 +1340,15 @@ unmap:
int is_index_unborn(struct index_state *istate)
{
- return (!istate->cache_nr && !istate->alloc && !istate->timestamp.sec);
+ return (!istate->cache_nr && !istate->timestamp.sec);
}
int discard_index(struct index_state *istate)
{
+ int i;
+
+ for (i = 0; i < istate->cache_nr; i++)
+ free(istate->cache[i]);
resolve_undo_clear_index(istate);
istate->cache_nr = 0;
istate->cache_changed = 0;
@@ -1374,8 +1357,6 @@ int discard_index(struct index_state *istate)
istate->name_hash_initialized = 0;
free_hash(&istate->name_hash);
cache_tree_free(&(istate->cache_tree));
- free(istate->alloc);
- istate->alloc = NULL;
istate->initialized = 0;
/* no need to throw away allocated active_cache */