# # # patch "README" # from [9f8f3733a57d238f540764b3ad8bd7ed0cf27c10] # to [1bfe02c50e6a3cf27edbf7a5f1927a26101beaf4] # # patch "tracvc/mtn/backend.py" # from [96c10000b1c2e58cef92cb6efe3563cd92a192b8] # to [16047bbc0b40cabc3375d8fa43017c916c23d15b] # # patch "tracvc/mtn/cache.py" # from [74ba6b640de58de20e8922c97eda6f77aecc2a27] # to [4a30ff0444dffafb15cdab7d65908b41b99692fd] # ============================================================ --- README 9f8f3733a57d238f540764b3ad8bd7ed0cf27c10 +++ README 1bfe02c50e6a3cf27edbf7a5f1927a26101beaf4 @@ -40,13 +40,22 @@ Configuration - Currently, there's not much to configure. All configuration options - have to be placed in the [mtn] section of the conf/trac.ini file. + All configuration options have to be placed in the [mtn] section of + the conf/trac.ini file. * The full path to the Monotone binary can be specified using the 'mtn_binary' option. + * A caching method for Monotone manifests, certs and changesets can + be specified using the 'cachespec' option. The format is: + cachespec = backend[:opt1[:opt2[...]]] + Currently two backends are provided: + - 'localmem': (default) uses local memory for caching. Takes no + options. + - 'dbmshelve:prefix': Persistent, uses Unix DBM databases named + prefix*.{pag|dir}. All directories in prefix must exist. + Known Problems/Missing Features * SECURITY: The monotone select functionality is exposed. Selectors @@ -61,7 +70,7 @@ * Log on per-file basis is missing, and the browser view shows the same revision for all files. - * Some operations are very slow. + * Some operations are somewhat slow. * Revision and Cert data is cached forever. This will be adjustable in the future. ============================================================ --- tracvc/mtn/backend.py 96c10000b1c2e58cef92cb6efe3563cd92a192b8 +++ tracvc/mtn/backend.py 16047bbc0b40cabc3375d8fa43017c916c23d15b @@ -41,6 +41,9 @@ mtn_binary = Option('mtn', 'mtn_binary', '/usr/bin/mtn', '''Full path to the monotone binary.''') + cachespec = Option('mtn', 'cachespec', 'localmem', + '''Select a caching mechanism.''') + # IRepositoryConnector methods def __init__(self): self.repos = {} @@ -55,7 +58,8 @@ # note: we don't use type or authname, therefore we can always # return the same Repository object for the same database path if not path in self.repos: - self.repos[path] = MonotoneRepository(path, self.log, self.mtn_binary) + self.repos[path] = MonotoneRepository(path, self.log, + self.mtn_binary, self.cachespec) return self.repos[path] # IWikiSyntaxProvider methods @@ -96,8 +100,8 @@ class MonotoneRepository(Repository): - def __init__(self, path, log, binary): - cachespec = 'localmem' + + def __init__(self, path, log, binary, cachespec): self.mtn = MTN(path, log, binary, cachespec) Repository.__init__(self, 'mtn:%s' % path, None, log) ============================================================ --- tracvc/mtn/cache.py 74ba6b640de58de20e8922c97eda6f77aecc2a27 +++ tracvc/mtn/cache.py 4a30ff0444dffafb15cdab7d65908b41b99692fd @@ -26,6 +26,8 @@ from threading import Lock except ImportError: from dummy_threading import Lock +from shelve import Shelf +import dbm class Cache(object): @@ -126,7 +128,7 @@ def add(self, key, value): self.lock.acquire() - if key not in self.cache: + if not key in self.cache: self.cache[key] = value self.lock.release() @@ -142,6 +144,26 @@ Cache.add_backend('localmem', LocalMem) +# Unfortunately, dbash (i.e. bsddb) doesn't work reliably, at least on +# my system, so we can't simply use anydb, which prefers dbhash. + +class DBMShelve(LocalMem): + """Using Python's shelve on a DBM database.""" + + def __init__(self, realm, prefix): + LocalMem.__init__(self, realm) + self.dbname = prefix + realm + self.cache = Shelf(dbm.open(self.dbname, 'c')) + + def __del__(self): + self.cache.close() + + def flush_all(self): + self.cache = Shelf(dbm.open(self.dbname, 'n')) + +Cache.add_backend('dbmshelve', DBMShelve) + + def memoize(get_cachespec, realm = None): """Decorates a method with the Memoize decorator. get_cachespec is a method of the same class which returns the desired cachespec, @@ -162,12 +184,15 @@ return self def __call__(self, *args): + # shelve only supports keys of type integer or string + key = len(args)==1 and args[0] or args try: - return self.cache.get(args) + return self.cache.get(key) except KeyError: # not yet in the cache + #print "CACHEMISS", self.realm, key value = self.function(self.instance, *args) - self.cache.add(args, value) + self.cache.add(key, value) return value except AttributeError: # oops, no cache yet, get one and restart