[Twisted-web] html cache with timeout
Valentino Volonghi aka Dialtone
dialtone at divmod.com
Tue Feb 1 09:05:40 MST 2005
On Tue, 01 Feb 2005 12:58:49 GMT, Valentino Volonghi aka Dialtone <dialtone at divmod.com> wrote:
The first version of the patch didn't actually work. But I wrote a new version, also thanks to fzZzy and this time it works although it has a flaw since in weever caching the content slot (which is filled with a Fragment) results in 2 big red Nones and the rendered fragment.
As I said in the first mail you can use caching with:
t.cached(name=some_sensible_name, lifetime=MAX_LIFE)[cached_content]
This patch provides, probably, the finest granularity in caching the rendering.
Anyway the patch is below:
Index: nevow/tags.py
===================================================================
--- nevow/tags.py (revision 1136)
+++ nevow/tags.py (working copy)
@@ -25,7 +25,7 @@
"""
-from nevow.stan import Proto, Tag, directive, raw, xml, CommentProto, invisible, slot, cdata
+from nevow.stan import Proto, Tag, directive, raw, xml, CommentProto, invisible, slot, cdata, cached
comment = CommentProto()
@@ -62,7 +62,9 @@
def inlineJS(s):
return script(type="text/javascript", language="JavaScript")[xml('\n//<![CDATA[\n%s\n//]]>\n' % s)]
-__all__ = tags + ['invisible', 'comment', '_dir', '_del', '_object', '_map', 'drange', 'Tag', 'directive', 'xml', 'raw', 'slot', 'cdata', 'inlineJS'] + ['_%s' % x for x in range(100)]
+__all__ = tags + ['invisible', 'comment', '_dir', '_del', '_object',
+ '_map', 'drange', 'Tag', 'directive', 'xml', 'raw',
+ 'slot', 'cached', 'cdata', 'inlineJS'] + ['_%s' % x for x in range(100)]
########################
Index: nevow/flat/flatstan.py
===================================================================
--- nevow/flat/flatstan.py (revision 1136)
+++ nevow/flat/flatstan.py (working copy)
@@ -9,7 +9,7 @@
from nevow import util
from nevow.stan import Proto, Tag, xml, directive, Unset, invisible
from nevow.inevow import IRenderer, IRendererFactory, IGettable, IData
-from nevow.flat import precompile, serialize
+from nevow.flat import precompile, serialize, iterflatten
from nevow.accessors import convertToData
from nevow.context import WovenContext
@@ -226,6 +226,56 @@
return serialize(original.default, context)
return serialize(data, context)
+_CACHE = {}
+from time import time as now
+from cStringIO import StringIO
+from twisted.internet import defer
+def CachedSerializer(original, context):
+ cached = _CACHE.get(original.name, None)
+ life = now()-original.lifetime
+ if cached and cached[0] > life:
+## print "="*20
+## print cached[0]
+## print life
+## print "="*20
+ yield cached[1]
+ return
+## if cached:
+## print "="*20
+## print cached[0]
+## print life
+## print "="*20
+ io = StringIO()
+ for child in iterflatten(original.children, context, io.write,
+ lambda item: True):
+ if isinstance(child, tuple):
+ childDeferred, childReturner = child
+
+ d = defer.Deferred() ## A new deferred for the outer loop, whose result
+ ## we don't care about, because we don't want the outer loop to write
+ ## anything when this deferred fires -- only when the entire for loop
+ ## has completed and we have all the "children" flattened
+
+ def innerDeferredResultAvailable(result):
+ childReturner(result) ## Cause the inner iterflatten to continue
+ d.callback('') ## Cause the outer iterflatten to continue
+ return ''
+
+ childDeferred.addCallback(innerDeferredResultAvailable)
+
+ ## Make the outer loop wait on our new deferred.
+ ## We call the new deferred back with ''
+ ## Which will cause the outer loop to write '' to the request,
+ ## which doesn't matter. It will then call our "returner",
+ ## which is just the noop lambda below, because we don't care
+ ## about the return result of the new deferred, which is just
+ ## ''
+
+ yield d, lambda result: None
+ result = io.getvalue()
+ _CACHE[original.name] = (now(), result)
+ yield result
+
def ContextSerializer(original, context):
originalContext = original.clone(deep=False)
originalContext.precompile = context and context.precompile or False
Index: nevow/__init__.py
===================================================================
--- nevow/__init__.py (revision 1136)
+++ nevow/__init__.py (working copy)
@@ -182,6 +182,7 @@
nevow.flat.flatstan.RendererSerializer nevow.inevow.IRenderer
nevow.flat.flatstan.DirectiveSerializer nevow.stan.directive
nevow.flat.flatstan.SlotSerializer nevow.stan.slot
+nevow.flat.flatstan.CachedSerializer nevow.stan.cached
nevow.flat.flatstan.ContextSerializer nevow.context.WovenContext
nevow.flat.flatstan.DeferredSerializer twisted.internet.defer.Deferred
nevow.flat.flatstan.DeferredSerializer twisted.internet.defer.DeferredList
Index: nevow/stan.py
===================================================================
--- nevow/stan.py (revision 1136)
+++ nevow/stan.py (working copy)
@@ -119,8 +119,33 @@
"""
raise NotImplementedError, "Stan slot instances are not iterable."
+class cached(object):
+ """Marker for cached content
+ """
+ __slots__ = ['name', 'children', 'lifetime']
+ def __init__(self, name, lifetime=0):
+ self.name = name
+ self.children = []
+ self.lifetime = lifetime
+ def __repr__(self):
+ return "cached('%s','%s')" % self.name, self.lifetime
+
+ def __getitem__(self, children):
+ """cached content is what is being cached
+ """
+ if not isinstance(children, (list, tuple)):
+ children = [children]
+ self.children.extend(children)
+ return self
+
+ def __iter__(self):
+ """Prevent an infinite loop if someone tries to do
+ for x in cached('foo'):
+ """
+ raise NotImplementedError, "Stan slot instances are not iterable."
+
class Tag(object):
"""Tag instances represent XML tags with a tag name, attributes,
and children. Tag instances can be constructed using the Prototype
More information about the Twisted-web
mailing list