Thu Nov 17 03:10:28 UTC 2005 Alberto Bertogli * Implement a simple cache. This patch implements a very simple but effective cache, so darcsweb can avoid regenerating everything all the time. Based on an idea from Alexandre Rossi. diff -rN -u old-darcsweb/config.py.sample new-darcsweb/config.py.sample --- old-darcsweb/config.py.sample 2016-02-07 22:12:59.000000000 +0000 +++ new-darcsweb/config.py.sample 2016-02-07 22:12:59.000000000 +0000 @@ -29,6 +29,17 @@ # alternative footer here; it's optional, of course #footer = "I don't like shoes" + # It is possible to have a cache where darcsweb will store the pages + # it generates; entries are automatically updated when the repository + # changes. This will speed things up significatively, specially for + # popular sites. + # It's recommended that you clean the directory with some regularity, + # to avoid having too many unused files. A simple rm will do just + # fine. + # If you leave the entry commented, no cache will be ever used; + # otherwise the directory is assumed to exist and be writeable. + #cachedir = '/tmp/darcsweb-cache' + # # From now on, every class is a repo configuration, with the same format diff -rN -u old-darcsweb/darcsweb.cgi new-darcsweb/darcsweb.cgi --- old-darcsweb/darcsweb.cgi 2016-02-07 22:12:59.000000000 +0000 +++ new-darcsweb/darcsweb.cgi 2016-02-07 22:12:59.000000000 +0000 @@ -13,6 +13,7 @@ import string import time import stat +import sha import cgi import cgitb; cgitb.enable() import urllib @@ -384,6 +385,91 @@ print "Content-type: text/plain; charset=utf-8\n" + +# +# basic caching +# + +class Cache: + def __init__(self, basedir, url): + self.basedir = basedir + self.url = url + self.fname = sha.sha(url).hexdigest() + self.file = None + self.mode = None + self.real_stdout = sys.stdout + + def open(self): + "Returns 1 on hit, 0 on miss" + fname = self.basedir + '/' + self.fname + + if not os.access(fname, os.R_OK): + # the file doesn't exist, direct miss + pid = str(os.getpid()) + fname = self.basedir + '/.' + self.fname + '-' + pid + self.file = open(fname, 'w') + self.mode = 'w' + + # step over stdout so when "print" tries to write + # output, we get it first + sys.stdout = self + return 0 + + inv = config.repodir + '/_darcs/inventory' + cache_lastmod = os.stat(fname).st_mtime + repo_lastmod = os.stat(inv).st_mtime + + if repo_lastmod > cache_lastmod: + # the entry is too old, remove it and return a miss + close(self.file) + os.unlink(fname) + + pid = str(os.getpid()) + fname = self.basedir + '/.' + self.fname + '-' + pid + self.file = open(fname, 'w') + self.mode = 'w' + sys.stdout = self + return 0 + + # the entry is still valid, hit! + self.file = open(fname, 'r') + self.mode = 'r' + return 1 + + + def dump(self): + for l in self.file: + self.real_stdout.write(l) + + def write(self, s): + # this gets called from print, because we replaced stdout with + # ourselves + self.file.write(s) + self.real_stdout.write(s) + + def close(self): + if self.file: + self.file.close() + sys.stdout = self.real_stdout + if self.mode == 'w': + pid = str(os.getpid()) + fname1 = self.basedir + '/.' + self.fname + '-' + pid + fname2 = self.basedir + '/' + self.fname + os.rename(fname1, fname2) + self.mode = 'c' + + def cancel(self): + "Like close() but don't save the entry." + if self.file: + self.file.close() + sys.stdout = self.real_stdout + if self.mode == 'w': + pid = str(os.getpid()) + fname = self.basedir + '/.' + self.fname + '-' + pid + os.unlink(fname) + self.mode = 'c' + + # # darcs repo manipulation # @@ -1693,7 +1779,6 @@ print_header() print "

Error! Malformed query

" print_footer() - sys.exit(1) def do_listrepos(): @@ -1860,6 +1945,11 @@ These are all the available repositories.
""" + if "cachedir" in dir(base): + config.cachedir = base.cachedir + else: + config.cachedir = None + if name and "footer" in dir(c): config.footer = c.footer elif "footer" in dir(base): @@ -1869,6 +1959,7 @@ + "crece desde el pie" + # # main # @@ -1892,6 +1983,18 @@ else: action = filter_act(form["a"].value) +# check if we have the page in the cache +if config.cachedir: + url_request = os.environ['QUERY_STRING'] + cache = Cache(config.cachedir, url_request) + if cache.open(): + # we have a hit, dump and run + cache.dump() + cache.close() + sys.exit(0) + # if there is a miss, the cache will step over stdout, intercepting + # all "print"s and writing them to the cache file automatically + # see what should we do according to the received action if action == "summary": @@ -2021,6 +2124,9 @@ else: action = "invalid query" do_die() + cache.cancel() +if config.cachedir: + cache.close()