Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions django/core/cache/backends/memcached.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,18 @@ def __init__(self, server, params, library, value_not_found_exception):
self.LibraryValueNotFoundException = value_not_found_exception

self._lib = library
self._options = params.get('OPTIONS')
self._options = params.get('OPTIONS') or {}
self._options.setdefault('CLIENT_OPTIONS', {})

@property
def _cache(self):
"""
Implements transparent thread-safe access to a memcached client.
"""
if getattr(self, '_client', None) is None:
self._client = self._lib.Client(self._servers)
client_options = dict(servers=self._servers)
client_options.update(self._options['CLIENT_OPTIONS'])
self._client = self._lib.Client(**client_options)

return self._client

Expand Down Expand Up @@ -163,7 +166,9 @@ def __init__(self, server, params):
@property
def _cache(self):
if getattr(self, '_client', None) is None:
self._client = self._lib.Client(self._servers, pickleProtocol=pickle.HIGHEST_PROTOCOL)
client_options = dict(servers=self._servers, pickleProtocol=pickle.HIGHEST_PROTOCOL)
client_options.update(self._options['CLIENT_OPTIONS'])
self._client = self._lib.Client(**client_options)
return self._client


Expand All @@ -177,7 +182,9 @@ def __init__(self, server, params):

@cached_property
def _cache(self):
client = self._lib.Client(self._servers)
client_options = dict(servers=self._servers)
client_options.update(self._options['CLIENT_OPTIONS'])
client = self._lib.Client(**client_options)
if self._options:
client.behaviors = self._options

Expand Down
2 changes: 2 additions & 0 deletions docs/releases/1.10.txt
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,8 @@ Cache
~~~~~

* The file-based cache backend now uses the highest pickling protocol.
* ``CLIENT_OPTIONS`` can be used to pass settings to memcached client instance.
See :ref:`memcached <memcached>` for example.

CSRF
~~~~
Expand Down
21 changes: 21 additions & 0 deletions docs/topics/cache.txt
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,27 @@ When using the ``pylibmc`` binding, do not include the ``unix:/`` prefix::
}
}

.. versionchanged:: 1.10

You can set ``CLIENT_OPTIONS`` in ``OPTIONS`` setting to pass additional parameter
to memcached client. The following example will pass socket_timeout option to
memcached client instance, limiting time spent waiting for connection with
potentially unavailable memcached server to 1 second instead of default 3.
Consult client ``__init__`` method to get list of available options
that can be passed this way.::

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
'OPTIONS': {
'CLIENT_OPTIONS': {
'socket_timeout': 1,
}
}
}
}

One excellent feature of Memcached is its ability to share a cache over
multiple servers. This means you can run Memcached daemons on multiple
machines, and the program will treat the group of machines as a *single*
Expand Down
8 changes: 8 additions & 0 deletions tests/cache/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,9 @@ def test_incr_decr_timeout(self):
memcached_far_future_params = memcached_params.copy()
memcached_far_future_params['TIMEOUT'] = 31536000 # 60*60*24*365, 1 year

memcached_client_options_params = memcached_params.copy()
memcached_client_options_params['OPTIONS'] = {'CLIENT_OPTIONS': {'socket_timeout': 0.5}}


@unittest.skipUnless(memcached_params, "memcached not available")
@override_settings(CACHES=caches_setting_for_tests(base=memcached_params))
Expand Down Expand Up @@ -1179,6 +1182,11 @@ def test_default_far_future_timeout(self):
cache.set('future_foo', 'bar')
self.assertEqual(cache.get('future_foo'), 'bar')

@override_settings(CACHES=caches_setting_for_tests(base=memcached_client_options_params))
def test_passing_client_options(self):
cache.set('foo', 'bar')
self.assertEqual(cache._client.socket_timeout, 0.5)

def test_cull(self):
# culling isn't implemented, memcached deals with it.
pass
Expand Down