Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Z
Zope
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
Zope
Commits
996ebaa9
Commit
996ebaa9
authored
Jul 11, 2010
by
Hanno Schlichting
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Factored out Products.StandardCacheManagers
parent
3af382d3
Changes
23
Show whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
7 additions
and
1761 deletions
+7
-1761
buildout.cfg
buildout.cfg
+1
-0
doc/CHANGES.rst
doc/CHANGES.rst
+4
-3
setup.py
setup.py
+1
-0
sources.cfg
sources.cfg
+1
-0
src/Products/StandardCacheManagers/AcceleratedHTTPCacheManager.py
...ucts/StandardCacheManagers/AcceleratedHTTPCacheManager.py
+0
-278
src/Products/StandardCacheManagers/RAMCacheManager-internals.txt
...ducts/StandardCacheManagers/RAMCacheManager-internals.txt
+0
-51
src/Products/StandardCacheManagers/RAMCacheManager.py
src/Products/StandardCacheManagers/RAMCacheManager.py
+0
-509
src/Products/StandardCacheManagers/__init__.py
src/Products/StandardCacheManagers/__init__.py
+0
-38
src/Products/StandardCacheManagers/cache.gif
src/Products/StandardCacheManagers/cache.gif
+0
-0
src/Products/StandardCacheManagers/configure.zcml
src/Products/StandardCacheManagers/configure.zcml
+0
-24
src/Products/StandardCacheManagers/dtml/addAccel.dtml
src/Products/StandardCacheManagers/dtml/addAccel.dtml
+0
-31
src/Products/StandardCacheManagers/dtml/addRCM.dtml
src/Products/StandardCacheManagers/dtml/addRCM.dtml
+0
-31
src/Products/StandardCacheManagers/dtml/propsAccel.dtml
src/Products/StandardCacheManagers/dtml/propsAccel.dtml
+0
-65
src/Products/StandardCacheManagers/dtml/propsRCM.dtml
src/Products/StandardCacheManagers/dtml/propsRCM.dtml
+0
-85
src/Products/StandardCacheManagers/dtml/statsAccel.dtml
src/Products/StandardCacheManagers/dtml/statsAccel.dtml
+0
-61
src/Products/StandardCacheManagers/dtml/statsRCM.dtml
src/Products/StandardCacheManagers/dtml/statsRCM.dtml
+0
-119
src/Products/StandardCacheManagers/help/Accel.stx
src/Products/StandardCacheManagers/help/Accel.stx
+0
-63
src/Products/StandardCacheManagers/help/RAM.stx
src/Products/StandardCacheManagers/help/RAM.stx
+0
-68
src/Products/StandardCacheManagers/subscribers.py
src/Products/StandardCacheManagers/subscribers.py
+0
-26
src/Products/StandardCacheManagers/tests/__init__.py
src/Products/StandardCacheManagers/tests/__init__.py
+0
-17
src/Products/StandardCacheManagers/tests/test_AcceleratedHTTPCacheManager.py
...rdCacheManagers/tests/test_AcceleratedHTTPCacheManager.py
+0
-154
src/Products/StandardCacheManagers/tests/test_CacheManagerLocation.py
.../StandardCacheManagers/tests/test_CacheManagerLocation.py
+0
-137
src/Products/StandardCacheManagers/version.txt
src/Products/StandardCacheManagers/version.txt
+0
-1
No files found.
buildout.cfg
View file @
996ebaa9
...
...
@@ -52,6 +52,7 @@ eggs =
Products.BTreeFolder2
Products.ExternalMethod
Products.PythonScripts
Products.StandardCacheManagers
Products.ZCTextIndex
Record
RestrictedPython
...
...
doc/CHANGES.rst
View file @
996ebaa9
...
...
@@ -37,9 +37,10 @@ Restructuring
database manager ZMI.
- Factored out the `Products.BTreeFolder2`, `Products.ExternalMethod`,
`Products.MIMETools`, `Products.OFSP` and `Products.PythonScripts` packages
into their own distributions. They will no longer be included by default in
Zope 2.14 but live on as independent add-ons.
`Products.MIMETools`, `Products.OFSP`, `Products.PythonScripts` and
`Products.StandardCacheManagers` packages into their own distributions. They
will no longer be included by default in Zope 2.14 but live on as independent
add-ons.
- Factored out the `Products.ZSQLMethods` into its own distribution. The
distribution also includes the `Shared.DC.ZRDB` code. The Zope2 distribution
...
...
setup.py
View file @
996ebaa9
...
...
@@ -104,6 +104,7 @@ setup(name='Zope2',
'Products.MIMETools'
,
'Products.OFSP'
,
'Products.PythonScripts'
,
'Products.StandardCacheManagers'
,
],
include_package_data
=
True
,
...
...
sources.cfg
View file @
996ebaa9
...
...
@@ -14,6 +14,7 @@ Products.ExternalMethod = svn ^/Products.ExternalMethod/trunk
Products.MIMETools = svn ^/Products.MIMETools/trunk
Products.OFSP = svn ^/Products.OFSP/trunk
Products.PythonScripts = svn ^/Products.PythonScripts/trunk
Products.StandardCacheManagers = svn ^/Products.StandardCacheManagers/trunk
Products.ZCTextIndex = svn ^/Products.ZCTextIndex/trunk
Record = svn ^/Record/trunk
tempstorage = svn ^/tempstorage/trunk
...
...
src/Products/StandardCacheManagers/AcceleratedHTTPCacheManager.py
deleted
100644 → 0
View file @
3af382d3
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
'''
Accelerated HTTP cache manager --
Adds caching headers to the response so that downstream caches will
cache according to a common policy.
$Id$
'''
from
cgi
import
escape
import
httplib
import
logging
import
socket
import
time
from
urllib
import
quote
import
urlparse
from
AccessControl.class_init
import
InitializeClass
from
AccessControl.Permissions
import
view_management_screens
from
AccessControl.SecurityInfo
import
ClassSecurityInfo
from
App.Common
import
rfc1123_date
from
App.special_dtml
import
DTMLFile
from
OFS.Cache
import
Cache
from
OFS.Cache
import
CacheManager
from
OFS.SimpleItem
import
SimpleItem
logger
=
logging
.
getLogger
(
'Zope.AcceleratedHTTPCacheManager'
)
class
AcceleratedHTTPCache
(
Cache
):
# Note the need to take thread safety into account.
# Also note that objects of this class are not persistent,
# nor do they use acquisition.
connection_factory
=
httplib
.
HTTPConnection
def
__init__
(
self
):
self
.
hit_counts
=
{}
def
initSettings
(
self
,
kw
):
# Note that we lazily allow AcceleratedHTTPCacheManager
# to verify the correctness of the internal settings.
self
.
__dict__
.
update
(
kw
)
def
ZCache_invalidate
(
self
,
ob
):
# Note that this only works for default views of objects at
# their canonical path. If an object is viewed and cached at
# any other path via acquisition or virtual hosting, that
# cache entry cannot be purged because there is an infinite
# number of such possible paths, and Squid does not support
# any kind of fuzzy purging; we have to specify exactly the
# URL to purge. So we try to purge the known paths most
# likely to turn up in practice: the physical path and the
# current absolute_url_path. Any of those can be
# wrong in some circumstances, but it may be the best we can
# do :-(
# It would be nice if Squid's purge feature was better
# documented. (pot! kettle! black!)
phys_path
=
ob
.
getPhysicalPath
()
if
self
.
hit_counts
.
has_key
(
phys_path
):
del
self
.
hit_counts
[
phys_path
]
purge_paths
=
(
ob
.
absolute_url_path
(),
quote
(
'/'
.
join
(
phys_path
)))
# Don't purge the same path twice.
if
purge_paths
[
0
]
==
purge_paths
[
1
]:
purge_paths
=
purge_paths
[:
1
]
results
=
[]
for
url
in
self
.
notify_urls
:
if
not
url
.
strip
():
continue
# Send the PURGE request to each HTTP accelerator.
if
url
[:
7
].
lower
()
==
'http://'
:
u
=
url
else
:
u
=
'http://'
+
url
(
scheme
,
host
,
path
,
params
,
query
,
fragment
)
=
urlparse
.
urlparse
(
u
)
if
path
.
lower
().
startswith
(
'/http://'
):
path
=
path
.
lstrip
(
'/'
)
for
ob_path
in
purge_paths
:
p
=
path
.
rstrip
(
'/'
)
+
ob_path
h
=
self
.
connection_factory
(
host
)
logger
.
debug
(
'PURGING host %s, path %s'
%
(
host
,
p
))
# An exception on one purge should not prevent the others.
try
:
h
.
request
(
'PURGE'
,
p
)
# This better not hang. I wish httplib gave us
# control of timeouts.
except
socket
.
gaierror
:
msg
=
'socket.gaierror: maybe the server '
+
\
'at %s is down, or the cache manager '
+
\
'is misconfigured?'
logger
.
error
(
msg
%
url
)
continue
r
=
h
.
getresponse
()
status
=
'%s %s'
%
(
r
.
status
,
r
.
reason
)
results
.
append
(
status
)
logger
.
debug
(
'purge response: %s'
%
status
)
return
'Server response(s): '
+
';'
.
join
(
results
)
def
ZCache_get
(
self
,
ob
,
view_name
,
keywords
,
mtime_func
,
default
):
return
default
def
ZCache_set
(
self
,
ob
,
data
,
view_name
,
keywords
,
mtime_func
):
# Note the blatant ignorance of view_name and keywords.
# Standard HTTP accelerators are not able to make use of this
# data. mtime_func is also ignored because using "now" for
# Last-Modified is as good as using any time in the past.
REQUEST
=
ob
.
REQUEST
RESPONSE
=
REQUEST
.
RESPONSE
anon
=
1
u
=
REQUEST
.
get
(
'AUTHENTICATED_USER'
,
None
)
if
u
is
not
None
:
if
u
.
getUserName
()
!=
'Anonymous User'
:
anon
=
0
phys_path
=
ob
.
getPhysicalPath
()
if
self
.
hit_counts
.
has_key
(
phys_path
):
hits
=
self
.
hit_counts
[
phys_path
]
else
:
self
.
hit_counts
[
phys_path
]
=
hits
=
[
0
,
0
]
if
anon
:
hits
[
0
]
=
hits
[
0
]
+
1
else
:
hits
[
1
]
=
hits
[
1
]
+
1
if
not
anon
and
self
.
anonymous_only
:
return
# Set HTTP Expires and Cache-Control headers
seconds
=
self
.
interval
expires
=
rfc1123_date
(
time
.
time
()
+
seconds
)
RESPONSE
.
setHeader
(
'Last-Modified'
,
rfc1123_date
(
time
.
time
()))
RESPONSE
.
setHeader
(
'Cache-Control'
,
'max-age=%d'
%
seconds
)
RESPONSE
.
setHeader
(
'Expires'
,
expires
)
caches
=
{}
PRODUCT_DIR
=
__name__
.
split
(
'.'
)[
-
2
]
class
AcceleratedHTTPCacheManager
(
CacheManager
,
SimpleItem
):
' '
security
=
ClassSecurityInfo
()
security
.
setPermissionDefault
(
'Change cache managers'
,
(
'Manager'
,))
manage_options
=
(
{
'label'
:
'Properties'
,
'action'
:
'manage_main'
,
'help'
:(
PRODUCT_DIR
,
'Accel.stx'
),},
{
'label'
:
'Statistics'
,
'action'
:
'manage_stats'
,
'help'
:(
PRODUCT_DIR
,
'Accel.stx'
),},
)
+
CacheManager
.
manage_options
+
SimpleItem
.
manage_options
meta_type
=
'Accelerated HTTP Cache Manager'
def
__init__
(
self
,
ob_id
):
self
.
id
=
ob_id
self
.
title
=
''
self
.
_settings
=
{
'anonymous_only'
:
1
,
'interval'
:
3600
,
'notify_urls'
:()}
self
.
_resetCacheId
()
def
getId
(
self
):
' '
return
self
.
id
security
.
declarePrivate
(
'_remove_data'
)
def
_remove_data
(
self
):
caches
.
pop
(
self
.
__cacheid
,
None
)
security
.
declarePrivate
(
'_resetCacheId'
)
def
_resetCacheId
(
self
):
self
.
__cacheid
=
'%s_%f'
%
(
id
(
self
),
time
.
time
())
security
.
declarePrivate
(
'ZCacheManager_getCache'
)
def
ZCacheManager_getCache
(
self
):
cacheid
=
self
.
__cacheid
try
:
return
caches
[
cacheid
]
except
KeyError
:
cache
=
AcceleratedHTTPCache
()
cache
.
initSettings
(
self
.
_settings
)
caches
[
cacheid
]
=
cache
return
cache
security
.
declareProtected
(
view_management_screens
,
'getSettings'
)
def
getSettings
(
self
):
' '
return
self
.
_settings
.
copy
()
# Don't let UI modify it.
security
.
declareProtected
(
view_management_screens
,
'manage_main'
)
manage_main
=
DTMLFile
(
'dtml/propsAccel'
,
globals
())
security
.
declareProtected
(
'Change cache managers'
,
'manage_editProps'
)
def
manage_editProps
(
self
,
title
,
settings
=
None
,
REQUEST
=
None
):
' '
if
settings
is
None
:
settings
=
REQUEST
self
.
title
=
str
(
title
)
self
.
_settings
=
{
'anonymous_only'
:
settings
.
get
(
'anonymous_only'
)
and
1
or
0
,
'interval'
:
int
(
settings
[
'interval'
]),
'notify_urls'
:
tuple
(
settings
[
'notify_urls'
]),}
cache
=
self
.
ZCacheManager_getCache
()
cache
.
initSettings
(
self
.
_settings
)
if
REQUEST
is
not
None
:
return
self
.
manage_main
(
self
,
REQUEST
,
manage_tabs_message
=
'Properties changed.'
)
security
.
declareProtected
(
view_management_screens
,
'manage_stats'
)
manage_stats
=
DTMLFile
(
'dtml/statsAccel'
,
globals
())
def
_getSortInfo
(
self
):
"""
Returns the value of sort_by and sort_reverse.
If not found, returns default values.
"""
req
=
self
.
REQUEST
sort_by
=
req
.
get
(
'sort_by'
,
'anon'
)
sort_reverse
=
int
(
req
.
get
(
'sort_reverse'
,
1
))
return
sort_by
,
sort_reverse
security
.
declareProtected
(
view_management_screens
,
'getCacheReport'
)
def
getCacheReport
(
self
):
"""
Returns the list of objects in the cache, sorted according to
the user's preferences.
"""
sort_by
,
sort_reverse
=
self
.
_getSortInfo
()
c
=
self
.
ZCacheManager_getCache
()
rval
=
[]
for
path
,
(
anon
,
auth
)
in
c
.
hit_counts
.
items
():
rval
.
append
({
'path'
:
'/'
.
join
(
path
),
'anon'
:
anon
,
'auth'
:
auth
})
if
sort_by
:
rval
.
sort
(
lambda
e1
,
e2
,
sort_by
=
sort_by
:
cmp
(
e1
[
sort_by
],
e2
[
sort_by
]))
if
sort_reverse
:
rval
.
reverse
()
return
rval
security
.
declareProtected
(
view_management_screens
,
'sort_link'
)
def
sort_link
(
self
,
name
,
id
):
"""
Utility for generating a sort link.
"""
# XXX This ought to be in a library or something.
sort_by
,
sort_reverse
=
self
.
_getSortInfo
()
url
=
self
.
absolute_url
()
+
'/manage_stats?sort_by='
+
id
newsr
=
0
if
sort_by
==
id
:
newsr
=
not
sort_reverse
url
=
url
+
'&sort_reverse='
+
(
newsr
and
'1'
or
'0'
)
return
'<a href="%s">%s</a>'
%
(
escape
(
url
,
1
),
escape
(
name
))
InitializeClass
(
AcceleratedHTTPCacheManager
)
manage_addAcceleratedHTTPCacheManagerForm
=
DTMLFile
(
'dtml/addAccel'
,
globals
())
def
manage_addAcceleratedHTTPCacheManager
(
self
,
id
,
REQUEST
=
None
):
' '
self
.
_setObject
(
id
,
AcceleratedHTTPCacheManager
(
id
))
if
REQUEST
is
not
None
:
return
self
.
manage_main
(
self
,
REQUEST
)
# FYI good resource: http://www.web-caching.com/proxy-caches.html
src/Products/StandardCacheManagers/RAMCacheManager-internals.txt
deleted
100644 → 0
View file @
3af382d3
Preface
=======
This document is intended for people interested in the internals of
RAMCacheManager, such as maintainers. It should be updated when any
significant changes are made to the RAMCacheManager.
$Id$
Introduction
===============
The caching framework does not interpret the data in any way, it acts
just as a general storage for data passed to it. It tries to check if
the data is pickleable though. IOW, only pickleable data is
cacheable.
The idea behind the RAMCacheManager is that it should be shared between
threads, so that the same objects are not cached in each thread. This
is achieved by storing the cache data structure itself as a module
level variable (RAMCacheManager.caches). This, of course, requires
locking on modifications of that data structure.
Each RAMCacheManager instance has one cache in RAMCacheManager.caches
dictionary. A unique __cacheid is generated when creating a cache
manager and it's used as a key for caches.
Object Hierarchy
================
RAMCacheManager
RAMCache
ObjectCacheEntries
CacheEntry
RAMCacheManager is a persistent placeful object. It is assigned a
unique __cacheid on its creation. It is then used as a key to look up
the corresponding RAMCache object in the global caches dictionary.
So, each RAMCacheManager has a single RAMCache related to it.
RAMCache is a volatile cache, unique for each RAMCacheManager. It is
shared among threads and does all the locking. It has a writelock.
No locking is done on reading though. RAMCache keeps a dictionary of
ObjectCacheEntries indexed by the physical path of a cached object.
ObjectCacheEntries is a container for cached values for a single object.
The values in it are indexed by a tuple of a view_name, interesting
request variables, and extra keywords passed to Cache.ZCache_set().
CacheEntry is a wrapper around a single cached value. It stores the
data itself, creation time, view_name and keeps the access count.
src/Products/StandardCacheManagers/RAMCacheManager.py
deleted
100644 → 0
View file @
3af382d3
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
'''
RAM cache manager --
Caches the results of method calls in RAM.
$Id$
'''
from
cgi
import
escape
from
thread
import
allocate_lock
import
time
from
AccessControl.class_init
import
InitializeClass
from
AccessControl.Permissions
import
view_management_screens
from
AccessControl.SecurityInfo
import
ClassSecurityInfo
from
App.special_dtml
import
DTMLFile
from
OFS.Cache
import
Cache
from
OFS.Cache
import
CacheManager
from
OFS.SimpleItem
import
SimpleItem
try
:
from
cPickle
import
Pickler
from
cPickle
import
HIGHEST_PROTOCOL
except
ImportError
:
from
pickle
import
Pickler
from
pickle
import
HIGHEST_PROTOCOL
_marker
=
[]
# Create a new marker object.
class
CacheException
(
Exception
):
'''
A cache-related exception.
'''
class
CacheEntry
:
'''
Represents a cached value.
'''
def
__init__
(
self
,
index
,
data
,
view_name
):
try
:
# This is a protective barrier that hopefully prevents
# us from caching something that might result in memory
# leaks. It's also convenient for determining the
# approximate memory usage of the cache entry.
# DM 2004-11-29: this code causes excessive time.
# Note also that it does not prevent us from
# caching objects with references to persistent objects
# When we do, nasty persistency errors are likely
# to occur ("shouldn't load data while connection is closed").
#self.size = len(dumps(index)) + len(dumps(data))
sizer
=
_ByteCounter
()
pickler
=
Pickler
(
sizer
,
HIGHEST_PROTOCOL
)
pickler
.
dump
(
index
)
pickler
.
dump
(
data
)
self
.
size
=
sizer
.
getCount
()
except
:
raise
CacheException
(
'The data for the cache is not pickleable.'
)
self
.
created
=
time
.
time
()
self
.
data
=
data
self
.
view_name
=
view_name
self
.
access_count
=
0
class
ObjectCacheEntries
:
'''
Represents the cache for one Zope object.
'''
hits
=
0
misses
=
0
def
__init__
(
self
,
path
):
self
.
physical_path
=
path
self
.
lastmod
=
0
# Mod time of the object, class, etc.
self
.
entries
=
{}
def
aggregateIndex
(
self
,
view_name
,
req
,
req_names
,
local_keys
):
'''
Returns the index to be used when looking for or inserting
a cache entry.
view_name is a string.
local_keys is a mapping or None.
'''
req_index
=
[]
# Note: req_names is already sorted.
for
key
in
req_names
:
if
req
is
None
:
val
=
''
else
:
val
=
req
.
get
(
key
,
''
)
req_index
.
append
((
str
(
key
),
str
(
val
)))
if
local_keys
:
local_index
=
[]
for
key
,
val
in
local_keys
.
items
():
local_index
.
append
((
str
(
key
),
str
(
val
)))
local_index
.
sort
()
else
:
local_index
=
()
return
(
str
(
view_name
),
tuple
(
req_index
),
tuple
(
local_index
))
def
getEntry
(
self
,
lastmod
,
index
):
if
self
.
lastmod
<
lastmod
:
# Expired.
self
.
entries
=
{}
self
.
lastmod
=
lastmod
return
_marker
return
self
.
entries
.
get
(
index
,
_marker
)
def
setEntry
(
self
,
lastmod
,
index
,
data
,
view_name
):
self
.
lastmod
=
lastmod
self
.
entries
[
index
]
=
CacheEntry
(
index
,
data
,
view_name
)
def
delEntry
(
self
,
index
):
try
:
del
self
.
entries
[
index
]
except
KeyError
:
pass
class
RAMCache
(
Cache
):
# Note the need to take thread safety into account.
# Also note that objects of this class are not persistent,
# nor do they make use of acquisition.
max_age
=
0
def
__init__
(
self
):
# cache maps physical paths to ObjectCacheEntries.
self
.
cache
=
{}
self
.
writelock
=
allocate_lock
()
self
.
next_cleanup
=
0
def
initSettings
(
self
,
kw
):
# Note that we lazily allow RAMCacheManager
# to verify the correctness of the internal settings.
self
.
__dict__
.
update
(
kw
)
def
getObjectCacheEntries
(
self
,
ob
,
create
=
0
):
"""
Finds or creates the associated ObjectCacheEntries object.
Remember to lock writelock when calling with the 'create' flag.
"""
cache
=
self
.
cache
path
=
ob
.
getPhysicalPath
()
oc
=
cache
.
get
(
path
,
None
)
if
oc
is
None
:
if
create
:
cache
[
path
]
=
oc
=
ObjectCacheEntries
(
path
)
else
:
return
None
return
oc
def
countAllEntries
(
self
):
'''
Returns the count of all cache entries.
'''
count
=
0
for
oc
in
self
.
cache
.
values
():
count
=
count
+
len
(
oc
.
entries
)
return
count
def
countAccesses
(
self
):
'''
Returns a mapping of
(n) -> number of entries accessed (n) times
'''
counters
=
{}
for
oc
in
self
.
cache
.
values
():
for
entry
in
oc
.
entries
.
values
():
access_count
=
entry
.
access_count
counters
[
access_count
]
=
counters
.
get
(
access_count
,
0
)
+
1
return
counters
def
clearAccessCounters
(
self
):
'''
Clears access_count for each cache entry.
'''
for
oc
in
self
.
cache
.
values
():
for
entry
in
oc
.
entries
.
values
():
entry
.
access_count
=
0
def
deleteEntriesAtOrBelowThreshold
(
self
,
threshold_access_count
):
"""
Deletes entries that haven't been accessed recently.
"""
self
.
writelock
.
acquire
()
try
:
for
p
,
oc
in
self
.
cache
.
items
():
for
agindex
,
entry
in
oc
.
entries
.
items
():
if
entry
.
access_count
<=
threshold_access_count
:
del
oc
.
entries
[
agindex
]
if
len
(
oc
.
entries
)
<
1
:
del
self
.
cache
[
p
]
finally
:
self
.
writelock
.
release
()
def
deleteStaleEntries
(
self
):
"""
Deletes entries that have expired.
"""
if
self
.
max_age
>
0
:
self
.
writelock
.
acquire
()
try
:
min_created
=
time
.
time
()
-
self
.
max_age
for
p
,
oc
in
self
.
cache
.
items
():
for
agindex
,
entry
in
oc
.
entries
.
items
():
if
entry
.
created
<
min_created
:
del
oc
.
entries
[
agindex
]
if
len
(
oc
.
entries
)
<
1
:
del
self
.
cache
[
p
]
finally
:
self
.
writelock
.
release
()
def
cleanup
(
self
):
'''
Removes cache entries.
'''
self
.
deleteStaleEntries
()
new_count
=
self
.
countAllEntries
()
if
new_count
>
self
.
threshold
:
counters
=
self
.
countAccesses
()
priorities
=
counters
.
items
()
# Remove the least accessed entries until we've reached
# our target count.
if
len
(
priorities
)
>
0
:
priorities
.
sort
()
access_count
=
0
for
access_count
,
effect
in
priorities
:
new_count
=
new_count
-
effect
if
new_count
<=
self
.
threshold
:
break
self
.
deleteEntriesAtOrBelowThreshold
(
access_count
)
self
.
clearAccessCounters
()
def
getCacheReport
(
self
):
"""
Reports on the contents of the cache.
"""
rval
=
[]
for
oc
in
self
.
cache
.
values
():
size
=
0
ac
=
0
views
=
[]
for
entry
in
oc
.
entries
.
values
():
size
=
size
+
entry
.
size
ac
=
ac
+
entry
.
access_count
view
=
entry
.
view_name
or
'<default>'
if
view
not
in
views
:
views
.
append
(
view
)
views
.
sort
()
info
=
{
'path'
:
'/'
.
join
(
oc
.
physical_path
),
'hits'
:
oc
.
hits
,
'misses'
:
oc
.
misses
,
'size'
:
size
,
'counter'
:
ac
,
'views'
:
views
,
'entries'
:
len
(
oc
.
entries
)
}
rval
.
append
(
info
)
return
rval
def
ZCache_invalidate
(
self
,
ob
):
'''
Invalidates the cache entries that apply to ob.
'''
path
=
ob
.
getPhysicalPath
()
# Invalidates all subobjects as well.
self
.
writelock
.
acquire
()
try
:
for
p
,
oc
in
self
.
cache
.
items
():
pp
=
oc
.
physical_path
if
pp
[:
len
(
path
)]
==
path
:
del
self
.
cache
[
p
]
finally
:
self
.
writelock
.
release
()
def
ZCache_get
(
self
,
ob
,
view_name
=
''
,
keywords
=
None
,
mtime_func
=
None
,
default
=
None
):
'''
Gets a cache entry or returns default.
'''
oc
=
self
.
getObjectCacheEntries
(
ob
)
if
oc
is
None
:
return
default
lastmod
=
ob
.
ZCacheable_getModTime
(
mtime_func
)
index
=
oc
.
aggregateIndex
(
view_name
,
ob
.
REQUEST
,
self
.
request_vars
,
keywords
)
entry
=
oc
.
getEntry
(
lastmod
,
index
)
if
entry
is
_marker
:
return
default
if
self
.
max_age
>
0
and
entry
.
created
<
time
.
time
()
-
self
.
max_age
:
# Expired.
self
.
writelock
.
acquire
()
try
:
oc
.
delEntry
(
index
)
finally
:
self
.
writelock
.
release
()
return
default
oc
.
hits
=
oc
.
hits
+
1
entry
.
access_count
=
entry
.
access_count
+
1
return
entry
.
data
def
ZCache_set
(
self
,
ob
,
data
,
view_name
=
''
,
keywords
=
None
,
mtime_func
=
None
):
'''
Sets a cache entry.
'''
now
=
time
.
time
()
if
self
.
next_cleanup
<=
now
:
self
.
cleanup
()
self
.
next_cleanup
=
now
+
self
.
cleanup_interval
lastmod
=
ob
.
ZCacheable_getModTime
(
mtime_func
)
self
.
writelock
.
acquire
()
try
:
oc
=
self
.
getObjectCacheEntries
(
ob
,
create
=
1
)
index
=
oc
.
aggregateIndex
(
view_name
,
ob
.
REQUEST
,
self
.
request_vars
,
keywords
)
oc
.
setEntry
(
lastmod
,
index
,
data
,
view_name
)
oc
.
misses
=
oc
.
misses
+
1
finally
:
self
.
writelock
.
release
()
caches
=
{}
PRODUCT_DIR
=
__name__
.
split
(
'.'
)[
-
2
]
class
RAMCacheManager
(
CacheManager
,
SimpleItem
):
"""Manage a RAMCache, which stores rendered data in RAM.
This is intended to be used as a low-level cache for
expensive Python code, not for objects published
under their own URLs such as web pages.
RAMCacheManager *can* be used to cache complete publishable
pages, such as DTMLMethods/Documents and Page Templates,
but this is not advised: such objects typically do not attempt
to cache important out-of-band data such as 3xx HTTP responses,
and the client would get an erroneous 200 response.
Such objects should instead be cached with an
AcceleratedHTTPCacheManager and/or downstream
caching.
"""
security
=
ClassSecurityInfo
()
security
.
setPermissionDefault
(
'Change cache managers'
,
(
'Manager'
,))
manage_options
=
(
{
'label'
:
'Properties'
,
'action'
:
'manage_main'
,
'help'
:(
PRODUCT_DIR
,
'RAM.stx'
),},
{
'label'
:
'Statistics'
,
'action'
:
'manage_stats'
,
'help'
:(
PRODUCT_DIR
,
'RAM.stx'
),},
)
+
CacheManager
.
manage_options
+
SimpleItem
.
manage_options
meta_type
=
'RAM Cache Manager'
def
__init__
(
self
,
ob_id
):
self
.
id
=
ob_id
self
.
title
=
''
self
.
_settings
=
{
'threshold'
:
1000
,
'cleanup_interval'
:
300
,
'request_vars'
:
(
'AUTHENTICATED_USER'
,),
'max_age'
:
3600
,
}
self
.
_resetCacheId
()
def
getId
(
self
):
' '
return
self
.
id
security
.
declarePrivate
(
'_remove_data'
)
def
_remove_data
(
self
):
caches
.
pop
(
self
.
__cacheid
,
None
)
security
.
declarePrivate
(
'_resetCacheId'
)
def
_resetCacheId
(
self
):
self
.
__cacheid
=
'%s_%f'
%
(
id
(
self
),
time
.
time
())
ZCacheManager_getCache__roles__
=
()
def
ZCacheManager_getCache
(
self
):
cacheid
=
self
.
__cacheid
try
:
return
caches
[
cacheid
]
except
KeyError
:
cache
=
RAMCache
()
cache
.
initSettings
(
self
.
_settings
)
caches
[
cacheid
]
=
cache
return
cache
security
.
declareProtected
(
view_management_screens
,
'getSettings'
)
def
getSettings
(
self
):
'Returns the current cache settings.'
res
=
self
.
_settings
.
copy
()
if
not
res
.
has_key
(
'max_age'
):
res
[
'max_age'
]
=
0
return
res
security
.
declareProtected
(
view_management_screens
,
'manage_main'
)
manage_main
=
DTMLFile
(
'dtml/propsRCM'
,
globals
())
security
.
declareProtected
(
'Change cache managers'
,
'manage_editProps'
)
def
manage_editProps
(
self
,
title
,
settings
=
None
,
REQUEST
=
None
):
'Changes the cache settings.'
if
settings
is
None
:
settings
=
REQUEST
self
.
title
=
str
(
title
)
request_vars
=
list
(
settings
[
'request_vars'
])
request_vars
.
sort
()
self
.
_settings
=
{
'threshold'
:
int
(
settings
[
'threshold'
]),
'cleanup_interval'
:
int
(
settings
[
'cleanup_interval'
]),
'request_vars'
:
tuple
(
request_vars
),
'max_age'
:
int
(
settings
[
'max_age'
]),
}
cache
=
self
.
ZCacheManager_getCache
()
cache
.
initSettings
(
self
.
_settings
)
if
REQUEST
is
not
None
:
return
self
.
manage_main
(
self
,
REQUEST
,
manage_tabs_message
=
'Properties changed.'
)
security
.
declareProtected
(
view_management_screens
,
'manage_stats'
)
manage_stats
=
DTMLFile
(
'dtml/statsRCM'
,
globals
())
def
_getSortInfo
(
self
):
"""
Returns the value of sort_by and sort_reverse.
If not found, returns default values.
"""
req
=
self
.
REQUEST
sort_by
=
req
.
get
(
'sort_by'
,
'hits'
)
sort_reverse
=
int
(
req
.
get
(
'sort_reverse'
,
1
))
return
sort_by
,
sort_reverse
security
.
declareProtected
(
view_management_screens
,
'getCacheReport'
)
def
getCacheReport
(
self
):
"""
Returns the list of objects in the cache, sorted according to
the user's preferences.
"""
sort_by
,
sort_reverse
=
self
.
_getSortInfo
()
c
=
self
.
ZCacheManager_getCache
()
rval
=
c
.
getCacheReport
()
if
sort_by
:
rval
.
sort
(
lambda
e1
,
e2
,
sort_by
=
sort_by
:
cmp
(
e1
[
sort_by
],
e2
[
sort_by
]))
if
sort_reverse
:
rval
.
reverse
()
return
rval
security
.
declareProtected
(
view_management_screens
,
'sort_link'
)
def
sort_link
(
self
,
name
,
id
):
"""
Utility for generating a sort link.
"""
sort_by
,
sort_reverse
=
self
.
_getSortInfo
()
url
=
self
.
absolute_url
()
+
'/manage_stats?sort_by='
+
id
newsr
=
0
if
sort_by
==
id
:
newsr
=
not
sort_reverse
url
=
url
+
'&sort_reverse='
+
(
newsr
and
'1'
or
'0'
)
return
'<a href="%s">%s</a>'
%
(
escape
(
url
,
1
),
escape
(
name
))
security
.
declareProtected
(
'Change cache managers'
,
'manage_invalidate'
)
def
manage_invalidate
(
self
,
paths
,
REQUEST
=
None
):
""" ZMI helper to invalidate an entry """
for
path
in
paths
:
try
:
ob
=
self
.
unrestrictedTraverse
(
path
)
except
(
AttributeError
,
KeyError
):
pass
ob
.
ZCacheable_invalidate
()
if
REQUEST
is
not
None
:
msg
=
'Cache entries invalidated'
return
self
.
manage_stats
(
manage_tabs_message
=
msg
)
InitializeClass
(
RAMCacheManager
)
class
_ByteCounter
:
'''auxiliary file like class which just counts the bytes written.'''
_count
=
0
def
write
(
self
,
bytes
):
self
.
_count
+=
len
(
bytes
)
def
getCount
(
self
):
return
self
.
_count
manage_addRAMCacheManagerForm
=
DTMLFile
(
'dtml/addRCM'
,
globals
())
def
manage_addRAMCacheManager
(
self
,
id
,
REQUEST
=
None
):
'Adds a RAM cache manager to the folder.'
self
.
_setObject
(
id
,
RAMCacheManager
(
id
))
if
REQUEST
is
not
None
:
return
self
.
manage_main
(
self
,
REQUEST
)
src/Products/StandardCacheManagers/__init__.py
deleted
100644 → 0
View file @
3af382d3
##############################################################################
#
# Copyright (c) 2002 Zope Foundation and Contributors.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE
#
##############################################################################
'''
Some standard Zope cache managers from Digital Creations.
$Id$
'''
import
RAMCacheManager
import
AcceleratedHTTPCacheManager
def
initialize
(
context
):
context
.
registerClass
(
RAMCacheManager
.
RAMCacheManager
,
constructors
=
(
RAMCacheManager
.
manage_addRAMCacheManagerForm
,
RAMCacheManager
.
manage_addRAMCacheManager
),
icon
=
"cache.gif"
)
context
.
registerClass
(
AcceleratedHTTPCacheManager
.
AcceleratedHTTPCacheManager
,
constructors
=
(
AcceleratedHTTPCacheManager
.
manage_addAcceleratedHTTPCacheManagerForm
,
AcceleratedHTTPCacheManager
.
manage_addAcceleratedHTTPCacheManager
),
icon
=
"cache.gif"
)
context
.
registerHelp
()
src/Products/StandardCacheManagers/cache.gif
deleted
100644 → 0
View file @
3af382d3
158 Bytes
src/Products/StandardCacheManagers/configure.zcml
deleted
100644 → 0
View file @
3af382d3
<configure xmlns="http://namespaces.zope.org/zope">
<subscriber
for="Products.StandardCacheManagers.RAMCacheManager.RAMCacheManager
OFS.interfaces.IObjectClonedEvent"
handler="Products.StandardCacheManagers.subscribers.cloned" />
<subscriber
for="Products.StandardCacheManagers.RAMCacheManager.RAMCacheManager
zope.lifecycleevent.ObjectRemovedEvent"
handler="Products.StandardCacheManagers.subscribers.removed" />
<subscriber
for="Products.StandardCacheManagers.AcceleratedHTTPCacheManager.AcceleratedHTTPCacheManager
OFS.interfaces.IObjectClonedEvent"
handler="Products.StandardCacheManagers.subscribers.cloned" />
<subscriber
for="Products.StandardCacheManagers.AcceleratedHTTPCacheManager.AcceleratedHTTPCacheManager
zope.lifecycleevent.ObjectRemovedEvent"
handler="Products.StandardCacheManagers.subscribers.removed" />
</configure>
src/Products/StandardCacheManagers/dtml/addAccel.dtml
deleted
100644 → 0
View file @
3af382d3
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add Accelerated HTTP Cache Manager',
)">
<form action="manage_addAcceleratedHTTPCacheManager" method="POST">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value=" Add " />
</div>
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
src/Products/StandardCacheManagers/dtml/addRCM.dtml
deleted
100644 → 0
View file @
3af382d3
<dtml-var manage_page_header>
<dtml-var "manage_form_title(this(), _,
form_title='Add RAM Cache Manager',
)">
<form action="manage_addRAMCacheManager" method="POST">
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-label">
Id
</div>
</td>
<td align="left" valign="top">
<input type="text" name="id" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value=" Add " />
</div>
</td>
</tr>
</table>
</form>
<dtml-var manage_page_footer>
src/Products/StandardCacheManagers/dtml/propsAccel.dtml
deleted
100644 → 0
View file @
3af382d3
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<form action="manage_editProps" method="POST">
<dtml-with getSettings mapping>
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-optional">
Title
</div>
</td>
<td align="left" valign="top">
<input type="text" name="title" size="40"
value="&dtml-title;" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Interval (seconds)
</div>
</td>
<td align="left" valign="top">
<input type="text" name="interval" size="40"
value="&dtml-interval;" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Cache anonymous <br />connections only?
</div>
</td>
<td align="left" valign="top">
<input type="checkbox" name="anonymous_only" value="1"<dtml-if
anonymous_only> checked="checked"</dtml-if> />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Notify URLs (via PURGE)
</div>
</td>
<td align="left" valign="top">
<textarea name="notify_urls:lines" rows="5" cols="30"><dtml-in
notify_urls>&dtml-sequence-item;</dtml-in></textarea>
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value="Save Changes" />
</div>
</td>
</tr>
</table>
</dtml-with>
</form>
<dtml-var manage_page_footer>
src/Products/StandardCacheManagers/dtml/propsRCM.dtml
deleted
100644 → 0
View file @
3af382d3
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<p class="form-help">
The <em>RAM Cache Manager</em> allows you to cache the result of
calling expensive objects, such as Python Scripts and External
Methods, in memory. Because it does <em>not</em> cache HTTP headers,
caching full web pages is generally not advised.
</p>
<form action="manage_editProps" method="POST">
<dtml-with getSettings mapping>
<table cellspacing="0" cellpadding="2" border="0">
<tr>
<td align="left" valign="top">
<div class="form-optional">
Title
</div>
</td>
<td align="left" valign="top">
<input type="text" name="title" size="40"
value="&dtml-title;" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
REQUEST variables
</div>
</td>
<td align="left" valign="top">
<textarea name="request_vars:lines" rows="5" cols="30"><dtml-in
request_vars>&dtml-sequence-item;
</dtml-in></textarea>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Threshold entries
</div>
</td>
<td align="left" valign="top">
<input type="text" name="threshold" size="40"
value="&dtml-threshold;" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Maximum age of a cache entry (seconds)
</div>
</td>
<td align="left" valign="top">
<input type="text" name="max_age" size="40"
value="&dtml-max_age;" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Cleanup interval (seconds)
</div>
</td>
<td align="left" valign="top">
<input type="text" name="cleanup_interval" size="40"
value="&dtml-cleanup_interval;" />
</td>
</tr>
<tr>
<td align="left" valign="top">
</td>
<td align="left" valign="top">
<div class="form-element">
<input class="form-element" type="submit" name="submit"
value="Save Changes" />
</div>
</td>
</tr>
</table>
</dtml-with>
</form>
<dtml-var manage_page_footer>
src/Products/StandardCacheManagers/dtml/statsAccel.dtml
deleted
100644 → 0
View file @
3af382d3
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<p class="form-help">
Cache manager hits generally correspond to HTTP accelerator misses.
A hit is counted in the "authenticated hits" column even if headers
are only set for anonymous requests.
</p>
<dtml-if getCacheReport>
<table width="100%" cellspacing="0" cellpadding="2" border="0">
<tr class="list-header">
<td align="left" valign="top">
<div class="list-nav">
<dtml-var expr="sort_link('Path', 'path')">
</div>
</td>
<td align="left" valign="top">
<div class="list-nav">
<dtml-var expr="sort_link('Anonymous hits', 'anon')">
</div>
</td>
<td align="left" valign="top">
<div class="list-nav">
<dtml-var expr="sort_link('Authenticated hits', 'auth')">
</div>
</td>
</tr>
<dtml-in getCacheReport mapping>
<dtml-if sequence-odd>
<tr class="row-normal">
<dtml-else>
<tr class="row-hilite">
</dtml-if>
<td align="left" valign="top">
<div class="list-item">
<a href="&dtml-path;/ZCacheable_manage">&dtml-path;</a>
</div>
</td>
<td align="left" valign="top">
<div class="list-item">
&dtml-anon;
</div>
</td>
<td align="left" valign="top">
<div class="list-item">
&dtml-auth;
</div>
</td>
</tr>
</dtml-in>
</table>
<dtml-else>
<p class="form-text">
<strong>Nothing is in the cache.</strong>
</p>
</dtml-if>
<dtml-var manage_page_footer>
src/Products/StandardCacheManagers/dtml/statsRCM.dtml
deleted
100644 → 0
View file @
3af382d3
<dtml-var manage_page_header>
<dtml-var manage_tabs>
<p class="form-help">
Memory usage is approximate. It is based on the pickled value of the
cached data. The cache is cleaned up by removing the least frequently
accessed entries since the last cleanup operation. The determination
is made using the <em>recent hits</em> counter.
</p>
<dtml-if getCacheReport>
<form method="post" action="manage_invalidate">
<table width="100%" cellspacing="0" cellpadding="2" border="0">
<tr class="list-header">
<td align="left" valign="top" class="list-nav" width="16">
</td>
<td align="left" valign="top">
<div class="list-nav">
<dtml-var expr="sort_link('Path', 'path')">
</div>
</td>
<td align="left" valign="top">
<div class="list-nav">
<dtml-var expr="sort_link('Hits', 'hits')">
</div>
</td>
<td align="left" valign="top">
<div class="list-nav">
<dtml-var expr="sort_link('Recent Hits', 'counter')">
</div>
</td>
<td align="left" valign="top">
<div class="list-nav">
<dtml-var expr="sort_link('Misses', 'misses')">
</div>
</td>
<td align="left" valign="top">
<div class="list-nav">
<dtml-var expr="sort_link('Memory', 'size')">
</div>
</td>
<td align="left" valign="top">
<div class="list-nav">
<dtml-var expr="sort_link('Views', 'views')">
</div>
</td>
<td align="left" valign="top">
<div class="list-nav">
<dtml-var expr="sort_link('Entries', 'entries')">
</div>
</td>
</tr>
<dtml-in getCacheReport mapping>
<dtml-if sequence-odd>
<tr class="row-normal">
<dtml-else>
<tr class="row-hilite">
</dtml-if>
<td align="left" valign="top" width="16">
<input type="checkbox" name="paths:list" value="&dtml-path;" />
</td>
<td align="left" valign="top">
<div class="list-item">
<a href="&dtml-path;/ZCacheable_manage">&dtml-path;</a>
</div>
</td>
<td align="left" valign="top">
<div class="list-item">
&dtml-hits;
</div>
</td>
<td align="left" valign="top">
<div class="list-item">
&dtml-counter;
</div>
</td>
<td align="left" valign="top">
<div class="list-item">
&dtml-misses;
</div>
</td>
<td align="left" valign="top">
<div class="list-item">
&dtml-size;
</div>
</td>
<td align="left" valign="top">
<div class="list-item">
<dtml-var expr="_.string.join(views, ', ')" html_quote>
</div>
</td>
<td align="left" valign="top">
<div class="list-item">
&dtml-entries;
</div>
</td>
</tr>
</dtml-in>
<tr>
<td width="16"> </td>
<td colspan="7">
<input type="submit" value=" Remove " />
</td>
</tr>
</table>
</form>
<dtml-else>
<p class="form-text">
<strong>Nothing is in the cache.</strong>
</p>
</dtml-if>
<dtml-var manage_page_footer>
src/Products/StandardCacheManagers/help/Accel.stx
deleted
100644 → 0
View file @
3af382d3
Accelerated HTTP Cache Managers
The HTTP protocol provides for headers that can indicate to
downstream proxy caches, browser caches, and dedicated caches that
certain documents and images are cacheable. Most images, for example,
can safely be cached for a long time. Anonymous visits to most
primary pages can be cached as well.
An accelerated HTTP cache manager lets you control the headers that
get sent with the responses to requests so that downstream caches
will know what to cache and for how long. This allows you to reduce
the traffic to your site and handle larger loads than otherwise
possible. You can associate accelerated HTTP cache managers with
any kind of cacheable object that can be viewed through the web.
The main risk in using an accelerated HTTP cache manager involves
a part of a page setting headers that apply to the whole response.
If, for example, your home page contains three parts that are
cacheable and one of those parts is associated with an accelerated
HTTP cache manager, Zope will return the headers set by the part of
the page, making downstream caches think that the whole page should
be cached.
The workaround is simple: don't use an accelerated HTTP cache manager
with objects that make up parts of a page unless you really know
what you're doing.
There are some parameters available for accelerated HTTP cache managers.
The interval is the number of seconds the downstream caches should
cache the object. 3600 seconds, or one hour, is a good default.
If you find that some objects need one interval and other objects
should be set to another interval, use multiple cache managers.
If you set the *cache anonymous connections only* checkbox, you
will reduce the possibility of caching private data.
The *notify URLs* parameter allows you to specify the URLs of
specific downstream caches so they can receive invalidation messages
as 'PURGE' directives. Dedicated HTTP cache software such
as Squid will clear cached data for a given URL when receiving the
'PURGE' directive. (More details below.)
Simple statistics are provided. Remember that the only time Zope
receives a request that goes through an HTTP cache is when the
HTTP cache had a *miss*. So the hits seen by Zope correspond to
misses seen by the HTTP cache. To do traffic analysis, you should
consult the downstream HTTP caches.
When testing the accelerated HTTP cache manager, keep in mind that
the *reload* button on most browsers causes the 'Pragma: no-cache'
header to be sent, forcing HTTP caches to reload the page as well.
Try using telnet, netcat, or tcpwatch to observe the headers.
To allow Zope to execute the Squid PURGE directive, make sure the
following lines or the equivalent are in squid.conf (changing
'localhost' to the correct host name if Squid is on a different
machine)::
acl PURGE method purge
http_access allow localhost
http_access allow purge localhost
http_access deny purge
http_access deny all
src/Products/StandardCacheManagers/help/RAM.stx
deleted
100644 → 0
View file @
3af382d3
RAM Cache Managers
The RAM cache manager allows you to cache the result of calling
expensive objects, such as Python Scripts and External Methods,
in memory. It provides access statistics and simple configuration
options.
Not all objects are appropriate for use with a RAM Cache Manager.
See the **caveats** section below.
Storing the result in memory results in the fastest possible cache
retrieval, but carries some risks. Unconstrained, it can consume too
much RAM. And it doesn't reduce network traffic, it only helps
Zope return a result more quickly.
Fortunately, RAM cache managers have tunable parameters. You can
configure the threshold on the number of entries that should be in
the cache, which defaults to 1000. Reduce it if the cache is taking
up too much memory or increase it if entries are being cleared too
often.
You can also configure the cleanup interval. If the RAM cache is
fluctuating too much in memory usage, reduce the cleanup interval.
Finally, you can configure the list of REQUEST variables that will
be used in the cache key. This can be a simple and effective way
to distinguish requests from authenticated versus anonymous users
or those with session cookies.
If you find that some of your objects need certain cache parameters
while others need somewhat different parameters, create multiple
RAM cache managers.
The 'Statistics' tab allows you to view a summary of the contents
of the cache. Click the column headers to re-sort the list, twice
to sort backwards. You can use the statistics to gauge the
benefit of caching each of your objects. For a given object, if
the number of hits is less than or not much greater than the number
of misses, you probably need to re-evaluate how that object is
cached.
Caveats
You should generally not cache the following with RAM Cache Manager:
* Images
* Files
* Complete web pages
Although Zope does not prevent you from doing so,
it generally does not make sense to associate any of these objects
with a RAM cache manager. The cache will simply not cache image or
file data, since the data is already available in RAM.
In addition, be careful with complete web pages.
The problem is that most cacheable objects will cache only their
return value; important out-of-band information such as the HTTP
response code is typically not cached. For example, if you cache
a page which calls RESPONSE.redirect(), a client that gets
a cache hit will see an HTTP 200 response code instead
of the redirect.
For all of the above objects, another kind of cache manager, an
*accelerated HTTP cache manager*, is available and more suitable.
src/Products/StandardCacheManagers/subscribers.py
deleted
100644 → 0
View file @
3af382d3
##############################################################################
#
# Copyright (c) 2010 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" subscribers to events affecting StandardCacheManagers
"""
def
cloned
(
obj
,
event
):
"""
Reset the Id of the module level cache so the clone gets a different cache
than its source object
"""
obj
.
_resetCacheId
()
def
removed
(
obj
,
event
):
obj
.
_remove_data
()
src/Products/StandardCacheManagers/tests/__init__.py
deleted
100644 → 0
View file @
3af382d3
##############################################################################
#
# Copyright (c) 2005 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" Unit tests for StandardCacheManagers product.
$Id$
"""
src/Products/StandardCacheManagers/tests/test_AcceleratedHTTPCacheManager.py
deleted
100644 → 0
View file @
3af382d3
##############################################################################
#
# Copyright (c) 2005 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" Unit tests for AcceleratedCacheManager module.
$Id$
"""
import
unittest
from
Products.StandardCacheManagers.AcceleratedHTTPCacheManager
\
import
AcceleratedHTTPCache
,
AcceleratedHTTPCacheManager
class
DummyObject
:
def
__init__
(
self
,
path
=
'/path/to/object'
,
urlpath
=
None
):
self
.
path
=
path
if
urlpath
is
None
:
self
.
urlpath
=
path
else
:
self
.
urlpath
=
urlpath
def
getPhysicalPath
(
self
):
return
tuple
(
self
.
path
.
split
(
'/'
))
def
absolute_url_path
(
self
):
return
self
.
urlpath
class
MockResponse
:
status
=
'200'
reason
=
"who knows, I'm just a mock"
def
MockConnectionClassFactory
():
# Returns both a class that mocks an HTTPConnection,
# and a reference to a data structure where it logs requests.
request_log
=
[]
class
MockConnection
:
# Minimal replacement for httplib.HTTPConnection.
def
__init__
(
self
,
host
):
self
.
host
=
host
self
.
request_log
=
request_log
def
request
(
self
,
method
,
path
):
self
.
request_log
.
append
({
'method'
:
method
,
'host'
:
self
.
host
,
'path'
:
path
,})
def
getresponse
(
self
):
return
MockResponse
()
return
MockConnection
,
request_log
class
AcceleratedHTTPCacheTests
(
unittest
.
TestCase
):
def
_getTargetClass
(
self
):
return
AcceleratedHTTPCache
def
_makeOne
(
self
,
*
args
,
**
kw
):
return
self
.
_getTargetClass
()(
*
args
,
**
kw
)
def
test_PURGE_passes_Host_header
(
self
):
_TO_NOTIFY
=
'localhost:1888'
cache
=
self
.
_makeOne
()
cache
.
notify_urls
=
[
'http://%s'
%
_TO_NOTIFY
]
cache
.
connection_factory
,
requests
=
MockConnectionClassFactory
()
dummy
=
DummyObject
()
cache
.
ZCache_invalidate
(
dummy
)
self
.
assertEqual
(
len
(
requests
),
1
)
result
=
requests
[
-
1
]
self
.
assertEqual
(
result
[
'method'
],
'PURGE'
)
self
.
assertEqual
(
result
[
'host'
],
_TO_NOTIFY
)
self
.
assertEqual
(
result
[
'path'
],
dummy
.
path
)
def
test_multiple_notify
(
self
):
cache
=
self
.
_makeOne
()
cache
.
notify_urls
=
[
'http://foo'
,
'bar'
,
'http://baz/bat'
]
cache
.
connection_factory
,
requests
=
MockConnectionClassFactory
()
cache
.
ZCache_invalidate
(
DummyObject
())
self
.
assertEqual
(
len
(
requests
),
3
)
self
.
assertEqual
(
requests
[
0
][
'host'
],
'foo'
)
self
.
assertEqual
(
requests
[
1
][
'host'
],
'bar'
)
self
.
assertEqual
(
requests
[
2
][
'host'
],
'baz'
)
cache
.
ZCache_invalidate
(
DummyObject
())
self
.
assertEqual
(
len
(
requests
),
6
)
def
test_vhost_purging_1447
(
self
):
# Test for http://www.zope.org/Collectors/Zope/1447
cache
=
self
.
_makeOne
()
cache
.
notify_urls
=
[
'http://foo.com'
]
cache
.
connection_factory
,
requests
=
MockConnectionClassFactory
()
dummy
=
DummyObject
(
urlpath
=
'/published/elsewhere'
)
cache
.
ZCache_invalidate
(
dummy
)
# That should fire off two invalidations,
# one for the physical path and one for the abs. url path.
self
.
assertEqual
(
len
(
requests
),
2
)
self
.
assertEqual
(
requests
[
0
][
'path'
],
dummy
.
absolute_url_path
())
self
.
assertEqual
(
requests
[
1
][
'path'
],
dummy
.
path
)
class
CacheManagerTests
(
unittest
.
TestCase
):
def
_getTargetClass
(
self
):
return
AcceleratedHTTPCacheManager
def
_makeOne
(
self
,
*
args
,
**
kw
):
return
self
.
_getTargetClass
()(
*
args
,
**
kw
)
def
_makeContext
(
self
):
from
OFS.Folder
import
Folder
root
=
Folder
()
root
.
getPhysicalPath
=
lambda
:
(
''
,
'some_path'
,)
cm_id
=
'http_cache'
manager
=
self
.
_makeOne
(
cm_id
)
root
.
_setObject
(
cm_id
,
manager
)
manager
=
root
[
cm_id
]
return
root
,
manager
def
test_add
(
self
):
# ensure __init__ doesn't raise errors.
root
,
cachemanager
=
self
.
_makeContext
()
def
test_ZCacheManager_getCache
(
self
):
root
,
cachemanager
=
self
.
_makeContext
()
cache
=
cachemanager
.
ZCacheManager_getCache
()
self
.
assert_
(
isinstance
(
cache
,
AcceleratedHTTPCache
))
def
test_getSettings
(
self
):
root
,
cachemanager
=
self
.
_makeContext
()
settings
=
cachemanager
.
getSettings
()
self
.
assert_
(
'anonymous_only'
in
settings
.
keys
())
self
.
assert_
(
'interval'
in
settings
.
keys
())
self
.
assert_
(
'notify_urls'
in
settings
.
keys
())
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
AcceleratedHTTPCacheTests
))
suite
.
addTest
(
unittest
.
makeSuite
(
CacheManagerTests
))
return
suite
if
__name__
==
'__main__'
:
unittest
.
main
(
defaultTest
=
'test_suite'
)
src/Products/StandardCacheManagers/tests/test_CacheManagerLocation.py
deleted
100644 → 0
View file @
3af382d3
##############################################################################
#
# Copyright (c) 2010 Zope Foundation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" Unit tests for AcceleratedCacheManager module.
$Id$
"""
import
unittest
import
transaction
import
zope.component
from
zope.component
import
testing
as
componenttesting
from
zope.component
import
eventtesting
from
AccessControl
import
SecurityManager
from
AccessControl.SecurityManagement
import
newSecurityManager
from
AccessControl.SecurityManagement
import
noSecurityManager
from
OFS.Folder
import
Folder
from
OFS.tests.testCopySupport
import
CopySupportTestBase
from
OFS.tests.testCopySupport
import
UnitTestSecurityPolicy
from
OFS.tests.testCopySupport
import
UnitTestUser
from
Zope2.App
import
zcml
from
Products.StandardCacheManagers.RAMCacheManager
import
RAMCacheManager
from
Products.StandardCacheManagers.AcceleratedHTTPCacheManager
\
import
AcceleratedHTTPCacheManager
import
Products.StandardCacheManagers
CACHE_META_TYPES
=
tuple
(
dict
(
name
=
instance_class
.
meta_type
,
action
=
'unused_constructor_name'
,
permission
=
"Add %ss"
%
instance_class
.
meta_type
)
for
instance_class
in
(
RAMCacheManager
,
AcceleratedHTTPCacheManager
)
)
class
CacheManagerLocationTests
(
CopySupportTestBase
):
_targetClass
=
None
def
_makeOne
(
self
,
*
args
,
**
kw
):
return
self
.
_targetClass
(
*
args
,
**
kw
)
def
setUp
(
self
):
componenttesting
.
setUp
()
eventtesting
.
setUp
()
zcml
.
load_config
(
'meta.zcml'
,
zope
.
component
)
zcml
.
load_config
(
'configure.zcml'
,
Products
.
StandardCacheManagers
)
folder1
,
folder2
=
self
.
_initFolders
()
folder1
.
all_meta_types
=
folder2
.
all_meta_types
=
CACHE_META_TYPES
self
.
folder1
=
folder1
self
.
folder2
=
folder2
self
.
policy
=
UnitTestSecurityPolicy
()
self
.
oldPolicy
=
SecurityManager
.
setSecurityPolicy
(
self
.
policy
)
cm_id
=
'cache'
manager
=
self
.
_makeOne
(
cm_id
)
self
.
folder1
.
_setObject
(
cm_id
,
manager
)
self
.
cachemanager
=
self
.
folder1
[
cm_id
]
transaction
.
savepoint
(
optimistic
=
True
)
newSecurityManager
(
None
,
UnitTestUser
().
__of__
(
self
.
root
)
)
CopySupportTestBase
.
setUp
(
self
)
def
tearDown
(
self
):
noSecurityManager
()
SecurityManager
.
setSecurityPolicy
(
self
.
oldPolicy
)
del
self
.
oldPolicy
del
self
.
policy
del
self
.
folder2
del
self
.
folder1
self
.
_cleanApp
()
componenttesting
.
tearDown
()
CopySupportTestBase
.
tearDown
(
self
)
def
test_cache_differs_on_copy
(
self
):
# ensure copies don't hit the same cache
cache
=
self
.
cachemanager
.
ZCacheManager_getCache
()
cachemanager_copy
=
self
.
folder2
.
manage_clone
(
self
.
cachemanager
,
'cache_copy'
)
cache_copy
=
cachemanager_copy
.
ZCacheManager_getCache
()
self
.
assertNotEqual
(
cache
,
cache_copy
)
def
test_cache_remains_on_move
(
self
):
# test behaviour of cache on move.
# NOTE: This test verifies current behaviour, but there is no actual
# need for cache managers to maintain the same cache on move.
# if physical path starts being used as a cache key, this test might
# need to be fixed.
cache
=
self
.
cachemanager
.
ZCacheManager_getCache
()
cut
=
self
.
folder1
.
manage_cutObjects
([
'cache'
])
self
.
folder2
.
manage_pasteObjects
(
cut
)
cachemanager_moved
=
self
.
folder2
[
'cache'
]
cache_moved
=
cachemanager_moved
.
ZCacheManager_getCache
()
self
.
assertEqual
(
cache
,
cache_moved
)
def
test_cache_deleted_on_remove
(
self
):
old_cache
=
self
.
cachemanager
.
ZCacheManager_getCache
()
self
.
folder1
.
manage_delObjects
([
'cache'
])
new_cache
=
self
.
cachemanager
.
ZCacheManager_getCache
()
self
.
assertNotEqual
(
old_cache
,
new_cache
)
class
AcceleratedHTTPCacheManagerLocationTests
(
CacheManagerLocationTests
):
_targetClass
=
AcceleratedHTTPCacheManager
class
RamCacheManagerLocationTests
(
CacheManagerLocationTests
):
_targetClass
=
RAMCacheManager
def
test_suite
():
suite
=
unittest
.
TestSuite
()
suite
.
addTest
(
unittest
.
makeSuite
(
AcceleratedHTTPCacheManagerLocationTests
))
suite
.
addTest
(
unittest
.
makeSuite
(
RamCacheManagerLocationTests
))
return
suite
if
__name__
==
'__main__'
:
unittest
.
main
(
defaultTest
=
'test_suite'
)
src/Products/StandardCacheManagers/version.txt
deleted
100644 → 0
View file @
3af382d3
StandardCacheManagers-1-1-0
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment