Commits

David Chambers  committed 8b148f8

Overhauled caching logic – individual Document objects are cached as are collections of these objects. Added print statements to provide information about cache interaction.

  • Participants
  • Parent commits 4aabdb2

Comments (0)

Files changed (5)

File templates/category.dhtml

 {% extends 'base.dhtml' %}
 {% load mango_extras %}
 {% block content %}
-			<h1>{{ name|capfirst }}</h1>{% for document in category %}{% include 'excerpt.dhtml' %}{% empty %}
-			<p>This category is currently empty.</p>{% endfor %}
+			<h1>{{ name|capfirst }}</h1>
+			{% if category_pages %}{% if category_posts %}
+			<h2>Pages</h2>{% endif %}{% for document in category_pages %}{% include 'excerpt.dhtml' %}{% endfor %}{% endif %}
+			{% if category_posts %}{% if category_pages %}
+			<h2>Posts</h2>{% endif %}{% for document in category_posts %}{% include 'excerpt.dhtml' %}{% endfor %}{% endif %}
+			{% if not category_pages and not category_posts %}
+			<p>This category is currently empty.</p>{% endif %}
 {% endblock %}

File templates/index.dhtml

 {% extends 'base.dhtml' %}
 {% load mango_extras %}
 {% block header_title %}<h1><a href="/">{{ settings.SITE_TITLE }}</a></h1>{% endblock %}
-{% block content %}{% for document in documents %}{% if forloop.counter <= 5 %}{% include 'excerpt.dhtml' %}{% else %}{% if forloop.last %}
+{% block content %}{% for document in posts %}{% if forloop.counter <= 5 %}{% include 'excerpt.dhtml' %}{% else %}{% if forloop.last %}
 			<h2>Want more?</h2>
 			<p>Check out the <a href="{% url mango.views.archives %}">archives</a>.</p>{% endif %}{% endif %}{% empty %}
 			<h2>Welcome to your new blog</h2>

File templates/post.dhtml

 {% extends 'base.dhtml' %}
 {% load mango_extras %}
-{% block title %}{{ meta.title }}{% endblock %}
+{% block title %}{{ document.title }}{% endblock %}
 {% block content %}
 				<article>
 					<header>
 import os
 import re
 
+from django.conf import settings
 from django.core.cache import cache
 
 from mango.models import Document
 from mango.settings import *
 
-def get_contents(filepath):
+def get_document(filepath):
     """
-    Returns the contents of the file as a UTF-8 encoded string
-
-    >>> get_contents('mango/examples/1=>my-first-post.text')
-    u"date:\\t13 April ... **Congratulations!**\\n"
-    """
-    f = open(filepath)
-    u = unicode(f.read(), 'utf-8')
-    f.close()
-    return u
-
-def get_posts(path_to_posts, include_pages=False, reverse=True):
-    """
-    Returns all of the posts in the directory and all directories below it
+    Returns a Document object. First an attempt is made to retrieve the object
+    from the cache; if this fails a new Document object is created and cached.
     
-    >>> get_posts('mango/examples')[1].html
+    >>> get_document('mango/examples/1=>my-first-post.text').html
     u"\\n<p>Welcome to Mango. ... <strong>Congratulations!</strong></p>"
     """
-    documents = []
-    for dirpath, dirnames, filenames in os.walk(path_to_posts):
-        filenames[:] = [f for f in filenames if not f.startswith('.')]
-        for filename in filenames:
-            joined_path = os.path.join(dirpath, filename)
-            absolute_path = os.path.abspath(joined_path)
-            # ignore symlink if it points to a file (post) in same directory
-            if absolute_path == os.path.realpath(joined_path):
-                document = Document(get_contents(absolute_path))
-                document.convert().set_urls(absolute_path)
-                documents.append(document)
+    if not os.path.isabs(filepath):
+        project_path = os.path.split(os.path.split(__file__)[0])[0]
+        filepath = os.path.join(project_path, filepath)
 
-    posts = []
-    pages = []
-    for document in documents:
-        if document.type == 'page':
-            pages.append(document)
-        else:
-            posts.append(document)
+    document, mod_time = cache.get(filepath, (None, None)) # retrieve Document
+    if document and mod_time == os.path.getmtime(filepath):
+        if settings.DEBUG:
+            print 'Document retrieved from cache: %s' % filepath
+    else: # modified or not in cache, so create and cache a new Document object
+        f = open(filepath)
+        contents = unicode(f.read(), 'utf-8')
+        f.close()
+        document = Document(contents)
+        document.convert().set_urls(filepath)
+        cache.set(filepath, (document, os.path.getmtime(filepath)),
+                POST_CACHE_SECONDS)
+        if settings.DEBUG:
+            print 'Document created and cached: %s' % filepath
 
-    posts.sort(key=lambda post: post.datetime, reverse=reverse)
-    pages.sort(key=lambda page: page.title)
+    return document
 
-    documents = posts
-    if include_pages:
-        documents += pages
-
-    return documents
-
-def documents(path_to_posts=PATH_TO_POSTS, include_pages=False):
+def get_documents(path_to_posts=PATH_TO_POSTS, reverse=True):
     """
-    Simple wrapper for `get_posts` which returns cached posts if appropriate
+    Returns all of the posts in the directory and all directories below it.
     
-    >>> documents('mango/examples')[1].html
+    >>> posts, pages = get_documents('mango/examples')
+    >>> posts[1].html
     u"\\n<p>Welcome to Mango. ... <strong>Congratulations!</strong></p>"
     """
-    cache_key = u'posts%s:%s' % ('+pages' if include_pages else '', path_to_posts)
-    posts = cache.get(cache_key)
-    if posts:
-        return posts
+    posts_cache_key = u'posts:%s' % path_to_posts
+    pages_cache_key = u'pages:%s' % path_to_posts
 
-    posts = get_posts(path_to_posts, include_pages=include_pages)
-    cache.set(cache_key, posts, INDEX_CACHE_SECONDS)
-    return posts
+    posts = cache.get(posts_cache_key)
+    pages = cache.get(pages_cache_key)
+
+    if posts is None or pages is None:
+        documents = []
+        for dirpath, dirnames, filenames in os.walk(path_to_posts):
+            filenames[:] = [f for f in filenames if not f.startswith('.')]
+            for filename in filenames:
+                joined_path = os.path.join(dirpath, filename)
+                absolute_path = os.path.abspath(joined_path)
+                # ignore symlink if it points to a document in same directory
+                if absolute_path == os.path.realpath(joined_path):
+                    documents.append(get_document(absolute_path))
+
+        posts, pages = [], []
+        for document in documents:
+            if document.type == 'page':
+                pages.append(document)
+            else:
+                posts.append(document)
+
+        posts.sort(key=lambda post: post.datetime, reverse=reverse)
+        pages.sort(key=lambda page: page.title)
+
+        cache.set(posts_cache_key, posts, INDEX_CACHE_SECONDS)
+        cache.set(pages_cache_key, pages, INDEX_CACHE_SECONDS)
+
+        if settings.DEBUG:
+            num_posts, num_pages = len(posts), len(pages)
+            print '%s Document object%s created and cached: %s' % (
+                    num_posts, '' if num_posts is 1 else 's', posts_cache_key)
+            print '%s Document object%s created and cached: %s' % (
+                    num_pages, '' if num_pages is 1 else 's', pages_cache_key)
+
+    elif settings.DEBUG:
+        num_posts, num_pages = len(posts), len(pages)
+        print '%s Document object%s retrieved from cache: %s' % (
+                num_posts, '' if num_posts is 1 else 's', posts_cache_key)
+        print '%s Document object%s retrieved from cache: %s' % (
+                num_pages, '' if num_pages is 1 else 's', pages_cache_key)
+
+    return posts, pages
 
 def archives(path_to_posts=PATH_TO_POSTS):
     """
     Returns all of the posts in the directory and all directories below it,
-    in the form (year, month, [posts])
+    in the form (year, month, [posts]).
     
     >>> year, month, these_posts = archives('mango/examples')[1]
     >>> year == 2010
     >>> these_posts[0].html
     u"\\n<p>Welcome to Mango. ... <strong>Congratulations!</strong></p>"
     """
-    cache_key = u'archives:%s' % path_to_posts
-    archives = cache.get(cache_key) # won't conflict with the posts above as this will always be a folder
-    if archives:
-        return archives # there is no check for modification time, this is just always current for 5 minutes
-
     archives = []
-    posts = get_posts(path_to_posts)
+    posts, pages = get_documents(path_to_posts)
     if posts:
         year = posts[0].datetime.year
         month = posts[0].datetime.month
                 these_posts = [post]
         archives.append((year, month, these_posts))
 
-    cache.set(cache_key, archives, INDEX_CACHE_SECONDS)
     return archives
 
 def primary_author_email():
     """
-    Returns the email address of the primary author as set in the settings file
+    Returns the primary author's e-mail address as specified in Mango's
+    settings file.
     
     >>> primary_author_email()
     u'... <...@...>'
 
 import disqus
 
+from django.core.cache import cache
 from django.core.mail import EmailMultiAlternatives, send_mail
 from django.core.urlresolvers import reverse
 from django.http import Http404, HttpResponse, HttpResponsePermanentRedirect, HttpResponseRedirect
 def context_defaults(request):
     path_to_css, css = getattr(settings, 'CSS', (None, []))
     path_to_js, js = getattr(settings, 'JS', (None, []))
+    posts, pages = utils.get_documents()
     return {
         'archives': utils.archives(),
-        'documents': utils.documents(include_pages=True),
+        'posts': posts,
+        'pages': pages,
         'settings': settings,
         'stylesheets': [dict(media=media, href=path_to_css.lstrip('.')+filename) for media, stylesheets in css for filename in stylesheets],
         'scripts': [dict(src=path_to_js.lstrip('.')+filename) for filename in js],
         if view_source:
             return HttpResponsePermanentRedirect('../')
 
-        #TODO - caching
         match = re.match(RE['alias=>canon'], os.path.split(filepath)[1])
+        category_posts, category_pages = utils.get_documents(filepath)
         return render_to_response('category.dhtml', dict({
             'name': match.group('canon'),
-            'category': utils.documents(filepath, include_pages=True),
+            'category_posts': category_posts,
+            'category_pages': category_pages,
         }, **context_defaults(request)))
 
-    document = Document(utils.get_contents(filepath))
-    document.convert().set_urls(filepath)
+    document = utils.get_document(filepath)
 
     if is_short:
         url = document.urls['canon']['abs']