Changeset 3268

Show
Ignore:
Timestamp:
02/24/08 03:20:45 (9 months ago)
Author:
hvr
Message:

GitPlugin: various cleanups and minor improvements

Files:

Legend:

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

    r3267 r3268  
    5151        return partial(self.__execute, name.replace('_','-')) 
    5252 
     53    @staticmethod 
     54    def is_sha(sha): 
     55        """returns whether sha is a potential sha id 
     56        (i.e. proper hexstring between 4 and 40 characters""" 
     57        if len(sha) < 4 or len(sha) > 40: 
     58            return False 
     59        HEXCHARS = "0123456789abcdefABCDEF" 
     60        return all(s in HEXCHARS for s in sha) 
    5361 
    5462# helper class for caching... 
     
    115123class Storage: 
    116124    __SREV_MIN = 4 # minimum short-rev length 
     125 
     126    @staticmethod 
     127    def __rev_key(rev): 
     128        assert len(rev) >= 4 
     129        #assert GitCore.is_sha(rev) 
     130        srev_key = int(rev[:4], 16) 
     131        assert srev_key >= 0 and srev_key <= 0xffff 
     132        return srev_key 
    117133 
    118134    @staticmethod 
     
    152168        self.logger.debug("PyGIT.Storage instance %d constructed" % id(self)) 
    153169 
    154         self.git_dir = git_dir 
    155170        self.repo = GitCore(git_dir) 
    156171 
    157172        self.commit_encoding = None 
    158173 
    159         self._lock = Lock() 
    160         self.last_youngest_rev = -1 
    161         self._invalidate_caches() 
     174        # caches 
     175        self.__rev_cache = None 
     176        self.__rev_cache_lock = Lock() 
    162177 
    163178        # cache the last 200 commit messages 
     
    172187        self.logger.debug("PyGIT.Storage instance %d destructed" % id(self)) 
    173188 
    174     def _invalidate_caches(self,youngest_rev=None): 
    175         with self._lock: 
    176             rc = False 
    177             if self.last_youngest_rev != youngest_rev: 
    178                 self.logger.debug("invalidated caches (%s != %s)" % (self.last_youngest_rev, youngest_rev)) 
    179                 rc = True 
    180                 self._commit_db = None 
    181                 self._oldest_rev = None 
    182                 self.last_youngest_rev = None 
    183  
    184             return rc 
    185  
    186     def get_commits(self): 
    187         with self._lock: 
    188             if self._commit_db is None: 
     189    # 
     190    # cache handling 
     191    # 
     192 
     193    # called by Storage.sync() 
     194    def __rev_cache_sync(self, youngest_rev=None): 
     195        "invalidates revision db cache if necessary" 
     196        with self.__rev_cache_lock: 
     197            need_update = False 
     198            if self.__rev_cache: 
     199                last_youngest_rev = self.__rev_cache[0] 
     200                if last_youngest_rev != youngest_rev: 
     201                    self.logger.debug("invalidated caches (%s != %s)" % (last_youngest_rev, youngest_rev)) 
     202                    need_update = True 
     203            else: 
     204                need_update = True # almost NOOP 
     205 
     206            if need_update: 
     207                self.__rev_cache = None 
     208 
     209            return need_update 
     210 
     211    def get_rev_cache(self): 
     212        with self.__rev_cache_lock: 
     213            if self.__rev_cache is None: # can be cleared by Storage.__rev_cache_sync() 
    189214                self.logger.debug("triggered rebuild of commit tree db for %d" % id(self)) 
    190215                new_db = {} 
    191216                new_sdb = {} 
    192217                new_tags = set([]) 
    193                 parent = None 
    194218                youngest = None 
    195                 ord_rev = 0 
     219                oldest = None 
    196220                for revs in self.repo.rev_parse("--tags").readlines(): 
    197221                    new_tags.add(revs.strip()) 
     
    203227                    return __rev_seen.setdefault(rev, rev) 
    204228 
     229                ord_rev = 0 
    205230                for revs in self.repo.rev_list("--parents", "--all").readlines(): 
    206231                    revs = revs.strip().split() 
     
    211236 
    212237                    # shortrev "hash" map 
    213                     srev_key = int(rev[:self.__SREV_MIN], 16) 
    214                     assert srev_key >= 0 and srev_key <= 0xffff 
     238                    srev_key = self.__rev_key(rev) 
    215239                    new_sdb.setdefault(srev_key, []).append(rev) 
    216240 
     
    219243                    ord_rev += 1 
    220244 
     245                    # first rev seen is assumed to be the youngest one (and has ord_rev=1) 
    221246                    if not youngest: 
    222247                        youngest = rev 
     
    241266                            _children.append(rev) 
    242267 
     268                # last rev seen is assumed to be the oldest one (with highest ord_rev) 
     269                oldest = rev 
     270 
    243271                __rev_seen = None 
     272 
     273                assert len(new_db) == ord_rev 
    244274 
    245275                # convert children lists to tuples 
    246276                tmp = {} 
    247                 while True
    248                     try
     277                try
     278                    while True
    249279                        k,v = new_db.popitem() 
     280                        assert v[2] > 0 
    250281                        tmp[k] = tuple(v[0]),v[1],v[2] 
    251                     except KeyError: 
    252                         break 
     282                except KeyError: 
     283                    pass 
     284 
    253285                assert len(new_db) == 0 
    254286                new_db = tmp 
     
    257289                tmp = [()]*(max(new_sdb.keys())+1) if len(new_sdb) > 5000 else {} 
    258290 
    259                 while True
    260                     try
     291                try
     292                    while True
    261293                        k,v = new_sdb.popitem() 
    262294                        tmp[k] = tuple(v) 
    263                     except KeyError: 
    264                         break 
     295                except KeyError: 
     296                    pass 
    265297 
    266298                assert len(new_sdb) == 0 
    267299                new_sdb = tmp 
    268300 
    269                 # atomically update self._commit_db 
    270                 self._commit_db = new_db, parent, new_tags, new_sdb 
    271                 self.last_youngest_rev = youngest 
     301                # atomically update self.__rev_cache 
     302                self.__rev_cache = youngest, oldest, new_db, new_tags, new_sdb 
    272303                self.logger.debug("rebuilt commit tree db for %d with %d entries" % (id(self),len(new_db))) 
    273304 
    274             assert all([ e is not None for e in self._commit_db]) 
    275  
    276             return self._commit_db[0] 
    277  
    278     def sync(self): 
    279         rev = self.repo.rev_list("--max-count=1", "--all").read().strip() 
    280         return self._invalidate_caches(rev) 
     305            assert all(e is not None for e in self.__rev_cache) 
     306 
     307            return self.__rev_cache 
     308        # with self.__rev_cache_lock 
     309 
     310    # tuple: youngest_rev, oldest_rev, rev_dict, tag_dict, short_rev_dict 
     311    rev_cache = property(get_rev_cache) 
     312 
     313    def get_commits(self): 
     314        return self.rev_cache[2] 
    281315 
    282316    def oldest_rev(self): 
    283         self.get_commits() # trigger commit tree db build 
    284         return self._commit_db[1] 
     317        return self.rev_cache[1] 
    285318 
    286319    def youngest_rev(self): 
    287         self.get_commits() # trigger commit tree db build 
    288         return self.last_youngest_rev 
     320        return self.rev_cache[0] 
    289321 
    290322    def history_relative_rev(self, sha, rel_pos): 
     
    328360    def verifyrev(self, rev): 
    329361        "verify/lookup given revision object and return a sha id or None if lookup failed" 
    330         db = self.get_commits() 
    331         tag_db = self._commit_db[2] 
    332  
    333362        rev = str(rev) 
    334363 
    335         if db.has_key(rev): 
    336             return rev 
    337  
     364        db, tag_db = self.rev_cache[2:4] 
     365 
     366        if GitCore.is_sha(rev): 
     367            # maybe it's a short or full rev 
     368            fullrev = self.fullrev(rev) 
     369            if fullrev: 
     370                return fullrev 
     371 
     372        # fall back to external git calls 
    338373        rc = self.repo.rev_parse("--verify", rev).read().strip() 
    339374        if not rc: 
     
    352387        return None 
    353388 
    354     def shortrev(self, rev): 
     389    def shortrev(self, rev, min_len=7): 
    355390        "try to shorten sha id" 
    356391        #try to emulate the following: 
    357392        #return self.repo.rev_parse("--short", str(rev)).read().strip() 
    358  
    359393        rev = str(rev) 
    360394 
    361         db = self.get_commits() 
    362         sdb = self._commit_db[3] 
     395        if min_len < self.__SREV_MIN: 
     396            min_len = self.__SREV_MIN 
     397 
     398        db, tag_db, sdb = self.rev_cache[2:5] 
    363399 
    364400        if rev not in db: 
    365             return rev 
    366  
    367         srev = rev[:self.__SREV_MIN] 
    368         srev_key = int(srev, 16) 
    369         srevs = set(sdb[srev_key]) 
     401            return None 
     402 
     403        srev = rev[:min_len] 
     404        srevs = set(sdb[self.__rev_key(rev)]) 
    370405 
    371406        if len(srevs) == 1: 
     
    376411        crevs = srevs - set([rev]) 
    377412 
    378         for l in range(self.__SREV_MIN+1, 40): 
     413        for l in range(min_len+1, 40): 
    379414            srev = rev[:l] 
    380415            if srev not in [ r[:l] for r in crevs ]: 
     
    382417 
    383418        return rev # worst-case, all except the last character match 
     419 
     420    def fullrev(self, srev): 
     421        "try to reverse shortrev()" 
     422        srev = str(srev) 
     423        db, tag_db, sdb = self.rev_cache[2:5] 
     424 
     425        # short-cut 
     426        if len(srev) == 40 and srev in db: 
     427            return srev 
     428 
     429        if not GitCore.is_sha(srev): 
     430            return None 
     431 
     432        srevs = sdb[self.__rev_key(srev)] 
     433 
     434        srevs = filter(lambda s: s.startswith(srev), srevs) 
     435        if len(srevs) == 1: 
     436            return srevs[0] 
     437 
     438        return None 
    384439 
    385440    def get_branches(self): 
     
    495550            return [] 
    496551 
     552    def all_revs(self): 
     553        return self.get_commits().iterkeys() 
     554 
     555    def sync(self): 
     556        rev = self.repo.rev_list("--max-count=1", "--all").read().strip() 
     557        return self.__rev_cache_sync(rev) 
     558 
     559    def last_change(self, sha, path): 
     560        return self.repo.rev_list("--max-count=1", 
     561                                  sha, "--", path).read().strip() or None 
     562 
    497563    def history(self, sha, path, limit=None): 
    498564        if limit is None: 
     
    501567                                      str(sha), "--", path).readlines(): 
    502568            yield rev.strip() 
    503  
    504     def all_revs(self): 
    505         return self.get_commits().iterkeys() 
    506569 
    507570    def history_timerange(self, start, stop): 
     
    538601        assert not in_metadata 
    539602 
    540     def last_change(self, sha, path): 
    541         return self.repo.rev_list("--max-count=1", sha, "--", path).read().strip() or None 
    542  
    543603    def diff_tree(self, tree1, tree2, path="", find_renames=False): 
    544604        """calls `git diff-tree` and returns tuples of the kind 
     
    618678    print "statm =", proc_statm() 
    619679    __data_size = proc_statm()[5] 
     680    __data_size_last = __data_size 
    620681 
    621682    def print_data_usage(): 
    622         print "DATA:", proc_statm()[5] - __data_size 
     683        global __data_size_last 
     684        __tmp = proc_statm()[5] 
     685        print "DATA: %6d %+6d" % (__tmp - __data_size, __tmp - __data_size_last) 
     686        __data_size_last = __tmp 
    623687 
    624688    print_data_usage() 
     
    679743        for i in revs: 
    680744            i = str(i) 
    681             s = g.shortrev(i
     745            s = g.shortrev(i, min_len=4
    682746            assert i.startswith(s) 
     747            assert g.fullrev(s) == i 
    683748 
    684749    iters = 1 
     
    688753 
    689754    #print len(check4loops(g.oldest_rev())) 
    690  
    691755    #print len(list(g.children_recursive(g.oldest_rev()))) 
    692756 
     
    704768 
    705769            print "%s %s %10d [%s]" % (type, last_rev, s, name) 
     770 
     771    print "allocating 2nd instance" 
     772    print_data_usage() 
     773    g2 = Storage(sys.argv[1], logging) 
     774    g2.head() 
     775    print_data_usage() 
     776    print "allocating 3rd instance" 
     777    g3 = Storage(sys.argv[1], logging) 
     778    g3.head() 
     779    print_data_usage()