/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: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
220
220
    inventory,
221
221
    lock,
222
222
    osutils,
223
 
    static_tuple,
224
223
    trace,
225
224
    )
226
225
 
549
548
           self._ensure_block(block_index, entry_index, utf8path)
550
549
        self._dirblock_state = DirState.IN_MEMORY_MODIFIED
551
550
        if self._id_index:
552
 
            self._add_to_id_index(self._id_index, entry_key)
 
551
            self._id_index.setdefault(entry_key[2], set()).add(entry_key)
553
552
 
554
553
    def _bisect(self, paths):
555
554
        """Bisect through the disk structure for specific rows.
1567
1566
            return
1568
1567
        id_index = self._get_id_index()
1569
1568
        for file_id in new_ids:
1570
 
            for key in id_index.get(file_id, ()):
 
1569
            for key in id_index.get(file_id, []):
1571
1570
                block_i, entry_i, d_present, f_present = \
1572
1571
                    self._get_block_entry_index(key[0], key[1], tree_index)
1573
1572
                if not f_present:
1981
1980
                                          ' tree_index, file_id and path')
1982
1981
            return entry
1983
1982
        else:
1984
 
            possible_keys = self._get_id_index().get(fileid_utf8, ())
 
1983
            possible_keys = self._get_id_index().get(fileid_utf8, None)
1985
1984
            if not possible_keys:
1986
1985
                return None, None
1987
1986
            for key in possible_keys:
2144
2143
                yield entry
2145
2144
 
2146
2145
    def _get_id_index(self):
2147
 
        """Get an id index of self._dirblocks.
2148
 
        
2149
 
        This maps from file_id => [(directory, name, file_id)] entries where
2150
 
        that file_id appears in one of the trees.
2151
 
        """
 
2146
        """Get an id index of self._dirblocks."""
2152
2147
        if self._id_index is None:
2153
2148
            id_index = {}
2154
2149
            for key, tree_details in self._iter_entries():
2155
 
                self._add_to_id_index(id_index, key)
 
2150
                id_index.setdefault(key[2], set()).add(key)
2156
2151
            self._id_index = id_index
2157
2152
        return self._id_index
2158
2153
 
2159
 
    def _add_to_id_index(self, id_index, entry_key):
2160
 
        """Add this entry to the _id_index mapping."""
2161
 
        # This code used to use a set for every entry in the id_index. However,
2162
 
        # it is *rare* to have more than one entry. So a set is a large
2163
 
        # overkill. And even when we do, we won't ever have more than the
2164
 
        # number of parent trees. Which is still a small number (rarely >2). As
2165
 
        # such, we use a simple tuple, and do our own uniqueness checks. While
2166
 
        # the 'in' check is O(N) since N is nicely bounded it shouldn't ever
2167
 
        # cause quadratic failure.
2168
 
        # TODO: This should use StaticTuple
2169
 
        file_id = entry_key[2]
2170
 
        entry_key = static_tuple.StaticTuple.from_sequence(entry_key)
2171
 
        if file_id not in id_index:
2172
 
            id_index[file_id] = static_tuple.StaticTuple(entry_key,)
2173
 
        else:
2174
 
            entry_keys = id_index[file_id]
2175
 
            if entry_key not in entry_keys:
2176
 
                id_index[file_id] = entry_keys + (entry_key,)
2177
 
 
2178
 
    def _remove_from_id_index(self, id_index, entry_key):
2179
 
        """Remove this entry from the _id_index mapping.
2180
 
 
2181
 
        It is an programming error to call this when the entry_key is not
2182
 
        already present.
2183
 
        """
2184
 
        file_id = entry_key[2]
2185
 
        entry_keys = list(id_index[file_id])
2186
 
        entry_keys.remove(entry_key)
2187
 
        id_index[file_id] = static_tuple.StaticTuple.from_sequence(entry_keys)
2188
 
 
2189
2154
    def _get_output_lines(self, lines):
2190
2155
        """Format lines for final output.
2191
2156
 
2449
2414
                continue
2450
2415
            by_path[entry[0]] = [entry[1][0]] + \
2451
2416
                [DirState.NULL_PARENT_DETAILS] * parent_count
2452
 
            # TODO: Possibly inline this, since we know it isn't present yet
2453
 
            #       id_index[entry[0][2]] = (entry[0],)
2454
 
            self._add_to_id_index(id_index, entry[0])
 
2417
            id_index[entry[0][2]] = set([entry[0]])
2455
2418
 
2456
2419
        # now the parent trees:
2457
2420
        for tree_index, tree in enumerate(parent_trees):
2479
2442
                new_entry_key = (dirname, basename, file_id)
2480
2443
                # tree index consistency: All other paths for this id in this tree
2481
2444
                # index must point to the correct path.
2482
 
                for entry_key in id_index.get(file_id, ()):
 
2445
                for entry_key in id_index.setdefault(file_id, set()):
2483
2446
                    # TODO:PROFILING: It might be faster to just update
2484
2447
                    # rather than checking if we need to, and then overwrite
2485
2448
                    # the one we are located at.
2491
2454
                        by_path[entry_key][tree_index] = ('r', path_utf8, 0, False, '')
2492
2455
                # by path consistency: Insert into an existing path record (trivial), or
2493
2456
                # add a new one with relocation pointers for the other tree indexes.
2494
 
                entry_keys = id_index.get(file_id, ())
2495
 
                if new_entry_key in entry_keys:
 
2457
                if new_entry_key in id_index[file_id]:
2496
2458
                    # there is already an entry where this data belongs, just insert it.
2497
2459
                    by_path[new_entry_key][tree_index] = \
2498
2460
                        self._inv_entry_to_details(entry)
2503
2465
                    new_details = []
2504
2466
                    for lookup_index in xrange(tree_index):
2505
2467
                        # boundary case: this is the first occurence of file_id
2506
 
                        # so there are no id_indexes, possibly take this out of
 
2468
                        # so there are no id_indexs, possibly take this out of
2507
2469
                        # the loop?
2508
 
                        if not len(entry_keys):
 
2470
                        if not len(id_index[file_id]):
2509
2471
                            new_details.append(DirState.NULL_PARENT_DETAILS)
2510
2472
                        else:
2511
2473
                            # grab any one entry, use it to find the right path.
2512
2474
                            # TODO: optimise this to reduce memory use in highly
2513
2475
                            # fragmented situations by reusing the relocation
2514
2476
                            # records.
2515
 
                            a_key = iter(entry_keys).next()
 
2477
                            a_key = iter(id_index[file_id]).next()
2516
2478
                            if by_path[a_key][lookup_index][0] in ('r', 'a'):
2517
2479
                                # its a pointer or missing statement, use it as is.
2518
2480
                                new_details.append(by_path[a_key][lookup_index])
2523
2485
                    new_details.append(self._inv_entry_to_details(entry))
2524
2486
                    new_details.extend(new_location_suffix)
2525
2487
                    by_path[new_entry_key] = new_details
2526
 
                    self._add_to_id_index(id_index, new_entry_key)
 
2488
                    id_index[file_id].add(new_entry_key)
2527
2489
        # --- end generation of full tree mappings
2528
2490
 
2529
2491
        # sort and output all the entries
2681
2643
        if tracing:
2682
2644
            trace.mutter("set_state_from_inventory complete.")
2683
2645
 
2684
 
    def set_state_from_scratch(self, working_inv, parent_trees, parent_ghosts):
2685
 
        """Wipe the currently stored state and set it to something new.
2686
 
 
2687
 
        This is a hard-reset for the data we are working with.
2688
 
        """
2689
 
        # Technically, we really want a write lock, but until we write, we
2690
 
        # don't really need it.
2691
 
        self._requires_lock()
2692
 
        # root dir and root dir contents with no children. We have to have a
2693
 
        # root for set_state_from_inventory to work correctly.
2694
 
        empty_root = (('', '', inventory.ROOT_ID),
2695
 
                      [('d', '', 0, False, DirState.NULLSTAT)])
2696
 
        empty_tree_dirblocks = [('', [empty_root]), ('', [])]
2697
 
        self._set_data([], empty_tree_dirblocks)
2698
 
        self.set_state_from_inventory(working_inv)
2699
 
        self.set_parent_trees(parent_trees, parent_ghosts)
2700
 
 
2701
2646
    def _make_absent(self, current_old):
2702
2647
        """Mark current_old - an entry - as absent for tree 0.
2703
2648
 
2728
2673
            block[1].pop(entry_index)
2729
2674
            # if we have an id_index in use, remove this key from it for this id.
2730
2675
            if self._id_index is not None:
2731
 
                self._remove_from_id_index(self._id_index, current_old[0])
 
2676
                self._id_index[current_old[0][2]].remove(current_old[0])
2732
2677
        # update all remaining keys for this id to record it as absent. The
2733
2678
        # existing details may either be the record we are marking as deleted
2734
2679
        # (if there were other trees with the id present at this path), or may
2803
2748
                    else:
2804
2749
                        break
2805
2750
            # new entry, synthesis cross reference here,
2806
 
            existing_keys = id_index.get(key[2], ())
 
2751
            existing_keys = id_index.setdefault(key[2], set())
2807
2752
            if not existing_keys:
2808
2753
                # not currently in the state, simplest case
2809
2754
                new_entry = key, [new_details] + self._empty_parent_info()
2840
2785
                    # loop.
2841
2786
                    other_entry = other_block[other_entry_index]
2842
2787
                    other_entry[1][0] = ('r', path_utf8, 0, False, '')
2843
 
                    if self._maybe_remove_row(other_block, other_entry_index,
2844
 
                                              id_index):
2845
 
                        # If the row holding this was removed, we need to
2846
 
                        # recompute where this entry goes
2847
 
                        entry_index, _ = self._find_entry_index(key, block)
 
2788
                    self._maybe_remove_row(other_block, other_entry_index,
 
2789
                        id_index)
2848
2790
 
2849
2791
                # This loop:
2850
2792
                # adds a tuple to the new details for each column
2852
2794
                #  - or by creating a new pointer to the right row inside that column
2853
2795
                num_present_parents = self._num_present_parents()
2854
2796
                if num_present_parents:
2855
 
                    # TODO: This re-evaluates the existing_keys set, do we need
2856
 
                    #       to do that ourselves?
2857
2797
                    other_key = list(existing_keys)[0]
2858
2798
                for lookup_index in xrange(1, num_present_parents + 1):
2859
2799
                    # grab any one entry, use it to find the right path.
2878
2818
                        pointer_path = osutils.pathjoin(*other_key[0:2])
2879
2819
                        new_entry[1].append(('r', pointer_path, 0, False, ''))
2880
2820
            block.insert(entry_index, new_entry)
2881
 
            self._add_to_id_index(id_index, key)
 
2821
            existing_keys.add(key)
2882
2822
        else:
2883
2823
            # Does the new state matter?
2884
2824
            block[entry_index][1][0] = new_details
2893
2833
            # converted to relocated.
2894
2834
            if path_utf8 is None:
2895
2835
                raise AssertionError('no path')
2896
 
            existing_keys = id_index.get(key[2], ())
2897
 
            if key not in existing_keys:
2898
 
                raise AssertionError('We found the entry in the blocks, but'
2899
 
                    ' the key is not in the id_index.'
2900
 
                    ' key: %s, existing_keys: %s' % (key, existing_keys))
2901
 
            for entry_key in existing_keys:
 
2836
            for entry_key in id_index.setdefault(key[2], set()):
2902
2837
                # TODO:PROFILING: It might be faster to just update
2903
2838
                # rather than checking if we need to, and then overwrite
2904
2839
                # the one we are located at.
2928
2863
        """Remove index if it is absent or relocated across the row.
2929
2864
        
2930
2865
        id_index is updated accordingly.
2931
 
        :return: True if we removed the row, False otherwise
2932
2866
        """
2933
2867
        present_in_row = False
2934
2868
        entry = block[index]
2938
2872
                break
2939
2873
        if not present_in_row:
2940
2874
            block.pop(index)
2941
 
            self._remove_from_id_index(id_index, entry[0])
2942
 
            return True
2943
 
        return False
 
2875
            id_index[entry[0][2]].remove(entry[0])
2944
2876
 
2945
2877
    def _validate(self):
2946
2878
        """Check that invariants on the dirblock are correct.
3088
3020
                        raise AssertionError(
3089
3021
                            'file_id %r did not match entry key %s'
3090
3022
                            % (file_id, entry_key))
3091
 
                if len(entry_keys) != len(set(entry_keys)):
3092
 
                    raise AssertionError(
3093
 
                        'id_index contained non-unique data for %s'
3094
 
                        % (entry_keys,))
3095
3023
 
3096
3024
    def _wipe_state(self):
3097
3025
        """Forget all state information about the dirstate."""