Commit Graph

1045 Commits (master)

Author SHA1 Message Date
David Wilson 653c73c8f0 issue #156: also log target of wakes 6 years ago
David Wilson a5cc7cb43c issue #156: add extra debugging around Latch
Change from writing '\x00' to writing '\x7f', and verify that is the
byte that woke the sleeping thread. Add a bunch more IO logging.
6 years ago
David Wilson ac7a64dfa3 core: assign common expression to a variable. 6 years ago
David Wilson 148ce1d703 issue #155: increase context ID width to 32 bits
Needed to make large range allocations (1000 per ALLOCATE_ID roundtrip)
feasible.
6 years ago
David Wilson f241eac5ce parent: allow Python to determine its install prefix from argv[0]
Fixes support for virtualenv. Closes #152.
6 years ago
David Wilson 9cf889b846 issue #144: master: public/private Pool attributes. 6 years ago
David Wilson fe900087a2 issue #144: service: working service.Pool object.
It knows how to dispatch messages from multiple receivers (associated
with multiple services) to multiple threads, where the service
implementation is invoked on the message.

It wakes a maximum of one thread per received message.

It knows how to shut down gracefully.

Implication: due to the latch use, there are 2 file descriptors burned
for every thread. We don't need interruptibility here, so in future, it
might be nice to allow swapping a diferent queueing primitive into
Select (maybe a subclass?) just for this case.
6 years ago
David Wilson 4f361be7e7 issue #144: teach Select() to close its latch
Causes all threads sleeping on the select to wake.
6 years ago
David Wilson 8aada2646c core: support throwing LatchError in every sleeping thread
This is to allow Select() to be used as a generic queueing primitive
that supports graceful shutdown.
6 years ago
David Wilson ebfe733914 core: tidy up Stream.on_receive() branches. 6 years ago
David Wilson 86ede62241 issue #150: introduce separate connection multiplexer process
This is a work in progress.
6 years ago
David Wilson eee5423dd9 issue #150: tidy up mitogen.debug output for use next time 6 years ago
David Wilson 9adadb5c3a issue #150: import stack.py hack as mitogen.debug
Usage:
  - insert a call to mitogen.debug() in the desired process
  - kill -USR2 that process
  - observe its controlling TTY produces thread stack dumps
6 years ago
David Wilson df488237d4 core: fix race in PidfulStreamHandler
Need to re-test with the lock held, else >1 threads can end up waiting
for lock then reopening the log repeatedly.
6 years ago
David Wilson a06c92d285 core: enable_debug_logging() should reopen file post-fork. 6 years ago
David Wilson 4691ce0b95 issue #150: ansible: add basic Docker support. 6 years ago
David Wilson eba12e2ee2 issue #139: bump kernel socket buffer size to 128kb
This allows us to write 128kb at a time towards SSH, but it doesn't help
with sudo, where the ancient tty layer is always used.
6 years ago
David Wilson 728a0da8a4 issue #139: eliminate quadratic behaviour from transmit path
Implication: the entire message remains buffered until its last byte is
transmitted. Not wasting time on it, as there are pieces of work like
issue #6 that might invalidate these problems on the transmit path
entirely.
6 years ago
David Wilson a3b4b459fa issue #139: eliminate quadratic behaviour on input path
Rather than slowly build up a Python string over time, we just store a
deque of chunks (which, in a later commit, will now be around 128KB
each), and track the total buffer size in a separate integer.

The tricky loop is there to ensure the header does not need to be sliced
off the full message (which may be huge, causing yet another spike and
copy), but rather only off the much smaller first 128kb-sized chunk
received.

There is one more problem with this code: the ''.join() causes RAM usage
to temporarily double, but that was true of the old solution too. Shall
wait for bug reports before fixing this, as it gets very ugly very fast.
6 years ago
David Wilson ba9a06d0f5 issue #139: core: Side.write(): let the OS write as much as possible.
There is no penalty for just passing as much data to the OS as possible,
it is not copied, and for a non-blocking socket, the OS will just keep
buffer as much as it can and tell us how much that was.

Also avoids a rather pointless string slice.
6 years ago
David Wilson 49db4125d0 issue #139: core: bump CHUNK_SIZE from 16kb to 128Kb
Reduces the number of IO loop iterations required to receive large
messages at a small cost to RAM usage.

Note that when calling read() with a large buffer value like this,
Python must zero-allocate that much RAM. In other words, for even a
single byte received, 128kb of RAM might need to be written.
Consequently CHUNK_SIZE is quite a sensitive value and this might need
further tuning.
6 years ago
David Wilson 8e2b07a54e issue #139: add profiling=True option to mitogen.main(). 6 years ago
David Wilson 017e8105cf issue #131: disable non-blocking IO during UNIX accept()
accept() (per interface) returns a non-blocking socket because the
listener socket is in non-blocking mode, therefore it is pure scheduling
luck that a connecting-in child has a chance to write anything for the
top-level processs to read during the subsequent .recv().

A higher forks setting in ansible.cfg was enough to cause our luck to
run out, causing the .recv() to crashi with EGAIN, and the multiplexer
to respond to the handler's crash by calling its disconnect method. This
is why some reports mentioned ECONNREFUSED -- the listener really was
gone, because its Stream class had crashed.

Meanwhile since the window where we're waiting for the remote process to
identify itself is tiny, simply flip off O_NONBLOCK for the duration of
the connection handshake. Stream.accept() (via Side.__init__) will
reenable O_NONBLOCK for the descriptors it duplicates, so we don't even
need to bother turning this back off.

A better solution entails splitting Stream up into a state machine and
doing the handshake with non-blocking IO, but that isn't going to be
available until asynchronous connect is implemented. Meanwhile in
reality this solution is probably 100% fine.
6 years ago
David Wilson 44d36eccba issue #146: don't crash during on_broker_shutdown
There is some insane unidentifiable Mitogen context (the local context?)
that instantly crashes with a higher forks setting. It appears to be
harmless, but meanwhile this naturally shouldn't be happening.
6 years ago
David Wilson cb620500d1 issue #131: log stack and PPID with MITOGEN_ROUTER_DEBUG=1 6 years ago
David Wilson 83c8412474 issue #140: permit mitogen.unix.connect() to accept preconstructed Broker.
Part of an effort to make resource management a little more explicit.
6 years ago
David Wilson 65df36895e issue #140: prevent duplicate watcher thread creation
When a Broker() is running with install_watcher=True, arrange for only
one watcher thread to exist for each target thread, and to reset the
mapping of watchers to targets after process fork.

This is probably the last change I want to make to the watcher feature
before deciding to rip it out, it may be more trouble than it is worth.
6 years ago
David Wilson 1b93a4f51a issue #141: remove reference to incomplete change 6 years ago
David Wilson 587256bbce issue #141: unify connect deadline handling
Now there is a single deadline calculated by the parent.Stream
constructor, and reused for both SSH and sudo.
6 years ago
David Wilson d58b5ad777 core: prevent creation of unicode Message.data
Was triggering a crash indirectly due to Ansible passing us Unicode
strings. Needs a better fix.
6 years ago
David Wilson 31065ffe4a issue #143: avoid long-form options in sudo.py. 6 years ago
Alex Willmer f95b37429f parent: Read preamble in first stage with os.fdopen()
SSH command size: 439 (+4 bytes)
Preamble size: 8941 (no change)

This _increases_ the size of the first stage, but
- Eliminates one of the two remaining uses of `sys`
- Reads the preamble as a byte-string, no call `.encode()`
   is needed on Python 3 before calling `_()`
6 years ago
Alex Willmer a62edd0b7e parent: Use os.execl in first stage
SSH command size: 435 (-4 bytes)
Preamble size: 8962 (no change)

os.execl is the same as os.execv, but it take a variable number of
arguments instead of a single sequence.
6 years ago
Alex Willmer 545652c34f parent: Trim whitespace & e variable in first stage
SSH command size: 439 (-4 bytes)
Preamble size: 8962 (no change)
6 years ago
Alex Willmer 0336de6722 parent: Combine first stage imports
SSH command size: 443 (-5 bytes)
Preamble size: 8962
6 years ago
Alex Willmer 48949cd249 parent: Use 'zip' alias of 'zlib' decoder
SSH command size: 448 (-5 bytes)
Preamble size: 8941 (no change)

NB: The 'zip' alias was absent in Python 3.x, until Python 3.4. This
should change be reverted if Python 3.0, 3.2, or 3.3 support is
required.
6 years ago
Alex Willmer 0f82f68fee parent: Precompute preamble sizes for first stage
SSH command size: 453 (no change)
Preamble size: 8941 (-5 bytes)
6 years ago
Alex Willmer dfd7070ceb parent: reuse _=codecs.decode alias in exec'd first stage
SSH command size: 453 (-8 bytes)
Preamble size: 8946 (no change)
6 years ago
Alex Willmer 53a8c59ae5 parent: Remove redudant os.exit() in first stage
SSH command size: 461 (-8 bytes)
Preamble size: 8946 (no change)

Since python has reached the last statement this should occur anyway.
6 years ago
Alex Willmer e051cf0ea0 parent: Unroll os.close() loop in first stage
SSH command size: 469 (-11 bytes)
Preamble size: 8946 (no change)

Although the source is longer, the _compressed_ length is reduced.
6 years ago
Alex Willmer 85f36f4cb1 parent: Prefer "import foo;x=foo" in first stage
SSH command size: 481 (down 1)
Preamble size: 8946 (no change)
6 years ago
Alex Willmer f999b9adbf Crank zlib.compress() upto 9
SSH command size: 482 bytes (no change)
Preamble size: 8946 bytes (down 33)
6 years ago
David Wilson b243da087c issue #121: fix call_function_test by not raising the dead
A first small mea culpa to all my testing sins of late :)
6 years ago
David Wilson f1009b7502 issue #121: fix breakage caused by a9c6c13
This actually addresses multiple problems:

* Single-file programs were broken, since the fix introduced in
  6931cc10c4 caused builtin_find_module()
  to start indicating __main__ can always be loaded locally. That's
  broken, and there might be more cases where the same problem will crop
  up.

  Since it was indicated __main__ could be loaded locally, the built-in
  import machinery was allowed to attempt that (since we remove __main__
  from sys.modules during bootstrap), which caused a safety check to
  fire in the bowels of Python:

      "Cannot re-init internal module %.200s"

* The check for presence of the whitelist was totally broken, since the
  whitelist is never an empty list. Therefore 'self' was being returned
  for every module, including extension modules like 'termios'.

I have hand-verified this does not break the fix for issue #113. I
looked at writing a test for that, but it requires a Docker container
(or similar) with an ancient version of Ansible installed. Will open a
separate ticket tracking this.
6 years ago
David Wilson 5dddee62ea Revert "issue #121: minimal fix for nested_test."
Mega broken.

This reverts commit a7dbbd96aa.
6 years ago
David Wilson a0c4df72b0 issue #121: minimal fix for nested_test. 6 years ago
David Wilson b2a433dcc4 ssh: CompressionLevel is a v1-only option.
It's ignored by newer SSHes, which only pay attention to Compression.
6 years ago
Alex Willmer 2c05958ecc docs: Replace google.com as target of get_url()
Probably best to avoid angering the 800 lb gorilla with access to killer
robots.

https://example.org works, this is why it exists.
6 years ago
Alex Willmer 1c20c61605 docs: Convert all URLs that support https://
Excluded: graphml XML namespaces, links to e.g. Fabric homepage

Fixes #128
6 years ago
David Wilson 8329bee889 parent: log discard_until() input when IOLOG is enabled
Trying to diagnose a Reddit user's problem.
6 years ago
David Wilson 016d47aa91 Log and track PIDs everywhere for Ansible. 6 years ago
David Wilson 28afa955a3 importer: take priority over system packages when whitelisting is enabled
Might want to de-overload the meaning of whitelist in future, but in
the meantime it works fine for Ansible and I can't think of a
whitelisting use case that would break because of it.

Closes #114.
6 years ago
David Wilson 7aca02c2c7 importer: don't include related modules that are blacklisted
Cuts down on even more spam
6 years ago
David Wilson 37d38f8d9f importer: _is_stdlib_name() needed to handle relative paths
Was causing tons of log spam due to 'skipping absent related name'
6 years ago
David Wilson cf01c6b710 importer: avoid duplicate module load(!); closes #113.
Amazed this one managed to scrape through for so long. Calling
__import__ from within find_module() was causing the target module, in
this case cookielib, to be loaded *then overwritten* by a subsequent
duplicate load higher in the stack.

The result is that cookielib was loaded twice, and, per usual Python
import semantics, a reference to the partially initialized first
cookielib was installed in sys.modules while its code executed.

At the end of cookielib on 2.x, it imports _LWPCookieJar, which in turn
imports the partially built cookielib from sys.modules, then subclasses
the CookieJar from /that/ module.

Everything is wonderful. Then the call returns back up into the import
mechanism which restarts the entire process -- only this time,
_LWPCookieJar is /not/ reinitialized, so the copy in sys.modules is
still left with types pointing at the old module!

So the duplicate import creates a new CookieJar which is not the base
class of LWPCookieJar. Tada! 3 hours debugging.

This is probably a performance fix in disguise, didn't realize things
were so broken. It may also be a regression elsewhere. Urgently need to
finish the tests.
6 years ago
David Wilson 7ab1af043e ansible: redirect logging into display 'framework'. closes #111 6 years ago
David Wilson 5b0b973dba importer: quieten one more warning 6 years ago
David Wilson 6ec349b386 importer: quieten 'cannot find source' warning, closes #110 6 years ago
David Wilson 0ef23d8644 parent: Add hack for OS X /usr/bin/python
It's a magical switcher that needs argv[0], which we don't provide.
6 years ago
David Wilson 88508fcb61 sudo: accept -n too (issue #108) 6 years ago
David Wilson 9cfcf79f43 sudo: accept but discard -S option. fixes #108 6 years ago
David Wilson 95ea75907d ssh: Fix AttributeError. 6 years ago
David Wilson 3ddbf1a503 ansible: basic support for ssh_args 6 years ago
David Wilson 235e1df987 sudo: support parsing sudo flags back out into parameters 6 years ago
David Wilson d348a826ff master: tidy up trixxy importer syntax slightly 6 years ago
David Wilson 7cf2edc3a8 ansible: Support many more common playbook variables. 6 years ago
David Wilson ff617824a1 ansible: fix some flake8 errors
* Unused imports
* Undefined names in helpers.py
* Copyright header wrapping
6 years ago
Alex Willmer 33781aba2c core: Correct naming of Stream.sent_modules
Fixes #90
6 years ago
Alex Willmer d4a546dcbc parent: Fix ModuleForwarder not sending related packages
Found due to a LGTM warning about unused loop variable (related). As far
as I can tell the callback was sending fullname multiple times. KeyError
check added because I found NestedTest failed - mitogen.parent had
mitogen as one of it's related, and mitogen was not in the cache.

Refs #61
6 years ago
Alex Willmer 227cd3aa60 ssh, sudo: Remove redundant else clause on bootstrap loop
Since the for loops don't contain any break statements the StreamErrors
will always be raised when the loop completes without the method
resturning.

See https://lgtm.com/rules/5980098/

Refs #61
6 years ago
Alex Willmer a1aab30e63 core: Implement Dead.__ne__ & Dead.__hash__
Both these addtions are to address warnings in
https://lgtm.com/projects/g/dw/mitogen/alerts/?mode=list. Namely that if
a class defines an equality method then it should also define an
inequality and a hash method.

Refs #61
6 years ago
Alex Willmer 4b373c421b core: Standardise type of Importer.whitelist
This seemed a reasonable streamlining, but I'm happy to be overruled.
6 years ago
Alex Willmer ecaa8609f3 core: Add docstring to is_blacklisted_import()
This documents the existing behaviour, which may not be the intended.
6 years ago
David Wilson 5855f1739f core: Handle unpicklable data in dispatch_calls()
Sending just via .call_async() would previously crash the child, now it
generates CallError like intended.
6 years ago
Alex Willmer 8513b331b7 Use Pythabsoluteon 2.4 compatible module import
Python 2.4 does not support explicit relative imports. They were added
at Python 2.5, along with `from __future__ import absolute_import`.

On 2.x this will mean the import is first (implicitly) tried relative,
but on 3.x it will always be tried absolute.

Fixes #92
6 years ago
David Wilson 5036a9448f Add Docker method. 6 years ago
David Wilson d4169557f1 Fix some more Python 2.4 syntax 6 years ago
Alex Willmer 2dcab3fe06 master: Reword ModuleFinder.find_realted*() docstrings
Hopefully these are correct, and clearerabout the
behaviour/pre-conditions of these methods.
6 years ago
Alex Willmer c2405369d2 ModuleFinder: Get stdlib paths by sys.prefix, sys.real_prefix etc.
I took the liberty of renaming ModuleFinder.STDLIB_DIRS to
_STDLIB_PATHS, since it felt like an implementation detail that
shouldn't be baked into a public API and stdlib can also be imported
from e.g. a zip file.

I also changed it to a set to handle any duplicates.

Fixes #86
6 years ago
David Wilson b221eaaa10 ansible: log call timings 6 years ago
David Wilson afc8697288 core: Ensure add_handler() callbacks really receive _DEAD on shutdown 6 years ago
David Wilson 91116810a1 ansible: delete utils.py and promote cast() to mitogen.utils 6 years ago
David Wilson 18eaf14dca ansible: migrate logging variables into utils. 6 years ago
David Wilson 5d8cb0f5fb ansible: document the connection class. 6 years ago
David Wilson 020036f807 core: add a nasty hack for Ansible modules. 6 years ago
David Wilson fa804c7c80 parent: simplify route() call
Doesn't need to go via defer() since it's always running on the broker
thread.
6 years ago
David Wilson bdd8648bae ssh: enable compression by default
Using the same test as in 7af97c0365,
transmitted wire bytes drops from 135,531 to 133,071 (-1.81%), while
received drops from 21,073 to 14,775 (-30%).

Combined, both changes shave 13,914 bytes (-8.6%) off aggregate
bandwidth usage.

Make it configurable as compression hurts in some scenarios.
6 years ago
David Wilson 4d940f08ae importer: drop redundant prefix from pkg_present
For the 52 submodules of ansible.modules.system, this produced a 1602
byte pkg_present list. After stripping it becomes 406 bytes, and the
entire LOAD_MODULE size drops from 1988 bytes to 792 bytes (-60%).

For the 68 submodules of ansible.module_utils, 1902 bytes pkg_present
becomes 474 bytes (-75%), and LOAD_MODULE size drops from 2867 bytes to
1439 bytes (-49%).

In a simple test running Ansible's "setup" module followed by its "apt"
module, wire bytes sent drops from 140,357 to 135,531 (-3.4%).
6 years ago
David Wilson 71a6b9e32a master: Select.all() sugar 6 years ago
David Wilson b543b84e80 importer: share blacklist logic between master/parent 6 years ago
David Wilson 8ec6ae1da0 importer: module whitelist/blacklist support
Hoped to avoid it, but it's the obvious solution for Ansible.
6 years ago
David Wilson 43ba1c76dc core: wrap selects in EINTR handlers
This isn't nearly enough, but it catches the most common victim of
EINTR.
6 years ago
David Wilson aafe458a13 core: #39: don't call logging framework when logging is disabled
It looks ugly as sin, but this nets about a 20% drop in user CPU time,
and close to 15% increase in throughput.

The average log call is around 10 opcodes, prefixing with '_v and' costs
an extra 2, but both are simple operations, and the remaining 10 are
skipped entirely when _v or _vv are False.
6 years ago
David Wilson 2ce71b338b unix: add small explainer note until real docs exist 6 years ago
Alex Willmer 3261c561dd Fix AttributeError in mitogen.core.Context.send_await()
As of adc8fe3aed Receiver objects do not
have a get_data() method and Receiver.get() does not unpickle the
message.
6 years ago
David Wilson 6905dc4e8d master: use queue-like Latch in Select() too. 6 years ago
David Wilson 20afa5b90c Latch v2: combined queue + one self-pipe-per-thread
Turns out it is far too easy to burn through available file descriptors,
so try something else: self-pipes are per thread, and only temporarily
associated with a Lack that wishes to sleep.

Reduce pointless locking by giving Latch its own queue, and removing
Queue.Queue() use in some places.

Temporarily undo merging of of Waker and Latch, let's do this one step
at a time.
6 years ago
David Wilson e6a107c5aa core: replace Queue with Latch
On Python 2.x, operations on pthread objects with a timeout set actually
cause internal polling. When polling fails to yield a positive result,
it quickly backs off to a 50ms loop, which results in a huge amount of
latency throughout.

Instead, give up using Queue.Queue.get(timeout=...) and replace it with
the UNIX self-pipe trick. Knocks another 45% off my.yml in the Ansible
examples directory against a local VM.

This has the potential to burn a *lot* of file descriptors, but hell,
it's not the 1940s any more, RAM is all but infinite. I can live with
that.

This gets things down to around 75ms per playbook step, still hunting
for additional sources of latency.
6 years ago
David Wilson beb16d0db6 master: helper functions to force disconnect everything 6 years ago
David Wilson 9b5d0a9b97 service: initial version 6 years ago
David Wilson a35fcf44cc ansible: restructure to avoid intermediate imports 6 years ago
David Wilson 75a78c9ff4 ansible: connection plugin v2
Now featuring one roundtrip per module invocation.
6 years ago
David Wilson f3e51a7b18 core: CALL_FUNCTION should check auth_id, not src_id 6 years ago
David Wilson f001eba23e ansible: Merge module runner into helpers.py. 6 years ago
David Wilson 67d4c13ffa Remove old TCP draft. 6 years ago
David Wilson 32f6ee7d43 issue #40: mitogen.unix initial implementation. 6 years ago
David Wilson 37e3151be8 fakessh: restore unpickle() semantics. 6 years ago
David Wilson e63e9d299e docs: add Message documentation 6 years ago
David Wilson 10230f62dd core: Message.reply() helper function 6 years ago
David Wilson 6fc8fa5b22 core: Don't crash if a stream is missing a side. 6 years ago
David Wilson 9238e09ae8 core: Restore behaviour of unpickling Router-specific Context subclass 6 years ago
David Wilson dd088908df select: clean up API. 6 years ago
David Wilson df07e47d24 core: de-munge Message.unpickle() vs. Receiver.get(). 6 years ago
David Wilson a39cd44bf2 core: add auth_id field. 6 years ago
David Wilson a54c96faae core: remove unused SecurityError. 6 years ago
David Wilson 07d4d799f1 Add mitogen.main() decorator mainly for docs and demo use. 6 years ago
David Wilson 55c23e1c57 issue #68: replace sets with lists
Fix a MyPy warning by only passing lists to select.select(). At least on
Python 2.x, select.select() was internally converting the sets to lists
anyway.

By the time lists become inefficient here, it is likely that
select.select() itself will also be inefficient, and need replaced with
.poll() or similar.

No discernible performance different when transferring django.db.models
to a local VM.
6 years ago
David Wilson 09eb3fd9ba utils: support log_to_file(usec=True) 6 years ago
David Wilson 2848d35aff importer: warn on duplicate request, simplify preload logic
* Children should never generate a request for a module that has already
  been sent, however there are a variety of edge cases where, e.g.
  asynchronous calls are made into unloaded modules in a set of
  children, causing those children to request modules (and deps) in a
  different order, which might break deduplication. So add a warning to
  catch when this happens, so we can figure out how to handle it.
  Meanwhile it's only a warning since in the worst case, this just adds
  needless latency.

* Don't bother treating sent packages separately, there doesn't seem to
  be any need for this (after docs are updated to match how preloading
  actually works now).
6 years ago
David Wilson 2e729e54cc importer: fix glaring bug in find_related()
Overwriting 'fullname' variable caused basically nonsensical filtering.
Result was including the module being searched in the list of
dependencies, which was causing ModuleResponder to send it early, which
was causing contexts to start importing the module before preloading of
dependencies had completed.
6 years ago
David Wilson 0dbb1ec028 importer: warn once about missing source and cache negative hit 6 years ago
David Wilson a0d9d34231 core: fix profiling
* SIGTERM safety net prevents profiler from writing results, so disable
  it when profiling is active.
* fix warning corrupting stream when profiling=True
6 years ago
David Wilson b158259c86 Split up parent and master modules
Knocks 4kb off network footprint for a proxy connection.
6 years ago
David Wilson 5f2fa2cda6 importer: always refuse builtins and __builtin__. 6 years ago
David Wilson 0f899f34ff importer: new format to signal ImportError
Previously we'd send just None in GET_MODULE reply, but now since there
is no single request-reply structure, we must include the fullname in
the LOAD_MODULE response and make all of its data fields None to
indicate the same.
6 years ago
David Wilson 07ae14f11d importer: semi-functional preloader
Doesn't yet implement the rules in the docs, but I think the doc rules
could maybe change to match this. Needs lots of cleanup work and
thorough testing, but this is a great start.
6 years ago
David Wilson 4d01dc3ba6 Initial pass at module preloading
* Don't implement the rules for when preloading occurs yet
* Don't attempt to streamily preload modules downstream while this
  context hasn't yet received the final module. There is quite
  significant latency buried in here, but for now it's a lot of work to
  fix.

This works well enough to handle at least the mitogen package, but it's
likely broken for anything bigger.
6 years ago
David Wilson b75e77b410 master: force set_block() in tty_create_child too.
For gevent, just as in 5f7633cd56
6 years ago
David Wilson ed71ae72f8 master: make mitogen minimally functional under gevent
It seems gevent automatically sets blocking behaviour on fds produced by
the socket module, which causes the Python process we fork to fail
horribly. So in the child, always reset the blocking flag.
6 years ago
David Wilson 247f50e08d master: add comment 6 years ago
David Wilson bbcfc585a8 master: add a comment to explain what's going on, and fix log msg.
Closes #70
6 years ago
David Wilson 3cbe9baf6d issue #70: remove redundant 'raise SystemExit'
Either execvp succeeds, in which case the process image is replaced, or
execvp throws an exception, in which case control flow exits the frame
anyway.
6 years ago
David Wilson 326886832e Add license text everywhere. 6 years ago
David Wilson f1f36cec35 Simplify the API, make Broker optional and auto-shutdown on main thread exit. 6 years ago
David Wilson bbcf1a0bd4 Fix confusing return statements, closes #67. 6 years ago
Alex Willmer 3831ac360f Replace all calls to file() with open()
Although these are synonyms in Python 2.x, when using MyPy to typecheck
code use of file() causes spurious errors.

This commit also serves as one small step to Python 3.x compatibility,
since 3.x removes the file() builtin.
6 years ago
David Wilson c09dcd82a7 Fix Python 3 fix :/ closes #57 6 years ago
Alex Willmer 77d57a7e38 fakessh: Remove colon causing SyntaxError
fixes #58
6 years ago
David Wilson 658806bde8 fakessh: interruptible wait compatible with <2.7; closes #55 6 years ago
David Wilson b3491b190c master: Lazy-format more logging arguments, minor 3.x compat increments 6 years ago
Alex Willmer 0e7cc55e33 first stage: Remove/dedent else block
Since the above if block ends in a call to os.execv() this block will
only ever run when the if condition was false. Hence putting it in an
else clause is unnecessary.
6 years ago
Alex Willmer d1c10f64a5 first stage: Use string concatenation 6 years ago
Alex Willmer b490cde604 first stage: eliminate whitespace 6 years ago
Alex Willmer c7c0266e99 first stage: single letter variables 6 years ago
David Wilson 3d0e8c36d2 issue #49: 2.x/3.x compatible decode.
Much uglier command line, but it works across major Python releases.
6 years ago
David Wilson db9bec8720 Implement Alex's awesome idea of zlibbing the first stage too! Closes #49 6 years ago
David Wilson 0481c08beb Ensure _run_defer() fully executes at least once before shutdown
Without this, it's possible for Waker to be start_received() after the
shutdown signal has already been sent, resulting in 5 second delay
during shutdown.

Additionally mask EBADF during os.write() to waker's write side.
Necessary since nothing synchronizes writer threads from the broker
thread during shutdown. Could be done with a lock instead, but this is
cheaper.
6 years ago
David Wilson 828f60351b importer: Delete _get_module_via_parent entirely
Can't figure out what it's supposed to do any more, and can't find a
version of Ansible before August 2016 (when I wrote that code) that
seems to need it.

Add some more mitigations to avoid sending dylibs.
6 years ago
David Wilson b1ad04330b docs: move Router.route() into Sphinx. 6 years ago
David Wilson fb759f7c16 docs: move Broker docstrings into Sphinx. 6 years ago
David Wilson ffa063cc01 docs: annother barriage of cross-reference fixes. 6 years ago
David Wilson 7f3a58d514 core: Remove unused on_shutdown attribute. 6 years ago
David Wilson c9daa2ff30 docs: move fakessh docs into Sphinx. 6 years ago
David Wilson 6a10ab605e docs: move mitogen.utils docs to Sphinx. 6 years ago
David Wilson ec66152e37 docs: better io_op doc, move Side docs to Sphinx. 6 years ago
David Wilson 0767abf26f docs: move BasicStream docs into Sphinx. 6 years ago
David Wilson b7a9aa46cf core: More robust shutdown
Now there is a separate SHUTDOWN message that relies only on being
received by the broker thread, the main thread can be hung horribly and
the process will still eventually receive a SIGTERM.
6 years ago
David Wilson 3285fc2f75 Implement test_aborted_on_local_context_disconnect 6 years ago
David Wilson 690ee6dbe2 Fix select_test failure, remove crap old timing_test. 6 years ago
David Wilson 15bf0f54e2 Beginnings of module_finder_test 6 years ago
David Wilson 2454dcc990 core: loosen assertion to allow fakessh_test to succeed. 6 years ago
David Wilson 9b13a4cc61 Fix 2 call_function_test failures. 6 years ago
David Wilson 79dd00db5a master: hack to avoid executing __main__. 6 years ago
David Wilson 6f5d4882da We don't support sets, so don't use them in module loader(!) 6 years ago
David Wilson ecd39e4f2a add missing IOLOG, fixes _iter_read/SshTest. 6 years ago
David Wilson 451fb347d0 master: include related modules in ModuleResponder response 6 years ago
David Wilson 4af920094a iter_read: also treat 0-byte read as disconnection 6 years ago
David Wilson d169b55d64 select: fix typo 6 years ago
David Wilson af6812b458 Fix context naming for sudo and via=. 6 years ago
David Wilson f1d82c7284 More API documentation. 6 years ago
David Wilson b7f95e558f Better document Router API and constructors. 6 years ago
David Wilson 815f23bddd Sense of block= parameter was inverted. 6 years ago
David Wilson c4d9f124c6 Document Sender and Receiver classes. 6 years ago
David Wilson 849ccebe04 receiver: only permit one notify callback
There is no point spamming a list for every function call, there is no
use case where multiple notify callbacks would be useful.
6 years ago
David Wilson 1be10575a1 importer: Don't respond to non-.py[co] imports. 6 years ago
David Wilson 48bf987570 issue #20: fix queue.get() parameter list. 6 years ago
David Wilson f869e088f8 issue #20: tests and fixes for mitogen.master.Select(). 6 years ago
David Wilson e3d967ebeb issue #20: initial implementation of mitogen.master.Select(). 6 years ago
David Wilson 14783c75e8 issue #9: log warning when a cross-sibling CALL_FUNCTION occurs
First step to making it a fatal error.
6 years ago
David Wilson 9de1fca3bf issue #9: ensure messages arrive on the expected stream
If no ADD_ROUTE message has been received from the master associating a
stream with a particular context ID, then it is expected messages
originating from that context ID can only be routed via the parent.
6 years ago
David Wilson 4de321a3b0 Adjust get_boot_command to match _first_stage change
inspect module includes the staticmethod decorator added by
a8d1dc6730
6 years ago
David Wilson c810f66bcc issue #19: whoops, implement sliding window properly 6 years ago
David Wilson 43ccbf0459 issue #19: second attempt at import scanner
This version is based on the modulefinder standard library module,
pruned back just to handle modules we know have been loaded already, and
to scan module-level imports only, rather than imports occurring in
class and function scope (crappy heuristic, but assume they are lazy
imports).

The ast and compiler modules were far too slow, whereas this version can
bytecode compile and scan all the imports for django.db.models (58
modules) in around 200ms.. 3.4ms per dependency, it's probably not going
to get much faster than that.
6 years ago
David Wilson 175abee2c9 Fix inverted logic. 6 years ago
David Wilson 8054fa867a Only import compiler when necessary, it's not available in 3.x. 6 years ago
Alex Willmer aa817f1b83 Handle failure to import the ast module 6 years ago
Alex Willmer dd8271f061 Fix stale references to m.master.connect & m.ssh.connect
I'm fairly sure these updates are correct, but I'm not able to run the
test suite to confirm.
6 years ago
Alex Willmer d706b7d6b8 Update lingering references to with_broker & run_with_broker
A previous commit renamed run_with_broker() and with_broker() to
run_with_router() and with_router() respctively. Some references were
missed.
6 years ago
Alex Willmer dc26460a28 Add missing LOG import
Fixes an undefined variable error found by pylint
6 years ago
Alex Willmer 3b24314a8b Use fully qualified Context
Fixes an undefined variable error found by pylint
6 years ago
Alex Willmer 57a0aa26bf Add missing import of AnsibleError
Found with pylint
6 years ago
Alex Willmer f2ea38a963 Add missing auth_incorrect_msg used to in exception message
Found using pylint
6 years ago
Alex Willmer 1f955fc655 Declare self-less method as static
Found using pylint
6 years ago
Alex Willmer 36754254b2 Add missing imports: ast, compiler
Found using pylint
6 years ago
David Wilson 01729b18a5 core: use an output deque rather than string to improve worst case perf
This probably worsens performance in the common case, but it prevents
runaway producers (see e.g. issue #36) from spending all their CPU
copying around huge strings.

It's also a small step towards a solution to issue #6, which will
replace the output buffer with some sort of fancier queue anyway.

This reduces a particular 40 second run of rsync to 1.5 seconds.
6 years ago
David Wilson eb060e1a0e Document Router.profiling. 6 years ago
David Wilson effe4117e1 Treat EPIPE as disconnect too; needed for fakessh. 6 years ago
David Wilson 9c4bf37cfc Remove final vestiges of context.key. 6 years ago
David Wilson 05cc74d142 core: Support profiling 6 years ago
David Wilson b827ee1bc7 Delete mitogen.utils.log_to_tmp() 6 years ago
David Wilson 400c971f4a fakessh: SSH server uses user's shell to parse command line. 6 years ago
David Wilson 04ea5306e9 Document a bunch of mitogen.master and move more docstrings into Sphinx. 6 years ago
David Wilson b2f13f1fa4 master: propagate routes for IDs allocated via ALLOCATE_ID
needed for inter-child rsync.
6 years ago
David Wilson 750e9fab24 Make log_to_file accept string level rather than logging package constant
Saves an import, pain in the ass to type all the time.
6 years ago
David Wilson a9387b0504 core: remove pointless eval() of ARGV0 environment variable. 6 years ago
David Wilson 1411790f56 master: make write_all() handle O_NONBLOCK and deadlines. 6 years ago
David Wilson 2ee7309378 master: send_await() always unpickles now. 6 years ago
David Wilson 769ece2514 fakessh: improve logging slightly.
Makes it easier to match up reads/writes across log files by using
message byte count
6 years ago
David Wilson fb9ce1054c core: set O_NONBLOCK on every side. Closes #33
The last time I tested set_nonblock() as a fix for the rsync hang, I
used F_SETFD rather than F_SETFL, which resulted in no error, but also
did not set O_NONBLOCK. Turns out missing O_NONBLOCK was the problem.

The rsync hang was due to every context blocking in os.write() waiting
for either a parent or child buffer to empty, which was exacerbated by
rsync's own pipelining, that allows writes from both sides to proceed
even while reads aren't progressing. The hang was due to os.write() on a
blocking fd blocking until buffer space is available to complete the
write. Partial writes are only supported when O_NONBLOCK is enabled.
6 years ago
David Wilson db225638f0 core: Make iter_read() handle deadline (and non-blocking IO) properly 6 years ago
David Wilson 7a60b20dc6 core: Generalize/duplicate the call/send_await code using Receiver. 6 years ago
David Wilson 76d35df889 master: use decorators rather than call_with_deadline(with_context=..) 6 years ago
David Wilson 76d1e66790 fakessh: use decorators rather than call_with_deadline(with_context=..) 6 years ago
David Wilson e4c832685d core: synchronize Stream._output_buf by deferring send()
Previously _output_buf was racy. This may or may not be cheaper than
simply using a lock, but it requires much less code, so I prefer it for
now.
6 years ago
David Wilson ead67de883 core: make Side.write() return None rather than crash if side already closed. 6 years ago
David Wilson 74b31bbe47 core: better Message.__repr__. 6 years ago
David Wilson 2a365aa9b0 Replace `with_context` parameter with mitogen.core.takes_econtext decorator 6 years ago
David Wilson 8d4005c264 fakessh: fix non-master context ID allocation. 6 years ago
David Wilson bd8001d481 fakessh: Fix NameError. 6 years ago
David Wilson e7c70127bf fakessh: return child exit status 6 years ago
David Wilson 77b8d28c68 fakessh: Use local process's sys.executable. 6 years ago
David Wilson 175fe7a4e1 fakessh: IoPump() doesn't need Process reference. 6 years ago
David Wilson 8dad396e27 Make subsystem requests die with a useful error. 6 years ago
David Wilson 4244a4609c Reduce CHUNK_SIZE to paper over a hang with rsync 6 years ago
David Wilson c67119501b Keep allocate_id() in the enhanced router class. 6 years ago
David Wilson 02a37d2339 Fix format string. 6 years ago
David Wilson 4720eb1c55 core: add ALLOCATE_ID message for fakessh. 6 years ago
David Wilson e796487cca core: allow sending 0-byte messages. 6 years ago
David Wilson 78d5575d4e Fix proxy connection: pickling changes broke it. 6 years ago
David Wilson b809d43865 Move more docstrings out of core.py. 6 years ago
David Wilson 918edf5145 Add TODO 6 years ago
David Wilson 502266f115 Fix Channel constructor and add simple test; closes #32 6 years ago
David Wilson 4f50707b82 core: support takes_econtext and takes_router decorators. 6 years ago
David Wilson 76e476dcfa Tidy up logging of command lines for easier cutpaste. 6 years ago
David Wilson e66590f098 Initial version of ModuleFinder, but it's slooooow. 6 years ago
David Wilson 53467d394d Log forwarded events just as the docs suggest they're logged. 6 years ago
David Wilson dc446f9042 ssh: Learn to type passwords and supply pubkeys.
Now ssh requires a tty allocation. This presents a scalability problem,
a future version could selectively allocate a tty only if typing
passwords is desired.

Sudo's tty handling is now moved into mitogen.master.
6 years ago
David Wilson 38a9482860 Add hacks to allow Mock to be imported. 6 years ago
David Wilson 1f99dcb435 fix unbelievably dumb variable shadowing 6 years ago
David Wilson 4e8b9ecb27 ssh: Support disabling strict host key checking. 6 years ago
David Wilson 559b88ff12 ssh: Support specifying the port too. 6 years ago
David Wilson be9e55fe8c pickle: support Context(), use same unpickler everywhere.
* Support passing Context() objects in function calls and return values.
  Now the fakessh demo from the documentation index would work
  correctly.

* Since slaves can communicate with each other now, they should also use
  the same approach to unpickling as the master already used. Collapse
  away all the unpickle extension crap and hard-wire just the 3 types
  that support unpickling.
6 years ago
David Wilson 11acc031a9 pickle: Prevent access to the _Dead and CallError constructors
This should be pretty much identical the same behaviour as before, but
the extra assertion makes me feel happier.
6 years ago
David Wilson e75f1d8579 Add call_function_test, fix various exception bugs. 6 years ago
David Wilson e7ff6259a3 Initial commit. 6 years ago