summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2015-04-20 19:07:51 +0000
committerGerrit Code Review <review@openstack.org>2015-04-20 19:07:51 +0000
commitd8bed1986e7127223e53a8022f5fe066d410750f (patch)
tree47974466ee41d74eff6997fd4599ff2a44ec372e
parentc340b7dd4dd862d9500478bfa3ed2dcb1054d5fe (diff)
parent18ca7fabece4837ad56e435bc9d5f0b6278fa4be (diff)
downloadkeystone-d8bed1986e7127223e53a8022f5fe066d410750f.tar.gz
Merge "Make memcache client reusable across threads" into stable/kilo
-rw-r--r--keystone/common/cache/_memcache_pool.py21
-rw-r--r--keystone/tests/unit/common/test_connection_pool.py16
2 files changed, 32 insertions, 5 deletions
diff --git a/keystone/common/cache/_memcache_pool.py b/keystone/common/cache/_memcache_pool.py
index b15332db0..bc559781a 100644
--- a/keystone/common/cache/_memcache_pool.py
+++ b/keystone/common/cache/_memcache_pool.py
@@ -35,11 +35,22 @@ from keystone.i18n import _
LOG = log.getLogger(__name__)
-# This 'class' is taken from http://stackoverflow.com/a/22520633/238308
-# Don't inherit client from threading.local so that we can reuse clients in
-# different threads
-_MemcacheClient = type('_MemcacheClient', (object,),
- dict(memcache.Client.__dict__))
+
+class _MemcacheClient(memcache.Client):
+ """Thread global memcache client
+
+ As client is inherited from threading.local we have to restore object
+ methods overloaded by threading.local so we can reuse clients in
+ different threads
+ """
+ __delattr__ = object.__delattr__
+ __getattribute__ = object.__getattribute__
+ __new__ = object.__new__
+ __setattr__ = object.__setattr__
+
+ def __del__(self):
+ pass
+
_PoolItem = collections.namedtuple('_PoolItem', ['ttl', 'connection'])
diff --git a/keystone/tests/unit/common/test_connection_pool.py b/keystone/tests/unit/common/test_connection_pool.py
index 74d0420ce..3813e0339 100644
--- a/keystone/tests/unit/common/test_connection_pool.py
+++ b/keystone/tests/unit/common/test_connection_pool.py
@@ -10,9 +10,11 @@
# License for the specific language governing permissions and limitations
# under the License.
+import threading
import time
import mock
+import six
from six.moves import queue
import testtools
from testtools import matchers
@@ -117,3 +119,17 @@ class TestConnectionPool(core.TestCase):
# after it is available.
connection_pool.put_nowait(conn)
_acquire_connection()
+
+
+class TestMemcacheClientOverrides(core.BaseTestCase):
+
+ def test_client_stripped_of_threading_local(self):
+ """threading.local overrides are restored for _MemcacheClient"""
+ client_class = _memcache_pool._MemcacheClient
+ # get the genuine thread._local from MRO
+ thread_local = client_class.__mro__[2]
+ self.assertTrue(thread_local is threading.local)
+ for field in six.iterkeys(thread_local.__dict__):
+ if field not in ('__dict__', '__weakref__'):
+ self.assertNotEqual(id(getattr(thread_local, field, None)),
+ id(getattr(client_class, field, None)))