/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

Merge from 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
364
365
        # find the location in the block.
365
366
        # check its not there
366
367
        # add it.
367
 
        #------- copied from inventory.make_entry
 
368
        #------- copied from inventory.ensure_normalized_name - keep synced.
368
369
        # --- normalized_filename wants a unicode basename only, so get one.
369
370
        dirname, basename = osutils.split(path)
370
371
        # we dont import normalized_filename directly because we want to be
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:
1469
1470
        kind = inv_entry.kind
1470
1471
        minikind = DirState._kind_to_minikind[kind]
1471
1472
        tree_data = inv_entry.revision
1472
 
        assert len(tree_data) > 0, 'empty revision for the inv_entry.'
 
1473
        assert tree_data, 'empty revision for the inv_entry %s.' % \
 
1474
            inv_entry.file_id
1473
1475
        if kind == 'directory':
1474
1476
            fingerprint = ''
1475
1477
            size = 0
1511
1513
        return self._id_index
1512
1514
 
1513
1515
    def _get_output_lines(self, lines):
1514
 
        """format lines for final output.
 
1516
        """Format lines for final output.
1515
1517
 
1516
 
        :param lines: A sequece of lines containing the parents list and the
 
1518
        :param lines: A sequence of lines containing the parents list and the
1517
1519
            path lines.
1518
1520
        """
1519
1521
        output_lines = [DirState.HEADER_FORMAT_3]
1527
1529
        return output_lines
1528
1530
 
1529
1531
    def _make_deleted_row(self, fileid_utf8, parents):
1530
 
        """Return a deleted for for fileid_utf8."""
 
1532
        """Return a deleted row for fileid_utf8."""
1531
1533
        return ('/', 'RECYCLED.BIN', 'file', fileid_utf8, 0, DirState.NULLSTAT,
1532
1534
            ''), parents
1533
1535
 
1587
1589
            self._read_header()
1588
1590
 
1589
1591
    def _read_prelude(self):
1590
 
        """Read in the prelude header of the dirstate file
 
1592
        """Read in the prelude header of the dirstate file.
1591
1593
 
1592
1594
        This only reads in the stuff that is not connected to the crc
1593
1595
        checksum. The position will be correct to read in the rest of
1610
1612
 
1611
1613
        We reuse the existing file, because that prevents race conditions with
1612
1614
        file creation, and use oslocks on it to prevent concurrent modification
1613
 
        and reads - because dirstates incremental data aggretation is not
 
1615
        and reads - because dirstate's incremental data aggregation is not
1614
1616
        compatible with reading a modified file, and replacing a file in use by
1615
 
        another process is impossible on windows.
 
1617
        another process is impossible on Windows.
1616
1618
 
1617
1619
        A dirstate in read only mode should be smart enough though to validate
1618
1620
        that the file has not changed, and otherwise discard its cache and
1679
1681
            "path_id %r is not a plain string" % (new_id,)
1680
1682
        self._read_dirblocks_if_needed()
1681
1683
        if len(path):
1682
 
            # logic not written
 
1684
            # TODO: logic not written
1683
1685
            raise NotImplementedError(self.set_path_id)
1684
1686
        # TODO: check new id is unique
1685
1687
        entry = self._get_entry(0, path_utf8=path)
1787
1789
                        # this file id is at a different path in one of the
1788
1790
                        # other trees, so put absent pointers there
1789
1791
                        # This is the vertical axis in the matrix, all pointing
1790
 
                        # tot he real path.
 
1792
                        # to the real path.
1791
1793
                        by_path[entry_key][tree_index] = ('r', path_utf8, 0, False, '')
1792
1794
                # by path consistency: Insert into an existing path record (trivial), or 
1793
1795
                # add a new one with relocation pointers for the other tree indexes.
1862
1864
        new_iterator = new_inv.iter_entries_by_dir()
1863
1865
        # we will be modifying the dirstate, so we need a stable iterator. In
1864
1866
        # future we might write one, for now we just clone the state into a
1865
 
        # list - which is a shallow copy, so each 
 
1867
        # list - which is a shallow copy.
1866
1868
        old_iterator = iter(list(self._iter_entries()))
1867
1869
        # both must have roots so this is safe:
1868
1870
        current_new = new_iterator.next()
1936
1938
    def _make_absent(self, current_old):
1937
1939
        """Mark current_old - an entry - as absent for tree 0.
1938
1940
 
1939
 
        :return: True if this was the last details entry for they entry key:
 
1941
        :return: True if this was the last details entry for the entry key:
1940
1942
            that is, if the underlying block has had the entry removed, thus
1941
1943
            shrinking in length.
1942
1944
        """
1943
1945
        # build up paths that this id will be left at after the change is made,
1944
1946
        # so we can update their cross references in tree 0
1945
1947
        all_remaining_keys = set()
1946
 
        # Dont check the working tree, because its going.
 
1948
        # Dont check the working tree, because it's going.
1947
1949
        for details in current_old[1][1:]:
1948
1950
            if details[0] not in ('a', 'r'): # absent, relocated
1949
1951
                all_remaining_keys.add(current_old[0])
2238
2240
        self._split_path_cache = {}
2239
2241
 
2240
2242
    def lock_read(self):
2241
 
        """Acquire a read lock on the dirstate"""
 
2243
        """Acquire a read lock on the dirstate."""
2242
2244
        if self._lock_token is not None:
2243
2245
            raise errors.LockContention(self._lock_token)
2244
2246
        # TODO: jam 20070301 Rather than wiping completely, if the blocks are
2251
2253
        self._wipe_state()
2252
2254
 
2253
2255
    def lock_write(self):
2254
 
        """Acquire a write lock on the dirstate"""
 
2256
        """Acquire a write lock on the dirstate."""
2255
2257
        if self._lock_token is not None:
2256
2258
            raise errors.LockContention(self._lock_token)
2257
2259
        # TODO: jam 20070301 Rather than wiping completely, if the blocks are
2264
2266
        self._wipe_state()
2265
2267
 
2266
2268
    def unlock(self):
2267
 
        """Drop any locks held on the dirstate"""
 
2269
        """Drop any locks held on the dirstate."""
2268
2270
        if self._lock_token is None:
2269
2271
            raise errors.LockNotHeld(self)
2270
2272
        # TODO: jam 20070301 Rather than wiping completely, if the blocks are
2278
2280
        self._split_path_cache = {}
2279
2281
 
2280
2282
    def _requires_lock(self):
2281
 
        """Checks that a lock is currently held by someone on the dirstate"""
 
2283
        """Check that a lock is currently held by someone on the dirstate."""
2282
2284
        if not self._lock_token:
2283
2285
            raise errors.ObjectNotLocked(self)
2284
2286