Commit 497edbe1 authored by Julien Muchembled's avatar Julien Muchembled

master: add support for PyPy

parent f4cb59d2
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
from functools import wraps from functools import wraps
from time import time from time import time
import msgpack import msgpack
from msgpack.exceptions import UnpackValueError from msgpack.exceptions import OutOfData, UnpackValueError
from . import attributeTracker, logging from . import attributeTracker, logging
from .connector import ConnectorException, ConnectorDelayedConnection from .connector import ConnectorException, ConnectorDelayedConnection
...@@ -25,6 +25,17 @@ from .locking import RLock ...@@ -25,6 +25,17 @@ from .locking import RLock
from .protocol import uuid_str, Errors, PacketMalformedError, Packets, \ from .protocol import uuid_str, Errors, PacketMalformedError, Packets, \
Unpacker Unpacker
try:
msgpack.Unpacker().read_bytes(1)
except OutOfData: # fallback implementation
# monkey-patch for upstream issues 259 & 352
def read_bytes(self, n):
ret = self._read(min(n, len(self._buffer) - self._buff_i))
self._consume()
return ret
msgpack.Unpacker.read_bytes = read_bytes
del read_bytes
@apply @apply
class dummy_read_buffer(msgpack.Unpacker): class dummy_read_buffer(msgpack.Unpacker):
def feed(self, _): def feed(self, _):
......
...@@ -167,7 +167,11 @@ class NEOLogger(Logger): ...@@ -167,7 +167,11 @@ class NEOLogger(Logger):
q("PRAGMA synchronous = OFF") q("PRAGMA synchronous = OFF")
if 1: # Not only when logging everything, if 1: # Not only when logging everything,
# but also for interoperability with logrotate. # but also for interoperability with logrotate.
q("PRAGMA journal_mode = MEMORY") # Close the returned cursor to work around the following
# OperationalError with PyPy:
# cannot commit transaction - SQL statements in progress
# XXX: Is it enough?
q("PRAGMA journal_mode = MEMORY").close()
for t, columns in (('log', ( for t, columns in (('log', (
"level INTEGER NOT NULL", "level INTEGER NOT NULL",
"pathname TEXT", "pathname TEXT",
......
...@@ -318,6 +318,9 @@ class TestRunner(BenchmarkRunner): ...@@ -318,6 +318,9 @@ class TestRunner(BenchmarkRunner):
" passed.") " passed.")
parser.epilog = """ parser.epilog = """
Environment Variables: Environment Variables:
NEO_PYPY PyPy executable to run master nodes in functional
tests (and also in zodb tests depending on
NEO_TEST_ZODB_FUNCTIONAL).
NEO_TESTS_ADAPTER Default is SQLite for threaded clusters, NEO_TESTS_ADAPTER Default is SQLite for threaded clusters,
MySQL otherwise. MySQL otherwise.
......
...@@ -55,6 +55,26 @@ command_dict = { ...@@ -55,6 +55,26 @@ command_dict = {
DELAY_SAFETY_MARGIN = 10 DELAY_SAFETY_MARGIN = 10
MAX_START_TIME = 30 MAX_START_TIME = 30
PYPY_EXECUTABLE = os.getenv('NEO_PYPY')
if PYPY_EXECUTABLE:
import neo, msgpack
PYPY_TEMPLATE = """\
import os, signal, sys
def sigusr2(*_):
os.close(%r)
os.kill(os.getpid(), signal.SIGSTOP)
signal.signal(signal.SIGUSR2, sigusr2)
os.close(%r)
os.write(%r, '\\0')
sys.path.append({!r}); import msgpack; del sys.path[-1]
sys.path.insert(0, {!r}); import neo; del sys.path[0]
from neo.lib import logging
logging.default_root_handler.handle = lambda record: None
logging.backlog(%s, %s)
from neo.scripts.%s import main
main()
""".format(os.path.dirname(*msgpack.__path__), os.path.dirname(*neo.__path__))
class NodeProcessError(Exception): class NodeProcessError(Exception):
pass pass
...@@ -174,6 +194,13 @@ class Process(object): ...@@ -174,6 +194,13 @@ class Process(object):
from coverage import Coverage from coverage import Coverage
coverage = Coverage(coverage_data_path) coverage = Coverage(coverage_data_path)
coverage.start() coverage.start()
elif PYPY_EXECUTABLE and command == 'neomaster':
os.execlp(PYPY_EXECUTABLE, PYPY_EXECUTABLE, '-c',
PYPY_TEMPLATE % (
w, self._coverage_fd, w,
logging._max_size, logging._max_packet,
command),
*args)
# XXX: Sometimes, the handler is not called immediately. # XXX: Sometimes, the handler is not called immediately.
# The process is stuck at an unknown place and the test # The process is stuck at an unknown place and the test
# never ends. strace unlocks: # never ends. strace unlocks:
...@@ -186,7 +213,7 @@ class Process(object): ...@@ -186,7 +213,7 @@ class Process(object):
os.close(self._coverage_fd) os.close(self._coverage_fd)
os.write(w, '\0') os.write(w, '\0')
sys.argv = [command] + args sys.argv = [command] + args
setproctitle(self.command) setproctitle(command)
for on_fork in self.on_fork: for on_fork in self.on_fork:
on_fork() on_fork()
self.run() self.run()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment