bundle2: avoid unbound read when seeking
Currently, seekableunbundlepart.seek() will perform a read() during
seek operations. This will allocate a buffer to hold the raw data
over the seek distance. This can lead to very large allocations
and cause performance to suffer.
We change the code to perform read(32768) in a loop to avoid
potentially large allocations.
`hg perfbundleread` on an uncompressed Firefox bundle reveals
a performance impact:
! bundle2 iterparts()
! wall 2.992605 comb 2.990000 user 2.260000 sys 0.730000 (best of 4)
! bundle2 iterparts() seekable
! wall 3.863810 comb 3.860000 user 3.000000 sys 0.860000 (best of 3)
! bundle2 part seek()
! wall 6.213387 comb 6.200000 user 3.350000 sys 2.850000 (best of 3)
! wall 3.820347 comb 3.810000 user 2.980000 sys 0.830000 (best of 3)
Since seekable bundle parts are (only) used by bundlerepo, this /may/
speed up initial loading of bundle-based repos. But any improvement
will likely only be noticed on very large bundles.
Differential Revision: https://phab.mercurial-scm.org/D1394
#require no-pure
A script to generate nasty diff worst-case scenarios:
$ cat > s.py <<EOF
> import random
> for x in xrange(100000):
> print
> if random.randint(0, 100) >= 50:
> x += 1
> print(hex(x))
> EOF
$ hg init a
$ cd a
Check in a big file:
$ $PYTHON ../s.py > a
$ hg ci -qAm0
Modify it:
$ $PYTHON ../s.py > a
Time a check-in, should never take more than 10 seconds user time:
$ hg ci --time -m1
time: real .* secs .user [0-9][.].* sys .* (re)