From 695d0ec973e3c1252aaf613b1469fa662f506f8f Mon Sep 17 00:00:00 2001
From: Nicolas Delaby <nicolas@nexedi.com>
Date: Fri, 9 Apr 2010 15:48:40 +0000
Subject: [PATCH] Fix the way to access memcached.Client instances stored on
 connection_pool.

If the configuration of memcached.Client instances are different
to each other inside the same thread, the first created one is allways returned.
So this patch store the instances inside a intermediate
dictionary with keys build with discriminatory criterions.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@34441 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 .../CachePlugins/DistributedRamCache.py       | 33 +++++++++++--------
 product/ERP5Type/Tool/MemcachedTool.py        |  8 +++--
 2 files changed, 26 insertions(+), 15 deletions(-)

diff --git a/product/ERP5Type/CachePlugins/DistributedRamCache.py b/product/ERP5Type/CachePlugins/DistributedRamCache.py
index e879b1bf7a..3ba03b0efe 100644
--- a/product/ERP5Type/CachePlugins/DistributedRamCache.py
+++ b/product/ERP5Type/CachePlugins/DistributedRamCache.py
@@ -39,12 +39,11 @@ import zope.interface
 from base64 import encodestring
 
 try:
-  import memcache
   from Products.ERP5Type.Tool.MemcachedTool import MemcachedDict, SharedDict
 except ImportError:
   LOG('DistributedRamCache', 0, 'unable to import memcache')
 
-## global ditionary containing connection objects
+## global dictionary containing connection objects
 connection_pool = local()
 
 _MARKER = []
@@ -69,22 +68,30 @@ class DistributedRamCache(BaseCache):
     ## cache storage is a memcached server and no need to init it
     pass
 
-  def getCacheStorage(self, **kw):
-    ## if we use one connection object this causes 
-    ## "MemCached: while expecting 'STORED', got unexpected response 'END'"
-    ## messages in log files and can sometimes can block the thread. 
-    ## For the moment we create a new conn object for every thread.
+  def _getMemcachedDict(self):
+    """return a threading safe MemcachedDict instance
+    """
+    configuration_key = (self._servers, self._server_max_key_length,
+                         self._server_max_value_length,
+                         self._debug_level, self._key_prefix)
     try:
-      dictionary = connection_pool.memcached_dict
+      local_dict = connection_pool.local_dict
     except AttributeError:
-      dictionary = SharedDict(
-        MemcachedDict(self._servers.split('\n'),
+      local_dict = connection_pool.local_dict = {}
+    try:
+      dictionary = local_dict[configuration_key]
+    except KeyError:
+      dictionary = MemcachedDict(self._servers.split('\n'),
                       server_max_key_length=self._server_max_key_length,
-                      server_max_value_length=self._server_max_value_length),
-        prefix=self._key_prefix)
-      connection_pool.memcached_dict = dictionary
+                      server_max_value_length=self._server_max_value_length)
+      local_dict[configuration_key] = dictionary
     return dictionary
 
+  def getCacheStorage(self, **kw):
+    """Follow MemcachedTool.getMemcachedDict implementation
+    """
+    return SharedDict(self._getMemcachedDict(), prefix=self._key_prefix)
+
   def _getCacheId(self, cache_id, scope):
     return '%s_%s' % (scope, cache_id)
 
diff --git a/product/ERP5Type/Tool/MemcachedTool.py b/product/ERP5Type/Tool/MemcachedTool.py
index 6d5faf0b9a..b7b9bc710f 100644
--- a/product/ERP5Type/Tool/MemcachedTool.py
+++ b/product/ERP5Type/Tool/MemcachedTool.py
@@ -279,15 +279,19 @@ if memcache is not None:
         Create it if does not exist.
       """
       try:
-        dictionary = memcached_dict_pool.memcached_dict
+        local_dict = memcached_dict_pool.local_dict
       except AttributeError:
+        local_dict = memcached_dict_pool.local_dict = {}
+      try:
+        dictionary = local_dict[plugin_path]
+      except KeyError:
         memcached_plugin = self.restrictedTraverse(plugin_path, None)
         if memcached_plugin is None:
           raise ValueError, 'Memcached Plugin does not exists: %r' % (plugin_path,)
         dictionary = MemcachedDict((memcached_plugin.getUrlString(''),),
                    server_max_key_length=memcached_plugin.getServerMaxKeyLength(),
                    server_max_value_length=memcached_plugin.getServerMaxValueLength())
-        memcached_dict_pool.memcached_dict = dictionary
+        local_dict[plugin_path] = dictionary
       return dictionary
 
     security.declareProtected(Permissions.AccessContentsInformation, 'getMemcachedDict')
-- 
2.30.9