parser

Operator ^cache[]

Misha v.3 [October 19, 2005]

“Caching” is the word many of us have heard and some of us may even have a feeling that this machinery has been specifically designed to speed up data processing.

The caching machinery allows us to bypass repeating calculations, taking only the ready-to-use result that has been previously saved.

Caching complicated pages for at least a few minutes dramatically relieves the pressure on server, and, as long as such short-term caching is concerned, we don’t have to create a cache-dumping machinery to be triggered upon each change made through administrator interface; although a long-term caching together with cache-dumping machinery will relieve pressure even more.

In Parser 3, this task is tackled by the operator ^cache[file](seconds){code}.

The root directory auto.p is like this:

@auto[]
$sRequest[$request:uri]
$sQuery[$request:query]

# define default value for cache — 3600 seconds
$iDefaultCacheTime(3600)

^if(
#	the form was submitted using method POST – turn off caching
	$env:REQUEST_METHOD eq "POST"
#	the request came from a local machine – turn off cache
#	(most useful for developers – cache doesn’t interfere)
	|| ^env:REMOTE_ADDR.match[^^192\.168][]
){
	$bDisableCache(1)
}{
	$bDisableCache(0)
}

^if($bDisableCache){
	$iTime(0)
#	define cache-gag key...
	$sKey[dummy]
}{
#	if caching is on – load the table with caching preiod entries
	$tCache[^table::load[/../data/_cache.cfg]]

#	look through the table and see if there is a specific caching period specified for the requested page
#	hint: if there is a rigid format for the data in this file, the entry can be looked for by means of ^locate[] or
#		the table can be converted into hash and look up by appropriate means
	^tCache.menu{
		^if(^sRequest.match[^^^trim[$tCache.url;/]][]){$iTime[$tCache.time]}
	}
	$iTime(^iTime.int($iDefaultCacheTime))

#	As long as we may get a VERY long $request:query – we should "fold" it,
#	by using the in-built math:md5

#	table for replacements in query. This is an example. We should throw away all trash
	$tRepl[^table::create[nameless]{?	&&^#0Atemp=aaa	&&}]

#	clear query of pieces we don’t need.
	$sQuery[^sQuery.replace[$tRepl]]
	$sQuery[^sQuery.match[&{2,}][g]{}]

#	we need the filename to create the key
	$tPart[^sRequest.split[?][hl]]

#	finally, create the caching key: full path + encrypted query
	$sKey[$tPart.0^if(def $sQuery){^math:md5[$sQuery]}]
}
#end @auto[]


@myCache[body]
# $CACHE_DIR contains the path to where the cache data is stored
^cache[$CACHE_DIR/$sKey]($iTime){
	$body
}
#end @myCache[]

Here is an example of how it’s triggered e.g. from index.html:

@main[]
^myCache{
	^rem{ the code to generate the page. }
	^rem{ while calling the method myCache do not blunder: do not use square brackets... }
}
#end @main[]

If you have studied my previous examples, you must have noticed my operator ^location[]:

@location[sTargetUrl]
^try{
	^cache(0)
}{
	$exception.handled(1)
}
$response:location[$sTargetUrl]

It’s done like this just in case I will need to redirect a user to a different URL (for example, when a user has entered a URL pointing to the news which doesn’t exist and I need to output 404 message).

In this case, I use my ^Lib:location[] instead of the standard $response:location and I’m sure the request with this URL will not be stored in cache (why should it be there, for God’s sake?)

The code given above is a bit shortened and it has certain inconsistencies:

It should be noted that this is just one way of using the operator ^cache[], one of great many ways...

It should be remembered that the content of cache will be output to the visitors until its life time has expired. During this life time, the code inside the operator will not be executed. If you need the cache-dumping to follow your highly specific, genuine idea, just make it happen. The easiest way to do it is clear the entire cache content upon each change through administrator interface.

Note! As long as this example is just a theoretic representation based on my code, it may contain syntactical or other mistakes :).

This simple example which was described above works fine not always. Sometime we want to set to browser special HTTP headers ($response:status[404], $response:last-modified[...] for example). In this case all works fine only when we generate page content but not take it from cache because of cache operator works with page content only and know nothing about any HTTP headers.

For cache page with headers I wrote class cachepage which have the similar syntax and can be used instead of cache operator. Using this class the index.html from above example will be slightly different (and method @myCache[] don't needed anymore):

@main[][oCachePage]
^use[CachePage.p]
$oCachePage[^CachePage::create[
	$.sCacheDir[$CACHE_DIR]
]]

^oCachePage.run[$sKey]($iTime){
	^rem{ the code to generate the page. }
	^rem{ do not blunder: do not use square brackets... }
}
#end @main[]
Download:

CachePage.zip (02.04.2012  1.6 KB)
Class for cache whole page with HTTP headers