Changeset 3237

Show
Ignore:
Timestamp:
02/15/08 03:36:37 (10 months ago)
Author:
hvr
Message:

GitPlugin: put in-place caching logic of git-cat-file -s and git-cat-file commit calls

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • gitplugin/0.11/tracext/git/PyGIT.py

    r3236 r3237  
    1515from __future__ import with_statement 
    1616 
    17 import os, re, sys, time, weakref, threading 
     17import os, re, sys, time, weakref 
    1818from collections import deque 
    1919from functools import partial 
     20from threading import Lock 
    2021#from traceback import print_stack 
     22 
     23__all__ = ["git_version", "GitError", "GitErrorSha", "Storage", "StorageFactory"] 
    2124 
    2225class GitError(Exception): 
     
    2629    pass 
    2730 
    28 GIT_BIN = "git" 
    29 GIT_VERSION_MIN_REQUIRED = (1,5,2) 
    30  
    3131class GitCore: 
    32     def __init__(self, git_dir=None, git_bin=GIT_BIN): 
     32    def __init__(self, git_dir=None, git_bin="git"): 
    3333        self.__git_bin = git_bin 
    3434        self.__git_dir = git_dir 
     
    5050    def __getattr__(self, name): 
    5151        return partial(self.__execute, name.replace('_','-')) 
     52 
     53 
     54GIT_VERSION_MIN_REQUIRED = (1,5,2) # for PyGit.Storage 
    5255 
    5356def git_version(): 
     
    6972        raise GitError("Could not retrieve GIT version") 
    7073 
     74# helper class for caching... 
     75class SizedDict(dict): 
     76    def __init__(self, max_size=0): 
     77        dict.__init__(self) 
     78        self.__max_size = max_size 
     79        self.__key_fifo = deque() 
     80        self.__lock = Lock() 
     81 
     82    def __setitem__(self, name, value): 
     83        with self.__lock: 
     84            assert len(self) == len(self.__key_fifo) # invariant 
     85 
     86            if not self.__contains__(name): 
     87                self.__key_fifo.append(name) 
     88 
     89            rc = dict.__setitem__(self, name, value) 
     90 
     91            while len(self.__key_fifo) > self.__max_size: 
     92                self.__delitem__(self.__key_fifo.popleft()) 
     93 
     94            assert len(self) == len(self.__key_fifo) # invariant 
     95 
     96            return rc 
     97 
     98    def setdefault(k,d=None): 
     99        # TODO 
     100        raise AttributeError("SizedDict has no setdefault() method") 
     101 
    71102class StorageFactory: 
    72103    __dict = weakref.WeakValueDictionary() 
    73104    __dict_nonweak = dict() 
    74     __dict_lock = threading.Lock() 
     105    __dict_lock = Lock() 
    75106 
    76107    def __init__(self, repo, log, weak=True): 
     
    112143        self.commit_encoding = None 
    113144 
    114         self._lock = threading.Lock() 
     145        self._lock = Lock() 
    115146        self.last_youngest_rev = -1 
    116147        self._invalidate_caches() 
     148 
     149        # cache the last 200 commit messages 
     150        self.__commit_msg_cache = SizedDict(200) 
     151        self.__commit_msg_lock = Lock() 
     152 
     153        # cache the last 2000 file sizes 
     154        self.__fs_obj_size_cache = SizedDict(2000) 
     155        self.__fs_obj_size_lock = Lock() 
    117156 
    118157    def __del__(self): 
     
    281320                    self.repo.ls_tree("-z", rev, "--", path).read().split('\0') if e] 
    282321 
    283     def read_commit(self, sha): 
    284         if not sha: 
     322    def read_commit(self, commit_id): 
     323        if not commit_id: 
     324            raise GitErrorCommit_Id 
     325 
     326        commit_id = str(commit_id) 
     327 
     328        db = self.get_commits() 
     329        if commit_id not in db: 
     330            self.logger.info("read_commit failed for '%s'" % commit_id) 
    285331            raise GitErrorSha 
    286332 
    287         db = self.get_commits() 
    288         if sha not in db: 
    289             self.logger.info("read_commit failed for '%s'" % sha) 
    290             raise GitErrorSha 
    291  
    292         raw = self.repo.cat_file("commit", str(sha)).read() 
    293         raw = unicode(raw, self.get_commit_encoding(), 'replace') 
    294         lines = raw.splitlines() 
    295  
    296         if not lines: 
    297             raise GitErrorSha 
    298  
    299         line = lines.pop(0) 
    300         props = {} 
    301         while line: 
    302             (key,value) = line.split(None, 1) 
    303             props.setdefault(key,[]).append(value.strip()) 
     333        with self.__commit_msg_lock: 
     334            if self.__commit_msg_cache.has_key(commit_id): 
     335                # cache hit 
     336                result = self.__commit_msg_cache[commit_id] 
     337                return result[0], dict(result[1]) 
     338 
     339            # cache miss 
     340            raw = self.repo.cat_file("commit", commit_id).read() 
     341            raw = unicode(raw, self.get_commit_encoding(), 'replace') 
     342            lines = raw.splitlines() 
     343 
     344            if not lines: 
     345                raise GitErrorSha 
     346 
    304347            line = lines.pop(0) 
    305  
    306         return ("\n".join(lines), props) 
     348            props = {} 
     349            while line: 
     350                (key,value) = line.split(None, 1) 
     351                props.setdefault(key,[]).append(value.strip()) 
     352                line = lines.pop(0) 
     353 
     354            result = ("\n".join(lines), props) 
     355 
     356            self.__commit_msg_cache[commit_id] = result 
     357 
     358            return result[0], dict(result[1]) 
    307359 
    308360    def get_file(self, sha): 
     
    312364        sha = str(sha) 
    313365        try: 
    314             return int(self.repo.cat_file("-s", sha).read().strip()) 
     366            with self.__fs_obj_size_lock: 
     367                if self.__fs_obj_size_cache.has_key(sha): 
     368                    obj_size = self.__fs_obj_size_cache[sha] 
     369                else: 
     370                    obj_size = int(self.repo.cat_file("-s", sha).read().strip()) 
     371                    self.__fs_obj_size_cache[sha] = obj_size 
    315372        except ValueError: 
    316373            raise GitErrorSha("object '%s' not found" % sha) 
     374 
     375        return obj_size 
    317376 
    318377    def children(self, sha):