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
$ cat <<EOF > merge
> import sys, os
> print("merging for", os.path.basename(sys.argv[1]))
> EOF
$ HGMERGE="$PYTHON ../merge"; export HGMERGE
$ hg init A1
$ cd A1
$ echo This is file foo1 > foo
$ echo This is file bar1 > bar
$ hg add foo bar
$ hg commit -m "commit text"
$ cd ..
$ hg clone A1 B1
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd A1
$ rm bar
$ hg remove bar
$ hg commit -m "commit test"
$ cd ../B1
$ echo This is file foo22 > foo
$ hg commit -m "commit test"
$ cd ..
$ hg clone A1 A2
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg clone B1 B2
updating to branch default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd A1
$ hg pull ../B1
pulling from ../B1
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
new changesets b90e70beeb58
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg merge
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg commit -m "commit test"
bar should remain deleted.
$ hg manifest --debug
f9b0e817f6a48de3564c6b2957687c5e7297c5a0 644 foo
$ cd ../B2
$ hg pull ../A2
pulling from ../A2
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 0 changes to 0 files (+1 heads)
new changesets e1adc944e717
(run 'hg heads' to see heads, 'hg merge' to merge)
$ hg merge
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg commit -m "commit test"
bar should remain deleted.
$ hg manifest --debug
f9b0e817f6a48de3564c6b2957687c5e7297c5a0 644 foo
$ cd ..