Skip to content

Commit 1bfac99

Browse files
committed
PYTHON-724 Remove Gevent-specific code.
PyMongo 2.x has Gevent-specific code to support Gevent with or without patch_thread. However, patch_socket is always required with Gevent. In PyMongo 3, we remove all Gevent-specific code and rely on Gevent's patch_all. Remove the "use_greenlets" option and attribute for MongoClient and MongoReplicaSetClient.
1 parent 2177256 commit 1bfac99

File tree

7 files changed

+82
-393
lines changed

7 files changed

+82
-393
lines changed

pymongo/common.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,6 @@ def validate_read_preference_tags(name, value):
279279
'latencythresholdms': validate_positive_float,
280280
'secondaryacceptablelatencyms': validate_positive_float,
281281
'auto_start_request': validate_boolean,
282-
'use_greenlets': validate_boolean,
283282
'authmechanism': validate_auth_mechanism,
284283
'authsource': validate_string,
285284
'gssapiservicename': validate_string,

pymongo/mongo_client.py

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,6 @@ def __init__(self, host=None, port=None, max_pool_size=100,
292292
socket_timeout = options.get('sockettimeoutms')
293293
wait_queue_timeout = options.get('waitqueuetimeoutms')
294294
wait_queue_multiple = options.get('waitqueuemultiple')
295-
use_greenlets = options.get('use_greenlets', False)
296295
socket_keepalive = options.get('socketkeepalive', False)
297296

298297
ssl_context = None
@@ -330,26 +329,17 @@ def __init__(self, host=None, port=None, max_pool_size=100,
330329
wait_queue_timeout=wait_queue_timeout,
331330
wait_queue_multiple=wait_queue_multiple,
332331
ssl_context=ssl_context,
333-
use_greenlets=use_greenlets,
334332
socket_keepalive=socket_keepalive)
335333

336334
self.__pool_class = pool_class
337335

338336
self.__connecting = False
339-
if use_greenlets:
340-
# Greenlets don't need to lock around access to the Member;
341-
# they're only interrupted when they do I/O.
342-
self.__connecting_lock = thread_util.DummyLock()
343-
else:
344-
self.__connecting_lock = threading.Lock()
337+
self.__connecting_lock = threading.Lock()
345338

346339
if event_class:
347340
self.__event_class = event_class
348341
else:
349-
# Prevent a cycle; this lambda shouldn't refer to self.
350-
g = use_greenlets
351-
event_class = lambda: thread_util.create_event(g)
352-
self.__event_class = event_class
342+
self.__event_class = threading.Event
353343

354344
self.__future_member = None
355345
self.__document_class = document_class
@@ -556,15 +546,6 @@ def max_pool_size(self):
556546
"""
557547
return self.__pool_opts.max_pool_size
558548

559-
@property
560-
def use_greenlets(self):
561-
"""Whether calling :meth:`start_request` assigns greenlet-local,
562-
rather than thread-local, sockets.
563-
564-
.. versionadded:: 2.4.2
565-
"""
566-
return self.__pool_opts.use_greenlets
567-
568549
@property
569550
def nodes(self):
570551
"""List of all known nodes.

pymongo/mongo_replica_set_client.py

Lines changed: 18 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def _partition_node(node):
109109

110110
# Concurrency notes: A MongoReplicaSetClient keeps its view of the replica-set
111111
# state in an RSState instance. RSStates are immutable, except for
112-
# host-pinning. Pools, which are internally thread / greenlet safe, can be
112+
# host-pinning. Pools, which are internally thread-safe, can be
113113
# copied from old to new RSStates safely. The client updates its view of the
114114
# set's state not by modifying its RSState but by replacing it with an updated
115115
# copy.
@@ -133,7 +133,7 @@ def _partition_node(node):
133133

134134
class RSState(object):
135135
def __init__(
136-
self, threadlocal, hosts=None, host_to_member=None, arbiters=None,
136+
self, threadlocal=None, hosts=None, host_to_member=None, arbiters=None,
137137
writer=None, error_message='No primary available', exc=None,
138138
initial=False):
139139
"""An immutable snapshot of the client's view of the replica set state.
@@ -143,7 +143,7 @@ def __init__(
143143
in the most recent ismaster response.
144144
145145
:Parameters:
146-
- `threadlocal`: Thread-local storage
146+
- `threadlocal`: Optional thread-local storage
147147
- `hosts`: Sequence of (host, port) pairs
148148
- `host_to_member`: Optional dict: (host, port) -> Member instance
149149
- `arbiters`: Optional sequence of arbiters as (host, port)
@@ -152,7 +152,7 @@ def __init__(
152152
- `exc`: Optional error if state is unusable
153153
- `initial`: Whether this is the initial client state
154154
"""
155-
self._threadlocal = threadlocal # threading.local
155+
self._threadlocal = threadlocal or threading.local()
156156
self._arbiters = frozenset(arbiters or []) # set of (host, port)
157157
self._writer = writer # (host, port) of the primary, or None
158158
self._error_message = error_message
@@ -191,17 +191,12 @@ def clone_with_host_down(self, host, error_message):
191191
self._error_message,
192192
self._exc)
193193

194-
def clone_without_writer(self, threadlocal):
195-
"""Get a clone without a primary. Unpins all threads.
196-
197-
:Parameters:
198-
- `threadlocal`: Thread-local storage
199-
"""
194+
def clone_without_writer(self):
195+
"""Get a clone without a primary. Unpins all threads."""
200196
return RSState(
201-
threadlocal,
202-
self._hosts,
203-
self._host_to_member,
204-
self._arbiters)
197+
hosts=self._hosts,
198+
host_to_member=self._host_to_member,
199+
arbiters=self._arbiters)
205200

206201
def clone_with_error(self, exc):
207202
return RSState(
@@ -387,48 +382,6 @@ def run(self):
387382
self.monitor()
388383

389384

390-
have_gevent = False
391-
try:
392-
from gevent import Greenlet
393-
from gevent.event import Event
394-
395-
# Used by ReplicaSetConnection
396-
from gevent.local import local as gevent_local
397-
have_gevent = True
398-
399-
class MonitorGreenlet(Monitor, Greenlet):
400-
"""Greenlet based replica set monitor.
401-
"""
402-
def __init__(self, rsc):
403-
self.monitor_greenlet_alive = False
404-
Monitor.__init__(self, rsc, Event)
405-
Greenlet.__init__(self)
406-
407-
def start_sync(self):
408-
self.monitor_greenlet_alive = True
409-
410-
# Call superclass.
411-
Monitor.start_sync(self)
412-
413-
# Don't override `run` in a Greenlet. Add _run instead.
414-
# Refer to gevent's Greenlet docs and source for more
415-
# information.
416-
def _run(self):
417-
"""Define Greenlet's _run method.
418-
"""
419-
self.monitor()
420-
421-
def isAlive(self):
422-
# bool(self) isn't immediately True after someone calls start(),
423-
# but isAlive() is. Thus it's safe for greenlets to do:
424-
# "if not monitor.isAlive(): monitor.start()"
425-
# ... and be guaranteed only one greenlet starts the monitor.
426-
return self.monitor_greenlet_alive
427-
428-
except ImportError:
429-
pass
430-
431-
432385
class MongoReplicaSetClient(common.BaseObject):
433386
"""Connection to a MongoDB replica set.
434387
"""
@@ -619,15 +572,10 @@ def __init__(self, hosts_or_uri=None, max_pool_size=100,
619572
socket_timeout = self.__opts.get('sockettimeoutms')
620573
wait_queue_timeout = self.__opts.get('waitqueuetimeoutms')
621574
wait_queue_multiple = self.__opts.get('waitqueuemultiple')
622-
self.__use_greenlets = self.__opts.get('use_greenlets', False)
623-
if self.__use_greenlets and not have_gevent:
624-
raise ConfigurationError(
625-
"The gevent module is not available. "
626-
"Install the gevent package from PyPI.")
627575

628-
self.__rs_state = RSState(self.__make_threadlocal(), initial=True)
576+
self.__rs_state = RSState(initial=True)
629577

630-
self.__request_counter = thread_util.Counter(self.__use_greenlets)
578+
self.__request_counter = thread_util.Counter()
631579

632580
self.__auto_start_request = self.__opts.get('auto_start_request', False)
633581
if self.__auto_start_request:
@@ -674,9 +622,7 @@ def __init__(self, hosts_or_uri=None, max_pool_size=100,
674622
wait_queue_timeout=wait_queue_timeout,
675623
wait_queue_multiple=wait_queue_multiple,
676624
ssl_context=ssl_context,
677-
use_greenlets=self.__use_greenlets,
678-
socket_keepalive=socket_keepalive
679-
)
625+
socket_keepalive=socket_keepalive)
680626

681627
super(MongoReplicaSetClient, self).__init__(**self.__opts)
682628

@@ -706,21 +652,9 @@ def __init__(self, hosts_or_uri=None, max_pool_size=100,
706652

707653
# Start the monitor after we know the configuration is correct.
708654
if not self.__monitor_class:
709-
if self.__use_greenlets:
710-
self.__monitor_class = MonitorGreenlet
711-
else:
712-
# Common case: monitor RS with a background thread.
713-
self.__monitor_class = MonitorThread
714-
715-
if self.__use_greenlets:
716-
# Greenlets don't need to lock around access to the monitor.
717-
# A Greenlet can safely do:
718-
# "if not self.__monitor: self.__monitor = monitor_class()"
719-
# because it won't be interrupted between the check and the
720-
# assignment.
721-
self.__monitor_lock = DummyLock()
722-
else:
723-
self.__monitor_lock = threading.Lock()
655+
self.__monitor_class = MonitorThread
656+
657+
self.__monitor_lock = threading.Lock()
724658

725659
if _connect:
726660
self.__ensure_monitor()
@@ -902,15 +836,6 @@ def max_pool_size(self):
902836
"""
903837
return self.__pool_opts.max_pool_size
904838

905-
@property
906-
def use_greenlets(self):
907-
"""Whether calling :meth:`start_request` assigns greenlet-local,
908-
rather than thread-local, sockets.
909-
910-
.. versionadded:: 2.4.2
911-
"""
912-
return self.__pool_opts.use_greenlets
913-
914839
def get_document_class(self):
915840
"""document_class getter"""
916841
return self.__document_class
@@ -1059,12 +984,6 @@ def __ensure_monitor(self):
1059984
finally:
1060985
self.__monitor_lock.release()
1061986

1062-
def __make_threadlocal(self):
1063-
if self.__use_greenlets:
1064-
return gevent_local()
1065-
else:
1066-
return threading.local()
1067-
1068987
def refresh(self, initial=False):
1069988
"""Iterate through the existing host list, or possibly the
1070989
seed list, to update the list of hosts and arbiters in this
@@ -1201,7 +1120,7 @@ def __create_rs_state(self, rs_state, initial):
12011120
else:
12021121
# We unpin threads from members if the primary has changed, since
12031122
# no monotonic consistency can be promised now anyway.
1204-
threadlocal = self.__make_threadlocal()
1123+
threadlocal = None
12051124

12061125
# Get list of hosts in the RS config, including unreachable ones.
12071126
# Prefer the primary's list, otherwise any member's list.
@@ -1286,8 +1205,7 @@ def disconnect(self):
12861205
if rs_state.primary_member:
12871206
rs_state.primary_member.pool.reset()
12881207

1289-
threadlocal = self.__make_threadlocal()
1290-
self.__rs_state = rs_state.clone_without_writer(threadlocal)
1208+
self.__rs_state = rs_state.clone_without_writer()
12911209
self.__schedule_refresh()
12921210

12931211
def close(self):
@@ -1307,7 +1225,7 @@ def close(self):
13071225
The :meth:`close` method now terminates the replica set monitor.
13081226
"""
13091227
self.__closed = True
1310-
self.__rs_state = RSState(self.__make_threadlocal())
1228+
self.__rs_state = RSState()
13111229

13121230
monitor, self.__monitor = self.__monitor, None
13131231
if monitor:

pymongo/pool.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -50,20 +50,19 @@ class PoolOptions(object):
5050

5151
__slots__ = ('__max_pool_size', '__connect_timeout', '__socket_timeout',
5252
'__wait_queue_timeout', '__wait_queue_multiple',
53-
'__ssl_context', '__use_greenlets', '__socket_keepalive')
53+
'__ssl_context', '__socket_keepalive')
5454

5555
def __init__(self, max_pool_size=100, connect_timeout=None,
5656
socket_timeout=None, wait_queue_timeout=None,
5757
wait_queue_multiple=None, ssl_context=None,
58-
use_greenlets=False, socket_keepalive=False):
58+
socket_keepalive=False):
5959

6060
self.__max_pool_size = max_pool_size
6161
self.__connect_timeout = connect_timeout
6262
self.__socket_timeout = socket_timeout
6363
self.__wait_queue_timeout = wait_queue_timeout
6464
self.__wait_queue_multiple = wait_queue_multiple
6565
self.__ssl_context = ssl_context
66-
self.__use_greenlets = use_greenlets
6766
self.__socket_keepalive = socket_keepalive
6867

6968
@property
@@ -106,12 +105,6 @@ def ssl_context(self):
106105
"""
107106
return self.__ssl_context
108107

109-
@property
110-
def use_greenlets(self):
111-
"""Use greenlet ids for "thread affinity" in requests.
112-
"""
113-
return self.__use_greenlets
114-
115108
@property
116109
def socket_keepalive(self):
117110
"""Whether to send periodic messages to determine if a connection
@@ -251,17 +244,10 @@ def __init__(self, pair, options):
251244

252245
# Map self._ident.get() -> request socket
253246
self._tid_to_sock = {}
254-
255-
if self.opts.use_greenlets and not thread_util.have_gevent:
256-
raise ConfigurationError(
257-
"The Gevent module is not available. "
258-
"Install the gevent package from PyPI."
259-
)
260-
261-
self._ident = thread_util.create_ident(self.opts.use_greenlets)
247+
self._ident = thread_util.ThreadIdent()
262248

263249
# Count the number of calls to start_request() per thread.
264-
self._request_counter = thread_util.Counter(self.opts.use_greenlets)
250+
self._request_counter = thread_util.Counter()
265251

266252
if (self.opts.wait_queue_multiple is None or
267253
self.opts.max_pool_size is None):
@@ -271,7 +257,7 @@ def __init__(self, pair, options):
271257
self.opts.max_pool_size * self.opts.wait_queue_multiple)
272258

273259
self._socket_semaphore = thread_util.create_semaphore(
274-
self.opts.max_pool_size, max_waiters, self.opts.use_greenlets)
260+
self.opts.max_pool_size, max_waiters)
275261

276262
def reset(self):
277263
# Ignore this race condition -- if many threads are resetting at once,

0 commit comments

Comments
 (0)