Skip to content

Commit debed2a

Browse files
René Scharfegitster
authored andcommitted
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 <[email protected]> Signed-off-by: Rene Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 10b2a48 commit debed2a

File tree

2 files changed

+31
-51
lines changed

2 files changed

+31
-51
lines changed

cache.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,6 @@ struct index_state {
316316
struct string_list *resolve_undo;
317317
struct cache_tree *cache_tree;
318318
struct cache_time timestamp;
319-
void *alloc;
320319
unsigned name_hash_initialized : 1,
321320
initialized : 1;
322321
struct hash_table name_hash;

read-cache.c

Lines changed: 31 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,71 +1202,61 @@ int read_index(struct index_state *istate)
12021202
return read_index_from(istate, get_index_file());
12031203
}
12041204

1205-
static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_entry *ce)
1205+
static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk)
12061206
{
1207+
struct cache_entry *ce;
12071208
size_t len;
12081209
const char *name;
1210+
unsigned int flags;
12091211

1210-
ce->ce_ctime.sec = ntohl(ondisk->ctime.sec);
1211-
ce->ce_mtime.sec = ntohl(ondisk->mtime.sec);
1212-
ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec);
1213-
ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec);
1214-
ce->ce_dev = ntohl(ondisk->dev);
1215-
ce->ce_ino = ntohl(ondisk->ino);
1216-
ce->ce_mode = ntohl(ondisk->mode);
1217-
ce->ce_uid = ntohl(ondisk->uid);
1218-
ce->ce_gid = ntohl(ondisk->gid);
1219-
ce->ce_size = ntohl(ondisk->size);
12201212
/* On-disk flags are just 16 bits */
1221-
ce->ce_flags = ntohs(ondisk->flags);
1222-
1223-
hashcpy(ce->sha1, ondisk->sha1);
1213+
flags = ntohs(ondisk->flags);
1214+
len = flags & CE_NAMEMASK;
12241215

1225-
len = ce->ce_flags & CE_NAMEMASK;
1226-
1227-
if (ce->ce_flags & CE_EXTENDED) {
1216+
if (flags & CE_EXTENDED) {
12281217
struct ondisk_cache_entry_extended *ondisk2;
12291218
int extended_flags;
12301219
ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
12311220
extended_flags = ntohs(ondisk2->flags2) << 16;
12321221
/* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
12331222
if (extended_flags & ~CE_EXTENDED_FLAGS)
12341223
die("Unknown index entry format %08x", extended_flags);
1235-
ce->ce_flags |= extended_flags;
1224+
flags |= extended_flags;
12361225
name = ondisk2->name;
12371226
}
12381227
else
12391228
name = ondisk->name;
12401229

12411230
if (len == CE_NAMEMASK)
12421231
len = strlen(name);
1243-
/*
1244-
* NEEDSWORK: If the original index is crafted, this copy could
1245-
* go unchecked.
1246-
*/
1247-
memcpy(ce->name, name, len + 1);
1248-
}
12491232

1250-
static inline size_t estimate_cache_size(size_t ondisk_size, unsigned int entries)
1251-
{
1252-
long per_entry;
1233+
ce = xmalloc(cache_entry_size(len));
12531234

1254-
per_entry = sizeof(struct cache_entry) - sizeof(struct ondisk_cache_entry);
1235+
ce->ce_ctime.sec = ntohl(ondisk->ctime.sec);
1236+
ce->ce_mtime.sec = ntohl(ondisk->mtime.sec);
1237+
ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec);
1238+
ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec);
1239+
ce->ce_dev = ntohl(ondisk->dev);
1240+
ce->ce_ino = ntohl(ondisk->ino);
1241+
ce->ce_mode = ntohl(ondisk->mode);
1242+
ce->ce_uid = ntohl(ondisk->uid);
1243+
ce->ce_gid = ntohl(ondisk->gid);
1244+
ce->ce_size = ntohl(ondisk->size);
1245+
ce->ce_flags = flags;
12551246

1256-
/*
1257-
* Alignment can cause differences. This should be "alignof", but
1258-
* since that's a gcc'ism, just use the size of a pointer.
1259-
*/
1260-
per_entry += sizeof(void *);
1261-
return ondisk_size + entries*per_entry;
1247+
hashcpy(ce->sha1, ondisk->sha1);
1248+
1249+
memcpy(ce->name, name, len);
1250+
ce->name[len] = '\0';
1251+
return ce;
12621252
}
12631253

12641254
/* remember to discard_cache() before reading a different cache! */
12651255
int read_index_from(struct index_state *istate, const char *path)
12661256
{
12671257
int fd, i;
12681258
struct stat st;
1269-
unsigned long src_offset, dst_offset;
1259+
unsigned long src_offset;
12701260
struct cache_header *hdr;
12711261
void *mmap;
12721262
size_t mmap_size;
@@ -1305,29 +1295,18 @@ int read_index_from(struct index_state *istate, const char *path)
13051295
istate->cache_nr = ntohl(hdr->hdr_entries);
13061296
istate->cache_alloc = alloc_nr(istate->cache_nr);
13071297
istate->cache = xcalloc(istate->cache_alloc, sizeof(struct cache_entry *));
1308-
1309-
/*
1310-
* The disk format is actually larger than the in-memory format,
1311-
* due to space for nsec etc, so even though the in-memory one
1312-
* has room for a few more flags, we can allocate using the same
1313-
* index size
1314-
*/
1315-
istate->alloc = xmalloc(estimate_cache_size(mmap_size, istate->cache_nr));
13161298
istate->initialized = 1;
13171299

13181300
src_offset = sizeof(*hdr);
1319-
dst_offset = 0;
13201301
for (i = 0; i < istate->cache_nr; i++) {
13211302
struct ondisk_cache_entry *disk_ce;
13221303
struct cache_entry *ce;
13231304

13241305
disk_ce = (struct ondisk_cache_entry *)((char *)mmap + src_offset);
1325-
ce = (struct cache_entry *)((char *)istate->alloc + dst_offset);
1326-
convert_from_disk(disk_ce, ce);
1306+
ce = create_from_disk(disk_ce);
13271307
set_index_entry(istate, i, ce);
13281308

13291309
src_offset += ondisk_ce_size(ce);
1330-
dst_offset += ce_size(ce);
13311310
}
13321311
istate->timestamp.sec = st.st_mtime;
13331312
istate->timestamp.nsec = ST_MTIME_NSEC(st);
@@ -1361,11 +1340,15 @@ int read_index_from(struct index_state *istate, const char *path)
13611340

13621341
int is_index_unborn(struct index_state *istate)
13631342
{
1364-
return (!istate->cache_nr && !istate->alloc && !istate->timestamp.sec);
1343+
return (!istate->cache_nr && !istate->timestamp.sec);
13651344
}
13661345

13671346
int discard_index(struct index_state *istate)
13681347
{
1348+
int i;
1349+
1350+
for (i = 0; i < istate->cache_nr; i++)
1351+
free(istate->cache[i]);
13691352
resolve_undo_clear_index(istate);
13701353
istate->cache_nr = 0;
13711354
istate->cache_changed = 0;
@@ -1374,8 +1357,6 @@ int discard_index(struct index_state *istate)
13741357
istate->name_hash_initialized = 0;
13751358
free_hash(&istate->name_hash);
13761359
cache_tree_free(&(istate->cache_tree));
1377-
free(istate->alloc);
1378-
istate->alloc = NULL;
13791360
istate->initialized = 0;
13801361

13811362
/* no need to throw away allocated active_cache */

0 commit comments

Comments
 (0)