|
1 | 1 | --- |
2 | 2 | myst: |
3 | 3 | html_meta: |
4 | | - "description": "Caching in-memory support for Plone" |
5 | | - "property=og:description": "Caching in-memory support for Plone" |
6 | | - "property=og:title": "Caching in-memory support for Plone" |
7 | | - "keywords": "Plone, deployment, automation, caching" |
| 4 | + "description": "In-memory cache support in Plone" |
| 5 | + "property=og:description": "In-memory cache support in Plone" |
| 6 | + "property=og:title": "In-memory cache support in Plone" |
| 7 | + "keywords": "Plone, deployment, automation, caching, In-memory, RAM" |
8 | 8 | --- |
9 | 9 |
|
10 | 10 | (caching-ram-cache-label)= |
11 | 11 |
|
12 | | -# The RAM cache |
| 12 | +# RAM cache |
13 | 13 |
|
14 | | -In addition to caching content in users' browsers (through setting appropriate response headers) and a caching proxy, Plone can cache certain information in memory. |
| 14 | +In addition to caching content in users' browsers through setting appropriate response headers and a caching proxy, Plone can cache certain information in memory. |
15 | 15 | This is done in two main ways: |
16 | 16 |
|
17 | | -* Developers may use the `plone.memoize` package's `ram` module to cache the results of certain functions in RAM. |
18 | | - For example, some viewlets and portlets cache their rendered output in RAM for a time, alleviating the need to calculate them every time. |
| 17 | +- Developers may use the `plone.memoize` package's `ram` module to cache the results of certain functions in RAM. |
| 18 | + For example, some viewlets and portlets cache their rendered output in RAM for a time, alleviating the need to calculate them every time. |
| 19 | +- Some caching operations may cache an entire response in memory, so that they can later intercept the request to return a cached response. |
19 | 20 |
|
20 | | -* Some caching operations may cache an entire response in memory, so that they can later intercept the request to return a cached response. |
| 21 | +Caching in RAM in Zope is not as efficient as caching in a proxy, for a number of reasons. |
21 | 22 |
|
22 | | -Caching in RAM in Zope is not as efficient as caching in a proxy, for a number of reasons: |
| 23 | +- Zope still has to perform traversal, security, transaction management, and so on before serving a request with a RAM-cached response. |
| 24 | +- Zope's use of memory is not as efficient as that of a finely optimised caching proxy. |
| 25 | +- Storing lots of content in RAM may compete with the standard ZODB object cache and other memory pools used by Zope, thus slowing down Zope overall. |
| 26 | +- In multi-client ZEO setups, the RAM cache is (by default at least) not shared among instances, although it is shared among threads in that instance. |
| 27 | + Thus each Plone client process will maintain its own cache. |
23 | 28 |
|
24 | | -* Zope still has to perform traversal, security, transaction management and so on before serving a request with a RAM-cached response. |
25 | | - |
26 | | -* Zope's use of memory is not as efficient as that of a finely optimised caching proxy. |
27 | | - |
28 | | -* Storing lots of content in RAM may compete with the standard ZODB object cache and other memory pools used by Zope, thus slowing down Zope overall. |
29 | | - |
30 | | -* In multi-client ZEO setups, the RAM cache is (by default at least) not shared among instances (though it is shared among threads in that instance). |
31 | | - Thus, each Plone client process will maintain its own cache. |
32 | | - |
33 | | -You can use the *RAM cache* tab in the caching control panel to view statistics about the use of the RAM cache. |
34 | | -On the *Change settings* tab, you can also control the size of the cache, and the frequency with which it is purged of old items. |
| 29 | +You can use the {guilabel}`RAM cache` tab in the Caching control panel to view statistics about the use of the RAM cache. |
| 30 | +On the {guilabel}`Change settings` tab, you can also control the size of the cache, and the frequency with which it is purged of old items. |
35 | 31 |
|
36 | 32 |
|
37 | 33 | ## Alternative RAM cache implementations |
38 | 34 |
|
39 | 35 | The RAM cache exposed through `plone.memoize.ram` is looked up via an `ICacheChoser` utility. |
40 | 36 | The default implementation looks up a `zope.ramcache.interfaces.ram.IRAMCache` utility. |
41 | | -Plone installs a local such utility (to allows its settings to be persisted - the cache itself is not persistent), which is shared by all users of the cache. |
| 37 | +Plone installs a local utility (to allow its settings to be persisted; the cache itself is not persistent), which is shared by all users of the cache. |
42 | 38 |
|
43 | 39 | You can provide your own `ICacheChooser` utility to change this policy, by installing this as a local utility or overriding it in `overrides.zcml`. |
44 | 40 | One reason to do this may be to back the cache with a [memcached](https://memcached.org/) server, which would allow a single cache to be shared among multiple Zope clients. |
45 | 41 |
|
46 | | -Below is a sketch of such a cache chooser, courtesy of Wojciech Lichota: |
| 42 | +Below is a sketch of such a cache chooser, courtesy of Wojciech Lichota. |
47 | 43 |
|
48 | 44 | ```python |
49 | | - from plone.memoize.interfaces import ICacheChooser |
50 | | - from plone.memoize.ram import MemcacheAdapter |
51 | | - from pylibmc import Client |
52 | | - from threading import local |
53 | | - from zope.interface import implementer |
54 | | - |
55 | | - @implementer(ICacheChooser) |
56 | | - class MemcachedCacheChooser(): |
57 | | - _v_thread_local = local() |
58 | | - |
59 | | - def getClient(self): |
60 | | - """ |
61 | | - Return thread local connection to memcached. |
62 | | - """ |
63 | | - connection = getattr(self._v_thread_local, 'connection', None) |
64 | | - if connection is None: |
65 | | - connection = Client(['127.0.0.1:11211']) |
66 | | - self._v_thread_local.connection = connection |
67 | | - |
68 | | - return connection |
69 | | - |
70 | | - def __call__(self, fun_name): |
71 | | - """ |
72 | | - Create new adapter for plone.memoize.ram. |
73 | | - """ |
74 | | - return MemcacheAdapter(client=self.getClient(), globalkey=fun_name) |
| 45 | +from plone.memoize.interfaces import ICacheChooser |
| 46 | +from plone.memoize.ram import MemcacheAdapter |
| 47 | +from pylibmc import Client |
| 48 | +from threading import local |
| 49 | +from zope.interface import implementer |
| 50 | + |
| 51 | +@implementer(ICacheChooser) |
| 52 | +class MemcachedCacheChooser(): |
| 53 | + _v_thread_local = local() |
| 54 | + |
| 55 | + def getClient(self): |
| 56 | + """ |
| 57 | + Return thread local connection to memcached. |
| 58 | + """ |
| 59 | + connection = getattr(self._v_thread_local, 'connection', None) |
| 60 | + if connection is None: |
| 61 | + connection = Client(['127.0.0.1:11211']) |
| 62 | + self._v_thread_local.connection = connection |
| 63 | + |
| 64 | + return connection |
| 65 | + |
| 66 | + def __call__(self, fun_name): |
| 67 | + """ |
| 68 | + Create new adapter for plone.memoize.ram. |
| 69 | + """ |
| 70 | + return MemcacheAdapter(client=self.getClient(), globalkey=fun_name) |
75 | 71 | ``` |
76 | 72 |
|
77 | | -You could install this with the following lines in an overrides.zcml: |
| 73 | +You could install this with the following lines in an `overrides.zcml`. |
78 | 74 |
|
79 | 75 | ```xml |
80 | | - <utility factory=".memcached.MemcachedCacheChooser" /> |
| 76 | +<utility factory=".memcached.MemcachedCacheChooser" /> |
81 | 77 | ``` |
0 commit comments