/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/dirstate.py

  • Committer: Aaron Bentley
  • Date: 2007-09-17 12:46:56 UTC
  • mfrom: (2825 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2826.
  • Revision ID: abentley@panoramicfeedback.com-20070917124656-j3hhxhx9igy11mfc
merge bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
 
30
30
dirstate format = header line, full checksum, row count, parent details,
31
31
 ghost_details, entries;
32
 
header line = "#bazaar dirstate flat format 2", NL;
 
32
header line = "#bazaar dirstate flat format 3", NL;
33
33
full checksum = "crc32: ", ["-"], WHOLE_NUMBER, NL;
34
 
row count = "num_entries: ", digit, NL;
 
34
row count = "num_entries: ", WHOLE_NUMBER, NL;
35
35
parent_details = WHOLE NUMBER, {REVISION_ID}* NL;
36
36
ghost_details = WHOLE NUMBER, {REVISION_ID}*, NL;
37
37
entries = {entry};
118
118
where we need id->path mapping; we also usually read the whole file, so
119
119
I'm going to skip that for the moment, as we have the ability to locate
120
120
via bisect any path in any tree, and if we lookup things by path, we can
121
 
accumulate a id->path mapping as we go, which will tend to match what we
 
121
accumulate an id->path mapping as we go, which will tend to match what we
122
122
looked for.
123
123
 
124
124
I plan to implement this asap, so please speak up now to alter/tweak the
143
143
Locking:
144
144
 Eventually reuse dirstate objects across locks IFF the dirstate file has not
145
145
 been modified, but will require that we flush/ignore cached stat-hit data
146
 
 because we wont want to restat all files on disk just because a lock was
 
146
 because we won't want to restat all files on disk just because a lock was
147
147
 acquired, yet we cannot trust the data after the previous lock was released.
148
148
 
149
149
Memory representation:
162
162
      manageable number. Will scale badly on trees with 10K entries in a 
163
163
      single directory. compare with Inventory.InventoryDirectory which has
164
164
      a dictionary for the children. No bisect capability, can only probe for
165
 
      exact matches, or grab all elements and sorta.
166
 
    - Whats the risk of error here? Once we have the base format being processed
 
165
      exact matches, or grab all elements and sort.
 
166
    - What's the risk of error here? Once we have the base format being processed
167
167
      we should have a net win regardless of optimality. So we are going to 
168
 
      go with what seems reasonably.
 
168
      go with what seems reasonable.
169
169
open questions:
170
170
 
171
 
maybe we should do a test profile of these core structure - 10K simulated searches/lookups/etc?
 
171
Maybe we should do a test profile of the core structure - 10K simulated
 
172
searches/lookups/etc?
172
173
 
173
174
Objects for each row?
174
175
The lifetime of Dirstate objects is current per lock, but see above for
224
225
    # jam 20060614 it isn't really worth removing more entries if we
225
226
    # are going to leave it in packed form.
226
227
    # With only st_mtime and st_mode filesize is 5.5M and read time is 275ms
227
 
    # With all entries filesize is 5.9M and read time is mabye 280ms
 
228
    # With all entries, filesize is 5.9M and read time is maybe 280ms
228
229
    # well within the noise margin
229
230
 
230
231
    # base64 encoding always adds a final newline, so strip it off
651
652
        _bisect_dirblocks is meant to find the contents of directories, which
652
653
        differs from _bisect, which only finds individual entries.
653
654
 
654
 
        :param dir_list: An sorted list of directory names ['', 'dir', 'foo'].
 
655
        :param dir_list: A sorted list of directory names ['', 'dir', 'foo'].
655
656
        :return: A map from dir => entries_for_dir
656
657
        """
657
658
        # TODO: jam 20070223 A lot of the bisecting logic could be shared
1330
1331
            be attempted.
1331
1332
        :return: A tuple describing where the path is located, or should be
1332
1333
            inserted. The tuple contains four fields: the block index, the row
1333
 
            index, anda two booleans are True when the directory is present, and
1334
 
            when the entire path is present.  There is no guarantee that either
 
1334
            index, the directory is present (boolean), the entire path is
 
1335
            present (boolean).  There is no guarantee that either
1335
1336
            coordinate is currently reachable unless the found field for it is
1336
1337
            True. For instance, a directory not present in the searched tree
1337
1338
            may be returned with a value one greater than the current highest
1359
1360
        return block_index, entry_index, True, False
1360
1361
 
1361
1362
    def _get_entry(self, tree_index, fileid_utf8=None, path_utf8=None):
1362
 
        """Get the dirstate entry for path in tree tree_index
 
1363
        """Get the dirstate entry for path in tree tree_index.
1363
1364
 
1364
1365
        If either file_id or path is supplied, it is used as the key to lookup.
1365
1366
        If both are supplied, the fastest lookup is used, and an error is
1404
1405
                    continue
1405
1406
                # WARNING: DO not change this code to use _get_block_entry_index
1406
1407
                # as that function is not suitable: it does not use the key
1407
 
                # to lookup, and thus the wront coordinates are returned.
 
1408
                # to lookup, and thus the wrong coordinates are returned.
1408
1409
                block = self._dirblocks[block_index][1]
1409
1410
                entry_index, present = self._find_entry_index(key, block)
1410
1411
                if present:
1511
1512
        return self._id_index
1512
1513
 
1513
1514
    def _get_output_lines(self, lines):
1514
 
        """format lines for final output.
 
1515
        """Format lines for final output.
1515
1516
 
1516
 
        :param lines: A sequece of lines containing the parents list and the
 
1517
        :param lines: A sequence of lines containing the parents list and the
1517
1518
            path lines.
1518
1519
        """
1519
1520
        output_lines = [DirState.HEADER_FORMAT_3]
1527
1528
        return output_lines
1528
1529
 
1529
1530
    def _make_deleted_row(self, fileid_utf8, parents):
1530
 
        """Return a deleted for for fileid_utf8."""
 
1531
        """Return a deleted row for fileid_utf8."""
1531
1532
        return ('/', 'RECYCLED.BIN', 'file', fileid_utf8, 0, DirState.NULLSTAT,
1532
1533
            ''), parents
1533
1534
 
1587
1588
            self._read_header()
1588
1589
 
1589
1590
    def _read_prelude(self):
1590
 
        """Read in the prelude header of the dirstate file
 
1591
        """Read in the prelude header of the dirstate file.
1591
1592
 
1592
1593
        This only reads in the stuff that is not connected to the crc
1593
1594
        checksum. The position will be correct to read in the rest of
1610
1611
 
1611
1612
        We reuse the existing file, because that prevents race conditions with
1612
1613
        file creation, and use oslocks on it to prevent concurrent modification
1613
 
        and reads - because dirstates incremental data aggretation is not
 
1614
        and reads - because dirstate's incremental data aggregation is not
1614
1615
        compatible with reading a modified file, and replacing a file in use by
1615
 
        another process is impossible on windows.
 
1616
        another process is impossible on Windows.
1616
1617
 
1617
1618
        A dirstate in read only mode should be smart enough though to validate
1618
1619
        that the file has not changed, and otherwise discard its cache and
1679
1680
            "path_id %r is not a plain string" % (new_id,)
1680
1681
        self._read_dirblocks_if_needed()
1681
1682
        if len(path):
1682
 
            # logic not written
 
1683
            # TODO: logic not written
1683
1684
            raise NotImplementedError(self.set_path_id)
1684
1685
        # TODO: check new id is unique
1685
1686
        entry = self._get_entry(0, path_utf8=path)
1787
1788
                        # this file id is at a different path in one of the
1788
1789
                        # other trees, so put absent pointers there
1789
1790
                        # This is the vertical axis in the matrix, all pointing
1790
 
                        # tot he real path.
 
1791
                        # to the real path.
1791
1792
                        by_path[entry_key][tree_index] = ('r', path_utf8, 0, False, '')
1792
1793
                # by path consistency: Insert into an existing path record (trivial), or 
1793
1794
                # add a new one with relocation pointers for the other tree indexes.
1862
1863
        new_iterator = new_inv.iter_entries_by_dir()
1863
1864
        # we will be modifying the dirstate, so we need a stable iterator. In
1864
1865
        # future we might write one, for now we just clone the state into a
1865
 
        # list - which is a shallow copy, so each 
 
1866
        # list - which is a shallow copy.
1866
1867
        old_iterator = iter(list(self._iter_entries()))
1867
1868
        # both must have roots so this is safe:
1868
1869
        current_new = new_iterator.next()
1936
1937
    def _make_absent(self, current_old):
1937
1938
        """Mark current_old - an entry - as absent for tree 0.
1938
1939
 
1939
 
        :return: True if this was the last details entry for they entry key:
 
1940
        :return: True if this was the last details entry for the entry key:
1940
1941
            that is, if the underlying block has had the entry removed, thus
1941
1942
            shrinking in length.
1942
1943
        """
1943
1944
        # build up paths that this id will be left at after the change is made,
1944
1945
        # so we can update their cross references in tree 0
1945
1946
        all_remaining_keys = set()
1946
 
        # Dont check the working tree, because its going.
 
1947
        # Dont check the working tree, because it's going.
1947
1948
        for details in current_old[1][1:]:
1948
1949
            if details[0] not in ('a', 'r'): # absent, relocated
1949
1950
                all_remaining_keys.add(current_old[0])
2238
2239
        self._split_path_cache = {}
2239
2240
 
2240
2241
    def lock_read(self):
2241
 
        """Acquire a read lock on the dirstate"""
 
2242
        """Acquire a read lock on the dirstate."""
2242
2243
        if self._lock_token is not None:
2243
2244
            raise errors.LockContention(self._lock_token)
2244
2245
        # TODO: jam 20070301 Rather than wiping completely, if the blocks are
2251
2252
        self._wipe_state()
2252
2253
 
2253
2254
    def lock_write(self):
2254
 
        """Acquire a write lock on the dirstate"""
 
2255
        """Acquire a write lock on the dirstate."""
2255
2256
        if self._lock_token is not None:
2256
2257
            raise errors.LockContention(self._lock_token)
2257
2258
        # TODO: jam 20070301 Rather than wiping completely, if the blocks are
2264
2265
        self._wipe_state()
2265
2266
 
2266
2267
    def unlock(self):
2267
 
        """Drop any locks held on the dirstate"""
 
2268
        """Drop any locks held on the dirstate."""
2268
2269
        if self._lock_token is None:
2269
2270
            raise errors.LockNotHeld(self)
2270
2271
        # TODO: jam 20070301 Rather than wiping completely, if the blocks are
2278
2279
        self._split_path_cache = {}
2279
2280
 
2280
2281
    def _requires_lock(self):
2281
 
        """Checks that a lock is currently held by someone on the dirstate"""
 
2282
        """Check that a lock is currently held by someone on the dirstate."""
2282
2283
        if not self._lock_token:
2283
2284
            raise errors.ObjectNotLocked(self)
2284
2285