1
- .. uses periodic-executor.rst
1
+ .. _pymongo- periodic-executors:
2
2
3
3
Periodic Executors
4
4
==================
5
5
6
+ .. contents:: On this page
7
+ :local:
8
+ :backlinks: none
9
+ :depth: 1
10
+ :class: singlecol
11
+
12
+ .. facet::
13
+ :name: genre
14
+ :values: reference
15
+
16
+ .. meta::
17
+ :keywords: sleep, timeout, wake
18
+
6
19
PyMongo implements a ``~periodic_executor.PeriodicExecutor`` for two
7
20
purposes: as the background thread for ``~monitor.Monitor``, and to
8
21
regularly check if there are ``OP_KILL_CURSORS`` messages that must be sent to the server.
@@ -16,44 +29,42 @@ the cursor before finishing iteration:
16
29
17
30
.. code-block:: python
18
31
19
- for doc in collection.find():
20
- raise Exception()
32
+ for doc in collection.find():
33
+ raise Exception()
21
34
22
- We try to send an ``OP_KILL_CURSORS`` to the server to tell it to clean up the
23
- server-side cursor. But we must not take any locks directly from the cursor's
24
- destructor (see `PYTHON-799`_), so we cannot safely use the PyMongo data
25
- structures required to send a message. The solution is to add the cursor's id
35
+ The client tries to send an ``OP_KILL_CURSORS`` to the server to tell it to clean up the
36
+ server-side cursor. But the client must not take any locks directly from the cursor's
37
+ destructor (see `PYTHON-799 <https://jira.mongodb.org/browse/PYTHON-799>`__
38
+ ), so we cannot safely use the PyMongo data
39
+ structures required to send a message. The solution is to add the cursor's ID
26
40
to an array on the ``~mongo_client.MongoClient`` without taking any locks.
27
41
28
42
Each client has a ``~periodic_executor.PeriodicExecutor`` devoted to
29
- checking the array for cursor ids . Any it sees are the result of cursors that
43
+ checking the array for cursor IDs . Any it sees are the result of cursors that
30
44
were freed while the server-side cursor was still open. The executor can safely
31
45
take the locks it needs in order to send the ``OP_KILL_CURSORS`` message.
32
46
33
- .. _PYTHON-799: https://jira.mongodb.org/browse/PYTHON-799
34
-
35
47
Stopping Executors
36
48
------------------
37
49
38
50
Just as ``~cursor.Cursor`` must not take any locks from its destructor,
39
51
neither can ``~mongo_client.MongoClient`` and ``~topology.Topology``.
40
- Thus, although the client calls the ``close`` method on its kill-cursors thread, and
41
- the topology calls the ``close`` method on all its monitor threads, the the ``close`` method
42
- method cannot actually call the ``wake`` method on the executor, since the ``wake`` method
52
+ Thus, although the client calls the ``close() `` method on its kill-cursors thread, and
53
+ the topology calls the ``close() `` method on all its monitor threads, the ``close() `` method
54
+ method cannot actually call the ``wake() `` method on the executor, since the ``wake() `` method
43
55
takes a lock.
44
56
45
57
Instead, executors wake periodically to check if ``self.close`` is set,
46
- and if so they exit.
58
+ and if so, they exit.
47
59
48
60
A thread can log spurious errors if it wakes late in the Python interpreter's
49
61
shutdown sequence, so we try to join threads before then. Each periodic
50
62
executor (either a monitor or a kill-cursors thread) adds a weakref to itself
51
63
to a set called ``_EXECUTORS``, in the ``periodic_executor`` module.
52
64
53
- An `exit handler`_ runs on shutdown and tells all executors to stop, then
54
- tries (with a short timeout) to join all executor threads.
55
-
56
- .. _exit handler: https://docs.python.org/2/library/atexit.html
65
+ An `exit handler <https://docs.python.org/2/library/atexit.html>`__ runs on shutdown
66
+ and tells all executors to stop, then tries (with a short timeout) to join all
67
+ executor threads.
57
68
58
69
Monitoring
59
70
----------
@@ -65,52 +76,42 @@ callback to terminate itself soon after the topology is freed.
65
76
66
77
Solid lines represent strong references, dashed lines weak ones:
67
78
68
- .. generated with graphviz: "dot -Tpng periodic-executor-refs.dot > periodic-executor-refs.png"
69
-
70
79
.. image:: ../images/periodic-executor-refs.png
71
80
:alt: Periodic executor references
72
81
73
- See Stopping Executors above for an explanation of the ``_EXECUTORS`` set.
74
-
75
- It is a requirement of the `Server Discovery And Monitoring Spec`_ that a
76
- sleeping monitor can be awakened early. Aside from infrequent wakeups to do
82
+ Aside from infrequent wakeups to do
77
83
their appointed chores, and occasional interruptions, periodic executors also
78
84
wake periodically to check if they should terminate.
79
85
80
- Our first implementation of this idea was the obvious one: use the Python
81
- standard library's threading.Condition.wait with a timeout. Another thread
82
- wakes the executor early by signaling the condition variable.
86
+ Initially, {+driver-short+} used the Python
87
+ standard library's `` threading.Condition.wait()`` method with a timeout. Another thread
88
+ woke the executor early by signaling the condition variable.
83
89
84
90
A topology cannot signal the condition variable to tell the executor to
85
91
terminate, because it would risk a deadlock in the garbage collector: no
86
92
destructor or weakref callback can take a lock to signal the condition variable
87
- (see `PYTHON-863`_); thus the only way for a dying object to terminate a
88
- periodic executor is to set its "stopped" flag and let the executor see the
89
- flag next time it wakes.
93
+ (see `PYTHON-863 <https://jira.mongodb.org/browse/PYTHON-863>`__). The only way for a
94
+ dying object to terminate a periodic executor is to set its "stopped" flag and let the
95
+ executor see the flag next time it wakes.
90
96
91
97
We erred on the side of prompt cleanup, and set the check interval at 100ms. We
92
98
assumed that checking a flag and going back to sleep 10 times a second was
93
99
cheap on modern machines.
94
100
95
- Starting in Python 3.2, the builtin C implementation of lock.acquire takes a
96
- timeout parameter, so Python 3.2+ Condition variables sleep simply by calling
97
- lock.acquire; they are implemented as efficiently as expected.
101
+ Starting in Python 3.2, the built-in C implementation of the `` lock.acquire()`` method
102
+ takes a `` timeout`` parameter, so Python 3.2+ condition variables sleep simply by calling
103
+ `` lock.acquire()``. They are implemented as efficiently as expected.
98
104
99
- But in Python 2, lock.acquire has no timeout. To wait with a timeout, a Python
100
- 2 condition variable sleeps a millisecond, tries to acquire the lock, sleeps
105
+ But in Python 2, the `` lock.acquire()`` method has no timeout. To wait with a timeout, a Python
106
+ 2 condition variable sleeps for a millisecond, tries to acquire the lock, sleeps
101
107
twice as long, and tries again. This exponential backoff reaches a maximum
102
108
sleep time of 50ms.
103
109
104
- If PyMongo calls the condition variable's " wait" method with a short timeout,
110
+ If PyMongo calls the condition variable's `` wait()`` method with a short timeout,
105
111
the exponential backoff is restarted frequently. Overall, the condition variable
106
- is not waking a few times a second, but hundreds of times. (See `PYTHON-983`_.)
112
+ is not waking a few times a second, but hundreds of times.
113
+ (See `PYTHON-983 <https://jira.mongodb.org/browse/PYTHON-983>`__.)
107
114
108
- Thus the current design of periodic executors is surprisingly simple: they
109
- do a simple ``time.sleep`` for a half-second, check if it is time to wake or
115
+ Thus, the current design of periodic executors is surprisingly simple: they
116
+ call the ``time.sleep()`` method to pause for a half-second, check if it is time to wake or
110
117
terminate, and sleep again.
111
-
112
- .. _Server Discovery And Monitoring Spec: https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.rst#requesting-an-immediate-check
113
-
114
- .. _PYTHON-863: https://jira.mongodb.org/browse/PYTHON-863
115
-
116
- .. _PYTHON-983: https://jira.mongodb.org/browse/PYTHON-983
0 commit comments