~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/dirstate.py

Simplify update_minimal a bit more, by making id_index a
cached variable, which is updated on mutating operations
also use this to implement a faster id2path, and add direct tests
since id2path now uses a more complex implementation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
281
281
        self._state_file = None
282
282
        self._filename = path
283
283
        self._lock_token = None
 
284
        self._id_index = None
284
285
        self._end_of_header = None
285
286
        self._bisect_page_size = DirState.BISECT_PAGE_SIZE
286
287
 
1162
1163
            assert entry[0][2] and entry[1][tree_index][0] not in ('a', 'r'), 'unversioned entry?!?!'
1163
1164
            if fileid_utf8:
1164
1165
                if entry[0][2] != fileid_utf8:
1165
 
                    raise BzrError('integrity error ? : mismatching tree_index, file_id and path')
 
1166
                    raise errors.BzrError('integrity error ? : mismatching'
 
1167
                                          ' tree_index, file_id and path')
1166
1168
            return entry
1167
1169
        else:
1168
1170
            for entry in self._iter_entries():
1255
1257
 
1256
1258
    def _get_id_index(self):
1257
1259
        """Get an id index of self._dirblocks."""
1258
 
        id_index = {}
1259
 
        for key, tree_details in self._iter_entries():
1260
 
            id_index.setdefault(key[2], set()).add(key)
1261
 
        return id_index
 
1260
        if self._id_index is None:
 
1261
            id_index = {}
 
1262
            for key, tree_details in self._iter_entries():
 
1263
                id_index.setdefault(key[2], set()).add(key)
 
1264
            self._id_index = id_index
 
1265
        return self._id_index
1262
1266
 
1263
1267
    def _get_output_lines(self, lines):
1264
1268
        """format lines for final output.
1506
1510
        entry = self._get_entry(0, path_utf8=path)
1507
1511
        # mark the old path absent, and insert a new root path
1508
1512
        self._make_absent(entry)
1509
 
        id_index = self._get_id_index()
1510
1513
        self.update_minimal(('', '', new_id), 'd',
1511
 
            path_utf8='', id_index=id_index, packed_stat=entry[1][0][4])
 
1514
            path_utf8='', packed_stat=entry[1][0][4])
1512
1515
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
1513
1516
 
1514
1517
    def set_parent_trees(self, trees, ghosts):
1649
1652
        self._ghosts = list(ghosts)
1650
1653
        self._header_state = DirState.IN_MEMORY_MODIFIED
1651
1654
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
 
1655
        self._id_index = id_index
1652
1656
 
1653
1657
    def set_state_from_inventory(self, new_inv):
1654
1658
        """Set new_inv as the current state. 
1660
1664
        """
1661
1665
        self._read_dirblocks_if_needed()
1662
1666
        # sketch:
1663
 
        #  generate a byid index of the dirstate
1664
 
        id_index = self._get_id_index()
1665
 
 
1666
1667
        # incremental algorithm:
1667
1668
        # two iterators: current data and new data, both in dirblock order. 
1668
1669
        new_iterator = new_inv.iter_entries_by_dir()
1701
1702
                # old is finished: insert current_new into the state.
1702
1703
                self.update_minimal(new_entry_key, current_new_minikind,
1703
1704
                    executable=current_new[1].executable,
1704
 
                    id_index=id_index, path_utf8=new_path_utf8)
 
1705
                    path_utf8=new_path_utf8)
1705
1706
                current_new = advance(new_iterator)
1706
1707
            elif not current_new:
1707
1708
                # new is finished
1708
 
                self._make_absent(current_old, id_index)
 
1709
                self._make_absent(current_old)
1709
1710
                current_old = advance(old_iterator)
1710
1711
            elif new_entry_key == current_old[0]:
1711
1712
                # same -  common case
1716
1717
                    current_old[1][0][0] != current_new_minikind):
1717
1718
                    self.update_minimal(current_old[0], current_new_minikind,
1718
1719
                        executable=current_new[1].executable,
1719
 
                        id_index=id_index, path_utf8=new_path_utf8)
 
1720
                        path_utf8=new_path_utf8)
1720
1721
                # both sides are dealt with, move on
1721
1722
                current_old = advance(old_iterator)
1722
1723
                current_new = advance(new_iterator)
1725
1726
                # add a entry for this and advance new
1726
1727
                self.update_minimal(new_entry_key, current_new_minikind,
1727
1728
                    executable=current_new[1].executable,
1728
 
                    id_index=id_index, path_utf8=new_path_utf8)
 
1729
                    path_utf8=new_path_utf8)
1729
1730
                current_new = advance(new_iterator)
1730
1731
            else:
1731
1732
                # old comes before:
1732
 
                self._make_absent(current_old, id_index)
 
1733
                self._make_absent(current_old)
1733
1734
                current_old = advance(old_iterator)
1734
1735
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
1735
1736
 
1736
 
    def _make_absent(self, current_old, id_index=None):
 
1737
    def _make_absent(self, current_old):
1737
1738
        """Mark current_old - an entry - as absent for tree 0.
1738
1739
 
1739
 
        :param id_index: An index from fileid_utf8 to sets of keys, used by
1740
 
            some functions. If provided it will be updated if needed.
1741
1740
        :return: True if this was the last details entry for they entry key:
1742
1741
            that is, if the underlying block has had the entry removed, thus
1743
1742
            shrinking in length.
1763
1762
            assert present
1764
1763
            block[1].pop(entry_index)
1765
1764
            # if we have an id_index in use, remove this key from it for this id.
1766
 
            if id_index is not None:
1767
 
                id_index[current_old[0][2]].remove(current_old[0])
 
1765
            if self._id_index is not None:
 
1766
                self._id_index[current_old[0][2]].remove(current_old[0])
1768
1767
        # update all remaining keys for this id to record it as absent. The
1769
1768
        # existing details may either be the record we are making as deleted
1770
1769
        # (if there were other trees with the id present at this path), or may
1784
1783
        return last_reference
1785
1784
 
1786
1785
    def update_minimal(self, key, minikind, executable=False, fingerprint='',
1787
 
                       packed_stat=None, size=0, id_index=None, path_utf8=None):
 
1786
                       packed_stat=None, size=0, path_utf8=None):
1788
1787
        """Update an entry to the state in tree 0.
1789
1788
 
1790
1789
        This will either create a new entry at 'key' or update an existing one.
1798
1797
        :param fingerprint: Simple fingerprint for new entry.
1799
1798
        :param packed_stat: packed stat value for new entry.
1800
1799
        :param size: Size information for new entry
1801
 
        :param id_index: A mapping from file_id => key, as returned by
1802
 
                self._get_id_index
1803
1800
        :param path_utf8: key[0] + '/' + key[1], just passed in to avoid doing
1804
1801
                extra computation.
1805
1802
        """
1808
1805
            packed_stat = DirState.NULLSTAT
1809
1806
        entry_index, present = self._find_entry_index(key, block)
1810
1807
        new_details = (minikind, fingerprint, size, executable, packed_stat)
1811
 
        assert id_index is not None, 'need an id index to do updates for now !'
 
1808
        id_index = self._get_id_index()
1812
1809
        if not present:
1813
1810
            # new entry, synthesis cross reference here,
1814
1811
            existing_keys = id_index.setdefault(key[2], set())