comparison mercurial/manifest.py @ 24404:96cccf1e3257

treemanifest: make diff() faster Containment checking is slower in treemanifest than it is in manifestdict, making the current diff algorithm O(n log n). By traversing both treemanifests in parallel, we can make it O(n). More importantly, once we start lazily loading submanifests, we will be able to easily skip entire submanifest if they have the same nodeid.
author Martin von Zweigbergk <martinvonz@google.com>
date Thu, 19 Feb 2015 17:13:35 -0800
parents 0e23faa1511c
children cbe9d50d9e65
comparison
equal deleted inserted replaced
24403:0e23faa1511c 24404:96cccf1e3257
525 nodeid in the current/other manifest and fl1/fl2 is the flag 525 nodeid in the current/other manifest and fl1/fl2 is the flag
526 in the current/other manifest. Where the file does not exist, 526 in the current/other manifest. Where the file does not exist,
527 the nodeid will be None and the flags will be the empty 527 the nodeid will be None and the flags will be the empty
528 string. 528 string.
529 ''' 529 '''
530 diff = {} 530 result = {}
531 531 emptytree = treemanifest()
532 for fn, n1 in self.iteritems(): 532 def _diff(t1, t2):
533 fl1 = self.flags(fn) 533 for d, m1 in t1._dirs.iteritems():
534 n2 = m2.get(fn, None) 534 m2 = t2._dirs.get(d, emptytree)
535 fl2 = m2.flags(fn) 535 _diff(m1, m2)
536 if n2 is None: 536
537 fl2 = '' 537 for d, m2 in t2._dirs.iteritems():
538 if n1 != n2 or fl1 != fl2: 538 if d not in t1._dirs:
539 diff[fn] = ((n1, fl1), (n2, fl2)) 539 _diff(emptytree, m2)
540 elif clean: 540
541 diff[fn] = None 541 for fn, n1 in t1._files.iteritems():
542 542 fl1 = t1._flags.get(fn, '')
543 for fn, n2 in m2.iteritems(): 543 n2 = t2._files.get(fn, None)
544 if fn not in self: 544 fl2 = t2._flags.get(fn, '')
545 fl2 = m2.flags(fn) 545 if n1 != n2 or fl1 != fl2:
546 diff[fn] = ((None, ''), (n2, fl2)) 546 result[t1._subpath(fn)] = ((n1, fl1), (n2, fl2))
547 547 elif clean:
548 return diff 548 result[t1._subpath(fn)] = None
549
550 for fn, n2 in t2._files.iteritems():
551 if fn not in t1._files:
552 fl2 = t2._flags.get(fn, '')
553 result[t2._subpath(fn)] = ((None, ''), (n2, fl2))
554
555 _diff(self, m2)
556 return result
549 557
550 def text(self): 558 def text(self):
551 """Get the full data of this manifest as a bytestring.""" 559 """Get the full data of this manifest as a bytestring."""
552 fl = self.keys() 560 fl = self.keys()
553 _checkforbidden(fl) 561 _checkforbidden(fl)