Commit Graph

244 Commits

Author SHA1 Message Date
Martin von Zweigbergk
560e5ce4f1 changegroup: let callers pass in transaction to apply() (API)
I think passing in the transaction makes it a little clearer and more
consistent with bundle2.
2017-06-15 22:46:38 -07:00
Pierre-Yves David
92f804bd36 check-concurrency: expose the feature as 'concurrent-push-mode'
We move the feature to a proper configuration and document it. The config goes
in the 'server' section because it feels like something the server owner would
want to decide. We pick and open field because it seems likely that other
checking levels will emerge in the future. (eg: server like the mozilla-try
server will likely wants a "none" value)

The option name contains 'push' since this affects 'push' only. The option value
'check-related' is preferred over one explicitly containing 'allow' or 'deny'
because the client still have a strong decision power here. Here, the server is
just advising the client on the check mode to use.
2017-05-28 00:12:38 +02:00
Pierre-Yves David
a74c131fb4 push: add a way to allow concurrent pushes on unrelated heads
Client has a mechanism for the server to check that nothing changed server side
since the client prepared a push. That check is wide and any head changed on
the server will lead to an aborted push. We introduce a way for the client to
send a less strict checking. That logic will check that no heads impacted by
the push have been affected. If other unrelated heads (including named branches
heads) have been affected, the push will proceed.

This is very helpful for repositories with high developers traffic on different
heads, a common setup.

That behavior is currently controlled by an experimental option. The config
should live in the "server" section but bike-shedding of the name will happen
in the next changesets. Servers advertise this capability through a new bundle2
capability 'checkeads', using the value 'related'.

The 'test-push-race.t' is updated to check that new capabilities on the
documented cases.
2017-05-29 05:53:58 +02:00
Pierre-Yves David
8873a232c1 bundle: add an experimental knob to include obsmarkers in bundle
The "hg bundle" command is a good place to test if the inclusion of obsmarkers
within a bundle is working well (part exists, content is correct etc). So we
add a way to have them included.

Ideally, this would be controlled by a change around bundlespec (bundlespec
"v3" + arguments). However, my main goal is to have obsmarkers included in
bundle created by the 'hg strip' command, not the 'hg bundle' so for now I'm
avoiding the detour through bundlespec rework territory.

Better debug output for obsmarkers in 'debugbundle' will be added in later
changesets. The 'test-obsolete-bundle-strip.t' test will also get updated in a
later changeset to keep the current changeset smaller.
2017-05-28 11:50:43 -07:00
Pierre-Yves David
ffd8983573 bundle2: move function building obsmarker-part in the bundle2 module
We move it next to similar part building functions. We will need it for the
"writenewbundle" logic. This will allow us to easily include obsmarkers in
on-disk bundle, a necessary step before having `hg strip` also operate on
markers.

(Yes, the bundle2 module was already too large, but there any many
interdependencies between its components so it is non-trivial to split, this is
a quest for another adventure.)
2017-05-28 11:48:18 -07:00
Augie Fackler
0e18802e22 merge with stable 2017-05-21 02:45:32 -04:00
Pierre-Yves David
8f0cd8c82a obsolete: invalidate "volatile" set cache after merging marker
Adding markers to the repository might affect the set of obsolete changesets. So we
most remove the "volatile" set who rely in that data. We add two missing
invalidations after merging markers. This was caught by code change in the evolve
extensions tests.

This issues highlight that the current way to do things is a bit fragile,
however we keep things simple for stable.
2017-05-17 15:39:37 +02:00
Gregory Szorc
79225ac4bc bundle2: ignore errors seeking a bundle after an exception (issue4784)
Many have seen a "stream ended unexpectedly" error. This message is
raised from changegroup.readexactly() when a read(n) operation fails
to return exactly N bytes.

I believe most occurrences of this error in the wild stem from
the code changed in this patch. Before, if bundle2's part applicator
raised an Exception when processing/applying parts, the exception
handler would attempt to iterate the remaining parts. If I/O
during this iteration failed, it would likely raise the
"stream ended unexpectedly" exception.

The problem with this approach is that if we already encountered
an I/O error iterating the bundle2 data during application, then
any further I/O would almost certainly fail. If the original stream
were closed, changegroup.readexactly() would obtain an empty
string, triggering "stream ended unexpectedly" with "got 0." This is
the error message that users would see. What's worse is that the
original I/O related exception would be lost since a new exception
would be raised. This made debugging the actual I/O failure
effectively impossible.

This patch changes the exception handler for bundle2 application to
ignore errors when seeking the underlying stream. When the underlying
error is I/O related, the seek should fail fast and the original
exception will be re-raised. The output changes in
test-http-bad-server.t demonstrate this.

When the underlying error is not I/O related and the stream can be
seeked, the old behavior is preserved.
2017-04-16 11:55:08 -07:00
Pierre-Yves David
a8ff8b5088 bundle2: move 'seek' and 'tell' methods off the unpackermixin class
These methods are unrelated to unpacking. They are used internally by the
'unbundlepart' class only. So me move them there as private methods.

In the same go, we clarify their internal role in the their docstring.
2017-04-09 19:09:07 +02:00
Pierre-Yves David
c1bb70eed7 bundle2: move the 'close' method off the unpackermixin
This method is unrelated to unpacking and only used by the unbundle20 class.
We move it there for clarity.
2017-04-09 19:08:24 +02:00
Pierre-Yves David
72eb1f753d bundle2: clarify the docstring of unpackermixin methods
The unpackermixin is a utility used to implement the bundle2 protocol. It should
not be used when writing part handlers. We update the docstring to clarify this.
2017-04-09 18:12:54 +02:00
Pierre-Yves David
c1568c1200 bundle2: add documention to 'part.addparams'
There are some non-obvious limitations on the parameters of this method.
Add some documentation where people will likely look to understand how
to use this API.
2017-04-09 18:16:09 +02:00
Jun Wu
b99bc99ff6 bundle2: use ProgrammingError 2017-03-26 16:57:25 -07:00
Pierre-Yves David
68b43a6db4 bundle: add optional 'tagsfnodecache' data to on disk bundle (issue5543)
This should help performance when unbundling.
2017-05-05 17:31:15 +02:00
Pierre-Yves David
a8c6292f9c bundle2: move tagsfnodecache generation in a generic function
This will help us reusing the logic for `hg bundle`.
2017-05-05 17:28:52 +02:00
Pierre-Yves David
6777304ca7 bundle: introduce an higher level function to write bundle on disk
The current function ('writebundle') is focussing on getting an existing
changegroup to disk. It is no easy ways to includes more part in the generated
bundle2. So we introduce a slightly higher level function that is fed the
'outgoing' object (that defines the bundled spec) and the bundlespec parameters
(to control the changegroup generation and inclusion of other parts).

This is creating the third logic dedicated to create a consistent bundle2 (the
other 2 are the push code and the getbundle code). We should probably reconcile
them at some points but they all takes different types of input. So we need to
introduce an intermediate "object" that each different input could be converted
to. Such unified "bundle2 specification" could be fed to some unified code.

We start by having the `hg bundle` related code on its own to helps defines its
specific needs first. Once the common and specific parts of each logic will be
known we can start unification.
2017-05-05 17:09:47 +02:00
Yuya Nishihara
ffd3ffbc1a pycompat: extract helper to raise exception with traceback
It uses "raise excobj, None, tb" form which I think is simpler and more
useful than "raise exctype, args, tb".
2017-04-20 22:16:12 +09:00
Gregory Szorc
5ca0f908bf py3: add __bool__ to every class defining __nonzero__
__nonzero__ was renamed to __bool__ in Python 3. This patch simply
aliases __bool__ to __nonzero__ for every class implementing
__nonzero__.
2017-03-13 12:40:14 -07:00
Augie Fackler
d19fbe9c1b merge with stable 2017-02-15 11:22:01 -05:00
Siddharth Agarwal
7d1a6f9777 bundle2: fix assertion that 'compression' hasn't been set
`n.lower()` will return `compression`, not `Compression`.
2017-02-13 11:43:12 -08:00
Gregory Szorc
9efea3d15c bundle2: allow compression options to be passed to compressor
Compression engines allow options to be passed to them to control
behavior. This patch exposes an argument to bundle2.writebundle()
that passes options to the compression engine when writing compressed
bundles. The argument is honored for both bundle1 and bundle2, the
latter requiring a bit of plumbing to pass the value around.
2017-01-10 11:19:37 -08:00
Pierre-Yves David
683feeeddd bundle2: implement a basic __repr__ for bundle2 part
We display basic data as the part id and part type. This make debugging bundle2
related code friendlier.
2017-02-02 14:19:48 +01:00
Pierre-Yves David
24dbeff39a bundle2: drop an outdated comment
The function is no longer in "early" stage and have been used in production for
years. We can probably drop that part of the docstring...
2017-02-02 11:03:41 +01:00
Gregory Szorc
2e5ba752dd bundle2: equate 'UN' with no compression
An upcoming patch will change the "alg" argument passed to this
function from None to "UN" when no compression is wanted.

The existing implementation of bundle2 does not set a "Compression"
parameter if no compression is used. In theory, setting
"Compression=UN" should work. But I haven't audited the code to see if
all client versions supporting bundle2 will accept this.

Rather than take the risk, avoid the BC breakage and treat "UN"
the same as None.
2016-11-10 23:29:01 -08:00
Gregory Szorc
ddaa837b1a bundle2: use compressstream compression engine API
Compression engines now have an API for compressing a stream of
chunks. Switch to it and make low-level compression code disappear.
2016-11-07 18:46:37 -08:00
Gregory Szorc
e1a5352aa0 bundle2: use compression engines API to obtain decompressor
Like the recent change for the compressor side, this too is
relatively straightforward. We now store a compression engine
on the instance instead of a low-level decompressor. Again, this
will allow us to easily transition to different compression engine
APIs when they are implemented.
2016-11-07 18:36:48 -08:00
Gregory Szorc
1ddbc0cc5d bundle2: use new compression engine API for compression
Now that we have a new API to define compression engines, let's put it
to use!

The new code stores a reference to the compression engine instead of
a low-level compressor object. This will allow us to more easily
transition to different APIs on the compression engine interface
once we implement them.

As part of this, we change the registration in bundletypes to use 'UN'
instead of None. Previously, util.compressors had the no-op compressor
registered under both the 'UN' and None keys. Since we're switching to
a new API, I don't see the point in carrying this dual registration
forward.
2016-11-07 18:35:43 -08:00
Gregory Szorc
d694855e6f bundle2: only emit compressed chunks if they have data
This is similar to 72dcaa40df76. Not all calls into the compressor
return compressed data, as the compressor may buffer compressed
output internally. It is cheaper to check for empty chunks than to
send empty chunks through the generator.

When generating a gzip-v2 bundle of the mozilla-unified repo, this
change results in 50,093 empty chunks not being sent through the
generator (out of 1,902,996 total input chunks).
2016-10-15 17:10:53 -07:00
Yuya Nishihara
7c03e0d6ba pycompat: provide 'ispy3' constant
We compare version_info at several places, which seems enough to define
a constant.
2016-09-28 20:01:23 +09:00
Pierre-Yves David
5bcff70a60 merge with stable 2016-09-14 17:12:39 +02:00
Akihiko Odaki
82bf519632 bundle2: localize handleoutput remote prompts
Code archaeology suggests that there was no good reason for this not to
be localized. 'remote: ' is already localized elsewhere.
2016-09-01 13:16:55 -05:00
Gregory Szorc
c48909f844 bundle2: fail faster when interrupted
Before this patch, bundle2 application attempted to consume remaining
bundle2 part data when the process is interrupted (SIGINT) or when
sys.exit is called (translated into a SystemExit exception). This
meant that if one of these occurred when applying a say 1 GB
changegroup bundle2 part being downloaded over a network, it may take
Mercurial *several minutes* to terminate after a SIGINT because the
process is waiting on the network to stream megabytes of data. This is
not a great user experience and a regression from bundle1. Furthermore,
many process supervisors tend to only give processes a finite amount of
time to exit after delivering SIGINT: if processes take too long to
self-terminate, a SIGKILL is issued and Mercurial has no opportunity to
clean up. This would mean orphaned locks and transactions. Not good.

This patch changes the bundle2 application behavior to fail faster
when an interrupt or system exit is requested. It does so by not
catching BaseException (which includes KeyboardInterrupt and
SystemExit) and by explicitly checking for these conditions in
yet another handler which would also seek to the end of the current
bundle2 part on failure.

The end result of this patch is that SIGINT is now reacted to
significantly faster: the active transaction is rolled back
immediately without waiting for incoming bundle2 data to be consumed.
This restores the pre-bundle2 behavior and makes Mercurial treat
signals with the urgency they deserve.
2016-08-25 19:53:14 -07:00
Gregory Szorc
4ad5f2e492 bundle2: store changeset count when creating file bundles
The bundle2 changegroup part has an advisory param saying how many
changesets are in the part. Before this patch, we were setting
this part when generating bundle2 parts via the wire protocol but
not when generating local bundle2 files.

A side effect of not setting the changeset count part is that progress
bars don't work when applying changesets. As the tests show, this
impacted clone bundles, shelve, backup bundles, `hg unbundle`, and
anything touching bundle2 files.

This patch adds a backdoor to allow us to pass state from
changegroup generation into the unbundler. We store the number
of changesets in the changegroup in this state and use it to
populate the aforementioned advisory part parameter when generating
the bundle2 bundle.

I concede that I'm not thrilled by how state is being passed in
changegroup.py (it feels a bit hacky). I would love to overhaul the
rather confusing set of functions in changegroup.py with something that
passes rich objects around instead of e.g. low-level generators.
However, given the code freeze for 3.9 is imminent, I'd rather not
undertake this endeavor right now. This feels like the easiest way
to get the parameter added to the changegroup part.
2016-07-17 15:13:51 -07:00
Gregory Szorc
71e33a969a bundle2: use a sorted dict for holding parameters
An upcoming change that introduces a 2nd part parameter to a part
reveals that `hg debugbundle` isn't deterministic because parameters
are stored on n plain, unsorted dict.

While we could change that command to sort before output, I think
the more important underlying issue is that bundle2 reading is taking
an ordered data structure and converting it to an unordered one.
Plugging in util.sortdict() fixes that problem while preserving API
compatibility.

This patch also appears to shine light on the fact that we don't
have tests verifying parts with multiple parameters roundtrip
correctly. That would be a good thing to test (and fuzz)... someday.
2016-07-17 14:51:00 -07:00
Mads Kiilerich
f1004d7ba4 bundle2: don't assume ordering of heads checked after push
Usually, the heads will have the same ordering in handlecheckheads. Insisting
on the same ordering is however an unnecessary constraint that in some custom
cases can cause pushes to fail even though the actual heads didn't change. This
caused production issues for us in combination with the current version of
https://bitbucket.org/Unity-Technologies/hgwebcachingproxy/ .
2016-06-01 21:40:52 +02:00
Pulkit Goyal
9d5cc65520 py3: conditionalize the raise statement
raise E,V,T is not acceptable in Python 3, thats is conditionalized.
Moreover this will result in syntax error so we have to use exec() to
execute this. Related PEP- https://www.python.org/dev/peps/pep-3109/#id14

My implementation is motivated from the six implementation except they are
defining a new function exec_() to prevent adding an extra frame AFAIK :)

https://bitbucket.org/gutworth/six/src/ca4580a5a648/six.py#six.py-680
2016-08-08 23:51:11 +05:30
timeless
109fcbc79e pycompat: switch to util.urlreq/util.urlerr for py3 compat 2016-04-06 23:22:12 +00:00
Martin von Zweigbergk
d613237780 bundle: remove obsolete (and duplicate) comment
Change 760f9c8ad835 (changegroup: move chunk extraction into a
getchunks method of unbundle10, 2014-04-10) extracted some code to a
getchunks() method and copied a comment about the changegroup format
to the new method. The copy that remains in the old place, doesn't
make much sense there, so let's remove it.
2016-03-29 10:21:05 -07:00
Martin von Zweigbergk
4cc86f7b27 bundle: move writebundle() from changegroup.py to bundle2.py (API)
writebundle() writes a bundle2 bundle or a plain changegroup1. Imagine
away the "2" in "bundle2.py" for a moment and this change should makes
sense. The bundle wraps the changegroup, so it makes sense that it
knows about it. Another sign that this is correct is that the delayed
import of bundle2 in changegroup goes away.

I'll leave it for another time to remove the "2" in "bundle2.py"
(alternatively, extract a new bundle.py from it).
2016-03-28 14:41:29 -07:00
Martin von Zweigbergk
86ca76bafe changegroup: fix pulling to treemanifest repo from flat repo (issue5066)
In b89de5ee5b31 (changegroup: don't support versions 01 and 02 with
treemanifests, 2016-01-19), I stopped supporting use of cg1 and cg2
with treemanifest repos. What I had not considered was that it's
perfectly safe to pull *to* a treemanifest repo using any changegroup
version. As reported in issue5066, I therefore broke pull from old
repos into a treemanifest repo. It was not covered by the test case,
because that pulled from a local repo while enabling treemanifests,
which enabled treemanifests on the source repo as well. After
switching to pulling via HTTP, it breaks.

Fix by splitting up changegroup.supportedversions() into
supportedincomingversions() and supportedoutgoingversions().
2016-01-27 09:07:28 -08:00
Augie Fackler
54446bb7e0 cleanup: use modern @property/@foo.setter property specification
We can use this now that we're 2.6+, and this is more idiomatic modern
Python.
2016-01-16 10:50:28 -05:00
Martin von Zweigbergk
e5bd6473b3 changegroup: hide packermap behind methods
This is to prepare for hiding changegroup3 behind a config option.
2016-01-12 21:01:06 -08:00
Martin von Zweigbergk
417363259e treemanifests: set bundle2 part parameter indicating treemanifest
By adding a mandatory 'treemanifest' parameter in the bundle2 part, we
make it possible for the recipient to set repo requirements before the
manifest revlog is accessed.
2016-01-08 21:13:06 -08:00
Gregory Szorc
059667a51c bundle2: attribute remote failures to remote (issue4788)
Before bundle2, hook output from hook failures was prefixed with
"remote: ". Up to this point with bundle2, the output was converted to
the message to print in an Abort exception. This had 2 implications:

1) It was unclear whether an error message came from the local repo
   or the remote
2) The exit code changed from 1 to 255

This patch changes the handling of error:abort bundle2 parts during push
to prefix the error message with "remote: ". This restores the old
behavior.

We still preserve the behavior of raising an Abort during bundle2
application failure. This is a regression from pre-bundle2 because the
exit code changed.

Because we no longer raise an Abort with the remote's message, we needed
to insert a message for the new Abort. So, I invented a new error
message for that. This is another change from pre-bundle2. However, I
like the new error message because it states unambiguously who aborted
the push failed, which I think is important for users so they can decide
what's next.
2015-10-24 00:39:22 +01:00
Pierre-Yves David
2468be2e78 bundle2: make unbundle.compressed return True when compressed
We were returning 'False' in all cases, even when the bundle2 was actually
compressed.
2015-10-02 23:21:39 -07:00
Pierre-Yves David
fb85c76c3c applybundle: take url as argument
We allow specifying the url to carry it to hooks. This gets us closer to
'bundle1.apply(...)' and will allow us to remove regressions in multiple place
where we forget to pass the url to hooks.
2015-10-20 15:55:04 +02:00
Pierre-Yves David
737d464351 applybundle: take source as argument
We allow specifying the source to carry it to hooks. This gets us closer to
'bundle1.apply(...)' and will allow us to remove regressions in multiple places
where we forget to pass the source to hooks.
2015-10-20 15:52:42 +02:00
Pierre-Yves David
a8f2963ec8 applybundle: set 'bundle2=1' env for all transaction
This should be set for all bundle2 application, we enforce that at a low level.
This is for courtesy with hooks.
2015-10-20 15:48:24 +02:00
Pierre-Yves David
bffc6ff104 bundle2: introduce an "applybundle" function
There is a case where the intent is clear and the transaction is not optional. We
want to be able to alter that transaction in a wide and easy way. We cannot get
a unified '.apply(repo)' method for bundle1 and bundle2 yet because the api are
still a bit too far apart. But this is a good step forward to get the rc out.
2015-10-20 15:45:39 +02:00
Augie Fackler
b9b5df0ea1 bundle2: use cg?unpacker.apply() instead of changegroup.addchangegroup() 2015-10-13 17:11:52 -04:00