Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 17:02:57 -0800] rev 36870
hgweb: support using new response object for web commands
We have a "requestcontext" type for holding state for the current
request. Why we pass in the wsgirequest and templater instance
to @webcommand functions, I don't know.
I like the idea of standardizing on using "requestcontext" for passing
all state to @webcommand functions because that scales well without
API changes every time you want to pass a new piece of data. So,
we add our new request and response instances to "requestcontext" so
@webcommand functions can access them.
We also teach our command dispatcher to recognize a new calling
convention. Instead of returning content from the @webcommand
function, we return our response object. This signals that this
response object is to be used for sending output. The keyword
extension was wrapping various @webcommand and assuming the output
was iterable, so we had to teach it about the new calling convention.
To prove everything works, we convert the "filelog" @webcommand
to use the new convention.
The new calling convention is a bit wonky. I intend to improve this
once all commands are ported to use the new response object.
Differential Revision: https://phab.mercurial-scm.org/D2786
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 14:19:27 -0800] rev 36869
hgweb: inline caching() and port to modern mechanisms
We only had one consumer of this simple function. While it could be
a generic function, let's not over abstract the code.
As part of inlining, we port it off wsgirequest, fix some Python 3
issues, and set a response header on our new response object so it
is ready once we start using it to send responses.
Differential Revision: https://phab.mercurial-scm.org/D2785
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 14:06:58 -0800] rev 36868
hgweb: expose repo name on parsedrequest
I'm not a fan of doing this because I want to find a better solution to
the REPO_NAME hack. But this change gets us a few steps closer to
eliminating use of wsgirequest. We can worry about fixing REPO_NAME
once wsgirequest is gone.
Differential Revision: https://phab.mercurial-scm.org/D2784
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 14:00:40 -0800] rev 36867
hgweb: expose URL scheme and REMOTE_* attributes
These are consulted by the HTTP wire protocol handler by reading from
the env dict. Let's expose them as attributes instead.
With the wire protocol handler updates to use the new attributes, we
no longer have any consumers of the legacy wsgirequest type in the
wire protocol code (outside of a proxied call to the permissions
checker). So, we remove most references to it.
Differential Revision: https://phab.mercurial-scm.org/D2783
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 12:31:11 -0800] rev 36866
hgweb: remove wsgirequest.form (API)
Now that everything is ported to consume from parsedrequest.qsparams,
we no longer have a need for wsgirequest.form. Let's remove all
references to it.
.. api::
The WSGI request object no longer exposes a ``form`` attribute
containing parsed query string data. Use the ``qsparams`` attribute
instead.
Differential Revision: https://phab.mercurial-scm.org/D2782
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 12:36:36 -0800] rev 36865
hgweb: perform all parameter lookup via qsparams
I think I managed to update all call sites using wsgirequest.form
to use parsedrequest.qsparams.
Since behavior of qsparams is to retrieve last value, behavior will
change if a parameter was specified multiple times. But I think this
is acceptable.
I'm not a fan of the `req.req.qsparams` pattern. And some of the
modified code could be written better. But I was aiming for a
straight port with this change. Cleanup can come later.
Differential Revision: https://phab.mercurial-scm.org/D2781
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 12:11:26 -0800] rev 36864
hgweb: set variables in qsparams
We currently mutate wsgireq.form in a few places. Since it is
independent from req.qsparams, we will need to make changes on
req.qsparams as well before consumers can use qsparams. So let's
do that.
Eventually, we'll delete wsgireq.form and all references to it.
Differential Revision: https://phab.mercurial-scm.org/D2780
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:46:52 -0800] rev 36863
hgweb: use our new request object for "style" parameter
The "style" parameter is kind of wonky because it is explicitly
set and has lookups in random locations.
Let's port it to qsparams first because it isn't straightforward.
There is subtle change in behavior. But I don't think it is worth
calling out in a BC.
Our multidict's __getitem__ returns the last set value for a key,
not the first. So if the query string set a variable multiple times,
before we would get the first value and now we would get the last
value. It makes no sense to specify these things multiple times.
And I think last write wins is more sensible than first write wins.
Differential Revision: https://phab.mercurial-scm.org/D2779
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 12:35:38 -0800] rev 36862
hgweb: use a multidict for holding query string parameters
My intention with refactoring the WSGI code was to make it easier
to read. I initially wanted to vendor and use WebOb, because it seems
to be a pretty reasonable abstraction layer for WSGI. However, it isn't
using relative imports and I didn't want to deal with the hassle of
patching it. But that doesn't mean we can't use good ideas from WebOb.
WebOb has a "multidict" data structure for holding parsed query string
and POST form data. It quacks like a dict but allows you to store
multiple values for each key. It offers mechanisms to return just one
value, all values, or return 1 value asserting that only 1 value is
set. I quite like its API.
This commit implements a read-only "multidict" in the spirit of
WebOb's multidict.
We replace the query string attributes of our parsed request with
an instance of it.
Differential Revision: https://phab.mercurial-scm.org/D2776
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:23:05 -0800] rev 36861
hgweb: create dedicated type for WSGI responses
We have refactored the request side of WSGI processing into a dedicated
type. Now let's do the same thing for the response side.
We invent a ``wsgiresponse`` type. It takes an instance of a
request (for consulation) and the WSGI application's "start_response"
handler.
The type basically allows setting the HTTP status line, response
headers, and the response body.
The WSGI application calls sendresponse() to start sending output.
Output is emitted as a generator to be fed through the WSGI application.
According to PEP 3333, this is the preferred way for output to be
transmitted. (Our legacy ``wsgirequest`` exposed a write() to send
data. We do not wish to support this API because it isn't recommended
by PEP 3333.)
The wire protocol code has been ported to use the new API.
Differential Revision: https://phab.mercurial-scm.org/D2775
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:15:05 -0800] rev 36860
tests: add test for a wire protocol request to wrong base URL
We have code that validates that wire protocol commands (which are
specified via query string) must occur at the base URL of a repo.
But we have no test coverage for this behavior. Let's add some.
Differential Revision: https://phab.mercurial-scm.org/D2778
Gregory Szorc <gregory.szorc@gmail.com> [Fri, 09 Mar 2018 17:10:36 -0800] rev 36859
hgweb: remove support for short query string based aliases (BC)
Form data exposed by hgweb is post-processed to expand certain
shortcuts. For example, URLs with "?cs=@" is essentially expanded to
"?cmd=changeset&node=@". And the URL router treats this the same
as "/changeset/@".
These shortcuts were initially added in 2005 in
34cb3957d875 and
964baa35faf8. They have rarely been touched in the last decade (just
moving code around a bit).
We have almost no test coverage of this feature. AFAICT no templates
reference URLs of this form. I even looked at the initial version
of paper and coal from ~2008 and they use the "/command/params" URL
form and not these shortcuts.
Furthermore, I couldn't even get some shortcuts to work! For example,
"?sl=@" attempts to do a revision search instead of showing shortlog
starting at revision @. Maybe I'm just doing it wrong?
Because this is ancient, mostly untested code, there is a migration
path to something better, and because anyone passionate enough to
preserve URLs can install URL redirects, let's nuke the feature.
.. bc::
Query string shorts in hgweb like ``?cs=@`` have been removed. Use
URLs of the form ``/:cmd`` instead.
Differential Revision: https://phab.mercurial-scm.org/D2773
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:07:53 -0800] rev 36858
hgweb: remove support for POST form data (BC)
Previously, we called out to cgi.parse(), which for POST requests
parsed multipart/form-data and application/x-www-form-urlencoded
Content-Type requests for form data, combined it with query string
parameters, returned a union of the values.
As far as I know, nothing in Mercurial actually uses this mechanism
to submit data to the HTTP server. The wire protocol has its own
mechanism for passing parameters. And the web interface only does
GET requests. Removing support for parsing POST data doesn't break
any tests.
Another reason to not like this feature is that cgi.parse() may
modify the QUERY_STRING environment variable as a side-effect.
In addition, it merges both POST data and the query string into
one data structure. This prevents consumers from knowing whether
a variable came from the query string or POST data. That can matter
for some operations.
I suspect we use cgi.parse() because back when this code was
initially implemented, it was the function that was readily
available. In other words, I don't think there was conscious
choice to support POST data: we just got it because cgi.parse()
supported it.
Since nothing uses the feature and it is untested, let's remove
support for parsing POST form data. We can add it back in easily
enough if we need it in the future.
.. bc::
Hgweb no longer reads form data in POST requests from
multipart/form-data and application/x-www-form-urlencoded
requests. Arguments should be specified as URL path components
or in the query string in the URL instead.
Differential Revision: https://phab.mercurial-scm.org/D2774
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:06:13 -0800] rev 36857
hgweb: expose input stream on parsed WSGI request object
Our next step towards moving away from wsgirequest to our newer,
friendlier parsedrequest type is input stream access.
This commit exposes the input stream on the instance. Consumers
in the HTTP protocol server switch to it.
Because there were very few consumers of the input stream, we stopped
storing a reference to the input stream on wsgirequest directly. All
access now goes through parsedrequest. However, wsgirequest still
may read from this stream as part of cgi.parse(). So we still need to
create the stream from wsgirequest.
Differential Revision: https://phab.mercurial-scm.org/D2771
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:56:10 -0800] rev 36856
hgweb: make parsedrequest part of wsgirequest
This is kind of ugly. But an upcoming commit will teach parsedrequest
about the input stream. Because the input stream is global state and
can't be accessed without side-effects, we need to take actions to
ensure that multiple consumers don't read from it independently. The
easiest way to do this is for one object to hold a reference to both
items having access to the input stream so that when a copy is made,
we can remove the attribute from the other instance.
So we create our parsed request instance from the wsgirequest
constructor and hold a reference to it there. This is better than
our new type holding a reference to wsgirequest because all the
code for managing access will be temporary and we shouldn't pollute
parsedrequest with this ugly history.
Differential Revision: https://phab.mercurial-scm.org/D2770
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 11:03:45 -0800] rev 36855
hgweb: refactor the request draining code
The previous code for draining was only invoked in a few places in
the wire protocol. Behavior wasn't consist. Furthermore, it was
difficult to reason about.
With us converting the input stream to a capped reader, it is now
safe to always drain the input stream when its size is known because
we can never overrun the input and read into the next HTTP request.
The only question is "should we?"
This commit changes the draining code so every request is examined.
Draining now kicks in for a few requests where it wouldn't before.
But I think the code is sufficiently restricted so the behavior is
safe. Possibly the most dangerous part of this code is the issuing
of Connection: close for POST and PUT requests that don't have a
Content-Length. I don't think there are any such uses in our WSGI
application, so this should be safe.
In the near future, I plan to significantly refactor the WSGI
response handling. I anticipate this code evolving a bit. So any
minor regressions around draining or connection closing behavior
might be fixed as a result of that work.
All tests pass with this change. That scares me a bit because it
means we are lacking low-level tests for the HTTP protocol.
Differential Revision: https://phab.mercurial-scm.org/D2769
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:48:34 -0800] rev 36854
hgweb: use a capped reader for WSGI input stream
Per PEP 3333, the input stream from WSGI should respect EOF and
prevent reads past the end of the request body. However, not all
WSGI servers guarantee this. Notably, our BaseHTTPServer based
built-in HTTP server doesn't. Instead, it exposes the raw socket
and you can read() from it all you want, getting the connection in
a bad state by doing so.
We have a "cappedreader" utility class that proxies a file object
and prevents reading past a limit.
This commit converts the WSGI input stream into a capped reader when
the input length is advertised via Content-Length headers.
"cappedreader" only exposes a read() method. PEP 3333 states that
the input stream MUST also support readline(), readlines(hint), and
__iter__(). However, since our WSGI application code only calls
read() and since we're not manipulating the stream exposed by the
WSGI server, we're not violating the spec here.
Differential Revision: https://phab.mercurial-scm.org/D2768
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:47:30 -0800] rev 36853
hgweb: document continuereader
Differential Revision: https://phab.mercurial-scm.org/D2767
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 18:00:04 -0800] rev 36852
hgweb: remove wsgirequest.__iter__
This was added in
d0db3462d568 in 2006. I can't find a justification
for this method in PEP 3333. I suspect we were originally intending
to use this type as the WSGI application (which should be iterable)?
The tests all pass without this method. So let's nuke it.
Differential Revision: https://phab.mercurial-scm.org/D2749
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 17:57:07 -0800] rev 36851
hgweb: remove wsgirequest.read()
This was just a proxy to self.inp.read(). This method serves little
value. Let's nuke it.
Callers in the wire protocol server have been updated accordingly.
Differential Revision: https://phab.mercurial-scm.org/D2748
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:46:08 -0800] rev 36850
hgweb: remove unused methods on wsgirequest
writelines() isn't used in our code base.
close() was a no-op. It is an optional method per PEP 3333.
My eventual goal is to kill the wsgirequest class, hence why I'm
removing code.
Differential Revision: https://phab.mercurial-scm.org/D2747
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 17:17:48 -0800] rev 36849
wireprotoserver: remove unused argument from _handlehttperror()
Differential Revision: https://phab.mercurial-scm.org/D2746
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:44:56 -0800] rev 36848
hgweb: store and use request method on parsed request
PEP 3333 says that REQUEST_METHOD is always defined.
Differential Revision: https://phab.mercurial-scm.org/D2745
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:45:12 -0800] rev 36847
hgweb: handle CONTENT_LENGTH
PEP 3333 says CONTENT_LENGTH may be set. I /think/ WSGI servers are
allowed to invent this key even if the client didn't send it.
We had code in wireprotoserver looking for this key. So let's
just automagically convert this key to an HTTP request header
when parsing the request.
Differential Revision: https://phab.mercurial-scm.org/D2744
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 16:38:01 -0800] rev 36846
wireprotoserver: access headers through parsed request
Now that we can access headers via the parsed request object, let's
do that.
Since the new object uses bytes, hyphens, and is case-insensitive, a
bit of code around normalizing values has been removed. I think
the new code is much more intuitive because it more closely matches
what is going out over the wire.
Differential Revision: https://phab.mercurial-scm.org/D2743
Gregory Szorc <gregory.szorc@gmail.com> [Mon, 12 Mar 2018 13:15:00 -0700] rev 36845
hgweb: garbage collect on every request
There appears to be a cycle in localrepository or hgweb that
is preventing repositories from being garbage collected when
hgwebdir dispatches to hgweb. Every request creates a new
repository instance and then leaks that object and other referenced
objects. A periodic GC to find cycles will eventually collect the
old repositories. But these don't run reliably and rapid requests
to hgwebdir can result in rapidly increasing memory consumption.
With the Firefox repository, repeated requests to raw-file URLs
leak ~100 MB per hgwebdir request (most of this appears to be
cached manifest data structures). WSGI processes quickly grow
to >1 GB RSS.
Breaking the cycles in localrepository is going to be a bit of
work.
Because we know that hgwebdir leaks localrepository instances, let's
put a band aid on the problem in the form of an explicit gc.collect()
on every hgwebdir request.
As the inline comment states, ideally we'd do this in a finally
block for the current request iff it dispatches to hgweb. But
_runwsgi() returns an explicit value. We need the finally to run
after generator exhaustion. So we'd need to refactor _runwsgi()
to "yield" instead of "return." That's too much change for a patch
to stable. So we implement this hack one function above and run
it on every request.
The performance impact of this change should be minimal. Any
impact should be offset by benefits from not having hgwebdir
processes leak memory.
Yuya Nishihara <yuya@tcha.org> [Sun, 11 Mar 2018 20:10:38 +0900] rev 36844
amend: abort if unresolved merge conflicts found (
issue5805)
It was checked by repo.commit() before
e8a7c1a0565a "cmdutil: remove the
redundant commit during amend."
Yuya Nishihara <yuya@tcha.org> [Mon, 12 Mar 2018 22:47:33 +0900] rev 36843
debugwireproto: close the write end before consuming all available data
And make it read all available data deterministically. Otherwise util.poll()
may deadlock because both stdout and stderr could have no data.
Spotted by the next patch which removes stderr from the fds.
Joerg Sonnenberger <joerg@bec.de> [Fri, 09 Mar 2018 15:57:16 +0100] rev 36842
graft: check for missing revision first before scanning working copy
Differential Revision: https://phab.mercurial-scm.org/D2753
Matt Harbison <matt_harbison@yahoo.com> [Sat, 10 Mar 2018 22:02:58 -0500] rev 36841
hook: ensure stderr is flushed when an exception is raised, for test stability
Windows has had issues with output order in test-ssh-proto-unbundle.t[1] since
it was created a few weeks ago. Each of the problems occurred when an exception
was thrown out of the hook.
Now the only thing blocking D2720 is the fact that the "abort: ..." lines on
stderr are totally AWOL. I have no idea where there are.
[1] https://buildbot.mercurial-scm.org/builders/Win7%20x86_64%20hg%20tests/builds/541/steps/run-tests.py%20%28python%202.7.13%29/logs/stdio
Gregory Szorc <gregory.szorc@gmail.com> [Sat, 10 Mar 2018 10:27:56 -0800] rev 36840
wireproto: raise ProgrammingError instead of Abort
This isn't a user-facing error and can only be caused by bad
Python code.
Thanks to Yuya for spotting this.
Differential Revision: https://phab.mercurial-scm.org/D2777
Yuya Nishihara <yuya@tcha.org> [Sat, 10 Mar 2018 19:56:47 +0900] rev 36839
py3: make test-commit-interactive.t byte-safe
Yuya Nishihara <yuya@tcha.org> [Sat, 10 Mar 2018 19:49:09 +0900] rev 36838
py3: open patch file in binary mode and convert eol manually
Here we don't introduce a reader wrapper since it wouldn't be easy to make
read(n) handle partial data and length correctly.
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:45:57 -0600] rev 36837
py3: wrap file object to write patch in native eol preserving byte-ness
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:24:12 -0600] rev 36836
py3: drop b'' from debug message "moving bookmarks"
Yuya Nishihara <yuya@tcha.org> [Sat, 10 Mar 2018 15:57:16 +0900] rev 36835
py3: use r'' instead of sysstr('') to get around code transformer
Fewer function calls should be better.
Yuya Nishihara <yuya@tcha.org> [Sat, 10 Mar 2018 15:50:09 +0900] rev 36834
ui: remove any combinations of CR|LF from prompt response
On Windows, we have to accept both CR+LF and LF. This patch simply makes
any trailing CRs and LFs removed from a user input instead of doing stricter
parsing, as an input must be a readable text.
Matt Harbison <matt_harbison@yahoo.com> [Sat, 10 Mar 2018 12:45:10 -0500] rev 36833
sshpeer: check pipe validity before forwarding output from it
After the previous fix, fileobjectproxy._observedcall() (called when
win32.peekpipe() accesses .fileno) started exploding. With this fix, similar
checks are needed inside debugwireproto(). Since that is hardcoded to not use
os.devnull, IDK if those are worth fixing.
Matt Harbison <matt_harbison@yahoo.com> [Sat, 10 Mar 2018 12:22:08 -0500] rev 36832
util: forward __bool__()/__nonzero__() on fileobjectproxy
In trying to debug the Windows process hang in D2720, I changed the stderr pipe
to the peer to be os.devnull instead. That caused sshpeer._cleanuppipes()[1] to
explode, complaining NoneType has no __iter__ attribute, even though the
previous line checked for None.
[1] https://www.mercurial-scm.org/repo/hg/file/
b434965f984e/mercurial/sshpeer.py#l133
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:16:41 -0600] rev 36831
py3: fix slicing of bisect label in templatefilters.shortbisect()
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:15:01 -0600] rev 36830
templatefilters: inline hbisect.shortlabel()
It's pretty simple. I don't think the business logic has to be placed in
hbisect.py.
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:11:24 -0600] rev 36829
py3: make test-bisect.t bytes-safe
Yuya Nishihara <yuya@tcha.org> [Tue, 06 Mar 2018 07:10:50 -0600] rev 36828
py3: fix integer formatting in bisect error
Yuya Nishihara <yuya@tcha.org> [Sat, 10 Mar 2018 16:55:54 +0900] rev 36827
py3: silence f.write() in test-annotate.t
Jun Wu <quark@fb.com> [Fri, 09 Mar 2018 14:52:36 -0800] rev 36826
xdiff: resolve signed unsigned comparison warning
Since the value won't be changed inside the code (because context lines
feature was removed by D2705), let's just remove the variable and inline
the 0 value.
The code might be potentially further simplified. But I'd like to make sure
correctness is easily verifiable in this patch.
Differential Revision: https://phab.mercurial-scm.org/D2766
Jun Wu <quark@fb.com> [Fri, 09 Mar 2018 14:47:29 -0800] rev 36825
xdiff: use int64 for hash table size
Follow-up of the previous "long" -> "int64" change. Now xdiff only uses int
for return values and small integers (ex. booleans, shifting score, bits in
hash table size, etc) so it should be able to handle large input.
Differential Revision: https://phab.mercurial-scm.org/D2765
Jun Wu <quark@fb.com> [Fri, 09 Mar 2018 14:39:35 -0800] rev 36824
xdiff: remove unused xpp and xecfg parameters
They are unused. Thus removed.
Differential Revision: https://phab.mercurial-scm.org/D2764
Jun Wu <quark@fb.com> [Fri, 09 Mar 2018 14:37:55 -0800] rev 36823
xdiff: remove unused flags parameter
After D2683, the flags parameter in some functions is no longer needed.
Thus removed.
Differential Revision: https://phab.mercurial-scm.org/D2763
Jun Wu <quark@fb.com> [Fri, 09 Mar 2018 14:24:27 -0800] rev 36822
xdiff: replace {unsigned ,}long with {u,}int64_t
MSVC treats "long" as 4-byte. That could cause overflows since the xdiff
code uses "long" in places where "size_t" or "ssize_t" should be used.
Let's use explicit 8 byte integers to avoid
FWIW git avoids that overflow by limiting diff size to 1GB [1]. After
examining the code, I think the remaining risk (the use of "int") is low
since "int" is only used for return values and hash table size. Although a
wrong hash table size would not affect the correctness of the code, but that
could make the code extremely slow. The next patch will change hash table
size to 8-byte integer so the 1GB limit is unlikely needed.
This patch was done by using `sed`.
[1]: https://github.com/git/git/commit/
dcd1742e56ebb944c4ff62346da4548e1e3be67
Differential Revision: https://phab.mercurial-scm.org/D2762
Jun Wu <quark@fb.com> [Sun, 04 Mar 2018 11:30:16 -0800] rev 36821
xdiff: add comments for fields in xdfile_t
This makes the related code easier to understand.
Differential Revision: https://phab.mercurial-scm.org/D2685
Jun Wu <quark@fb.com> [Wed, 07 Mar 2018 14:45:31 -0800] rev 36820
xdiff: add a preprocessing step that trims files
xdiff has a `xdl_trim_ends` step that removes common lines, unmatchable
lines. That is in theory good, but happens too late - after splitting,
hashing, and adjusting the hash values so they are unique. Those splitting,
hashing and adjusting hash values steps could have noticeable overhead.
Diffing two large files with minor (one-line-ish) changes are not uncommon.
In that case, the raw performance of those preparation steps seriously
matter. Even allocating an O(N) array and storing line offsets to it is
expensive. Therefore my previous attempts [1] [2] cannot be good enough
since they do not remove the O(N) array assignment.
This patch adds a preprocessing step - `xdl_trim_files` that runs before
other preprocessing steps. It counts common prefix and suffix and lines in
them (needed for displaying line number), without doing anything else.
Testing with a crafted large (169MB) file, with minor change:
```
open('a','w').write(''.join('%s\n' % (i % 100000) for i in xrange(
30000000) if i != 6000000))
open('b','w').write(''.join('%s\n' % (i % 100000) for i in xrange(
30000000) if i != 6003000))
```
Running xdiff by a simple binary [3], this patch improves the xdiff perf by
more than 10x for the above case:
```
# xdiff before this patch
2.41s user 1.13s system 98% cpu 3.592 total
# xdiff after this patch
0.14s user 0.16s system 98% cpu 0.309 total
# gnu diffutils
0.12s user 0.15s system 98% cpu 0.272 total
# (best of 20 runs)
```
It's still slightly slower than GNU diffutils. But it's pretty close now.
Testing with real repo data:
For the whole repo, this patch makes xdiff 25% faster:
```
# hg perfbdiff --count 100 --alldata -c
d334afc585e2 --blocks [--xdiff]
# xdiff, after
! wall 0.058861 comb 0.050000 user 0.050000 sys 0.000000 (best of 100)
# xdiff, before
! wall 0.077816 comb 0.080000 user 0.080000 sys 0.000000 (best of 91)
# bdiff
! wall 0.117473 comb 0.120000 user 0.120000 sys 0.000000 (best of 67)
```
For files that are long (ex. commands.py), the speedup is more than 3x, very
significant:
```
# hg perfbdiff --count 3000 --blocks commands.py.i 1 [--xdiff]
# xdiff, after
! wall 0.690583 comb 0.690000 user 0.690000 sys 0.000000 (best of 12)
# xdiff, before
! wall 2.240361 comb 2.210000 user 2.210000 sys 0.000000 (best of 4)
# bdiff
! wall 2.469852 comb 2.440000 user 2.440000 sys 0.000000 (best of 4)
```
[1]: https://phab.mercurial-scm.org/D2631
[2]: https://phab.mercurial-scm.org/D2634
[3]:
```
// Code to run xdiff from command line. No proper error handling.
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "mercurial/thirdparty/xdiff/xdiff.h"
#define ensure(x) if (!(x)) exit(255);
mmfile_t readfile(const char *path) {
struct stat st; int fd = open(path, O_RDONLY);
fstat(fd, &st); mmfile_t file = { malloc(st.st_size), st.st_size };
ensure(read(fd, file.ptr, st.st_size) == st.st_size); close(fd);
return file;
}
int main(int argc, char const *argv[]) {
mmfile_t a = readfile(argv[1]), b = readfile(argv[2]);
xpparam_t xpp = {0}; xdemitconf_t xecfg = {0}; xdemitcb_t ecb = {0};
xdl_diff(&a, &b, &xpp, &xecfg, &ecb);
return 0;
}
```
Differential Revision: https://phab.mercurial-scm.org/D2686
Martin von Zweigbergk <martinvonz@google.com> [Fri, 09 Mar 2018 14:30:15 -0800] rev 36819
transaction: add a name and a __repr__ implementation (API)
This has been useful for me for debugging.
Differential Revision: https://phab.mercurial-scm.org/D2758
Joerg Sonnenberger <joerg@bec.de> [Fri, 09 Mar 2018 16:10:55 +0100] rev 36818
phabricator: update doc string for deprecated token argument
Differential Revision: https://phab.mercurial-scm.org/D2755
Joerg Sonnenberger <joerg@bec.de> [Fri, 09 Mar 2018 16:09:27 +0100] rev 36817
phabricator: print deprecation warning only once
Differential Revision: https://phab.mercurial-scm.org/D2754
Martin von Zweigbergk <martinvonz@google.com> [Thu, 08 Mar 2018 21:17:26 -0800] rev 36816
tests: add a few tests involving --collapse and rebase.singletransaction=1
I'm about to change the rebase code quite a bit and this was poorly
tested.
Differential Revision: https://phab.mercurial-scm.org/D2757
Martin von Zweigbergk <martinvonz@google.com> [Thu, 08 Mar 2018 20:55:51 -0800] rev 36815
tests: simplify test-rebase-transaction.t
The file was extracted from test-rebase-base.t in
8cef8f7d51d0
(test-rebase-base: clarify it is about the "--base" flag,
2017-10-05). This patch follows up that and clarifies the new file's
purpose and simplifies it a bit.
Differential Revision: https://phab.mercurial-scm.org/D2756
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 16:22:25 -0800] rev 36814
hgweb: parse and store HTTP request headers
WSGI transmits HTTP request headers as HTTP_* environment variables.
We teach our parser about these and hook up a dict-like data
structure that supports case insensitive header manipulation.
Differential Revision: https://phab.mercurial-scm.org/D2742
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 16:43:32 -0800] rev 36813
wireprotoserver: remove broken optimization for non-httplib client
There was an experimental non-httplib client in core for several
years. It was removed a week or so ago.
We kept the optimization for this client in the server code. I'm
not sure if that was intended or not. But it doesn't matter: the
code was wrong.
Because the code was accessing a WSGI environment dict, it needed to
access the HTTP_X_HGHTTP2 key to actually read the HTTP header. So
the code deleted by this commit wasn't actually doing anything
meaningful. Doh.
Differential Revision: https://phab.mercurial-scm.org/D2741
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 15:58:52 -0800] rev 36812
wireprotoserver: move all wire protocol handling logic out of hgweb
Previous patches from several days ago worked to isolate processing
of HTTP wire protocol requests to wireprotoserver. We still had a
little logic in hgweb. If feels like the right time to finish the
job.
This commit moves WSGI request servicing from hgweb to wireprotoserver.
The ugly dict holding the parsed request is no more. I think the new
code is cleaner.
As part of this, we now process wire protocol requests before the
block to obtain the "query" variable. This makes it clear that this
wonky "query" variable is not used by the wire protocol.
The wonkiest part about this code is the HTTP 404. I'm actually not
sure what all is going on here. It looks like the code is trying to
prevent URL with path components that specify a command from not
working. That part I grok. What I don't grok is why we need to send
a 404. I would think it would be OK to no-op and let another handler
try to service the request. But if we do this, we get some subrepo
test failures. So it looks like something is expecting the HTTP 404
and reacting to it in a specific way. It /might/ be possible to
change the behavior here. But it isn't something I'm comfortable
doing because I don't understand the problem space.
Differential Revision: https://phab.mercurial-scm.org/D2740
Gregory Szorc <gregory.szorc@gmail.com> [Thu, 08 Mar 2018 15:37:05 -0800] rev 36811
hgweb: use parsed request to construct query parameters
The way hgweb routes requests is kind of bonkers. If PATH_INFO is
set, we take the URL path after the repository. Otherwise, we take
the first part of the query string before "&" and the part before
";" in that.
We then kinda/sorta treat this as a path and route based on that.
This commit ports that code to use the parsed request object. This
required a new attribute on the parsed request to indicate whether
there is any PATH_INFO.
The new code still feels a bit convoluted for my liking. But we'll
need to rewrite more of the code before a better solution becomes
apparant. This code feels strictly better since we're no longer
doing low-level WSGI manipulation during routing.
Differential Revision: https://phab.mercurial-scm.org/D2739