Mon, 04 Jul 2016 11:18:03 -0700 mercurial: implement a source transforming module loader on Python 3
Gregory Szorc <gregory.szorc@gmail.com> [Mon, 04 Jul 2016 11:18:03 -0700] rev 29550
mercurial: implement a source transforming module loader on Python 3 The most painful part of ensuring Python code runs on both Python 2 and 3 is string encoding. Making this difficult is that string literals in Python 2 are bytes and string literals in Python 3 are unicode. So, to ensure consistent types are used, you have to use "from __future__ import unicode_literals" and/or prefix literals with their type (e.g. b'foo' or u'foo'). Nearly every string in Mercurial is bytes. So, to use the same source code on both Python 2 and 3 would require prefixing nearly every string literal with "b" to make it a byte literal. This is ugly and not something mpm is willing to do at this point in time. This patch implements a custom module loader on Python 3 that performs source transformation to convert string literals (unicode in Python 3) to byte literals. In effect, it changes Python 3's string literals to behave like Python 2's. In addition, the module loader recognizes well-known built-in functions (getattr, setattr, hasattr) and methods (encode and decode) that barf when bytes are used and prevents these from being rewritten. This prevents excessive source changes to accommodate this change (we would have to rewrite every occurrence of these functions passing string literals otherwise). The module loader is only used on Python packages belonging to Mercurial. The loader works by tokenizing the loaded source and replacing "string" tokens if necessary. The modified token stream is untokenized back to source and loaded like normal. This does add some overhead. However, this all occurs before caching: .pyc files will cache the transformed version. This means the transformation penalty is only paid on first load. As the extensive inline comments explain, the presence of a custom source transformer invalidates assumptions made by Python's built-in bytecode caching mechanism. So, we have to wrap bytecode loading and writing and add an additional header to bytecode files to facilitate additional cache validation when the source transformations change in the future. There are still a few things this code doesn't handle well, namely support for zip files as module sources and for extensions. Since Mercurial doesn't officially support Python 3 yet, I'm inclined to leave these as to-do items: getting a basic module loading mechanism in place to unblock further Python 3 porting effort is more important than comprehensive module importing support. check-py3-compat.py has been updated to ignore frames. This is necessary because CPython has built-in code to strip frames from the built-in importer. When our custom code is present, this doesn't work and the frames get all messed up. The new code is not perfect. It works for now. But once you start chasing import failures you find some edge cases where the files aren't being printed properly. This only burdens people doing future Python 3 porting work so I'm inclined to punt on the issue: the most important thing is for the source transforming module loader to land. There was a bit of churn in test-check-py3-compat.t because we now trip up on str/unicode/bytes failures as a result of source transformation. This is unfortunate but what are you going to do. It's worth noting that other approaches were investigated. We considered using a custom file encoding whose decode() would apply source transformations. This was rejected because it would require each source file to declare its custom Mercurial encoding. Furthermore, when changing the source transformation we'd need to version bump the encoding name otherwise the module caching layer wouldn't know the .pyc file was invalidated. This would mean mass updating every file when the source transformation changes. Yuck. We also considered transforming at the AST layer. However, Python's ast module is quite gnarly and doing AST transforms is quite complicated, even for trivial rewrites. There are whole Python packages that exist to make AST transformations usable. AST transforms would still require import machinery, so the choice was basically to perform source-level, token-level, or ast-level transforms. Token-level rewriting delivers the metadata we need to rewrite intelligently while being relatively easy to understand. So it won. General consensus seems to be that this approach is the best available to avoid bulk rewriting of '' to b''. However, we aren't confident that this approach will never be a future maintenance burden. This approach does unblock serious Python 3 porting efforts. So we can re-evaulate once more work is done to support Python 3.
Fri, 15 Jul 2016 23:54:56 +0900 compat: define ssize_t as int on 32bit Windows, silences C4142 warning
Yuya Nishihara <yuya@tcha.org> [Fri, 15 Jul 2016 23:54:56 +0900] rev 29549
compat: define ssize_t as int on 32bit Windows, silences C4142 warning It appears Python.h provides ssize_t, which is aliased to int. https://hg.python.org/cpython/file/v2.7.11/PC/pyconfig.h#l205
Sun, 22 May 2016 13:45:09 +0900 commandserver: drop old unixservice implementation
Yuya Nishihara <yuya@tcha.org> [Sun, 22 May 2016 13:45:09 +0900] rev 29548
commandserver: drop old unixservice implementation It's been superseded by unixforkingservice.
Sun, 22 May 2016 13:36:37 +0900 chgserver: switch to new forking service
Yuya Nishihara <yuya@tcha.org> [Sun, 22 May 2016 13:36:37 +0900] rev 29547
chgserver: switch to new forking service Threading and complex classes are no longer necessary. _autoexitloop() has been replaced by polling cycle in the main thread.
Sun, 22 May 2016 13:13:04 +0900 chgserver: extract stub factory of service object
Yuya Nishihara <yuya@tcha.org> [Sun, 22 May 2016 13:13:04 +0900] rev 29546
chgserver: extract stub factory of service object The class inheritance will be replaced by composition. See the next patch for details.
Sun, 22 May 2016 13:08:30 +0900 chgserver: reorder service classes to make future patches readable
Yuya Nishihara <yuya@tcha.org> [Sun, 22 May 2016 13:08:30 +0900] rev 29545
chgserver: reorder service classes to make future patches readable Includes no functional change.
Sun, 22 May 2016 11:43:18 +0900 commandserver: add new forking server implemented without using SocketServer
Yuya Nishihara <yuya@tcha.org> [Sun, 22 May 2016 11:43:18 +0900] rev 29544
commandserver: add new forking server implemented without using SocketServer SocketServer.ForkingMixIn of Python 2.x has a couple of issues, such as: - race condition that leads to 100% CPU usage (Python 2.6) https://bugs.python.org/issue21491 - can't wait for children belonging to different process groups (Python 2.6) - leaves at least one zombie process (Python 2.6, 2.7) https://bugs.python.org/issue11109 The first two are critical because we do setpgid(0, 0) in child process to isolate terminal signals. The last one isn't, but ForkingMixIn seems to be doing silly. So there are two choices: a) backport and maintain SocketServer until we can drop support for Python 2.x b) replace SocketServer by simpler one and eliminate glue codes I chose (b) because it's great time for getting rid of utterly complicated SocketServer stuff, and preparing for future move towards prefork service. New unixforkingservice is implemented loosely based on chg 531f8ef64be6. It is monolithic but much simpler than SocketServer. unixservicehandler provides customizing points for chg, and it will be shared with future prefork service. Old unixservice class is still used by chgserver. It will be removed later. Thanks to Jun Wu for investigating these issues.
Sun, 22 May 2016 12:49:22 +0900 commandserver: extract function that serves for the current connection
Yuya Nishihara <yuya@tcha.org> [Sun, 22 May 2016 12:49:22 +0900] rev 29543
commandserver: extract function that serves for the current connection This will be used by new server implementation.
(0) -10000 -3000 -1000 -300 -100 -30 -10 -8 +8 +10 +30 +100 +300 +1000 +3000 +10000 tip