Make memcache client reusable across threads
memcache.Client is inherited from threading._local so instances are only
accessible from current thread or eventlet. Present workaround broke
inheritance chain so super() call is unusable.
This patch makes artificial client class mimic inheritance from
threading._local while using generic object methods allowing reusability.
Change-Id: Ic5d5709695877afb995fd816bb0e4ce711b99b60
Closes-Bug: #1440493
(cherry picked from commit 33a95575fc
)
This commit is contained in:
parent
cedce339a0
commit
18ca7fabec
|
@ -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'])
|
||||
|
||||
|
|
|
@ -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)))
|
||||
|
|
Loading…
Reference in New Issue