Skip to content

Commit ce012de

Browse files
Kevin Willfordgitster
authored andcommitted
read-cache: avoid allocating every ondisk entry when writing
When writing the index for each entry an ondisk struct will be allocated and freed in ce_write_entry. We can do better by using a ondisk struct on the stack for each entry. This is accomplished by using a stack ondisk_cache_entry_extended outside looping through the entries in do_write_index. Only the fixed fields of this struct are used when writing and depending on whether it is extended or not the flags2 field will be written. The name field is not used and instead the cache_entry name field is used directly when writing out the name. Because ce_write is using a buffer and memcpy to fill the buffer before flushing to disk, we don't have to worry about doing multiple ce_write calls. Running the p0007-write-cache.sh tests would save anywhere between 3-7% when the index had over a million entries with no performance degradation on small repos. Signed-off-by: Kevin Willford <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b50386c commit ce012de

File tree

1 file changed

+25
-25
lines changed

1 file changed

+25
-25
lines changed

read-cache.c

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,7 @@ struct ondisk_cache_entry_extended {
14991499
};
15001500

15011501
/* These are only used for v3 or lower */
1502+
#define align_padding_size(size, len) ((size + (len) + 8) & ~7) - (size + len)
15021503
#define align_flex_name(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
15031504
#define ondisk_cache_entry_size(len) align_flex_name(ondisk_cache_entry,len)
15041505
#define ondisk_cache_entry_extended_size(len) align_flex_name(ondisk_cache_entry_extended,len)
@@ -2032,7 +2033,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
20322033
}
20332034

20342035
/* Copy miscellaneous fields but not the name */
2035-
static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
2036+
static void copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
20362037
struct cache_entry *ce)
20372038
{
20382039
short flags;
@@ -2056,32 +2057,35 @@ static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
20562057
struct ondisk_cache_entry_extended *ondisk2;
20572058
ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
20582059
ondisk2->flags2 = htons((ce->ce_flags & CE_EXTENDED_FLAGS) >> 16);
2059-
return ondisk2->name;
2060-
}
2061-
else {
2062-
return ondisk->name;
20632060
}
20642061
}
20652062

20662063
static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
2067-
struct strbuf *previous_name)
2064+
struct strbuf *previous_name, struct ondisk_cache_entry *ondisk)
20682065
{
20692066
int size;
2070-
struct ondisk_cache_entry *ondisk;
20712067
int saved_namelen = saved_namelen; /* compiler workaround */
2072-
char *name;
20732068
int result;
2069+
static unsigned char padding[8] = { 0x00 };
20742070

20752071
if (ce->ce_flags & CE_STRIP_NAME) {
20762072
saved_namelen = ce_namelen(ce);
20772073
ce->ce_namelen = 0;
20782074
}
20792075

2076+
if (ce->ce_flags & CE_EXTENDED)
2077+
size = offsetof(struct ondisk_cache_entry_extended, name);
2078+
else
2079+
size = offsetof(struct ondisk_cache_entry, name);
2080+
20802081
if (!previous_name) {
2081-
size = ondisk_ce_size(ce);
2082-
ondisk = xcalloc(1, size);
2083-
name = copy_cache_entry_to_ondisk(ondisk, ce);
2084-
memcpy(name, ce->name, ce_namelen(ce));
2082+
int len = ce_namelen(ce);
2083+
copy_cache_entry_to_ondisk(ondisk, ce);
2084+
result = ce_write(c, fd, ondisk, size);
2085+
if (!result)
2086+
result = ce_write(c, fd, ce->name, len);
2087+
if (!result)
2088+
result = ce_write(c, fd, padding, align_padding_size(size, len));
20852089
} else {
20862090
int common, to_remove, prefix_size;
20872091
unsigned char to_remove_vi[16];
@@ -2094,16 +2098,12 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
20942098
to_remove = previous_name->len - common;
20952099
prefix_size = encode_varint(to_remove, to_remove_vi);
20962100

2097-
if (ce->ce_flags & CE_EXTENDED)
2098-
size = offsetof(struct ondisk_cache_entry_extended, name);
2099-
else
2100-
size = offsetof(struct ondisk_cache_entry, name);
2101-
size += prefix_size + (ce_namelen(ce) - common + 1);
2102-
2103-
ondisk = xcalloc(1, size);
2104-
name = copy_cache_entry_to_ondisk(ondisk, ce);
2105-
memcpy(name, to_remove_vi, prefix_size);
2106-
memcpy(name + prefix_size, ce->name + common, ce_namelen(ce) - common);
2101+
copy_cache_entry_to_ondisk(ondisk, ce);
2102+
result = ce_write(c, fd, ondisk, size);
2103+
if (!result)
2104+
result = ce_write(c, fd, to_remove_vi, prefix_size);
2105+
if (!result)
2106+
result = ce_write(c, fd, ce->name + common, ce_namelen(ce) - common + 1);
21072107

21082108
strbuf_splice(previous_name, common, to_remove,
21092109
ce->name + common, ce_namelen(ce) - common);
@@ -2113,8 +2113,6 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
21132113
ce->ce_flags &= ~CE_STRIP_NAME;
21142114
}
21152115

2116-
result = ce_write(c, fd, ondisk, size);
2117-
free(ondisk);
21182116
return result;
21192117
}
21202118

@@ -2196,6 +2194,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
21962194
struct cache_entry **cache = istate->cache;
21972195
int entries = istate->cache_nr;
21982196
struct stat st;
2197+
struct ondisk_cache_entry_extended ondisk;
21992198
struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
22002199
int drop_cache_tree = 0;
22012200

@@ -2232,6 +2231,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
22322231
return -1;
22332232

22342233
previous_name = (hdr_version == 4) ? &previous_name_buf : NULL;
2234+
22352235
for (i = 0; i < entries; i++) {
22362236
struct cache_entry *ce = cache[i];
22372237
if (ce->ce_flags & CE_REMOVE)
@@ -2251,7 +2251,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
22512251

22522252
drop_cache_tree = 1;
22532253
}
2254-
if (ce_write_entry(&c, newfd, ce, previous_name) < 0)
2254+
if (ce_write_entry(&c, newfd, ce, previous_name, (struct ondisk_cache_entry *)&ondisk) < 0)
22552255
err = -1;
22562256

22572257
if (err)

0 commit comments

Comments
 (0)