##// END OF EJS Templates
treemanifest: lazily load manifests...
Martin von Zweigbergk -
r25222:0de132d5 default
parent child Browse files
Show More
@@ -441,10 +441,13 b' def _splittopdir(f):'
441 441 else:
442 442 return '', f
443 443
444 _noop = lambda: None
445
444 446 class treemanifest(object):
445 447 def __init__(self, dir='', text=''):
446 448 self._dir = dir
447 449 self._node = revlog.nullid
450 self._load = _noop
448 451 self._dirty = False
449 452 self._dirs = {}
450 453 # Using _lazymanifest here is a little slower than plain old dicts
@@ -461,18 +464,22 b' class treemanifest(object):'
461 464 return self._dir + path
462 465
463 466 def __len__(self):
467 self._load()
464 468 size = len(self._files)
465 469 for m in self._dirs.values():
466 470 size += m.__len__()
467 471 return size
468 472
469 473 def _isempty(self):
474 self._load() # for consistency; already loaded by all callers
470 475 return (not self._files and (not self._dirs or
471 476 all(m._isempty() for m in self._dirs.values())))
472 477
473 478 def __str__(self):
474 return ('<treemanifest dir=%s, node=%s, dirty=%s>' %
475 (self._dir, revlog.hex(self._node), self._dirty))
479 return ('<treemanifest dir=%s, node=%s, loaded=%s, dirty=%s>' %
480 (self._dir, revlog.hex(self._node),
481 bool(self._load is _noop),
482 self._dirty))
476 483
477 484 def dir(self):
478 485 '''The directory that this tree manifest represents, including a
@@ -491,6 +498,7 b' class treemanifest(object):'
491 498 self._dirty = False
492 499
493 500 def iteritems(self):
501 self._load()
494 502 for p, n in sorted(self._dirs.items() + self._files.items()):
495 503 if p in self._files:
496 504 yield self._subpath(p), n
@@ -499,6 +507,7 b' class treemanifest(object):'
499 507 yield f, sn
500 508
501 509 def iterkeys(self):
510 self._load()
502 511 for p in sorted(self._dirs.keys() + self._files.keys()):
503 512 if p in self._files:
504 513 yield self._subpath(p)
@@ -515,6 +524,7 b' class treemanifest(object):'
515 524 def __contains__(self, f):
516 525 if f is None:
517 526 return False
527 self._load()
518 528 dir, subpath = _splittopdir(f)
519 529 if dir:
520 530 if dir not in self._dirs:
@@ -524,6 +534,7 b' class treemanifest(object):'
524 534 return f in self._files
525 535
526 536 def get(self, f, default=None):
537 self._load()
527 538 dir, subpath = _splittopdir(f)
528 539 if dir:
529 540 if dir not in self._dirs:
@@ -533,6 +544,7 b' class treemanifest(object):'
533 544 return self._files.get(f, default)
534 545
535 546 def __getitem__(self, f):
547 self._load()
536 548 dir, subpath = _splittopdir(f)
537 549 if dir:
538 550 return self._dirs[dir].__getitem__(subpath)
@@ -540,6 +552,7 b' class treemanifest(object):'
540 552 return self._files[f]
541 553
542 554 def flags(self, f):
555 self._load()
543 556 dir, subpath = _splittopdir(f)
544 557 if dir:
545 558 if dir not in self._dirs:
@@ -551,6 +564,7 b' class treemanifest(object):'
551 564 return self._flags.get(f, '')
552 565
553 566 def find(self, f):
567 self._load()
554 568 dir, subpath = _splittopdir(f)
555 569 if dir:
556 570 return self._dirs[dir].find(subpath)
@@ -558,6 +572,7 b' class treemanifest(object):'
558 572 return self._files[f], self._flags.get(f, '')
559 573
560 574 def __delitem__(self, f):
575 self._load()
561 576 dir, subpath = _splittopdir(f)
562 577 if dir:
563 578 self._dirs[dir].__delitem__(subpath)
@@ -572,6 +587,7 b' class treemanifest(object):'
572 587
573 588 def __setitem__(self, f, n):
574 589 assert n is not None
590 self._load()
575 591 dir, subpath = _splittopdir(f)
576 592 if dir:
577 593 if dir not in self._dirs:
@@ -584,6 +600,7 b' class treemanifest(object):'
584 600 def setflag(self, f, flags):
585 601 """Set the flags (symlink, executable) for path f."""
586 602 assert 'd' not in flags
603 self._load()
587 604 dir, subpath = _splittopdir(f)
588 605 if dir:
589 606 if dir not in self._dirs:
@@ -597,10 +614,19 b' class treemanifest(object):'
597 614 copy = treemanifest(self._dir)
598 615 copy._node = self._node
599 616 copy._dirty = self._dirty
600 for d in self._dirs:
601 copy._dirs[d] = self._dirs[d].copy()
602 copy._files = dict.copy(self._files)
603 copy._flags = dict.copy(self._flags)
617 def _load():
618 self._load()
619 for d in self._dirs:
620 copy._dirs[d] = self._dirs[d].copy()
621 copy._files = dict.copy(self._files)
622 copy._flags = dict.copy(self._flags)
623 copy._load = _noop
624 copy._load = _load
625 if self._load == _noop:
626 # Chaining _load if it's _noop is functionally correct, but the
627 # chain may end up excessively long (stack overflow), and
628 # will prevent garbage collection of 'self'.
629 copy._load()
604 630 return copy
605 631
606 632 def filesnotin(self, m2):
@@ -609,6 +635,8 b' class treemanifest(object):'
609 635 def _filesnotin(t1, t2):
610 636 if t1._node == t2._node and not t1._dirty and not t2._dirty:
611 637 return
638 t1._load()
639 t2._load()
612 640 for d, m1 in t1._dirs.iteritems():
613 641 if d in t2._dirs:
614 642 m2 = t2._dirs[d]
@@ -631,6 +659,7 b' class treemanifest(object):'
631 659 return self._alldirs
632 660
633 661 def hasdir(self, dir):
662 self._load()
634 663 topdir, subdir = _splittopdir(dir)
635 664 if topdir:
636 665 if topdir in self._dirs:
@@ -673,6 +702,7 b' class treemanifest(object):'
673 702 return
674 703
675 704 # yield this dir's files and walk its submanifests
705 self._load()
676 706 for p in sorted(self._dirs.keys() + self._files.keys()):
677 707 if p in self._files:
678 708 fullp = self._subpath(p)
@@ -697,6 +727,7 b' class treemanifest(object):'
697 727 if not match.visitdir(self._dir[:-1] or '.'):
698 728 return ret
699 729
730 self._load()
700 731 for fn in self._files:
701 732 fullp = self._subpath(fn)
702 733 if not match(fullp):
@@ -734,6 +765,8 b' class treemanifest(object):'
734 765 def _diff(t1, t2):
735 766 if t1._node == t2._node and not t1._dirty and not t2._dirty:
736 767 return
768 t1._load()
769 t2._load()
737 770 for d, m1 in t1._dirs.iteritems():
738 771 m2 = t2._dirs.get(d, emptytree)
739 772 _diff(m1, m2)
@@ -784,6 +817,7 b' class treemanifest(object):'
784 817
785 818 def text(self, usemanifestv2=False):
786 819 """Get the full data of this manifest as a bytestring."""
820 self._load()
787 821 flags = self.flags
788 822 return _text(((f, self[f], flags(f)) for f in self.keys()),
789 823 usemanifestv2)
@@ -792,12 +826,23 b' class treemanifest(object):'
792 826 """Get the full data of this directory as a bytestring. Make sure that
793 827 any submanifests have been written first, so their nodeids are correct.
794 828 """
829 self._load()
795 830 flags = self.flags
796 831 dirs = [(d[:-1], self._dirs[d]._node, 'd') for d in self._dirs]
797 832 files = [(f, self._files[f], flags(f)) for f in self._files]
798 833 return _text(sorted(dirs + files), usemanifestv2)
799 834
835 def read(self, gettext, readsubtree):
836 def _load():
837 # Mark as loaded already here, so __setitem__ and setflag() don't
838 # cause infinite loops when they try to load.
839 self._load = _noop
840 self.parse(gettext(), readsubtree)
841 self._dirty = False
842 self._load = _load
843
800 844 def writesubtrees(self, m1, m2, writesubtree):
845 self._load() # for consistency; should never have any effect here
801 846 emptytree = treemanifest()
802 847 for d, subm in self._dirs.iteritems():
803 848 subp1 = m1._dirs.get(d, emptytree)._node
@@ -891,15 +936,17 b' class manifest(revlog.revlog):'
891 936 return self._newmanifest() # don't upset local cache
892 937 if node in self._mancache:
893 938 return self._mancache[node][0]
894 text = self.revision(node)
895 939 if self._treeondisk:
940 def gettext():
941 return self.revision(node)
896 942 def readsubtree(dir, subm):
897 943 return self.dirlog(dir).read(subm)
898 944 m = self._newmanifest()
899 m.parse(text, readsubtree)
945 m.read(gettext, readsubtree)
900 946 m.setnode(node)
901 947 arraytext = None
902 948 else:
949 text = self.revision(node)
903 950 m = self._newmanifest(text)
904 951 arraytext = array.array('c', text)
905 952 self._mancache[node] = (m, arraytext)
@@ -78,9 +78,11 b' Removing directory does not create an re'
78 78 $ rm before after
79 79
80 80 Check that hg files (calls treemanifest.walk()) works
81 without loading all directory revlogs
81 82
82 83 $ hg co 'desc("add dir2")'
83 84 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
85 $ mv .hg/store/meta/dir2 .hg/store/meta/dir2-backup
84 86 $ hg files -r . dir1
85 87 dir1/a (glob)
86 88 dir1/b (glob)
@@ -90,12 +92,14 b' Check that hg files (calls treemanifest.'
90 92 dir1/dir2/b (glob)
91 93
92 94 Check that status between revisions works (calls treemanifest.matches())
95 without loading all directory revlogs
93 96
94 97 $ hg status --rev 'desc("add dir1")' --rev . dir1
95 98 A dir1/dir1/a
96 99 A dir1/dir1/b
97 100 A dir1/dir2/a
98 101 A dir1/dir2/b
102 $ mv .hg/store/meta/dir2-backup .hg/store/meta/dir2
99 103
100 104 Merge creates 2-parent revision of directory revlog
101 105
General Comments 0
You need to be logged in to leave comments. Login now