#! /usr/bin/env python3.3 """FilelogCache.""" import logging LOG = logging.getLogger('p4gf_copy_to_git').getChild('filelog_cache') class FilelogCache: """A cache of p4 filelog results. Each item in the cache is the result of running p4 filelog @change Since the size of these items can vary considerably, it is not sufficient to just fix the cache size by the number of such items. Instead, the sizes of the items are summed to determine the total cache size. Since the filelog result is frequently empty, such items are tracked separately and without any caching limit due to the minimal memory requirement. """ MAX_SIZE = 1000000 def __init__(self, p2g): self.p2g = p2g self.empties = set() self.nonempties = {} self.sizeof = 0 self.hits = 0 self.misses = 0 self.sizeof_discarded = 0 def __del__(self): if self.hits or self.misses: LOG.debug("FilelogCache hit rate: {} ({}/{}), discarded: {}" .format(self.hits * 100 / (self.hits + self.misses), self.hits, self.hits + self.misses, self.sizeof_discarded)) def get(self, changenum): """Return filelog result for changenum. Return cached value, if possible; else run filelog and add result to cache. """ if changenum in self.empties: self.hits += 1 return ([], []) r = self.nonempties.get(changenum, None) if r: self.hits += 1 return (r[0], r[1]) self.misses += 1 r = self.p2g._calc_filelog_to_integ_source_list(changenum) # pylint: disable=protected-access if len(r[0]): while self.sizeof and (self.sizeof + r[2] > self.MAX_SIZE): LOG.debug3('_filelog_cache overweight: {}'.format(self.sizeof + r[2])) (_, v) = self.nonempties.popitem() self.sizeof -= v[2] self.sizeof_discarded += v[2] self.nonempties[changenum] = r self.sizeof += r[2] else: self.empties.add(changenum) return (r[0], r[1])