#! /usr/bin/env python3.3 """ChangeNumToCommitCache.""" import random class ChangeNumToCommitCache: """Maintains a limited size cache of (branch+change_num)-to-commit mappings for different branches. """ MAX_SIZE = 10000 def __init__(self): # dict[branch-id] to dict[change_num] to commit sha1 self._branches = {} self._count = 0 def clear(self): """Remove all elements from this cache.""" self._branches = {} self._count = 0 def _remove_one(self): """Remove a randomly selected element.""" assert self._count == ChangeNumToCommitCache.MAX_SIZE self._count -= 1 i = random.randrange(ChangeNumToCommitCache.MAX_SIZE) for j in self._branches.values(): if len(j) <= i: i -= len(j) continue key = list(j.keys())[i] del j[key] def append(self, change_num, branch_id, sha1): """Add an entry mapping change_num on branch_id to commit sha1.""" if self._count == ChangeNumToCommitCache.MAX_SIZE: self._remove_one() if branch_id not in self._branches: self._branches[branch_id] = {} self._branches[branch_id][change_num] = sha1 self._count += 1 def get(self, change_num, branch_id): """Return matching (branch_id, commit_sha1) if in cache, else None. If branch_id is None, return first matching element, or None. """ if not branch_id: return self._get_any_branch(change_num) branch_commits = self._branches.get(branch_id) if not branch_commits: return None sha1 = branch_commits.get(change_num) if not sha1: return None return branch_id, sha1 def _get_any_branch(self, change_num): """Return first matching (branch_id,commit_sha1) or None.""" for branch_id, changes in self._branches.items(): if change_num in changes: return branch_id, changes[change_num] return None