Changeset 3268
- Timestamp:
- 02/24/08 03:20:45 (9 months ago)
- Files:
-
- gitplugin/0.11/tracext/git/PyGIT.py (modified) (20 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
gitplugin/0.11/tracext/git/PyGIT.py
r3267 r3268 51 51 return partial(self.__execute, name.replace('_','-')) 52 52 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) 53 61 54 62 # helper class for caching... … … 115 123 class Storage: 116 124 __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 117 133 118 134 @staticmethod … … 152 168 self.logger.debug("PyGIT.Storage instance %d constructed" % id(self)) 153 169 154 self.git_dir = git_dir155 170 self.repo = GitCore(git_dir) 156 171 157 172 self.commit_encoding = None 158 173 159 self._lock = Lock()160 self. last_youngest_rev = -1161 self._ invalidate_caches()174 # caches 175 self.__rev_cache = None 176 self.__rev_cache_lock = Lock() 162 177 163 178 # cache the last 200 commit messages … … 172 187 self.logger.debug("PyGIT.Storage instance %d destructed" % id(self)) 173 188 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() 189 214 self.logger.debug("triggered rebuild of commit tree db for %d" % id(self)) 190 215 new_db = {} 191 216 new_sdb = {} 192 217 new_tags = set([]) 193 parent = None194 218 youngest = None 195 o rd_rev = 0219 oldest = None 196 220 for revs in self.repo.rev_parse("--tags").readlines(): 197 221 new_tags.add(revs.strip()) … … 203 227 return __rev_seen.setdefault(rev, rev) 204 228 229 ord_rev = 0 205 230 for revs in self.repo.rev_list("--parents", "--all").readlines(): 206 231 revs = revs.strip().split() … … 211 236 212 237 # 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) 215 239 new_sdb.setdefault(srev_key, []).append(rev) 216 240 … … 219 243 ord_rev += 1 220 244 245 # first rev seen is assumed to be the youngest one (and has ord_rev=1) 221 246 if not youngest: 222 247 youngest = rev … … 241 266 _children.append(rev) 242 267 268 # last rev seen is assumed to be the oldest one (with highest ord_rev) 269 oldest = rev 270 243 271 __rev_seen = None 272 273 assert len(new_db) == ord_rev 244 274 245 275 # convert children lists to tuples 246 276 tmp = {} 247 while True:248 try:277 try: 278 while True: 249 279 k,v = new_db.popitem() 280 assert v[2] > 0 250 281 tmp[k] = tuple(v[0]),v[1],v[2] 251 except KeyError: 252 break 282 except KeyError: 283 pass 284 253 285 assert len(new_db) == 0 254 286 new_db = tmp … … 257 289 tmp = [()]*(max(new_sdb.keys())+1) if len(new_sdb) > 5000 else {} 258 290 259 while True:260 try:291 try: 292 while True: 261 293 k,v = new_sdb.popitem() 262 294 tmp[k] = tuple(v) 263 except KeyError:264 break295 except KeyError: 296 pass 265 297 266 298 assert len(new_sdb) == 0 267 299 new_sdb = tmp 268 300 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 272 303 self.logger.debug("rebuilt commit tree db for %d with %d entries" % (id(self),len(new_db))) 273 304 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] 281 315 282 316 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] 285 318 286 319 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] 289 321 290 322 def history_relative_rev(self, sha, rel_pos): … … 328 360 def verifyrev(self, rev): 329 361 "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 333 362 rev = str(rev) 334 363 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 338 373 rc = self.repo.rev_parse("--verify", rev).read().strip() 339 374 if not rc: … … 352 387 return None 353 388 354 def shortrev(self, rev ):389 def shortrev(self, rev, min_len=7): 355 390 "try to shorten sha id" 356 391 #try to emulate the following: 357 392 #return self.repo.rev_parse("--short", str(rev)).read().strip() 358 359 393 rev = str(rev) 360 394 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] 363 399 364 400 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)]) 370 405 371 406 if len(srevs) == 1: … … 376 411 crevs = srevs - set([rev]) 377 412 378 for l in range( self.__SREV_MIN+1, 40):413 for l in range(min_len+1, 40): 379 414 srev = rev[:l] 380 415 if srev not in [ r[:l] for r in crevs ]: … … 382 417 383 418 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 384 439 385 440 def get_branches(self): … … 495 550 return [] 496 551 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 497 563 def history(self, sha, path, limit=None): 498 564 if limit is None: … … 501 567 str(sha), "--", path).readlines(): 502 568 yield rev.strip() 503 504 def all_revs(self):505 return self.get_commits().iterkeys()506 569 507 570 def history_timerange(self, start, stop): … … 538 601 assert not in_metadata 539 602 540 def last_change(self, sha, path):541 return self.repo.rev_list("--max-count=1", sha, "--", path).read().strip() or None542 543 603 def diff_tree(self, tree1, tree2, path="", find_renames=False): 544 604 """calls `git diff-tree` and returns tuples of the kind … … 618 678 print "statm =", proc_statm() 619 679 __data_size = proc_statm()[5] 680 __data_size_last = __data_size 620 681 621 682 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 623 687 624 688 print_data_usage() … … 679 743 for i in revs: 680 744 i = str(i) 681 s = g.shortrev(i )745 s = g.shortrev(i, min_len=4) 682 746 assert i.startswith(s) 747 assert g.fullrev(s) == i 683 748 684 749 iters = 1 … … 688 753 689 754 #print len(check4loops(g.oldest_rev())) 690 691 755 #print len(list(g.children_recursive(g.oldest_rev()))) 692 756 … … 704 768 705 769 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()
