Commit 605b3357 authored by Shane Hathaway's avatar Shane Hathaway

Merged CacheManagement_branch and added help topics.

parent 85c9478a
......@@ -82,7 +82,7 @@
# attributions are listed in the accompanying credits file.
#
##############################################################################
"$Id: DT_String.py,v 1.38 2000/09/01 14:00:41 brian Exp $"
"$Id: DT_String.py,v 1.39 2000/12/12 21:20:25 shane Exp $"
from string import split, strip
import regex, ts_regex
......@@ -91,7 +91,7 @@ from DT_Util import ParseError, InstanceDict, TemplateDict, render_blocks, str
from DT_Var import Var, Call, Comment
from DT_Return import ReturnTag, DTReturn
_marker = [] # Create a new marker object.
class String:
"""Document templates defined from strings.
......@@ -418,6 +418,14 @@ class String:
self.globals=vars
self._vars={}
ZDocumentTemplate_beforeRender__roles__ = ()
def ZDocumentTemplate_beforeRender(self, md, default):
return default
ZDocumentTemplate_afterRender__roles__ = ()
def ZDocumentTemplate_afterRender(self, md, result):
pass
def __call__(self,client=None,mapping={},**kw):
'''\
Generate a document from a document template.
......@@ -525,8 +533,14 @@ class String:
pushed=pushed+1
try:
try: return render_blocks(self._v_blocks, md)
except DTReturn, v: return v.v
value = self.ZDocumentTemplate_beforeRender(md, _marker)
if value is _marker:
try: result = render_blocks(self._v_blocks, md)
except DTReturn, v: result = v.v
self.ZDocumentTemplate_afterRender(md, result)
return result
else:
return value
finally:
if pushed: md._pop(pushed) # Get rid of circular reference!
md.level=level # Restore previous level
......
This diff is collapsed.
......@@ -84,7 +84,7 @@
##############################################################################
"""DTML Method objects."""
__version__='$Revision: 1.55 $'[11:-2]
__version__='$Revision: 1.56 $'[11:-2]
import History
from Globals import HTML, HTMLFile, MessageDialog
......@@ -99,18 +99,21 @@ from DateTime.DateTime import DateTime
from urllib import quote
import ts_regex, Globals, sys, Acquisition
from AccessControl import getSecurityManager
from Cache import Cacheable
_marker = [] # Create a new marker object.
class DTMLMethod(HTML, Acquisition.Implicit, RoleManager,
ElementWithTitle, Item_w__name__,
History.Historical,
Cacheable,
):
"""DTML Method objects are DocumentTemplate.HTML objects that act
as methods of their containers."""
meta_type='DTML Method'
_proxy_roles=()
index_html=None # Prevent accidental acquisition
_cache_namespace_keys=()
# Documents masquerade as functions:
class func_code: pass
......@@ -132,8 +135,9 @@ class DTMLMethod(HTML, Acquisition.Implicit, RoleManager,
+History.Historical.manage_options
+RoleManager.manage_options
+Item_w__name__.manage_options
+Cacheable.manage_options
)
__ac_permissions__=(
('View management screens',
('document_src', 'PrincipiaSearchSource')),
......@@ -142,6 +146,8 @@ class DTMLMethod(HTML, Acquisition.Implicit, RoleManager,
'manage_edit', 'manage_upload', 'PUT',
'manage_historyCopy',
'manage_beforeHistoryCopy', 'manage_afterHistoryCopy',
'ZCacheable_configHTML', 'getCacheNamespaceKeys',
'setCacheNamespaceKeys',
)
),
('Change proxy roles', ('manage_proxyForm', 'manage_proxy')),
......@@ -156,6 +162,13 @@ class DTMLMethod(HTML, Acquisition.Implicit, RoleManager,
def __call__(self, client=None, REQUEST={}, RESPONSE=None, **kw):
"""Render the document given a client object, REQUEST mapping,
Response, and key word arguments."""
if not self._cache_namespace_keys:
data = self.ZCacheable_get(default=_marker)
if data is not _marker:
# Return cached results.
return data
kw['document_id'] =self.getId()
kw['document_title']=self.title
......@@ -164,14 +177,19 @@ class DTMLMethod(HTML, Acquisition.Implicit, RoleManager,
try:
if client is None:
# Called as subtemplate, so don't need error propigation!
# Called as subtemplate, so don't need error propagation!
r=apply(HTML.__call__, (self, client, REQUEST), kw)
if RESPONSE is None: return r
return decapitate(r, RESPONSE)
if RESPONSE is None: result = r
else: result = decapitate(r, RESPONSE)
if not self._cache_namespace_keys:
self.ZCacheable_set(result)
return result
r=apply(HTML.__call__, (self, client, REQUEST), kw)
if type(r) is not type(''): return r
if RESPONSE is None: return r
if type(r) is not type('') or RESPONSE is None:
if not self._cache_namespace_keys:
self.ZCacheable_set(r)
return r
finally: security.removeContext(self)
......@@ -182,7 +200,55 @@ class DTMLMethod(HTML, Acquisition.Implicit, RoleManager,
else:
c, e=guess_content_type(self.getId(), r)
RESPONSE.setHeader('Content-Type', c)
return decapitate(r, RESPONSE)
result = decapitate(r, RESPONSE)
if not self._cache_namespace_keys:
self.ZCacheable_set(result)
return result
def ZDocumentTemplate_beforeRender(self, md, default):
# Tries to get a cached value.
if self._cache_namespace_keys:
# Use the specified keys from the namespace to identify a
# cache entry.
kw = {}
for key in self._cache_namespace_keys:
try: val = md[key]
except: val = None
kw[key] = val
return self.ZCacheable_get(keywords=kw, default=default)
return default
def ZDocumentTemplate_afterRender(self, md, result):
# Tries to set a cache value.
if self._cache_namespace_keys:
kw = {}
for key in self._cache_namespace_keys:
try: val = md[key]
except: val = None
kw[key] = val
self.ZCacheable_set(result, keywords=kw)
ZCacheable_configHTML = HTMLFile('cacheNamespaceKeys', globals())
def getCacheNamespaceKeys(self):
'''
Returns the cacheNamespaceKeys.
'''
return self._cache_namespace_keys
def setCacheNamespaceKeys(self, keys, REQUEST=None):
'''
Sets the list of names that should be looked up in the
namespace to provide a cache key.
'''
ks = []
for key in keys:
key = strip(str(key))
if key:
ks.append(key)
self._cache_namespace_keys = tuple(ks)
if REQUEST is not None:
return self.ZCacheable_manage(self, REQUEST)
def get_size(self):
return len(self.raw)
......@@ -238,6 +304,7 @@ class DTMLMethod(HTML, Acquisition.Implicit, RoleManager,
self.title=str(title)
if type(data) is not type(''): data=data.read()
self.munge(data)
self.ZCacheable_invalidate()
if REQUEST:
message="Content changed."
return self.manage_main(self,REQUEST,manage_tabs_message=message)
......@@ -247,6 +314,7 @@ class DTMLMethod(HTML, Acquisition.Implicit, RoleManager,
self._validateProxy(REQUEST)
if type(file) is not type(''): file=file.read()
self.munge(file)
self.ZCacheable_invalidate()
if REQUEST: return MessageDialog(
title ='Success!',
message='Your changes have been saved',
......@@ -278,6 +346,7 @@ class DTMLMethod(HTML, Acquisition.Implicit, RoleManager,
self._validateProxy(REQUEST, roles)
self._validateProxy(REQUEST)
self._proxy_roles=tuple(roles)
self.ZCacheable_invalidate()
if REQUEST: return MessageDialog(
title ='Success!',
message='Your changes have been saved',
......@@ -301,6 +370,7 @@ class DTMLMethod(HTML, Acquisition.Implicit, RoleManager,
body=REQUEST.get('BODY', '')
self._validateProxy(REQUEST)
self.munge(body)
self.ZCacheable_invalidate()
RESPONSE.setStatus(204)
return RESPONSE
......
......@@ -84,7 +84,7 @@
##############################################################################
"""Image object"""
__version__='$Revision: 1.117 $'[11:-2]
__version__='$Revision: 1.118 $'[11:-2]
import Globals, string, struct, content_types
from OFS.content_types import guess_content_type
......@@ -97,6 +97,7 @@ from cStringIO import StringIO
from Globals import Persistent
from Acquisition import Implicit
from DateTime import DateTime
from Cache import Cacheable
StringType=type('')
......@@ -128,8 +129,8 @@ def manage_addFile(self,id,file='',title='',precondition='', content_type='',
REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')
class File(Persistent,Implicit,PropertyManager,
RoleManager,Item_w__name__):
class File(Persistent, Implicit, PropertyManager,
RoleManager, Item_w__name__, Cacheable):
"""A File object is a content object for arbitrary files."""
meta_type='File'
......@@ -156,6 +157,7 @@ class File(Persistent,Implicit,PropertyManager,
)
+ RoleManager.manage_options
+ Item_w__name__.manage_options
+ Cacheable.manage_options
)
......@@ -231,6 +233,10 @@ class File(Persistent,Implicit,PropertyManager,
RESPONSE.setHeader('Content-Type', self.content_type)
RESPONSE.setHeader('Content-Length', self.size)
# Don't cache the data itself, but provide an opportunity
# for a cache manager to set response headers.
self.ZCacheable_set(None)
data=self.data
if type(data) is type(''): return data
......@@ -251,6 +257,7 @@ class File(Persistent,Implicit,PropertyManager,
if size is None: size=len(data)
self.size=size
self.data=data
self.ZCacheable_invalidate()
def manage_edit(self, title, content_type, precondition='', REQUEST=None):
"""
......@@ -260,6 +267,7 @@ class File(Persistent,Implicit,PropertyManager,
self.content_type=str(content_type)
if precondition: self.precondition=str(precondition)
elif self.precondition: del self.precondition
self.ZCacheable_invalidate()
if REQUEST:
message="Your changes have been saved"
return self.manage_main(self, REQUEST, manage_tabs_message=message)
......@@ -474,6 +482,7 @@ class Image(File):
)
+ RoleManager.manage_options
+ Item_w__name__.manage_options
+ Cacheable.manage_options
)
manage_editForm =HTMLFile('imageEdit',globals(),Kind='Image',kind='image')
......@@ -552,6 +561,8 @@ class Image(File):
# Now we should have the correct content type, or still None
if content_type is not None: self.content_type = content_type
self.ZCacheable_invalidate()
def __str__(self):
return self.tag()
......
Names from the DTML namespace to use as cache keys:<br>
<textarea name="keys:lines" cols="40" rows="5"><dtml-in
getCacheNamespaceKeys>&dtml-sequence-item;
</dtml-in></textarea>
<br>
<input type="submit" name="setCacheNamespaceKeys:method" value="Change">
<html><head><title>Cache</title></head>
<body bgcolor="#ffffff">
<dtml-var manage_tabs>
<h2>Caching properties</h2>
<form action="&dtml-absolute_url;" method="POST">
<dtml-if ZCacheable_isAMethod>
<input type="checkbox" name="enable" value="1"
<dtml-if ZCacheable_enabled>checked="checked"</dtml-if>>
Cache this view of the object<br>
<input type="submit" name="ZCacheable_setEnabled:method" value="Change">
<dtml-else>
Cache this object using:
<select name="manager_id">
<option value="">(None)</option>
<dtml-in ZCacheable_getManagerIds mapping>
<option value="&dtml-id;" <dtml-if
expr="id == ZCacheable_getManagerId()"
>selected="selected"</dtml-if>>&dtml-id;
<dtml-if title>(&dtml-title;)</dtml-if></option>
</dtml-in>
</select>
<input type="submit" name="ZCacheable_setManagerId:method" value="Change">
<dtml-if ZCacheable_getManagerURL>
<p>
<a href="&dtml-ZCacheable_getManagerURL;/manage_main">Settings</a>
</p>
<p>
<input type="submit" name="ZCacheable_invalidate:method" value="Invalidate">
</p>
</dtml-if>
</dtml-if>
<p><dtml-var ZCacheable_configHTML></p>
</form>
</body>
</html>
<html><head><title>Associate cacheable objects</title></head>
<body bgcolor="#ffffff">
<dtml-var manage_tabs>
<h2>Associate cacheable objects</h2>
<form action="&dtml-URL1;" method="POST">
<dtml-if show_results>
<dtml-if results>
<em>Select which objects should be cached using this cache manager. Only
those objects for which you have the "Change cache settings" permission
are shown.</em>
<table>
<dtml-in results mapping sort=sortkey>
<tr><td><input type="checkbox" name="associate_&dtml-path;:int" value="1"
<dtml-if associated>checked="checked"</dtml-if>>
<input type="hidden" name="associate_&dtml-path;:int:default" value="0">
</td>
<td><dtml-if icon><a href="../&dtml-path;/manage_main"><img src="&dtml-icon;"
border="0"></a> &nbsp;</dtml-if>
<a href="../&dtml-path;/manage_main">&dtml-path;</a>
<dtml-if title>(&dtml-title;)</dtml-if>
</td></tr>
</dtml-in>
</table>
<input type="submit" name="ZCacheManager_setAssociations:method"
value="Save changes">
<dtml-else>
<em>No objects matched your query.</em>
</dtml-if>
<hr>
</dtml-if>
<table>
<tr>
<td valign="top">
Locate cacheable objects:
</td>
<td valign="top">
<input type="radio" name="require_assoc:int" value="0" checked="checked"> All
<input type="radio" name="require_assoc:int" value="1">
Associated with this cache manager
<br>
<table><tr><td valign="top">
Meta types:
</td><td valign="top">
<select multiple="multiple" name="meta_types:list" size="5">
<option value="">All</option>
<dtml-in all_meta_types mapping sort=name>
<option value="&dtml-name;">&dtml-name;</option>
</dtml-in>
</select>
</td></tr></table>
<input type="checkbox" name="subfolders:int" value="1" checked="checked">
<input type="hidden" name="subfolders:int" value="0">
Search subfolders
<br>
<input type="submit" name="ZCacheManager_locate:method" value="Locate">
</td></tr></table>
</form>
</body>
</html>
Cache manager associations
For background information, see the
<a href="Caching.stx">description of cache management</a>.
The 'Associate' form lets you search for cacheable objects and
make or break multiple cache management associations at once.
Simply select the search criteria then click the 'Locate'
button. Zope will return a list of cacheable objects with a
checkbox for each one. Select or unselect objects and click the
'Save changes' button when you're done.
Cacheable objects
For background information, see the
<a href="Caching.stx">description of cache management</a>.
The 'Cache' tab allows you to associate a cacheable object with a
cache manager. It is only available when at least one cache manager
exists somewhere in the current context.
Use the drop-down box to select which cache manager should be
associated with the object. Some types of objects provide
additional caching options.
DTML methods can be cached according to the DTML namespace. The entry
box on the 'Cache' tab allows you to enter the names
(one per line) that Zope should look up in the namespace to create the
cache key. Note, however, that the namespace lookup operation can be
expensive, so use this feature with care. Also note that it is not
possible for accelerated HTTP cache managers to make use of this feature.
(TODO) Python scripts and SQL methods may also provide further options.
Cache Management: Configurable Caching
Performing some computations in Zope can take a long time or use
a lot of resources. One way to deal with expensive tasks is to
cache them. The first time the computation is requested, the results
are stored in a table or *cache*. Subsequent requests get the results
from the cache. This can result in a dramatic speed increase.
There are so many possible strategies for caching that no one could
possibly come up with them all. Caches can be
stored in memory, on disk, on other computers, or by other means.
Caches can be limited in size or unconstrained. They can be
made to work with only specific types of objects. They can be
tuned in different ways.
So instead of trying to provide for every possible caching strategy,
Zope defines an API called *cache management* that lets developers
write their own caching strategies, or *cache managers*, and lets
site administrators easily connect cacheable objects to those cache
managers.
You can use caching to speed up access to often-requested pages,
reduce disk access and network traffic, and deal with heavy loads.
All these benefits come with risks of excessive caching, however,
so it's important to fine-tune the cache settings. More on this
later.
How to set up caching
The first thing you need to do is create a cache manager instance.
In the Zope management interface, go to a folder containing objects
that would benefit from caching. From the add list, select a
cache manager type such as 'RAM Cache Manager'. Use an ID that
describes the purpose of the cache manager.
Next, visit one of the objects that you want to cache. A new tab
labeled 'Cache' should be visible. Select it. From the drop-down
box, select the cache manager you just created and press the
'Change' button.
The object is now ready to be cached. Visit the 'View' tab. If
the object is a script that takes a long time to render, the first
view will still take just as long as before. But if you're using
a RAM cache manager or similar, the second view should be much faster.
Press the *reload* button in your browser to try it out.
You can associate many objects to a cache manager at once using the
'Associate' tab of all cache managers. Visit the cache manager
object you created and select the 'Associate' tab. Press the
'Locate' button. Zope will locate all cacheable objects in the
folder. Select the checkboxes next to the objects you want to
cache and press the 'Save changes' button.
Inherent risks
Cache managers generally don't know the nature of what is being
cached, so here are some issues that can surface:
- Data that is intended for authorized viewers only can
be inadvertently cached in public caches.
- Data is cached for too long a time.
- If more than one cache is involved, data is purged from one
cache but not the other.
- A method that makes up part of the page sets the caching headers
for the entire response, fooling downstream caches into thinking
the whole response should be cached.
- Result data can depend on any number of objects. Early on it was
decided that the standard cache managers will not try to deduce
dependencies, but instead rely on the user for configuration of
simple dependencies.
Because of these risks, you should be careful when setting up caching.
You'll need to fine-tune the cache settings. Sometimes you'll find
that you can't cache one of your major pages, but that you can cache
pieces of it.
Also remember that caching can actually slow down Zope if it is
applied unscrupulously. You should perform speed tests to verify that
caching really does speed up your site.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment