summaryrefslogtreecommitdiff
path: root/docs/devel_guide_src/cache.tex
diff options
context:
space:
mode:
Diffstat (limited to 'docs/devel_guide_src/cache.tex')
-rwxr-xr-xdocs/devel_guide_src/cache.tex365
1 files changed, 365 insertions, 0 deletions
diff --git a/docs/devel_guide_src/cache.tex b/docs/devel_guide_src/cache.tex
new file mode 100755
index 0000000..043b8cf
--- /dev/null
+++ b/docs/devel_guide_src/cache.tex
@@ -0,0 +1,365 @@
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\section{Caching placeholders and \#cache}
+\label{cache}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Dynamic placeholder -- no cache}
+\label{cache.dynamic}
+
+The template:
+\begin{verbatim}
+Dynamic variable: $voom
+\end{verbatim}
+
+The command line and the output:
+\begin{verbatim}
+% voom='Voom!' python x.py --env
+Dynamic variable: Voom!
+\end{verbatim}
+
+The generated code:
+\begin{verbatim}
+write('Dynamic variable: ')
+write(filter(VFS(SL,"voom",1))) # generated from '$voom' at line 1, col 20.
+write('\n')
+\end{verbatim}
+
+Just what we expected, like any other dynamic placeholder.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Static placeholder}
+\label{cache.static}
+
+The template:
+\begin{verbatim}
+Cached variable: $*voom
+\end{verbatim}
+
+The command line and output:
+\begin{verbatim}
+% voom='Voom!' python x.py --env
+Cached variable: Voom!
+\end{verbatim}
+
+The generated code, with line numbers:
+\begin{verbatim}
+ 1 write('Cached variable: ')
+ 2 ## START CACHE REGION: at line, col (1, 19) in the source.
+ 3 RECACHE = True
+ 4 if not self._cacheData.has_key('19760169'):
+ 5 pass
+ 6 else:
+ 7 RECACHE = False
+ 8 if RECACHE:
+ 9 orig_trans = trans
+10 trans = cacheCollector = DummyTransaction()
+11 write = cacheCollector.response().write
+12 write(filter(VFS(SL,"voom",1))) # generated from '$*voom' at line 1,
+ # col 19.
+13 trans = orig_trans
+14 write = trans.response().write
+15 self._cacheData['19760169'] = cacheCollector.response().getvalue()
+16 del cacheCollector
+17 write(self._cacheData['19760169'])
+18 ## END CACHE REGION
+
+19 write('\n')
+\end{verbatim}
+
+That one little star generated a whole lotta code. First, instead of an
+ordinary \code{VFS} lookup (searchList) lookup, it converted the
+placeholder to a lookup in the \code{.\_cacheData} dictionary. Cheetah also
+generated a unique key (\code{'19760169'}) for our cached item -- this is its
+cache ID.
+
+Second, Cheetah put a pair of if-blocks before the \code{write}. The first
+(lines 3-7) determine whether the cache value is missing or out of date, and
+sets local variable \code{RECACHE} true or false.
+This stanza may look unnecessarily verbose -- lines 3-7 could be eliminated if
+line 8 was changed to
+\begin{verbatim}
+if not self._cacheData.has_key('19760169'):
+\end{verbatim}
+-- but this model is expandable for some of the cache features we'll see below.
+
+The second if-block, lines 8-16, do the cache updating if necessary.
+Clearly, the programmer is trying to stick as close to normal (dynamic)
+workflow as possible. Remember that \code{write}, even though it looks like a
+local function, is actually a method of a file-like object. So we create a
+temporary file-like object to divert the \code{write} object into, then read
+the result and stuff it into the cache.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Timed-refresh placeholder}
+\label{cache.timed}
+
+The template:
+\begin{verbatim}
+Timed cache: $*.5m*voom
+\end{verbatim}
+
+The command line and the output:
+\begin{verbatim}
+% voom='Voom!' python x.py --env
+Timed cache: Voom!
+\end{verbatim}
+
+The generated method's docstring:
+\begin{verbatim}
+"""
+This is the main method generated by Cheetah
+This cache will be refreshed every 30.0 seconds.
+"""
+\end{verbatim}
+
+The generated code:
+\begin{verbatim}
+ 1 write('Timed cache: ')
+ 2 ## START CACHE REGION: at line, col (1, 15) in the source.
+ 3 RECACHE = True
+ 4 if not self._cacheData.has_key('55048032'):
+ 5 self.__cache55048032__refreshTime = currentTime() + 30.0
+ 6 elif currentTime() > self.__cache55048032__refreshTime:
+ 7 self.__cache55048032__refreshTime = currentTime() + 30.0
+ 8 else:
+ 9 RECACHE = False
+10 if RECACHE:
+11 orig_trans = trans
+12 trans = cacheCollector = DummyTransaction()
+13 write = cacheCollector.response().write
+14 write(filter(VFS(SL,"voom",1))) # generated from '$*.5m*voom' at
+ # line 1, col 15.
+15 trans = orig_trans
+16 write = trans.response().write
+17 self._cacheData['55048032'] = cacheCollector.response().getvalue()
+18 del cacheCollector
+19 write(self._cacheData['55048032'])
+20 ## END CACHE REGION
+
+21 write('\n')
+\end{verbatim}
+
+This code is identical to the static cache example except for the docstring
+and the first if-block. (OK, so the cache ID is different and the comment on
+line 14 is different too. Big deal.)
+
+Each timed-refresh cache item has a corrsponding private attribute
+\code{.\_\_cache\#\#\#\#\#\#\#\#\_\_refreshTime} giving the refresh time
+in ticks (=seconds since January 1, 1970). The first if-block (lines 3-9)
+checks whether the cache value is missing or its update time has passed, and if
+so, sets \code{RECACHE} to true and also schedules another refresh at the next
+interval.
+
+The method docstring reminds the user how often the cache will be refreshed.
+This information is unfortunately not as robust as it could be. Each
+timed-cache placeholder blindly generates a line in the docstring. If all
+refreshes are at the same interval, there will be multiple identical lines
+in the docstring. If the refreshes are at different intervals, you get a
+situation like this:
+\begin{verbatim}
+"""
+This is the main method generated by Cheetah
+This cache will be refreshed every 30.0 seconds.
+This cache will be refreshed every 60.0 seconds.
+This cache will be refreshed every 120.0 seconds.
+"""
+\end{verbatim}
+The docstring tells only that ``something'' will be refreshed every 60.0
+seconds, but doesn't reveal {\em which} placeholder that is. Only if you
+know the relative order of the placeholders in the template can you figure
+that out.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{Timed-refresh placeholder with braces}
+\label{cache.timed.braces}
+
+This example is the same but with the long placeholder syntax. It's here
+because it's a Cheetah FAQ whether to put the cache interval inside or outside
+the braces. (It's also here so I can look it up because I frequently forget.)
+The answer is: outside. The braces go around only the placeholder name (and
+perhaps some output-filter arguments.)
+
+The template:
+\begin{verbatim}
+Timed with {}: $*.5m*{voom}
+\end{verbatim}
+
+The output:
+\begin{verbatim}
+Timed with {}: Voom!
+\end{verbatim}
+
+The generated code differs only in the comment. Inside the cache-refresh
+if-block:
+\begin{verbatim}
+write(filter(VFS(SL,"voom",1))) # generated from '$*.5m*{voom}' at line 1,
+ #col 17.
+\end{verbatim}
+
+If you try to do it this way:
+\begin{verbatim}
+Timed with {}: ${*.5m*voom} ## Wrong!
+\end{verbatim}
+you get:
+\begin{verbatim}
+Timed with {}: ${*.5m*voom}
+\end{verbatim}
+\verb+${+ is not a valid placeholder, so it gets treated as ordinary text.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{\#cache}
+\label{cache.directive}
+
+The template:
+\begin{verbatim}
+#cache
+This is a cached region. $voom
+#end cache
+\end{verbatim}
+
+The output:
+\begin{verbatim}
+This is a cached region. Voom!
+\end{verbatim}
+
+The generated code:
+\begin{verbatim}
+ 1 ## START CACHE REGION: at line, col (1, 1) in the source.
+ 2 RECACHE = True
+ 3 if not self._cacheData.has_key('23711421'):
+ 4 pass
+ 5 else:
+ 6 RECACHE = False
+ 7 if RECACHE:
+ 8 orig_trans = trans
+ 9 trans = cacheCollector = DummyTransaction()
+10 write = cacheCollector.response().write
+11 write('This is a cached region. ')
+12 write(filter(VFS(SL,"voom",1))) # generated from '$voom' at line 2,
+ # col 27.
+13 write('\n')
+14 trans = orig_trans
+15 write = trans.response().write
+16 self._cacheData['23711421'] = cacheCollector.response().getvalue()
+17 del cacheCollector
+18 write(self._cacheData['23711421'])
+19 ## END CACHE REGION
+\end{verbatim}
+
+This is the same as the \code{\$*voom} example, except that the plain text
+around the placeholder is inside the second if-block.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{\#cache with timer and id}
+\label{cache.directive.timer}
+
+The template:
+\begin{verbatim}
+#cache timer='.5m', id='cache1'
+This is a cached region. $voom
+#end cache
+\end{verbatim}
+
+The output:
+\begin{verbatim}
+This is a cached region. Voom!
+\end{verbatim}
+
+The generated code is the same as the previous example except the first
+if-block:
+\begin{verbatim}
+RECACHE = True
+if not self._cacheData.has_key('13925129'):
+ self._cacheIndex['cache1'] = '13925129'
+ self.__cache13925129__refreshTime = currentTime() + 30.0
+elif currentTime() > self.__cache13925129__refreshTime:
+ self.__cache13925129__refreshTime = currentTime() + 30.0
+else:
+ RECACHE = False
+\end{verbatim}
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+\subsection{\#cache with test: expression and method conditions}
+\label{cache.directive.test}
+
+The template:
+\begin{verbatim}
+#cache test=$isDBUpdated
+This is a cached region. $voom
+#end cache
+\end{verbatim}
+
+(Analysis postponed: bug in Cheetah produces invalid Python.)
+
+%The output:
+%\begin{verbatim}
+%\end{verbatim}
+
+%The generated code:
+%\begin{verbatim}
+%\end{verbatim}
+
+
+The template:
+\begin{verbatim}
+#cache id='cache1', test=($isDBUpdated or $someOtherCondition)
+This is a cached region. $voom
+#end cache
+\end{verbatim}
+
+The output:
+\begin{verbatim}
+This is a cached region. Voom!
+\end{verbatim}
+
+The first if-block in the generated code:
+\begin{verbatim}
+RECACHE = True
+if not self._cacheData.has_key('36798144'):
+ self._cacheIndex['cache1'] = '36798144'
+elif (VFS(SL,"isDBUpdated",1) or VFS(SL,"someOtherCondition",1)):
+ RECACHE = True
+else:
+ RECACHE = False
+\end{verbatim}
+The second if-block is the same as in the previous example. If you leave
+out the \code{()} around the test expression, the result is the same, although
+it may be harder for the template maintainer to read.
+
+You can even combine arguments, although this is of questionable value.
+
+The template:
+\begin{verbatim}
+#cache id='cache1', timer='30m', test=$isDBUpdated or $someOtherCondition
+This is a cached region. $voom
+#end cache
+\end{verbatim}
+
+The output:
+\begin{verbatim}
+This is a cached region. Voom!
+\end{verbatim}
+
+The first if-block:
+\begin{verbatim}
+RECACHE = True
+if not self._cacheData.has_key('88939345'):
+ self._cacheIndex['cache1'] = '88939345'
+ self.__cache88939345__refreshTime = currentTime() + 1800.0
+elif currentTime() > self.__cache88939345__refreshTime:
+ self.__cache88939345__refreshTime = currentTime() + 1800.0
+elif VFS(SL,"isDBUpdated",1) or VFS(SL,"someOtherCondition",1):
+ RECACHE = True
+else:
+ RECACHE = False
+\end{verbatim}
+
+We are planning to add a \code{'varyBy'} keyword argument in the future that
+will allow separate cache instances to be created for a variety of conditions,
+such as different query string parameters or browser types. This is inspired by
+ASP.net's varyByParam and varyByBrowser output caching keywords. Since this is
+not implemented yet, I cannot provide examples here.
+
+% Local Variables:
+% TeX-master: "devel_guide"
+% End: