#22845: Memcached backend handles infinite (None) timeout defined in default
settings improperly
-------------------------------------+------------------------------
     Reporter:  Althalus             |      Owner:  nobody
         Type:  Bug                  |     Status:  new
    Component:  Core (Cache system)  |    Version:  master
     Severity:  Normal               |   Keywords:  cache, memcached
 Triage Stage:  Unreviewed           |  Has patch:  0
Easy pickings:  0                    |      UI/UX:  0
-------------------------------------+------------------------------
 #9595 introduced a way to use `None` as way to set infinite memcached
 timeout.
 It works fine while you specify this timeout explicitly like
 `cache.set('key', 'val', None)`.
 But it works wrong if you define it as a default cache timeout in
 django.conf.settings.CACHES.

 Consider the following parts:

 {{{#!python
 # base.py
 class BaseCache(object):
     def __init__(self, params):
         timeout = params.get('timeout', params.get('TIMEOUT', 300))
         if timeout is not None:
             try:
                 timeout = int(timeout)
             except (ValueError, TypeError):
                 timeout = 300
         self.default_timeout = timeout
 }}}

 {{{#!python
     # memcached.py
     def get_backend_timeout(self, timeout=DEFAULT_TIMEOUT):
         """
         Memcached deals with long (> 30 days) timeouts in a special
         way. Call this function to obtain a safe value for your timeout.
         """
         if timeout == DEFAULT_TIMEOUT:
             return self.default_timeout

         if timeout is None:
             # Using 0 in memcache sets a non-expiring timeout.
             return 0
         elif int(timeout) == 0:
             # Other cache backends treat 0 as set-and-expire. To achieve
 this
             # in memcache backends, a negative timeout must be passed.
             timeout = -1

         if timeout > 2592000:  # 60*60*24*30, 30 days
             # See http://code.google.com/p/memcached/wiki/FAQ
             # "You can set expire times up to 30 days in the future. After
 that
             # memcached interprets it as a date, and will expire the item
 after
             # said date. This is a simple (but obscure) mechanic."
             #
             # This means that we have to switch to absolute timestamps.
             timeout += int(time.time())
         return int(timeout)
 }}}

 As you can see special handling of `None`, `0` and long timeouts is
 performed in `get_backend_timeout`.
 But it only handles explicit timeouts. For default timeout there's no
 special processing while it's needed - timeout is just taken from
 `BaseCache.__init__`.

 So when trying to set `None` as default timeout django just transfers it
 to the memcached driver and which leads to errors.
 Also when timeout is set to some high value (more then 30 days) it is not
 converted to timestamp as memcached requires. In my case it caused all my
 cache entries to expire immidiately.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/22845>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/051.5de1d0ac65a15cb07e4834ca462b56b0%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to