From bf8689474a9b3930cceed4c5f855a73ce89b1d4e Mon Sep 17 00:00:00 2001 From: Mehdi Abaakouk Date: Thu, 22 Oct 2015 17:33:09 +0200 Subject: [PATCH] monkeypatch thread for keystoneclient keystoneclient uses threading.Lock(), but swift doesn't monkeypatch threading, this result in lockup when two greenthreads try to acquire a non green lock. This change fixes that. Change-Id: I9b44284a5eb598a6978364819f253e031f4eaeef Closes-bug: #1508424 --- swift/common/utils.py | 15 +++++++++------ swift/common/wsgi.py | 3 ++- test/unit/common/middleware/test_ratelimit.py | 15 ++++++++------- test/unit/common/test_manager.py | 8 +++++--- test/unit/common/test_utils.py | 3 ++- test/unit/common/test_wsgi.py | 9 ++++++--- test/unit/test_locale/test_locale.py | 4 +++- 7 files changed, 35 insertions(+), 22 deletions(-) diff --git a/swift/common/utils.py b/swift/common/utils.py index a4647e80bf..bfdea9e305 100644 --- a/swift/common/utils.py +++ b/swift/common/utils.py @@ -26,7 +26,6 @@ import os import pwd import re import sys -import threading as stdlib_threading import time import uuid import functools @@ -63,7 +62,6 @@ import six from six.moves import cPickle as pickle from six.moves.configparser import (ConfigParser, NoSectionError, NoOptionError, RawConfigParser) -from six.moves.queue import Queue, Empty from six.moves import range from six.moves.urllib.parse import ParseResult from six.moves.urllib.parse import quote as _quote @@ -74,6 +72,11 @@ import swift.common.exceptions from swift.common.http import is_success, is_redirection, HTTP_NOT_FOUND, \ HTTP_PRECONDITION_FAILED, HTTP_REQUESTED_RANGE_NOT_SATISFIABLE +if six.PY3: + stdlib_queue = eventlet.patcher.original('queue') +else: + stdlib_queue = eventlet.patcher.original('Queue') +stdlib_threading = eventlet.patcher.original('threading') # logging doesn't import patched as cleanly as one would like from logging.handlers import SysLogHandler @@ -2333,7 +2336,7 @@ class GreenAsyncPile(object): def next(self): try: rv = self._responses.get_nowait() - except Empty: + except eventlet.queue.Empty: if self._inflight == 0: raise StopIteration() rv = self._responses.get() @@ -2984,8 +2987,8 @@ class ThreadPool(object): def __init__(self, nthreads=2): self.nthreads = nthreads - self._run_queue = Queue() - self._result_queue = Queue() + self._run_queue = stdlib_queue.Queue() + self._result_queue = stdlib_queue.Queue() self._threads = [] self._alive = True @@ -3065,7 +3068,7 @@ class ThreadPool(object): while True: try: ev, success, result = queue.get(block=False) - except Empty: + except stdlib_queue.Empty: break try: diff --git a/swift/common/wsgi.py b/swift/common/wsgi.py index 5d8ded023a..996f045ba6 100644 --- a/swift/common/wsgi.py +++ b/swift/common/wsgi.py @@ -407,7 +407,8 @@ def run_server(conf, logger, sock, global_conf=None): wsgi.WRITE_TIMEOUT = int(conf.get('client_timeout') or 60) eventlet.hubs.use_hub(get_hub()) - eventlet.patcher.monkey_patch(all=False, socket=True) + # NOTE(sileht): monkey-patching thread is required by python-keystoneclient + eventlet.patcher.monkey_patch(all=False, socket=True, thread=True) eventlet_debug = config_true_value(conf.get('eventlet_debug', 'no')) eventlet.debug.hub_exceptions(eventlet_debug) wsgi_logger = NullLogger() diff --git a/test/unit/common/middleware/test_ratelimit.py b/test/unit/common/middleware/test_ratelimit.py index 2d865f5b50..44136d2801 100644 --- a/test/unit/common/middleware/test_ratelimit.py +++ b/test/unit/common/middleware/test_ratelimit.py @@ -18,7 +18,6 @@ import time import eventlet import mock from contextlib import contextmanager -from threading import Thread from test.unit import FakeLogger from swift.common.middleware import ratelimit @@ -28,6 +27,8 @@ from swift.common.memcached import MemcacheConnectionError from swift.common.swob import Request from swift.common import utils +threading = eventlet.patcher.original('threading') + class FakeMemcache(object): @@ -313,10 +314,10 @@ class TestRateLimit(unittest.TestCase): req = Request.blank('/v/a/c') req.environ['swift.cache'] = FakeMemcache() - class rate_caller(Thread): + class rate_caller(threading.Thread): def __init__(self, parent): - Thread.__init__(self) + threading.Thread.__init__(self) self.parent = parent def run(self): @@ -356,10 +357,10 @@ class TestRateLimit(unittest.TestCase): req = Request.blank('/v/b/c') req.environ['swift.cache'] = FakeMemcache() - class rate_caller(Thread): + class rate_caller(threading.Thread): def __init__(self, parent): - Thread.__init__(self) + threading.Thread.__init__(self) self.parent = parent def run(self): @@ -505,11 +506,11 @@ class TestRateLimit(unittest.TestCase): req.method = 'PUT' req.environ = {} - class rate_caller(Thread): + class rate_caller(threading.Thread): def __init__(self, name): self.myname = name - Thread.__init__(self) + threading.Thread.__init__(self) def run(self): for j in range(num_calls): diff --git a/test/unit/common/test_manager.py b/test/unit/common/test_manager.py index d408e84262..c1f64305ce 100644 --- a/test/unit/common/test_manager.py +++ b/test/unit/common/test_manager.py @@ -22,12 +22,14 @@ import resource import signal import errno from collections import defaultdict -from threading import Thread from time import sleep, time from swift.common import manager from swift.common.exceptions import InvalidPidFileException +import eventlet +threading = eventlet.patcher.original('threading') + DUMMY_SIG = 1 @@ -1153,9 +1155,9 @@ class TestServer(unittest.TestCase): server = manager.Server('test') self.assertEqual(server.wait(), 0) - class MockProcess(Thread): + class MockProcess(threading.Thread): def __init__(self, delay=0.1, fail_to_start=False): - Thread.__init__(self) + threading.Thread.__init__(self) # setup pipe rfd, wfd = os.pipe() # subprocess connection to read stdout diff --git a/test/unit/common/test_utils.py b/test/unit/common/test_utils.py index 5aafe597c5..198300253f 100644 --- a/test/unit/common/test_utils.py +++ b/test/unit/common/test_utils.py @@ -40,7 +40,6 @@ from six.moves import range from textwrap import dedent import tempfile -import threading import time import traceback import unittest @@ -64,6 +63,8 @@ from swift.common.container_sync_realms import ContainerSyncRealms from swift.common.swob import Request, Response, HeaderKeyDict from test.unit import FakeLogger +threading = eventlet.patcher.original('threading') + class MockOs(object): diff --git a/test/unit/common/test_wsgi.py b/test/unit/common/test_wsgi.py index dcd6ede28e..4c81d575bb 100644 --- a/test/unit/common/test_wsgi.py +++ b/test/unit/common/test_wsgi.py @@ -380,7 +380,8 @@ class TestWSGI(unittest.TestCase): self.assertEqual(30, _wsgi.WRITE_TIMEOUT) _eventlet.hubs.use_hub.assert_called_with(utils.get_hub()) _eventlet.patcher.monkey_patch.assert_called_with(all=False, - socket=True) + socket=True, + thread=True) _eventlet.debug.hub_exceptions.assert_called_with(False) self.assertTrue(_wsgi.server.called) args, kwargs = _wsgi.server.call_args @@ -468,7 +469,8 @@ class TestWSGI(unittest.TestCase): self.assertEqual(30, _wsgi.WRITE_TIMEOUT) _eventlet.hubs.use_hub.assert_called_with(utils.get_hub()) _eventlet.patcher.monkey_patch.assert_called_with(all=False, - socket=True) + socket=True, + thread=True) _eventlet.debug.hub_exceptions.assert_called_with(False) self.assertTrue(_wsgi.server.called) args, kwargs = _wsgi.server.call_args @@ -519,7 +521,8 @@ class TestWSGI(unittest.TestCase): self.assertEqual(30, _wsgi.WRITE_TIMEOUT) _eventlet.hubs.use_hub.assert_called_with(utils.get_hub()) _eventlet.patcher.monkey_patch.assert_called_with(all=False, - socket=True) + socket=True, + thread=True) _eventlet.debug.hub_exceptions.assert_called_with(True) self.assertTrue(mock_server.called) args, kwargs = mock_server.call_args diff --git a/test/unit/test_locale/test_locale.py b/test/unit/test_locale/test_locale.py index fcaca52ef5..de3380e50f 100644 --- a/test/unit/test_locale/test_locale.py +++ b/test/unit/test_locale/test_locale.py @@ -16,10 +16,12 @@ # limitations under the License. from __future__ import print_function +import eventlet import os import unittest import sys -import threading + +threading = eventlet.patcher.original('threading') try: from subprocess import check_output