diff options
author | lhchavez <lhchavez@lhchavez.com> | 2021-09-07 07:14:39 -0700 |
---|---|---|
committer | lhchavez <lhchavez@lhchavez.com> | 2021-09-07 07:14:39 -0700 |
commit | 66a75fdee622557346700bae8314ca4af166e0f9 (patch) | |
tree | 23a4a7fe0505a3c433339e4ef7852c1d621762f2 | |
parent | 109b4c887ffb63962c7017a66fc4a1f48becb48e (diff) | |
download | libgit2-66a75fdee622557346700bae8314ca4af166e0f9.tar.gz |
indexer: Avoid one `mmap(2)`/`munmap(2)` pair per `git_indexer_append` call
This change makes `append_to_pack` completely rely on `p_pwrite` to do
all its I/O instead of splitting it between `p_pwrite` and a
`mmap(2)`/`munmap(2)`+`memcpy(3)`. This saves a good chunk of user CPU
time and avoids making two syscalls per round, but doesn't really cut
down a lot of wall time (~1% on cloning the
[git](https://github.com/git/git.git) repository).
-rw-r--r-- | src/indexer.c | 49 |
1 files changed, 2 insertions, 47 deletions
diff --git a/src/indexer.c b/src/indexer.c index d546888cc..a5c282a24 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -603,7 +603,6 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size) static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size) { -#ifdef NO_MMAP size_t remaining_size = size; const char *ptr = (const char *)data; @@ -619,65 +618,21 @@ static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t s offset += nb; remaining_size -= nb; } -#else - git_file fd = idx->pack->mwf.fd; - size_t mmap_alignment; - size_t page_offset; - off64_t page_start; - unsigned char *map_data; - git_map map; - int error; - - GIT_ASSERT_ARG(data); - GIT_ASSERT_ARG(size); - - if ((error = git__mmap_alignment(&mmap_alignment)) < 0) - return error; - - /* the offset needs to be at the mmap boundary for the platform */ - page_offset = offset % mmap_alignment; - page_start = offset - page_offset; - - if ((error = p_mmap(&map, page_offset + size, GIT_PROT_WRITE, GIT_MAP_SHARED, fd, page_start)) < 0) - return error; - - map_data = (unsigned char *)map.data; - memcpy(map_data + page_offset, data, size); - p_munmap(&map); -#endif return 0; } static int append_to_pack(git_indexer *idx, const void *data, size_t size) { - off64_t new_size; - size_t mmap_alignment; - size_t page_offset; - off64_t page_start; - off64_t current_size = idx->pack->mwf.size; - int error; - if (!size) return 0; - if ((error = git__mmap_alignment(&mmap_alignment)) < 0) - return error; - - /* Write a single byte to force the file system to allocate space now or - * report an error, since we can't report errors when writing using mmap. - * Round the size up to the nearest page so that we only need to perform file - * I/O when we add a page, instead of whenever we write even a single byte. */ - new_size = current_size + size; - page_offset = new_size % mmap_alignment; - page_start = new_size - page_offset; - - if (p_pwrite(idx->pack->mwf.fd, data, 1, page_start + mmap_alignment - 1) < 0) { + if (write_at(idx, data, idx->pack->mwf.size, size) < 0) { git_error_set(GIT_ERROR_OS, "cannot extend packfile '%s'", idx->pack->pack_name); return -1; } - return write_at(idx, data, idx->pack->mwf.size, size); + return 0; } static int read_stream_object(git_indexer *idx, git_indexer_progress *stats) |