#! /usr/bin/env python3.3 """TreeCache.""" import binascii import logging import random import bisect import p4gf_object_type_util as util import p4gf_path LOG = logging.getLogger(__name__) class TreeCache: """Keeps track of which tree objects exist in perforce.""" MAX_SIZE = 10000 def __init__(self): self._tree_cache = [None]*TreeCache.MAX_SIZE self._tree_cache_size = 0 def clear(self): """Remove all elements from this cache.""" self._tree_cache = [None]*TreeCache.MAX_SIZE self._tree_cache_size = 0 def _tree_cache_insert(self, j, bsha1): """Insert an entry in the cache of tree sha1 values. If the cache is already full, remove one entry at random first. """ # NOP if already in list if j < self._tree_cache_size and self._tree_cache[j] == bsha1: return # just insert if not at capacity if self._tree_cache_size < TreeCache.MAX_SIZE: self._tree_cache = self._tree_cache[:j] \ + [bsha1] \ + self._tree_cache[j:TreeCache.MAX_SIZE-1] self._tree_cache_size += 1 return # remove a random entry and insert new entry i = random.randrange(TreeCache.MAX_SIZE) if i == j: self._tree_cache[i] = bsha1 elif i < j: self._tree_cache = self._tree_cache[:i] \ + self._tree_cache[i+1:j] \ + [bsha1] + self._tree_cache[j:] else: self._tree_cache = self._tree_cache[:j] \ + [bsha1] \ + self._tree_cache[j:i] \ + self._tree_cache[i+1:] def tree_exists(self, p4, sha1): """Return true if sha1 identifies a tree object in the //P4GF_DEPOT/objects/... hierarchy. """ # convert to binary rep for space savings bsha1 = binascii.a2b_hex(sha1) # test if already in cache j = bisect.bisect_left(self._tree_cache, bsha1, hi=self._tree_cache_size) if j < self._tree_cache_size and self._tree_cache[j] == bsha1: LOG.debug2('tree cache hit for {}'.format(sha1)) return True # not in cache, check server LOG.debug2("tree cache miss for {}".format(sha1)) LOG.debug("fetching tree objects for {}".format(sha1)) path = p4gf_path.tree_p4_path(sha1) r = [f for f in util.run_p4files(p4, path)] if len(r) != 1: return False m = util.OBJPATH_TREE_REGEX.search(r[0]) if not m: return False found_sha1 = m.group('slashed_sha1').replace('/', '') if sha1 != found_sha1: return False self._tree_cache_insert(j, bsha1) return True