summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan McGee <dan@archlinux.org>2010-05-04 10:53:40 -0500
committerDan McGee <dan@archlinux.org>2010-05-04 10:53:40 -0500
commit4b7335f7137c587e775013d49bccc28bc32387c8 (patch)
tree6af5a46efe4eb3618afcc5cac72906e46d614a3d
parentc546630ad8609bf30b6ac24326bc7f04aac8d99c (diff)
Add a hacked version of Django UpdateCacheMiddlewarerelease_2010-05-04
This is to address a rather large issue with caching of feed objects in Django. Because they are built up using an XML library that does multiple writes on a file-like object, a single feed object, even when pulled from memcached, generates 1582 writes to the open socket rather than the optimal one it could do. Some version of this fix will be making it upstream, but I need to figure out how to approach that before I do so and for now this will address one of our larger performance issues on the live site since the packages feed is hit as often as it is. Signed-off-by: Dan McGee <dan@archlinux.org>
-rw-r--r--main/middleware.py52
-rw-r--r--settings.py2
2 files changed, 53 insertions, 1 deletions
diff --git a/main/middleware.py b/main/middleware.py
index db2c1104..4d343b41 100644
--- a/main/middleware.py
+++ b/main/middleware.py
@@ -14,3 +14,55 @@ def get_user():
'''Get the currently logged in request.user'''
return user_holder.user
+# begin copy of stock Django UpdateCacheMiddleware
+# this is to address feeds caching issue which makes it horribly
+# unperformant
+
+from django.conf import settings
+from django.core.cache import cache
+from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age
+
+class UpdateCacheMiddleware(object):
+ """
+ Response-phase cache middleware that updates the cache if the response is
+ cacheable.
+
+ Must be used as part of the two-part update/fetch cache middleware.
+ UpdateCacheMiddleware must be the first piece of middleware in
+ MIDDLEWARE_CLASSES so that it'll get called last during the response phase.
+ """
+ def __init__(self):
+ self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
+ self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
+ self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False)
+
+ def process_response(self, request, response):
+ """Sets the cache, if needed."""
+ if not hasattr(request, '_cache_update_cache') or not request._cache_update_cache:
+ # We don't need to update the cache, just return.
+ return response
+ if request.method != 'GET':
+ # This is a stronger requirement than above. It is needed
+ # because of interactions between this middleware and the
+ # HTTPMiddleware, which throws the body of a HEAD-request
+ # away before this middleware gets a chance to cache it.
+ return response
+ if not response.status_code == 200:
+ return response
+ # Try to get the timeout from the "max-age" section of the "Cache-
+ # Control" header before reverting to using the default cache_timeout
+ # length.
+ timeout = get_max_age(response)
+ if timeout == None:
+ timeout = self.cache_timeout
+ elif timeout == 0:
+ # max-age was set to 0, don't bother caching.
+ return response
+ patch_response_headers(response, timeout)
+ if timeout:
+ response.content = response.content
+ cache_key = learn_cache_key(request, response, timeout, self.key_prefix)
+ cache.set(cache_key, response, timeout)
+ return response
+
+# vim: set ts=4 sw=4 et:
diff --git a/settings.py b/settings.py
index 61ed067c..88adf19d 100644
--- a/settings.py
+++ b/settings.py
@@ -43,7 +43,7 @@ TEMPLATE_LOADERS = (
)
MIDDLEWARE_CLASSES = (
- 'django.middleware.cache.UpdateCacheMiddleware',
+ 'main.middleware.UpdateCacheMiddleware',
"django.contrib.sessions.middleware.SessionMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
'django.middleware.http.ConditionalGetMiddleware',