Many docs updates.

pull/35/head
David Wilson 9 years ago
parent 6a01ae03e3
commit 1f27872eda

@ -12,13 +12,13 @@ document them thoroughly below.
The UNIX First Stage The UNIX First Stage
-------------------- --------------------
To allow delivery of the bootstrap compressed using ``zlib``, it is necessary To allow delivery of the bootstrap compressed using :py:mod:`zlib`, it is
for something on the remote to be prepared to decompress the payload and feed necessary for something on the remote to be prepared to decompress the payload
it to a Python interpreter. Since we would like to avoid writing an error-prone and feed it to a Python interpreter. Since we would like to avoid writing an
shell fragment to implement this, and since we must avoid writing to the remote error-prone shell fragment to implement this, and since we must avoid writing
machine's disk in case it is read-only, the Python process started on the to the remote machine's disk in case it is read-only, the Python process
remote machine by ``econtext`` immediately forks in order to implement the started on the remote machine by ``econtext`` immediately forks in order to
decompression. implement the decompression.
Python Command Line Python Command Line
@ -49,15 +49,15 @@ can be recovered by the bootstrapped process later. It then forks into a new
process. process.
After fork, the parent half overwrites its ``stdin`` with the read end of the After fork, the parent half overwrites its ``stdin`` with the read end of the
pipe, and the child half begins reading the ``zlib``-compressed payload pipe, and the child half begins reading the :py:mod:`zlib`-compressed payload
supplied on ``stdin`` by the econtext master, and writing the decompressed supplied on ``stdin`` by the econtext master, and writing the decompressed
result to the write-end of the UNIX pipe. result to the write-end of the UNIX pipe.
To allow recovery of ``stdin`` for reuse by the bootstrapped process for To allow recovery of ``stdin`` for reuse by the bootstrapped process for
master<->slave communication, it is necessary for the first stage to avoid master<->slave communication, it is necessary for the first stage to avoid
closing ``stdin`` or reading from it until until EOF. Therefore, the master closing ``stdin`` or reading from it until until EOF. Therefore, the master
sends the zlib-compressed payload prefixed with an integer size, allowing sends the :py:mod:`zlib`-compressed payload prefixed with an integer size,
reading by the first stage of exactly the required bytes. allowing reading by the first stage of exactly the required bytes.
Configuring argv[0] Configuring argv[0]
@ -80,8 +80,8 @@ connected to ``stdin``.
Bootstrap Preparation Bootstrap Preparation
##################### #####################
Now we have the mechanism in place to send a zlib-compressed script to the Now we have the mechanism in place to send a :py:mod:`zlib`-compressed script
remote Python interpreter, it is time to choose what to send. to the remote Python interpreter, it is time to choose what to send.
The script sent is simply the source code for :py:mod:`econtext.core`, with a The script sent is simply the source code for :py:mod:`econtext.core`, with a
single line suffixed to trigger execution of the single line suffixed to trigger execution of the
@ -150,7 +150,7 @@ Setup Logging
The slave's :py:mod:`logging` package root logger is configured to have the The slave's :py:mod:`logging` package root logger is configured to have the
same log level as the root logger in the master, and same log level as the root logger in the master, and
:py:class:`econtext.core.LogHandler` is installed to forward logs to the master :py:class:`econtext.core.LogHandler` is installed to forward logs to the master
context's ``FORWARD_LOG`` handle. context's :py:data:`FORWARD_LOG <econtext.core.FORWARD_LOG>` handle.
The log level is copied into the slave to avoid generating a potentially large The log level is copied into the slave to avoid generating a potentially large
amount of network IO forwarding logs that will simply be filtered away once amount of network IO forwarding logs that will simply be filtered away once
@ -161,8 +161,8 @@ The Module Importer
################### ###################
An instance of :py:class:`econtext.core.Importer` is installed in An instance of :py:class:`econtext.core.Importer` is installed in
`sys.meta_path`, where Python's ``import`` statement will execute it before :py:data:`sys.meta_path`, where Python's ``import`` statement will execute it
attempting to find a module locally. before attempting to find a module locally.
Standard IO Redirection Standard IO Redirection
@ -180,8 +180,8 @@ master and slave to be accidentally corrupted by subprocesses run by user code.
The inherited ``stdin`` is replaced by a file descriptor pointing to The inherited ``stdin`` is replaced by a file descriptor pointing to
``/dev/null``. ``/dev/null``.
Finally Python's `sys.stdout` is reopened to ensure line buffering is active, Finally Python's :py:data:`sys.stdout` is reopened to ensure line buffering is
so that ``print`` statements and suchlike promptly appear in the logs. active, so that ``print`` statements and suchlike promptly appear in the logs.
Function Call Dispatch Function Call Dispatch
@ -189,9 +189,10 @@ Function Call Dispatch
After all initialization is complete, the slave's main thread sits in a loop After all initialization is complete, the slave's main thread sits in a loop
reading from a :py:class:`Channel <econtext.core.Channel>` connected to the reading from a :py:class:`Channel <econtext.core.Channel>` connected to the
``CALL_FUNCTION`` handle. This handle is written to by :py:data:`CALL_FUNCTION <econtext.core.CALL_FUNCTION>` handle. This handle is
:py:meth:`call_with_deadline() <econtext.master.Context.call_with_deadline>` and written to by
:py:meth:`call() <econtext.master.Context.call>`. :py:meth:`call_with_deadline() <econtext.master.Context.call_with_deadline>`
and :py:meth:`call() <econtext.master.Context.call>`.
@ -217,31 +218,36 @@ value to be delivered to the target.
Masters listen on the following handles: Masters listen on the following handles:
``econtext.core.FORWARD_LOG`` .. data:: econtext.core.FORWARD_LOG
Receives `(logger_name, level, msg)` 3-tuples and writes them to the Receives `(logger_name, level, msg)` 3-tuples and writes them to the
master's ``econtext.ctx.<context_name>`` logger. master's ``econtext.ctx.<context_name>`` logger.
``econtext.core.GET_MODULE`` .. data:: econtext.core.GET_MODULE
Receives `(reply_to, fullname)` 2-tuples, looks up the source code for the Receives `(reply_to, fullname)` 2-tuples, looks up the source code for the
module named ``fullname``, and writes the source along with some metadata module named ``fullname``, and writes the source along with some metadata
back to the handle ``reply_to``. If lookup fails, ``None`` is sent instead. back to the handle ``reply_to``. If lookup fails, ``None`` is sent instead.
Slaves listen on the following handles: Slaves listen on the following handles:
``econtext.core.CALL_FUNCTION``: .. data:: econtext.core.CALL_FUNCTION
Receives `(with_context, mod_name, class_name, func_name, args, kwargs)` Receives `(with_context, mod_name, class_name, func_name, args, kwargs)`
5-tuples from :py:meth:`econtext.master.Context.call_with_deadline`, 5-tuples from
imports ``mod_name``, then attempts to execute `class_name.func_name(*args, :py:meth:`call_with_deadline() <econtext.master.Context.call_with_deadline>`,
**kwargs)`. imports ``mod_name``, then attempts to execute
`class_name.func_name(\*args, \**kwargs)`.
.. data:: econtext.core.SHUTDOWN
``econtext.core.SHUTDOWN``:
Triggers :py:meth:`econtext.core.Broker.shutdown` remotely, causing the Triggers :py:meth:`econtext.core.Broker.shutdown` remotely, causing the
slave to drain its :py:class:`IoLoggers <econtext.core.IoLogger>` and slave to drain its :py:class:`IoLoggers <econtext.core.IoLogger>` and
output stream buffer before disconnecting from the master and terminating output stream buffer before disconnecting from the master and terminating
the process. the process.
Additional handles are created to receive the result of every function call Additional handles are created to receive the result of every function call
triggered by :py:meth:`econtext.master.Context.call_with_deadline`. triggered by :py:meth:`call_with_deadline() <econtext.master.Context.call_with_deadline>`.
Use of Pickle Use of Pickle
@ -328,9 +334,9 @@ In Python 2.x, Python will first try to load ``mypkg.sys`` and ``mypkg.os``,
which do not exist, before falling back on :py:mod:`sys` and :py:mod:`os`. which do not exist, before falling back on :py:mod:`sys` and :py:mod:`os`.
These negative imports present a challenge, as they introduce a large number of These negative imports present a challenge, as they introduce a large number of
pointless network roundtrips. Therefore in addition to the zlib-compressed pointless network roundtrips. Therefore in addition to the
source, for packages the master sends along a list of child modules known to :py:mod:`zlib`-compressed source, for packages the master sends along a list of
exist. child modules known to exist.
Before indicating it can satisfy an import request, Before indicating it can satisfy an import request,
:py:class:`econtext.core.Importer` first checks to see if the module belongs to :py:class:`econtext.core.Importer` first checks to see if the module belongs to
@ -353,10 +359,10 @@ multiplexer always retains control flow in order to shut down gracefully, say,
if the user's code has hung and the master context has disconnected. if the user's code has hung and the master context has disconnected.
While it is possible for the IO multiplexer to recover control of a hung While it is possible for the IO multiplexer to recover control of a hung
function call on UNIX using for example ``signal.SIGALRM``, this mechanism is function call on UNIX using for example :py:mod:`signal.SIGALRM <signal>`, this
not portable to non-UNIX operating systems, and does not work in every case, mechanism is not portable to non-UNIX operating systems, and does not work in
for example when Python blocks signals during a variety of :py:mod:`threading` every case, for example when Python blocks signals during a variety of
package operations. :py:mod:`threading` package operations.
At some point it is likely econtext will be extended to support starting slaves At some point it is likely econtext will be extended to support starting slaves
running on Windows. When that happens, it would be nice if the process model on running on Windows. When that happens, it would be nice if the process model on

@ -56,8 +56,8 @@ connection.
$ python preamble_size.py $ python preamble_size.py
SSH command size: 411 SSH command size: 411
Preamble size: 4892 (4.78KiB) Preamble size: 4845 (4.73KiB)
econtext.master size: 2627 (2.57KiB) econtext.master size: 2640 (2.58KiB)
Once bootstrapped, the remote process is configured with a customizable Once bootstrapped, the remote process is configured with a customizable
**argv[0]**, readily visible to system administrators of the remote machine **argv[0]**, readily visible to system administrators of the remote machine
@ -94,12 +94,14 @@ Module Forwarder
################ ################
In addition to an IO multiplexer, the external context is configured with a In addition to an IO multiplexer, the external context is configured with a
custom **PEP-302 importer** that forwards requests for unknown Python modules custom `PEP-302 importer`_ that forwards requests for unknown Python modules
back to the host machine. When your program asks an external context to execute back to the host machine. When your program asks an external context to execute
code from an unknown module, all requisite modules are transferred code from an unknown module, all requisite modules are transferred
automatically and imported entirely in RAM without need for further automatically and imported entirely in RAM without need for further
configuration. configuration.
.. _PEP-302 importer: https://www.python.org/dev/peps/pep-0302/
.. code-block:: python .. code-block:: python
import myapp.mypkg.mymodule import myapp.mypkg.mymodule
@ -170,6 +172,12 @@ After:
context.call(install_app) context.call(install_app)
Or even:
.. code-block:: python
context.call(os.system, 'tar zxvf app.tar.gz')
Exceptions raised by function calls are propagated back to the parent program, Exceptions raised by function calls are propagated back to the parent program,
and timeouts can be configured to ensure failed calls do not block progress of and timeouts can be configured to ensure failed calls do not block progress of
the parent. the parent.

@ -146,8 +146,8 @@ class LocalStream(econtext.core.Stream):
def on_shutdown(self): def on_shutdown(self):
"""Request the slave gracefully shut itself down.""" """Request the slave gracefully shut itself down."""
LOG.debug('%r enqueuing SHUTDOWN', self) LOG.debug('%r closing CALL_FUNCTION channel', self)
self.enqueue(econtext.core.SHUTDOWN, None) self.enqueue(econtext.core.CALL_FUNCTION, econtext.core._DEAD)
def _find_global(self, module_name, class_name): def _find_global(self, module_name, class_name):
"""Return the class implementing `module_name.class_name` or raise """Return the class implementing `module_name.class_name` or raise

Loading…
Cancel
Save