[Twisted-web] html cache with timeout
Valentino Volonghi aka Dialtone
dialtone at divmod.com
Tue Feb 1 05:58:49 MST 2005
On Tue, 1 Feb 2005 00:32:25 -0500, James Y Knight <foom at fuhm.net> wrote:
> Yes, it is. One thing that I think would make it more useful, if it can
> be pulled off, is to allow caching at any level. That is, something
> like the following stan:
> html[body[cached(timeout=10, keys=(IFoo,
> IBar))[semi_constant_header_stuff], very_dynamic_content]]
>
> That is, a function which will render its contents to a string the
> first time it's called, and store/return it for the next 10 seconds,
> using the same mechanism as the posted patch. The cache would be keyed
> off certain interfaces, and only those will get passed on to the
> functions being rendered inside, thus ensuring the safety of the cache.
>
> I think there are a lot of pages that are mostly "semi-static", but
> have some very dynamic content in them, so something like could be
> *very* useful.
>
> Anyhow, this is just an outline of how I think it might work, but I
> haven't tried to implement it yet, so I don't know if it will work out
> the way I'd like it to. :)
Here I am. Below there's a more fine grained implementation. You can use it like this:
cached(name="foo", lifetime=10)[t.p['hi boy']]
the name should be enough to give a cache for everyone since you can do:
cached(name=IAvatar(ctx).uid, lifetime=60)[t.p['Hi ', IAvatar(ctx).username]]
If you don't pass the lifetime parameter it won't be cached.
I must admit I haven't tested it yet since I don't know how to write unittests for this stuff... ;P. Let me know what do you think about. I also think that having another nevow tag for this cached would be ok.
Index: nevow/tags.py
===================================================================
--- nevow/tags.py (revision 1136)
+++ nevow/tags.py (working copy)
@@ -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)
@@ -226,6 +226,31 @@
return serialize(original.default, context)
return serialize(data, context)
+_CACHE = {}
+from time import time as now
+def CachedSerializer(original, context):
+ if context.precompile:
+ original.children = precompile(original.children, context)
+ return original
+
+ cached = _CACHE.get(original.name, None)
+ if cached and cached[0] > now()-original.lifetime:
+ return cached[1]
+ toSerialize = serialize(original.children, context)
+ tmp = []
+ while 1:
+ try:
+ d = toSerialize.next()
+ tmp.append(d)
+ except StopIteration:
+ c = ''.join(tmp)
+ break
+ except AttributeError:
+ c = toSerialize
+ break
+ _CACHE[original.name] = (now(), c)
+ return c
+
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