aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Kuzminski <marcin@python-works.com>2012-11-23 11:54:14 +0100
committerMarcin Kuzminski <marcin@python-works.com>2012-11-23 11:54:14 +0100
commit01a58cca8fee270287dfa6242abf3bc425267473 (patch)
treead61c41284f3f7b193c9b4a41cabaef416bd7642
parent222aba5cb8ef4374cb9fbc972ae0035b591336e2 (diff)
added caching layer into RSS/ATOM feeds
- updated code for new LimitedDiffContainers - invalidate rss/atom cache keys on push - --HG-- branch : beta
-rw-r--r--rhodecode/controllers/feed.py128
-rw-r--r--rhodecode/lib/utils2.py12
-rwxr-xr-xrhodecode/model/db.py9
3 files changed, 97 insertions, 52 deletions
diff --git a/rhodecode/controllers/feed.py b/rhodecode/controllers/feed.py
index c05bbb29..4b145553 100644
--- a/rhodecode/controllers/feed.py
+++ b/rhodecode/controllers/feed.py
@@ -28,12 +28,14 @@ import logging
from pylons import url, response, tmpl_context as c
from pylons.i18n.translation import _
+from beaker.cache import cache_region, region_invalidate
from webhelpers.feedgenerator import Atom1Feed, Rss201rev2Feed
from rhodecode.lib import helpers as h
from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
from rhodecode.lib.base import BaseRepoController
-from rhodecode.lib.diffs import DiffProcessor
+from rhodecode.lib.diffs import DiffProcessor, LimitedDiffContainer
+from rhodecode.model.db import CacheInvalidation
log = logging.getLogger(__name__)
@@ -51,6 +53,9 @@ class FeedController(BaseRepoController):
self.language = 'en-us'
self.ttl = "5"
self.feed_nr = 20
+ # we need to protect from parsing huge diffs here other way
+ # we can kill the server, 32*1024 chars is a reasonable limit
+ self.feed_diff_limit = 32 * 1024
def _get_title(self, cs):
return "%s" % (
@@ -59,26 +64,28 @@ class FeedController(BaseRepoController):
def __changes(self, cs):
changes = []
- _diff = cs.diff()
- # we need to protect from parsing huge diffs here other way
- # we can kill the server, 32*1024 chars is a reasonable limit
- HUGE_DIFF = 32 * 1024
- if len(_diff) > HUGE_DIFF:
- changes = ['\n ' + _('Changeset was too big and was cut off...')]
- return changes
- diffprocessor = DiffProcessor(_diff)
- stats = diffprocessor.prepare(inline_diff=False)
- for st in stats:
+ diff_processor = DiffProcessor(cs.diff(),
+ diff_limit=self.feed_diff_limit)
+ _parsed = diff_processor.prepare(inline_diff=False)
+ limited_diff = False
+ if isinstance(_parsed, LimitedDiffContainer):
+ limited_diff = True
+
+ for st in _parsed:
st.update({'added': st['stats'][0],
'removed': st['stats'][1]})
changes.append('\n %(operation)s %(filename)s '
'(%(added)s lines added, %(removed)s lines removed)'
% st)
+ if limited_diff:
+ changes = changes + ['\n ' +
+ _('Changeset was too big and was cut off...')]
return changes
def __get_desc(self, cs):
desc_msg = []
- desc_msg.append('%s %s %s:<br/>' % (cs.author, _('commited on'),
+ desc_msg.append('%s %s %s<br/>' % (h.person(cs.author),
+ _('commited on'),
h.fmt_date(cs.date)))
#branches, tags, bookmarks
if cs.branch:
@@ -102,46 +109,67 @@ class FeedController(BaseRepoController):
def atom(self, repo_name):
"""Produce an atom-1.0 feed via feedgenerator module"""
- feed = Atom1Feed(
- title=self.title % repo_name,
- link=url('summary_home', repo_name=repo_name,
- qualified=True),
- description=self.description % repo_name,
- language=self.language,
- ttl=self.ttl
- )
-
- for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
- feed.add_item(title=self._get_title(cs),
- link=url('changeset_home', repo_name=repo_name,
- revision=cs.raw_id, qualified=True),
- author_name=cs.author,
- description=''.join(self.__get_desc(cs)),
- pubdate=cs.date,
- )
- response.content_type = feed.mime_type
- return feed.writeString('utf-8')
+ @cache_region('long_term')
+ def _get_feed_from_cache(key):
+ feed = Atom1Feed(
+ title=self.title % repo_name,
+ link=url('summary_home', repo_name=repo_name,
+ qualified=True),
+ description=self.description % repo_name,
+ language=self.language,
+ ttl=self.ttl
+ )
+
+ for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
+ feed.add_item(title=self._get_title(cs),
+ link=url('changeset_home', repo_name=repo_name,
+ revision=cs.raw_id, qualified=True),
+ author_name=cs.author,
+ description=''.join(self.__get_desc(cs)),
+ pubdate=cs.date,
+ )
+
+ response.content_type = feed.mime_type
+ return feed.writeString('utf-8')
+
+ key = repo_name + '_ATOM'
+ inv = CacheInvalidation.invalidate(key)
+ if inv is not None:
+ region_invalidate(_get_feed_from_cache, None, key)
+ CacheInvalidation.set_valid(inv.cache_key)
+ return _get_feed_from_cache(key)
def rss(self, repo_name):
"""Produce an rss2 feed via feedgenerator module"""
- feed = Rss201rev2Feed(
- title=self.title % repo_name,
- link=url('summary_home', repo_name=repo_name,
- qualified=True),
- description=self.description % repo_name,
- language=self.language,
- ttl=self.ttl
- )
- for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
- feed.add_item(title=self._get_title(cs),
- link=url('changeset_home', repo_name=repo_name,
- revision=cs.raw_id, qualified=True),
- author_name=cs.author,
- description=''.join(self.__get_desc(cs)),
- pubdate=cs.date,
- )
-
- response.content_type = feed.mime_type
- return feed.writeString('utf-8')
+ @cache_region('long_term')
+ def _get_feed_from_cache(key):
+ feed = Rss201rev2Feed(
+ title=self.title % repo_name,
+ link=url('summary_home', repo_name=repo_name,
+ qualified=True),
+ description=self.description % repo_name,
+ language=self.language,
+ ttl=self.ttl
+ )
+
+ for cs in reversed(list(c.rhodecode_repo[-self.feed_nr:])):
+ feed.add_item(title=self._get_title(cs),
+ link=url('changeset_home', repo_name=repo_name,
+ revision=cs.raw_id, qualified=True),
+ author_name=cs.author,
+ description=''.join(self.__get_desc(cs)),
+ pubdate=cs.date,
+ )
+
+ response.content_type = feed.mime_type
+ return feed.writeString('utf-8')
+
+ key = repo_name + '_RSS'
+ inv = CacheInvalidation.invalidate(key)
+ if inv is not None:
+ region_invalidate(_get_feed_from_cache, None, key)
+ CacheInvalidation.set_valid(inv.cache_key)
+ return _get_feed_from_cache(key)
+
diff --git a/rhodecode/lib/utils2.py b/rhodecode/lib/utils2.py
index 5e36e670..1b2fb178 100644
--- a/rhodecode/lib/utils2.py
+++ b/rhodecode/lib/utils2.py
@@ -279,6 +279,18 @@ def safe_str(unicode_, to_encoding=None):
return safe_str
+def remove_suffix(s, suffix):
+ if s.endswith(suffix):
+ s = s[:-1 * len(suffix)]
+ return s
+
+
+def remove_prefix(s, prefix):
+ if s.startswith(prefix):
+ s = s[:-1 * len(prefix)]
+ return s
+
+
def engine_from_config(configuration, prefix='sqlalchemy.', **kwargs):
"""
Custom engine_from_config functions that makes sure we use NullPool for
diff --git a/rhodecode/model/db.py b/rhodecode/model/db.py
index 22251271..74aff8fe 100755
--- a/rhodecode/model/db.py
+++ b/rhodecode/model/db.py
@@ -46,7 +46,7 @@ from rhodecode.lib.vcs.exceptions import VCSError
from rhodecode.lib.vcs.utils.lazy import LazyProperty
from rhodecode.lib.utils2 import str2bool, safe_str, get_changeset_safe, \
- safe_unicode
+ safe_unicode, remove_suffix
from rhodecode.lib.compat import json
from rhodecode.lib.caching_query import FromCache
@@ -941,6 +941,7 @@ class Repository(Base, BaseModel):
@LazyProperty
def scm_instance(self):
+ return self.scm_instance_cached()
return self.__get_instance()
def scm_instance_cached(self, cache_map=None):
@@ -1440,7 +1441,11 @@ class CacheInvalidation(Base, BaseModel):
iid = rhodecode.CONFIG.get('instance_id')
if iid:
prefix = iid
- return "%s%s" % (prefix, key), prefix, key.rstrip('_README')
+ #remove specific suffixes like _README or _RSS
+ key = remove_suffix(key, '_README')
+ key = remove_suffix(key, '_RSS')
+ key = remove_suffix(key, '_ATOM')
+ return "%s%s" % (prefix, key), prefix, key
@classmethod
def get_by_key(cls, key):