Annotation of embedaddon/lighttpd/doc/outdated/cml.txt, revision 1.1
1.1 ! misho 1: =========================
! 2: CML (Cache Meta Language)
! 3: =========================
! 4:
! 5: ---------------
! 6: Module: mod_cml
! 7: ---------------
! 8:
! 9: :Author: Jan Kneschke
! 10: :Date: $Date: 2004/11/03 22:26:05 $
! 11: :Revision: $Revision: 1.2 $
! 12:
! 13: :abstract:
! 14: CML is a Meta language to describe the dependencies of a page at one side and building a page from its fragments on the other side using LUA.
! 15:
! 16: .. meta::
! 17: :keywords: lighttpd, cml, lua
! 18:
! 19: .. contents:: Table of Contents
! 20:
! 21: Description
! 22: ===========
! 23:
! 24: CML (Cache Meta Language) wants to solves several problems:
! 25:
! 26: * dynamic content needs caching to perform
! 27: * checking if the content is dirty inside of the application is usually more expensive than sending out the cached data
! 28: * a dynamic page is usually fragmented and the fragments have different livetimes
! 29: * the different fragements can be cached independently
! 30:
! 31: Cache Decision
! 32: --------------
! 33:
! 34: A simple example should show how to a content caching the very simple way in PHP.
! 35:
! 36: jan.kneschke.de has a very simple design:
! 37:
! 38: * the layout is taken from a template in templates/jk.tmpl
! 39: * the menu is generated from a menu.csv file
! 40: * the content is coming from files on the local directory named content-1, content-2 and so on
! 41:
! 42: The page content is static as long non of the those tree items changes. A change in the layout
! 43: is affecting all pages, a change of menu.csv too, a change of content-x file only affects the
! 44: cached page itself.
! 45:
! 46: If we model this in PHP we get: ::
! 47:
! 48: <?php
! 49:
! 50: ## ... fetch all content-* files into $content
! 51: $cachefile = "/cache/dir/to/cached-content";
! 52:
! 53: function is_cachable($content, $cachefile) {
! 54: if (!file_exists($cachefile)) {
! 55: return 0;
! 56: } else {
! 57: $cachemtime = filemtime($cachefile);
! 58: }
! 59:
! 60: foreach($content as $k => $v) {
! 61: if (isset($v["file"]) &&
! 62: filemtime($v["file"]) > $cachemtime) {
! 63: return 0;
! 64: }
! 65: }
! 66:
! 67: if (filemtime("/menu/menu.csv") > $cachemtime) {
! 68: return 0;
! 69: }
! 70: if (filemtime("/templates/jk.tmpl") > $cachemtime) {
! 71: return 0;
! 72: }
! 73: }
! 74:
! 75: if (is_cachable(...), $cachefile) {
! 76: readfile($cachefile);
! 77: exit();
! 78: } else {
! 79: # generate content and write it to $cachefile
! 80: }
! 81: ?>
! 82:
! 83: Quite simple. No magic involved. If the one of the files is new than the cached
! 84: content, the content is dirty and has to be regenerated.
! 85:
! 86: Now let take a look at the numbers:
! 87:
! 88: * 150 req/s for a Cache-Hit
! 89: * 100 req/s for a Cache-Miss
! 90:
! 91: As you can see the increase is not as good as it could be. The main reason as the overhead
! 92: of the PHP interpreter to start up (a byte-code cache has been used here).
! 93:
! 94: Moving these decisions out of the PHP script into a server module will remove the need
! 95: to start PHP for a cache-hit.
! 96:
! 97: To transform this example into a CML you need 'index.cml' in the list of indexfiles
! 98: and the following index.cml file: ::
! 99:
! 100: output_contenttype = "text/html"
! 101:
! 102: b = request["DOCUMENT_ROOT"]
! 103: cwd = request["CWD"]
! 104:
! 105: output_include = { b .. "_cache.html" }
! 106:
! 107: trigger_handler = "index.php"
! 108:
! 109: if file_mtime(b .. "../lib/php/menu.csv") > file_mtime(cwd .. "_cache.html") or
! 110: file_mtime(b .. "templates/jk.tmpl") > file_mtime(cwd .. "_cache.html") or
! 111: file_mtime(b .. "content.html") > file_mtime(cwd .. "_cache.html") then
! 112: return CACHE_MISS
! 113: else
! 114: return CACHE_HIT
! 115: end
! 116:
! 117: Numbers again:
! 118:
! 119: * 4900 req/s for Cache-Hit
! 120: * 100 req/s for Cache-Miss
! 121:
! 122: Content Assembling
! 123: ------------------
! 124:
! 125: Sometimes the different fragment are already generated externally. You have to cat them together: ::
! 126:
! 127: <?php
! 128: readfile("head.html");
! 129: readfile("menu.html");
! 130: readfile("spacer.html");
! 131: readfile("db-content.html");
! 132: readfile("spacer2.html");
! 133: readfile("news.html");
! 134: readfile("footer.html");
! 135: ?>
! 136:
! 137: We we can do the same several times faster directly in the webserver.
! 138:
! 139: Don't forget: Webserver are built to send out static content, that is what they can do best.
! 140:
! 141: The index.cml for this looks like: ::
! 142:
! 143: output_contenttype = "text/html"
! 144:
! 145: cwd = request["CWD"]
! 146:
! 147: output_include = { cwd .. "head.html",
! 148: cwd .. "menu.html",
! 149: cwd .. "spacer.html",
! 150: cwd .. "db-content.html",
! 151: cwd .. "spacer2.html",
! 152: cwd .. "news.html",
! 153: cwd .. "footer.html" }
! 154:
! 155: return CACHE_HIT
! 156:
! 157: Now we get about 10000 req/s instead of 600 req/s.
! 158:
! 159: Power Magnet
! 160: ------------
! 161:
! 162: Next to all the features about Cache Decisions CML can do more. Starting
! 163: with lighttpd 1.4.9 a power-magnet was added which attracts each request
! 164: and allows you to manipulate the request for your needs.
! 165:
! 166: We want to display a maintainance page by putting a file in a specified
! 167: place:
! 168:
! 169: We enable the power magnet: ::
! 170:
! 171: cml.power-magnet = "/home/www/power-magnet.cml"
! 172:
! 173: and create /home/www/power-magnet.cml with: ::
! 174:
! 175: dr = request["DOCUMENT_ROOT"]
! 176:
! 177: if file_isreg(dr .. 'maintainance.html') then
! 178: output_include = { 'maintainance.html' }
! 179: return CACHE_HIT
! 180: end
! 181:
! 182: return CACHE_MISS
! 183:
! 184: For each requested file the /home/www/power-magnet.cml is executed which
! 185: checks if maintainance.html exists in the docroot and displays it
! 186: instead of handling the usual request.
! 187:
! 188: Another example, create thumbnail for requested image and serve it instead
! 189: of sending the big image: ::
! 190:
! 191: ## image-url is /album/baltic_winter_2005.jpg
! 192: ## no params -> 640x480 is served
! 193: ## /album/baltic_winter_2005.jpg/orig for full size
! 194: ## /album/baltic_winter_2005.jpg/thumb for thumbnail
! 195:
! 196: dr = request["DOCUMENT_ROOT"]
! 197: sn = request["SCRIPT_NAME"]
! 198:
! 199: ## to be continued :) ...
! 200:
! 201: trigger_handler = '/gen_image.php'
! 202:
! 203: return CACHE_MISS
! 204:
! 205:
! 206: Installation
! 207: ============
! 208:
! 209: You need `lua <http://www.lua.org/>`_ and should install `libmemcache-1.3.x <http://people.freebsd.org/~seanc/libmemcache/>`_ and have to configure lighttpd with: ::
! 210:
! 211: ./configure ... --with-lua --with-memcache
! 212:
! 213: To use the plugin you have to load it: ::
! 214:
! 215: server.modules = ( ..., "mod_cml", ... )
! 216:
! 217: Options
! 218: =======
! 219:
! 220: :cml.extension:
! 221: the file extension that is bound to the cml-module
! 222: :cml.memcache-hosts:
! 223: hosts for the memcache.* functions
! 224: :cml.memcache-namespace:
! 225: (not used yet)
! 226: :cml.power-magnet:
! 227: a cml file that is executed for each request
! 228:
! 229: Language
! 230: ========
! 231:
! 232: The language used for CML is provided by `LUA <http://www.lua.org/>`_.
! 233:
! 234: Additionally to the functions provided by lua mod_cml provides: ::
! 235:
! 236: tables:
! 237:
! 238: request
! 239: - REQUEST_URI
! 240: - SCRIPT_NAME
! 241: - SCRIPT_FILENAME
! 242: - DOCUMENT_ROOT
! 243: - PATH_INFO
! 244: - CWD
! 245: - BASEURI
! 246:
! 247: get
! 248: - parameters from the query-string
! 249:
! 250: functions:
! 251: string md5(string)
! 252: number file_mtime(string)
! 253: string memcache_get_string(string)
! 254: number memcache_get_long(string)
! 255: boolean memcache_exists(string)
! 256:
! 257:
! 258: What ever your script does, it has to return either CACHE_HIT or CACHE_MISS.
! 259: It case a error occures check the error-log, the user will get a error 500. If you don't like
! 260: the standard error-page use ``server.errorfile-prefix``.
! 261:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>