Mercurial > hg
view tests/test-bundle2-exchange.t @ 30155:b7a966ce89ed
changelog: disable delta chains
This patch disables delta chains on changelogs. After this patch, new
entries on changelogs - including existing changelogs - will be stored
as the fulltext of that data (likely compressed). No delta computation
will be performed.
An overview of delta chains and data justifying this change follows.
Revlogs try to store entries as a delta against a previous entry (either
a parent revision in the case of generaldelta or the previous physical
revision when not using generaldelta). Most of the time this is the
correct thing to do: it frequently results in less CPU usage and smaller
storage.
Delta chains are most effective when the base revision being deltad
against is similar to the current data. This tends to occur naturally
for manifests and file data, since only small parts of each tend to
change with each revision. Changelogs, however, are a different story.
Changelog entries represent changesets/commits. And unless commits in a
repository are homogonous (same author, changing same files, similar
commit messages, etc), a delta from one entry to the next tends to be
relatively large compared to the size of the entry. This means that
delta chains tend to be short. How short? Here is the full vs delta
revision breakdown on some real world repos:
Repo % Full % Delta Max Length
hg 45.8 54.2 6
mozilla-central 42.4 57.6 8
mozilla-unified 42.5 57.5 17
pypy 46.1 53.9 6
python-zstandard 46.1 53.9 3
(I threw in python-zstandard as an example of a repo that is homogonous.
It contains a small Python project with changes all from the same
author.)
Contrast this with the manifest revlog for these repos, where 99+% of
revisions are deltas and delta chains run into the thousands.
So delta chains aren't as useful on changelogs. But even a short delta
chain may provide benefits. Let's measure that.
Delta chains may require less CPU to read revisions if the CPU time
spent reading smaller deltas is less than the CPU time used to
decompress larger individual entries. We can measure this via
`hg perfrevlog -c -d 1` to iterate a revlog to resolve each revision's
fulltext. Here are the results of that command on a repo using delta
chains in its changelog and on a repo without delta chains:
hg (forward)
! wall 0.407008 comb 0.410000 user 0.410000 sys 0.000000 (best of 25)
! wall 0.390061 comb 0.390000 user 0.390000 sys 0.000000 (best of 26)
hg (reverse)
! wall 0.515221 comb 0.520000 user 0.520000 sys 0.000000 (best of 19)
! wall 0.400018 comb 0.400000 user 0.390000 sys 0.010000 (best of 25)
mozilla-central (forward)
! wall 4.508296 comb 4.490000 user 4.490000 sys 0.000000 (best of 3)
! wall 4.370222 comb 4.370000 user 4.350000 sys 0.020000 (best of 3)
mozilla-central (reverse)
! wall 5.758995 comb 5.760000 user 5.720000 sys 0.040000 (best of 3)
! wall 4.346503 comb 4.340000 user 4.320000 sys 0.020000 (best of 3)
mozilla-unified (forward)
! wall 4.957088 comb 4.950000 user 4.940000 sys 0.010000 (best of 3)
! wall 4.660528 comb 4.650000 user 4.630000 sys 0.020000 (best of 3)
mozilla-unified (reverse)
! wall 6.119827 comb 6.110000 user 6.090000 sys 0.020000 (best of 3)
! wall 4.675136 comb 4.670000 user 4.670000 sys 0.000000 (best of 3)
pypy (forward)
! wall 1.231122 comb 1.240000 user 1.230000 sys 0.010000 (best of 8)
! wall 1.164896 comb 1.160000 user 1.160000 sys 0.000000 (best of 9)
pypy (reverse)
! wall 1.467049 comb 1.460000 user 1.460000 sys 0.000000 (best of 7)
! wall 1.160200 comb 1.170000 user 1.160000 sys 0.010000 (best of 9)
The data clearly shows that it takes less wall and CPU time to resolve
revisions when there are no delta chains in the changelogs, regardless
of the direction of traversal. Furthermore, not using a delta chain
means that fulltext resolution in reverse is as fast as iterating
forward. So not using delta chains on the changelog is a clear CPU win
for reading operations.
An example of a user-visible operation showing this speed-up is revset
evaluation. Here are results for
`hg perfrevset 'author(gps) or author(mpm)'`:
hg
! wall 1.655506 comb 1.660000 user 1.650000 sys 0.010000 (best of 6)
! wall 1.612723 comb 1.610000 user 1.600000 sys 0.010000 (best of 7)
mozilla-central
! wall 17.629826 comb 17.640000 user 17.600000 sys 0.040000 (best of 3)
! wall 17.311033 comb 17.300000 user 17.260000 sys 0.040000 (best of 3)
What about 00changelog.i size?
Repo Delta Chains No Delta Chains
hg 7,033,250 6,976,771
mozilla-central 82,978,748 81,574,623
mozilla-unified 88,112,349 86,702,162
pypy 20,740,699 20,659,741
The data shows that removing delta chains from the changelog makes the
changelog smaller.
Delta chains are also used during changegroup generation. This
operation essentially converts a series of revisions to one large
delta chain. And changegroup generation is smart: if the delta in
the revlog matches what the changegroup is emitting, it will reuse
the delta instead of recalculating it. We can measure the impact
removing changelog delta chains has on changegroup generation via
`hg perfchangegroupchangelog`:
hg
! wall 1.589245 comb 1.590000 user 1.590000 sys 0.000000 (best of 7)
! wall 1.788060 comb 1.790000 user 1.790000 sys 0.000000 (best of 6)
mozilla-central
! wall 17.382585 comb 17.380000 user 17.340000 sys 0.040000 (best of 3)
! wall 20.161357 comb 20.160000 user 20.120000 sys 0.040000 (best of 3)
mozilla-unified
! wall 18.722839 comb 18.720000 user 18.680000 sys 0.040000 (best of 3)
! wall 21.168075 comb 21.170000 user 21.130000 sys 0.040000 (best of 3)
pypy
! wall 4.828317 comb 4.830000 user 4.820000 sys 0.010000 (best of 3)
! wall 5.415455 comb 5.420000 user 5.410000 sys 0.010000 (best of 3)
The data shows eliminating delta chains makes the changelog part of
changegroup generation slower. This is expected since we now have to
compute deltas for revisions where we could recycle the delta before.
It is worth putting this regression into context of overall changegroup
times. Here is the rough total CPU time spent in changegroup generation
for various repos while using delta chains on the changelog:
Repo CPU Time (s) CPU Time w/ compression
hg 4.50 7.05
mozilla-central 111.1 222.0
pypy 28.68 75.5
Before compression, removing delta chains from the changegroup adds
~4.4% overhead to hg changegroup generation, 1.3% to mozilla-central,
and 2.0% to pypy. When you factor in zlib compression, these percentages
are roughly divided by 2.
While the increased CPU usage for changegroup generation is unfortunate,
I think it is acceptable because the percentage is small, server
operators (those likely impacted most by this) have other mechanisms
to mitigate CPU consumption (namely reducing zlib compression level and
pre-generated clone bundles), and because there is room to optimize this
in the future. For example, we could use the nullid as the base revision,
effectively encoding the full revision for each entry in the changegroup.
When doing this, `hg perfchangegroupchangelog` nearly halves:
mozilla-unified
! wall 21.168075 comb 21.170000 user 21.130000 sys 0.040000 (best of 3)
! wall 11.196461 comb 11.200000 user 11.190000 sys 0.010000 (best of 3)
This looks very promising as a future optimization opportunity.
It's worth that the changes in test-acl.t to the changegroup part size.
This is because revision 6 in the changegroup had a delta chain of
length 2 before and after this patch the base revision is nullrev.
When the base revision is nullrev, cg2packer.deltaparent() hardcodes
the *previous* revision from the changegroup as the delta parent.
This caused the delta in the changegroup to switch base revisions,
the delta to change, and the size to change accordingly. While the
size increased in this case, I think sizes will remain the same
on average, as the delta base for changelog revisions doesn't matter
too much (as this patch shows). So, I don't consider this a regression.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 13 Oct 2016 12:50:27 +0200 |
parents | 531e85eec23c |
children | 4c8dcb491974 |
line wrap: on
line source
Test exchange of common information using bundle2 $ getmainid() { > hg -R main log --template '{node}\n' --rev "$1" > } enable obsolescence $ cp $HGRCPATH $TESTTMP/hgrc.orig $ cat > $TESTTMP/bundle2-pushkey-hook.sh << EOF > echo pushkey: lock state after \"\$HG_NAMESPACE\" > hg debuglock > EOF $ cat >> $HGRCPATH << EOF > [experimental] > evolution=createmarkers,exchange > bundle2-output-capture=True > [ui] > ssh=python "$TESTDIR/dummyssh" > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline} > [web] > push_ssl = false > allow_push = * > [phases] > publish=False > [hooks] > pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n" > txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n" > txnclose.env = sh -c "HG_LOCAL= printenv.py txnclose" > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh" > EOF The extension requires a repo (currently unused) $ hg init main $ cd main $ touch a $ hg add a $ hg commit -m 'a' pre-close-tip:3903775176ed draft postclose-tip:3903775176ed draft txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob) $ hg unbundle $TESTDIR/bundles/rebase.hg adding changesets adding manifests adding file changes added 8 changesets with 7 changes to 7 files (+3 heads) pre-close-tip:02de42196ebe draft postclose-tip:02de42196ebe draft txnclose hook: HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNID=TXN:* HG_TXNNAME=unbundle (glob) bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob) (run 'hg heads' to see heads, 'hg merge' to merge) $ cd .. Real world exchange ===================== Add more obsolescence information $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc` pre-close-tip:02de42196ebe draft postclose-tip:02de42196ebe draft txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob) $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c` pre-close-tip:02de42196ebe draft postclose-tip:02de42196ebe draft txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob) clone --pull $ hg -R main phase --public cd010b8cd998 pre-close-tip:02de42196ebe draft postclose-tip:02de42196ebe draft txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob) $ hg clone main other --pull --rev 9520eea781bc adding changesets adding manifests adding file changes added 2 changesets with 2 changes to 2 files 1 new obsolescence markers pre-close-tip:9520eea781bc draft postclose-tip:9520eea781bc draft txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=9520eea781bcca16c1e15acc0ba14335a0e8e5ba HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob) file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob) updating to branch default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg -R other log -G @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E | o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A $ hg -R other debugobsolete 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} pull $ hg -R main phase --public 9520eea781bc pre-close-tip:02de42196ebe draft postclose-tip:02de42196ebe draft txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob) $ hg -R other pull -r 24b6387c8c8c pulling from $TESTTMP/main (glob) searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) 1 new obsolescence markers pre-close-tip:24b6387c8c8c draft postclose-tip:24b6387c8c8c draft txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_NODE_LAST=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob) file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob) (run 'hg heads' to see heads, 'hg merge' to merge) $ hg -R other log -G o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F | | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A $ hg -R other debugobsolete 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} pull empty (with phase movement) $ hg -R main phase --public 24b6387c8c8c pre-close-tip:02de42196ebe draft postclose-tip:02de42196ebe draft txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob) $ hg -R other pull -r 24b6387c8c8c pulling from $TESTTMP/main (glob) no changes found pre-close-tip:24b6387c8c8c public postclose-tip:24b6387c8c8c public txnclose hook: HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob) file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob) $ hg -R other log -G o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F | | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A $ hg -R other debugobsolete 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} pull empty $ hg -R other pull -r 24b6387c8c8c pulling from $TESTTMP/main (glob) no changes found pre-close-tip:24b6387c8c8c public postclose-tip:24b6387c8c8c public txnclose hook: HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob) file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob) $ hg -R other log -G o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F | | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A $ hg -R other debugobsolete 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} add extra data to test their exchange during push $ hg -R main bookmark --rev eea13746799a book_eea1 pre-close-tip:02de42196ebe draft postclose-tip:02de42196ebe draft txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob) $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a` pre-close-tip:02de42196ebe draft postclose-tip:02de42196ebe draft txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob) $ hg -R main bookmark --rev 02de42196ebe book_02de pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob) $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe` pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob) $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob) $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16` pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob) $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob) $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8` pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob) $ hg -R main bookmark --rev 32af7686d403 book_32af pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob) $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403` pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob) $ hg -R other bookmark --rev cd010b8cd998 book_eea1 pre-close-tip:24b6387c8c8c public postclose-tip:24b6387c8c8c public txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob) $ hg -R other bookmark --rev cd010b8cd998 book_02de pre-close-tip:24b6387c8c8c public postclose-tip:24b6387c8c8c public txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob) $ hg -R other bookmark --rev cd010b8cd998 book_42cc pre-close-tip:24b6387c8c8c public postclose-tip:24b6387c8c8c public txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob) $ hg -R other bookmark --rev cd010b8cd998 book_5fdd pre-close-tip:24b6387c8c8c public postclose-tip:24b6387c8c8c public txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob) $ hg -R other bookmark --rev cd010b8cd998 book_32af pre-close-tip:24b6387c8c8c public postclose-tip:24b6387c8c8c public txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob) $ hg -R main phase --public eea13746799a pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob) push $ hg -R main push other --rev eea13746799a --bookmark book_eea1 pushing to other searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 0 changes to 0 files (-1 heads) remote: 1 new obsolescence markers remote: pre-close-tip:eea13746799a public book_eea1 remote: pushkey: lock state after "phases" remote: lock: free remote: wlock: free remote: pushkey: lock state after "bookmarks" remote: lock: free remote: wlock: free remote: postclose-tip:eea13746799a public book_eea1 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_NODE_LAST=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=file:$TESTTMP/other (glob) updating bookmark book_eea1 pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob) file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob) $ hg -R other log -G o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G |\ | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F | | @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A $ hg -R other debugobsolete 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} pull over ssh $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de pulling from ssh://user@dummy/main searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) 1 new obsolescence markers updating bookmark book_02de pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob) ssh://user@dummy/main HG_URL=ssh://user@dummy/main (run 'hg heads' to see heads, 'hg merge' to merge) $ hg -R other debugobsolete 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} pull over http $ hg serve -R main -p $HGPORT -d --pid-file=main.pid -E main-error.log $ cat main.pid >> $DAEMON_PIDS $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc pulling from http://localhost:$HGPORT/ searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files (+1 heads) 1 new obsolescence markers updating bookmark book_42cc pre-close-tip:42ccdea3bb16 draft book_42cc postclose-tip:42ccdea3bb16 draft book_42cc txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_NODE_LAST=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob) http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/ (run 'hg heads .' to see heads, 'hg merge' to merge) $ cat main-error.log $ hg -R other debugobsolete 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} push over ssh $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd pushing to ssh://user@dummy/other searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: 1 new obsolescence markers remote: pre-close-tip:5fddd98957c8 draft book_5fdd remote: pushkey: lock state after "bookmarks" remote: lock: free remote: wlock: free remote: postclose-tip:5fddd98957c8 draft book_5fdd remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_NODE_LAST=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:ssh:127.0.0.1 (glob) updating bookmark book_5fdd pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob) ssh://user@dummy/other HG_URL=ssh://user@dummy/other $ hg -R other log -G o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C | o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B | | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H | | | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G | |/| | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F |/ / | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A $ hg -R other debugobsolete 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} push over http $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log $ cat other.pid >> $DAEMON_PIDS $ hg -R main phase --public 32af7686d403 pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob) $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af pushing to http://localhost:$HGPORT2/ searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: 1 new obsolescence markers remote: pre-close-tip:32af7686d403 public book_32af remote: pushkey: lock state after "phases" remote: lock: free remote: wlock: free remote: pushkey: lock state after "bookmarks" remote: lock: free remote: wlock: free remote: postclose-tip:32af7686d403 public book_32af remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=32af7686d403cf45b5d95f2d70cebea587ac806a HG_NODE_LAST=32af7686d403cf45b5d95f2d70cebea587ac806a HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:http:127.0.0.1: (glob) updating bookmark book_32af pre-close-tip:02de42196ebe draft book_02de postclose-tip:02de42196ebe draft book_02de txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob) http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/ $ cat other-error.log Check final content. $ hg -R other log -G o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D | o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C | o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B | | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H | | | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G | |/| | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F |/ / | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E |/ o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A $ hg -R other debugobsolete 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'} (check that no 'pending' files remain) $ ls -1 other/.hg/bookmarks* other/.hg/bookmarks $ ls -1 other/.hg/store/phaseroots* other/.hg/store/phaseroots $ ls -1 other/.hg/store/00changelog.i* other/.hg/store/00changelog.i Error Handling ============== Check that errors are properly returned to the client during push. Setting up $ cat > failpush.py << EOF > """A small extension that makes push fails when using bundle2 > > used to test error handling in bundle2 > """ > > from mercurial import error > from mercurial import bundle2 > from mercurial import exchange > from mercurial import extensions > > def _pushbundle2failpart(pushop, bundler): > reason = pushop.ui.config('failpush', 'reason', None) > part = None > if reason == 'abort': > bundler.newpart('test:abort') > if reason == 'unknown': > bundler.newpart('test:unknown') > if reason == 'race': > # 20 Bytes of crap > bundler.newpart('check:heads', data='01234567890123456789') > > @bundle2.parthandler("test:abort") > def handleabort(op, part): > raise error.Abort('Abandon ship!', hint="don't panic") > > def uisetup(ui): > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart > exchange.b2partsgenorder.insert(0, 'failpart') > > EOF $ cd main $ hg up tip 3 files updated, 0 files merged, 1 files removed, 0 files unresolved $ echo 'I' > I $ hg add I $ hg ci -m 'I' pre-close-tip:e7ec4e813ba6 draft postclose-tip:e7ec4e813ba6 draft txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob) $ hg id e7ec4e813ba6 tip $ cd .. $ cat << EOF >> $HGRCPATH > [extensions] > failpush=$TESTTMP/failpush.py > EOF $ killdaemons.py $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log $ cat other.pid >> $DAEMON_PIDS Doing the actual push: Abort error $ cat << EOF >> $HGRCPATH > [failpush] > reason = abort > EOF $ hg -R main push other -r e7ec4e813ba6 pushing to other searching for changes abort: Abandon ship! (don't panic) [255] $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6 pushing to ssh://user@dummy/other searching for changes remote: Abandon ship! abort: push failed on remote (don't panic) [255] $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6 pushing to http://localhost:$HGPORT2/ searching for changes remote: Abandon ship! abort: push failed on remote (don't panic) [255] Doing the actual push: unknown mandatory parts $ cat << EOF >> $HGRCPATH > [failpush] > reason = unknown > EOF $ hg -R main push other -r e7ec4e813ba6 pushing to other searching for changes abort: missing support for test:unknown [255] $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6 pushing to ssh://user@dummy/other searching for changes abort: missing support for test:unknown [255] $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6 pushing to http://localhost:$HGPORT2/ searching for changes abort: missing support for test:unknown [255] Doing the actual push: race $ cat << EOF >> $HGRCPATH > [failpush] > reason = race > EOF $ hg -R main push other -r e7ec4e813ba6 pushing to other searching for changes abort: push failed: 'repository changed while pushing - please try again' [255] $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6 pushing to ssh://user@dummy/other searching for changes abort: push failed: 'repository changed while pushing - please try again' [255] $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6 pushing to http://localhost:$HGPORT2/ searching for changes abort: push failed: 'repository changed while pushing - please try again' [255] Doing the actual push: hook abort $ cat << EOF >> $HGRCPATH > [failpush] > reason = > [hooks] > pretxnclose.failpush = sh -c "echo 'You shall not pass!'; false" > txnabort.failpush = sh -c "echo 'Cleaning up the mess...'" > EOF $ killdaemons.py $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log $ cat other.pid >> $DAEMON_PIDS $ hg -R main push other -r e7ec4e813ba6 pushing to other searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: pre-close-tip:e7ec4e813ba6 draft remote: You shall not pass! remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed abort: pretxnclose.failpush hook exited with status 1 [255] $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6 pushing to ssh://user@dummy/other searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: pre-close-tip:e7ec4e813ba6 draft remote: You shall not pass! remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed remote: pretxnclose.failpush hook exited with status 1 abort: push failed on remote [255] $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6 pushing to http://localhost:$HGPORT2/ searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: pre-close-tip:e7ec4e813ba6 draft remote: You shall not pass! remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed remote: pretxnclose.failpush hook exited with status 1 abort: push failed on remote [255] (check that no 'pending' files remain) $ ls -1 other/.hg/bookmarks* other/.hg/bookmarks $ ls -1 other/.hg/store/phaseroots* other/.hg/store/phaseroots $ ls -1 other/.hg/store/00changelog.i* other/.hg/store/00changelog.i Check error from hook during the unbundling process itself $ cat << EOF >> $HGRCPATH > pretxnchangegroup = sh -c "echo 'Fail early!'; false" > EOF $ killdaemons.py # reload http config $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log $ cat other.pid >> $DAEMON_PIDS $ hg -R main push other -r e7ec4e813ba6 pushing to other searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: Fail early! remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed abort: pretxnchangegroup hook exited with status 1 [255] $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6 pushing to ssh://user@dummy/other searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: Fail early! remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed remote: pretxnchangegroup hook exited with status 1 abort: push failed on remote [255] $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6 pushing to http://localhost:$HGPORT2/ searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: Fail early! remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed remote: pretxnchangegroup hook exited with status 1 abort: push failed on remote [255] Check output capture control. (should be still forced for http, disabled for local and ssh) $ cat >> $HGRCPATH << EOF > [experimental] > bundle2-output-capture=False > EOF $ hg -R main push other -r e7ec4e813ba6 pushing to other searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files Fail early! transaction abort! Cleaning up the mess... rollback completed abort: pretxnchangegroup hook exited with status 1 [255] $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6 pushing to ssh://user@dummy/other searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: Fail early! remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed remote: pretxnchangegroup hook exited with status 1 abort: push failed on remote [255] $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6 pushing to http://localhost:$HGPORT2/ searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: Fail early! remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed remote: pretxnchangegroup hook exited with status 1 abort: push failed on remote [255] Check abort from mandatory pushkey $ cat > mandatorypart.py << EOF > from mercurial import exchange > from mercurial import pushkey > from mercurial import node > from mercurial import error > @exchange.b2partsgenerator('failingpuskey') > def addfailingpushey(pushop, bundler): > enc = pushkey.encode > part = bundler.newpart('pushkey') > part.addparam('namespace', enc('phases')) > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex())) > part.addparam('old', enc(str(0))) # successful update > part.addparam('new', enc(str(0))) > def fail(pushop, exc): > raise error.Abort('Correct phase push failed (because hooks)') > pushop.pkfailcb[part.id] = fail > EOF $ cat >> $HGRCPATH << EOF > [hooks] > pretxnchangegroup= > pretxnclose.failpush= > prepushkey.failpush = sh -c "echo 'do not push the key !'; false" > [extensions] > mandatorypart=$TESTTMP/mandatorypart.py > EOF $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log $ cat other.pid >> $DAEMON_PIDS (Failure from a hook) $ hg -R main push other -r e7ec4e813ba6 pushing to other searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files do not push the key ! pushkey-abort: prepushkey.failpush hook exited with status 1 transaction abort! Cleaning up the mess... rollback completed abort: Correct phase push failed (because hooks) [255] $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6 pushing to ssh://user@dummy/other searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: do not push the key ! remote: pushkey-abort: prepushkey.failpush hook exited with status 1 remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed abort: Correct phase push failed (because hooks) [255] $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6 pushing to http://localhost:$HGPORT2/ searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: do not push the key ! remote: pushkey-abort: prepushkey.failpush hook exited with status 1 remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed abort: Correct phase push failed (because hooks) [255] (Failure from a the pushkey) $ cat > mandatorypart.py << EOF > from mercurial import exchange > from mercurial import pushkey > from mercurial import node > from mercurial import error > @exchange.b2partsgenerator('failingpuskey') > def addfailingpushey(pushop, bundler): > enc = pushkey.encode > part = bundler.newpart('pushkey') > part.addparam('namespace', enc('phases')) > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex())) > part.addparam('old', enc(str(4))) # will fail > part.addparam('new', enc(str(3))) > def fail(pushop, exc): > raise error.Abort('Clown phase push failed') > pushop.pkfailcb[part.id] = fail > EOF $ cat >> $HGRCPATH << EOF > [hooks] > prepushkey.failpush = > EOF $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log $ cat other.pid >> $DAEMON_PIDS $ hg -R main push other -r e7ec4e813ba6 pushing to other searching for changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files transaction abort! Cleaning up the mess... rollback completed pushkey: lock state after "phases" lock: free wlock: free abort: Clown phase push failed [255] $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6 pushing to ssh://user@dummy/other searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed remote: pushkey: lock state after "phases" remote: lock: free remote: wlock: free abort: Clown phase push failed [255] $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6 pushing to http://localhost:$HGPORT2/ searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files remote: transaction abort! remote: Cleaning up the mess... remote: rollback completed remote: pushkey: lock state after "phases" remote: lock: free remote: wlock: free abort: Clown phase push failed [255] Test lazily acquiring the lock during unbundle $ cp $TESTTMP/hgrc.orig $HGRCPATH $ cat >> $HGRCPATH <<EOF > [ui] > ssh=python "$TESTDIR/dummyssh" > EOF $ cat >> $TESTTMP/locktester.py <<EOF > import os > from mercurial import extensions, bundle2, util > def checklock(orig, repo, *args, **kwargs): > if repo.svfs.lexists("lock"): > raise util.Abort("Lock should not be taken") > return orig(repo, *args, **kwargs) > def extsetup(ui): > extensions.wrapfunction(bundle2, 'processbundle', checklock) > EOF $ hg init lazylock $ cat >> lazylock/.hg/hgrc <<EOF > [extensions] > locktester=$TESTTMP/locktester.py > EOF $ hg clone -q ssh://user@dummy/lazylock lazylockclient $ cd lazylockclient $ touch a && hg ci -Aqm a $ hg push pushing to ssh://user@dummy/lazylock searching for changes remote: Lock should not be taken abort: push failed on remote [255] $ cat >> ../lazylock/.hg/hgrc <<EOF > [experimental] > bundle2lazylocking=True > EOF $ hg push pushing to ssh://user@dummy/lazylock searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files $ cd .. Servers can disable bundle1 for clone/pull operations $ killdaemons.py $ hg init bundle2onlyserver $ cd bundle2onlyserver $ cat > .hg/hgrc << EOF > [server] > bundle1.pull = false > EOF $ touch foo $ hg -q commit -A -m initial $ hg serve -p $HGPORT -d --pid-file=hg.pid $ cat hg.pid >> $DAEMON_PIDS $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2 requesting all changes abort: remote error: incompatible Mercurial client; bundle2 required (see https://www.mercurial-scm.org/wiki/IncompatibleClient) [255] $ killdaemons.py $ cd .. bundle1 can still pull non-generaldelta repos when generaldelta bundle1 disabled $ hg --config format.usegeneraldelta=false init notgdserver $ cd notgdserver $ cat > .hg/hgrc << EOF > [server] > bundle1gd.pull = false > EOF $ touch foo $ hg -q commit -A -m initial $ hg serve -p $HGPORT -d --pid-file=hg.pid $ cat hg.pid >> $DAEMON_PIDS $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-1 requesting all changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ killdaemons.py $ cd ../bundle2onlyserver bundle1 pull can be disabled for generaldelta repos only $ cat > .hg/hgrc << EOF > [server] > bundle1gd.pull = false > EOF $ hg serve -p $HGPORT -d --pid-file=hg.pid $ cat hg.pid >> $DAEMON_PIDS $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2 requesting all changes abort: remote error: incompatible Mercurial client; bundle2 required (see https://www.mercurial-scm.org/wiki/IncompatibleClient) [255] $ killdaemons.py Verify the global server.bundle1 option works $ cat > .hg/hgrc << EOF > [server] > bundle1 = false > EOF $ hg serve -p $HGPORT -d --pid-file=hg.pid $ cat hg.pid >> $DAEMON_PIDS $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT not-bundle2 requesting all changes abort: remote error: incompatible Mercurial client; bundle2 required (see https://www.mercurial-scm.org/wiki/IncompatibleClient) [255] $ killdaemons.py $ cat > .hg/hgrc << EOF > [server] > bundle1gd = false > EOF $ hg serve -p $HGPORT -d --pid-file=hg.pid $ cat hg.pid >> $DAEMON_PIDS $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2 requesting all changes abort: remote error: incompatible Mercurial client; bundle2 required (see https://www.mercurial-scm.org/wiki/IncompatibleClient) [255] $ killdaemons.py $ cd ../notgdserver $ cat > .hg/hgrc << EOF > [server] > bundle1gd = false > EOF $ hg serve -p $HGPORT -d --pid-file=hg.pid $ cat hg.pid >> $DAEMON_PIDS $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-2 requesting all changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ killdaemons.py $ cd ../bundle2onlyserver Verify bundle1 pushes can be disabled $ cat > .hg/hgrc << EOF > [server] > bundle1.push = false > [web] > allow_push = * > push_ssl = false > EOF $ hg serve -p $HGPORT -d --pid-file=hg.pid -E error.log $ cat hg.pid >> $DAEMON_PIDS $ cd .. $ hg clone http://localhost:$HGPORT bundle2-only requesting all changes adding changesets adding manifests adding file changes added 1 changesets with 1 changes to 1 files updating to branch default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ cd bundle2-only $ echo commit > foo $ hg commit -m commit $ hg --config devel.legacy.exchange=bundle1 push pushing to http://localhost:$HGPORT/ searching for changes abort: remote error: incompatible Mercurial client; bundle2 required (see https://www.mercurial-scm.org/wiki/IncompatibleClient) [255] $ hg push pushing to http://localhost:$HGPORT/ searching for changes remote: adding changesets remote: adding manifests remote: adding file changes remote: added 1 changesets with 1 changes to 1 files