Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Revert "Use Memcache and clean up caching setup."
This reverts commit 728e5bc.

Conflicts:
	settings.py
  • Loading branch information
groovecoder committed Jan 14, 2014
1 parent 61973a9 commit b9c6776
Show file tree
Hide file tree
Showing 27 changed files with 273 additions and 106 deletions.
6 changes: 6 additions & 0 deletions apps/actioncounters/fields.py
Expand Up @@ -122,3 +122,9 @@ def _change_total(self, delta):
# race condition. A subsequent save() could clobber concurrent counter
# changes.
self.total = self.total + delta

# HACK: Invalidate this object in cache-machine, if the method is available.
if hasattr(m_cls.objects, 'invalidate'):
m_cls.objects.invalidate(self.instance)


39 changes: 38 additions & 1 deletion apps/demos/helpers.py
@@ -1,4 +1,5 @@
import datetime
import functools
import hashlib
import random

Expand All @@ -21,18 +22,54 @@
from .models import Submission, TAG_DESCRIPTIONS, DEMO_LICENSES
from . import DEMOS_CACHE_NS_KEY

from devmo.helpers import register_cached_inclusion_tag
# Monkeypatch threadedcomments URL reverse() to use devmo's
from devmo.urlresolvers import reverse
threadedcommentstags.reverse = reverse


TEMPLATE_INCLUDE_CACHE_EXPIRES = getattr(settings,
'TEMPLATE_INCLUDE_CACHE_EXPIRES', 300)


def new_context(context, **kw):
c = dict(context.items())
c.update(kw)
return c


# TODO:liberate ?
def register_cached_inclusion_tag(template, key_fn=None,
expires=TEMPLATE_INCLUDE_CACHE_EXPIRES):
"""Decorator for inclusion tags with output caching.
Accepts a string or function to generate a cache key based on the incoming
parameters, along with an expiration time configurable as
INCLUDE_CACHE_EXPIRES or an explicit parameter"""

if key_fn is None:
key_fn = template

def decorator(f):
@functools.wraps(f)
def wrapper(*args, **kw):

if type(key_fn) is str:
cache_key = key_fn
else:
cache_key = key_fn(*args, **kw)

out = cache.get(cache_key)
if out is None:
context = f(*args, **kw)
t = jingo.env.get_template(template).render(context)
out = jinja2.Markup(t)
cache.set(cache_key, out, expires)
return out

return register.function(wrapper)
return decorator


def submission_key(prefix):
"""Produce a cache key function with a prefix, which generates the rest of
the key based on a submission ID and last-modified timestamp."""
Expand Down
43 changes: 3 additions & 40 deletions apps/devmo/helpers.py
@@ -1,18 +1,17 @@
import datetime
import functools
import httplib
import re
import socket
import httplib
import urllib
import urlparse
import socket

from django.conf import settings
from django.core.cache import cache
from django.template import defaultfilters
from django.utils.html import strip_tags

import bleach
from jingo import register, env
from jingo import register
import jinja2
import pytz
from soapbox.models import Message
Expand All @@ -30,10 +29,6 @@
register.filter(utils.entity_decode)


TEMPLATE_INCLUDE_CACHE_EXPIRES = getattr(settings,
'TEMPLATE_INCLUDE_CACHE_EXPIRES', 300)


@register.function
def page_title(title):
return u'%s | MDN' % title
Expand Down Expand Up @@ -151,35 +146,3 @@ def get_soapbox_messages(url):
@register.inclusion_tag('devmo/elements/soapbox_messages.html')
def soapbox_messages(soapbox_messages):
return {'soapbox_messages': soapbox_messages}


def register_cached_inclusion_tag(template, key_fn=None,
expires=TEMPLATE_INCLUDE_CACHE_EXPIRES):
"""Decorator for inclusion tags with output caching.
Accepts a string or function to generate a cache key based on the incoming
parameters, along with an expiration time configurable as
INCLUDE_CACHE_EXPIRES or an explicit parameter"""

if key_fn is None:
key_fn = template

def decorator(f):
@functools.wraps(f)
def wrapper(*args, **kw):

if isinstance(key_fn, basestring):
cache_key = key_fn
else:
cache_key = key_fn(*args, **kw)

out = cache.get(cache_key)
if out is None:
context = f(*args, **kw)
t = env.get_template(template).render(context)
out = jinja2.Markup(t)
cache.set(cache_key, out, expires)
return out

return register.function(wrapper)
return decorator
16 changes: 13 additions & 3 deletions apps/devmo/models.py
Expand Up @@ -14,6 +14,7 @@
from django.db import models
from django.utils.functional import cached_property

import caching.base
import constance.config
import xml.sax
from xml.sax.handler import ContentHandler
Expand All @@ -37,7 +38,16 @@
'DEFAULT_AVATAR', settings.MEDIA_URL + 'img/avatar-default.png')


class UserProfile(models.Model):
class ModelBase(caching.base.CachingMixin, models.Model):
"""Common base model for all MDN models: Implements caching."""

objects = caching.base.CachingManager()

class Meta:
abstract = True


class UserProfile(ModelBase):
"""
The UserProfile *must* exist for each
django.contrib.auth.models.User object. This may be relaxed
Expand Down Expand Up @@ -271,7 +281,7 @@ def parse_header_line(header_line):
FIELD_MAP[field_name][1] = ''


class Calendar(models.Model):
class Calendar(ModelBase):
"""The Calendar spreadsheet"""

shortname = models.CharField(max_length=255)
Expand Down Expand Up @@ -357,7 +367,7 @@ def __unicode__(self):
return self.shortname


class Event(models.Model):
class Event(ModelBase):
"""An event"""

date = models.DateField()
Expand Down
2 changes: 1 addition & 1 deletion apps/devmo/tests/test_views.py
Expand Up @@ -511,7 +511,7 @@ class LoggingTests(test_utils.TestCase):
urls = 'devmo.tests.logging_urls'

def setUp(self):
self.old_logging = settings.LOGGING.copy()
self.old_logging = settings.LOGGING

def tearDown(self):
settings.LOGGING = self.old_logging
Expand Down
13 changes: 12 additions & 1 deletion apps/docs/views.py
Expand Up @@ -3,9 +3,10 @@
import random

from django.conf import settings
from django.http import HttpResponseRedirect
from django.http import (HttpResponseRedirect)
from django.shortcuts import render

from caching.base import cached
import commonware
from dateutil.parser import parse as date_parse
from tower import ugettext as _
Expand All @@ -29,6 +30,9 @@ def docs(request):
if next.startswith('/'):
return HttpResponseRedirect(next)

# Doc of the day
dotd = cached(_get_popular_item, 'kuma_docs_dotd', 24*60*60)

# Recent updates
active_docs = []
entries = Entry.objects.filter(feed__shortname='mdc-latest')
Expand Down Expand Up @@ -58,3 +62,10 @@ def docs(request):
'review_flag_docs': review_flag_docs,
'dotd': dotd}
return render(request, 'docs/docs.html', data)


def _get_popular_item():
"""Get a single, random item off the popular pages list."""
# MindTouch is gone, and so is popular.json. Returning None for
# historical compatibility.
return None
16 changes: 9 additions & 7 deletions apps/feeder/models.py
@@ -1,12 +1,14 @@
from django.db import models
from django.utils.functional import cached_property

import caching.base
import jsonpickle

from devmo import SECTIONS_TWITTER, SECTIONS_UPDATES
from devmo.models import ModelBase
import utils


class BundleManager(models.Manager):
class BundleManager(caching.base.CachingManager):
"""Custom manager for bundles."""

def recent_entries(self, bundles):
Expand All @@ -20,7 +22,7 @@ def recent_entries(self, bundles):
feed__bundles__shortname__in=bundles)


class Bundle(models.Model):
class Bundle(ModelBase):
"""A bundle of several feeds. A feed can be in several (or no) bundles."""

shortname = models.SlugField(
Expand All @@ -34,7 +36,7 @@ def __unicode__(self):
return self.shortname


class Feed(models.Model):
class Feed(ModelBase):
"""A feed holds the metadata of an RSS feed."""

shortname = models.SlugField(
Expand Down Expand Up @@ -76,7 +78,7 @@ def delete_old_entries(self):
item.delete()


class Entry(models.Model):
class Entry(ModelBase):
"""An entry is an item representing feed content."""

feed = models.ForeignKey(Feed, related_name='entries')
Expand All @@ -102,12 +104,12 @@ class Meta:
def __unicode__(self):
return '%s: %s' % (self.feed.shortname, self.guid)

@cached_property
@utils.cached_property
def parsed(self):
"""Unpickled feed data."""
return jsonpickle.decode(self.raw)

@cached_property
@utils.cached_property
def section(self):
"""The section this entry is associated with."""
try:
Expand Down
7 changes: 4 additions & 3 deletions apps/kpi/models.py
@@ -1,21 +1,22 @@
from django.db import models
from django.db.models import (CharField, DateField, ForeignKey,
PositiveIntegerField)

from sumo.models import ModelBase


L10N_METRIC_CODE = 'general wiki:l10n:coverage'
KB_L10N_CONTRIBUTORS_METRIC_CODE = 'general wiki:l10n:contributors'


class MetricKind(models.Model):
class MetricKind(ModelBase):
"""A programmer-readable identifier of a metric, like 'clicks: search'"""
code = CharField(max_length=255, unique=True)

def __unicode__(self):
return self.code


class Metric(models.Model):
class Metric(ModelBase):
"""A single numeric measurement aggregated over a span of time.
For example, the number of hits to a page during a specific week.
Expand Down
6 changes: 3 additions & 3 deletions apps/landing/helpers.py
Expand Up @@ -10,17 +10,17 @@
from decimal import Decimal
from django.utils.formats import number_format


from devmo import SECTIONS, SECTION_USAGE
from devmo.helpers import register_cached_inclusion_tag


@register_cached_inclusion_tag('landing/newsfeed.html')
@register.inclusion_tag('landing/newsfeed.html')
def newsfeed(entries, section_headers=False):
"""Landing page news feed."""
return {'updates': entries, 'section_headers': section_headers}


@register_cached_inclusion_tag('landing/discussions.html')
@register.inclusion_tag('landing/discussions.html')
def discussions_feed(entries):
"""Landing page news feed."""
return {'updates': entries}
Expand Down
2 changes: 2 additions & 0 deletions apps/landing/templates/landing/newsfeed.html
@@ -1,3 +1,4 @@
{% cache updates %}
<ul class="hfeed">
{% for entry in updates %}
{% with e = entry.parsed %}
Expand All @@ -18,3 +19,4 @@ <h2 class="entry-title"><a href="{{ e.link }}" rel="bookmark">{{ e.title|entity_
{% endwith %}
{% endfor %}
</ul>
{% endcache %}
2 changes: 2 additions & 0 deletions apps/landing/templates/sidebar/twitter.html
@@ -1,3 +1,4 @@
{% cache tweet_qs %}
<div class="module" id="mdn-twitter">
<h3 class="mod-title">{{ _('MDN on Twitter') }}</h3>
{% if title %}<p class="mod-intro">{{ title }}</p>{% endif %}
Expand All @@ -19,3 +20,4 @@ <h4 class="entry-title vcard">
{% endfor %}
</ul>
</div>
{% endcache %}
2 changes: 1 addition & 1 deletion apps/notifications/events.py
Expand Up @@ -246,7 +246,7 @@ def _watches_belonging_to_user(cls, user_or_email, object_id=None,
return Watch.objects.none()

# Filter by stuff in the Watch row:
watches = Watch.objects.filter(
watches = Watch.uncached.filter(
user_condition,
Q(content_type=ContentType.objects.get_for_model(cls.content_type))
if cls.content_type
Expand Down
8 changes: 4 additions & 4 deletions apps/notifications/models.py
Expand Up @@ -5,7 +5,7 @@
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType

from sumo.models import LocaleField
from sumo.models import ModelBase, LocaleField
from sumo.urlresolvers import reverse


Expand All @@ -31,7 +31,7 @@ def multi_raw(query, params, models):
for model_class in models]


class EventWatch(models.Model):
class EventWatch(ModelBase):
"""
Allows anyone to watch a specific item for changes. Uses email instead of
user ID so anonymous visitors can also watch things eventually.
Expand Down Expand Up @@ -74,7 +74,7 @@ def get_remove_url(self):
return urlparams(url_, email=self.email)


class Watch(models.Model):
class Watch(ModelBase):
"""Watch events."""
# Key used by an Event to find watches it manages:
event_type = models.CharField(max_length=30, db_index=True)
Expand Down Expand Up @@ -108,7 +108,7 @@ def activate(self):
return self


class WatchFilter(models.Model):
class WatchFilter(ModelBase):
"""Additional key/value pairs that pare down the scope of a watch"""
watch = models.ForeignKey(Watch, related_name='filters')
name = models.CharField(max_length=20)
Expand Down

0 comments on commit b9c6776

Please sign in to comment.