[PATCH v3 00/10] upload-pack: reduce lock contention when writing packfile data
- From
Patrick Steinhardt <ps@pks.im>
- Date
- Mar 10, 2026, 13:24 UTC
- Message-ID
- <20260310-pks-upload-pack-write-contention-v3-0-8bc97aa3e267@pks.im>
- In-Reply-To
- <20260227-pks-upload-pack-write-contention-v1-0-7166fe255704@pks.im>
Hi,
this small patch series fixes some heavy lock contention when writing data from git-upload-pack(1) into pipes. This lock contention can be observed when having hundreds of git-upload-pack(1) processes active at the same time that write data into pipes at dozens of gigabits per second.
I have uploaded the flame graph that clearly shows the lock contention at [1].
Changes in v3:
- Fix handling of `iov_len` overflows in writev(3p) wrapper.
- Add another patch that causes us to flush out data instead of
sending a 0005 keepalive packet.
- Link to v2: https://lore.kernel.org/r/20260303-pks-upload-pack-write-contention-v2-0-7321830f08fe@pks.imChanges in v2:
- Change the buffer size in git-pack-objects(1) to also reduce the
number of write syscalls over there.
- Introduce writev to half the number of syscalls when writing
pktlines.
- Use `sizeof(os->buffer)` instead of open-coding its size.
- Improve keepalive logic in git-upload-pack(1) to account for
buffering.
- Link to v1: https://lore.kernel.org/r/20260227-pks-upload-pack-write-contention-v1-0-7166fe255704@pks.imThanks!
Patrick
[1]: https://gitlab.com/gitlab-org/git/-/work_items/675
---
Patrick Steinhardt (10):
upload-pack: fix debug statement when flushing packfile data
upload-pack: adapt keepalives based on buffering
upload-pack: prefer flushing data over sending keepalive
upload-pack: reduce lock contention when writing packfile data
compat/posix: introduce writev(3p) wrapper
wrapper: introduce writev(3p) wrappers
sideband: use writev(3p) to send pktlines
csum-file: introduce `hashfd_ext()`
csum-file: drop `hashfd_throughput()`
builtin/pack-objects: reduce lock contention when writing packfile dataMakefile | 4 +++ builtin/pack-objects.c | 23 +++++++++++--- compat/posix.h | 14 +++++++++ compat/writev.c | 44 +++++++++++++++++++++++++++ config.mak.uname | 2 ++ csum-file.c | 28 +++++------------ csum-file.h | 16 ++++++++-- meson.build | 1 + sideband.c | 14 +++++++-- upload-pack.c | 81 +++++++++++++++++++++++++++++++++++++++----------- wrapper.c | 41 +++++++++++++++++++++++++ wrapper.h | 9 ++++++ write-or-die.c | 8 +++++ write-or-die.h | 1 + 14 files changed, 239 insertions(+), 47 deletions(-)
Range-diff versus v2:
1: ef3244ffcc = 1: 540b577540 upload-pack: fix debug statement when flushing packfile data
2: 3297edd609 = 2: 253d119b10 upload-pack: adapt keepalives based on buffering
-: ---------- > 3: 960c650063 upload-pack: prefer flushing data over sending keepalive
3: 84671fb222 = 4: 0e147c41cf upload-pack: reduce lock contention when writing packfile data
4: bd1f070cb4 < -: ---------- git-compat-util: introduce `cast_size_t_to_ssize_t()`
5: d5acbd1584 ! 5: b6fbd89b8e compat/posix: introduce writev(3p) wrapper
@@ compat/writev.c (new)
+ssize_t git_writev(int fd, const struct iovec *iov, int iovcnt)
+{
+ size_t total_written = 0;
++ size_t sum = 0;
++
++ /*
++ * According to writev(3p), the syscall shall error with EINVAL in case
++ * the sum of `iov_len` overflows `ssize_t`.
++ */
++ for (int i = 0; i < iovcnt; i++) {
++ if (iov[i].iov_len > maximum_signed_value_of_type(ssize_t) ||
++ iov[i].iov_len + sum > maximum_signed_value_of_type(ssize_t)) {
++ errno = EINVAL;
++ return -1;
++ }
++
++ sum += iov[i].iov_len;
++ }
+
+ for (int i = 0; i < iovcnt; i++) {
+ const char *bytes = iov[i].iov_base;
@@ compat/writev.c (new)
+ }
+
+out:
-+ return cast_size_t_to_ssize_t(total_written);
++ return (ssize_t) total_written;
+}
## config.mak.uname ##
6: e3525cd25e = 6: 0a90ab2f62 wrapper: introduce writev(3p) wrappers
7: fe07f2d331 = 7: 5e29cfbf10 sideband: use writev(3p) to send pktlines
8: 4563ad923f = 8: 32b59d5f29 csum-file: introduce `hashfd_ext()`
9: 549b3dbefc = 9: a5b0eb3627 csum-file: drop `hashfd_throughput()`
10: 155f79b128 = 10: a82959772e builtin/pack-objects: reduce lock contention when writing packfile data--- base-commit: fb1b83bcddff60463f6e86bb021784c88d0b748c change-id: 20260227-pks-upload-pack-write-contention-435ce01f5fe9