~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/index.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2009-11-17 03:20:35 UTC
  • mfrom: (4792.4.3 456036)
  • Revision ID: pqm@pqm.ubuntu.com-20091117032035-s3sgtlixj1lrminn
(Gordon Tyler) Fix IndexError during 'bzr ignore /' (#456036)

Show diffs side-by-side

added added

removed removed

Lines of Context:
93
93
        :param key_elements: The number of bytestrings in each key.
94
94
        """
95
95
        self.reference_lists = reference_lists
 
96
        self._keys = set()
96
97
        # A dict of {key: (absent, ref_lists, value)}
97
98
        self._nodes = {}
98
 
        # Keys that are referenced but not actually present in this index
99
 
        self._absent_keys = set()
100
99
        self._nodes_by_key = None
101
100
        self._key_length = key_elements
102
101
        self._optimize_for_size = False
166
165
            return
167
166
        key_dict = self._nodes_by_key
168
167
        if self.reference_lists:
169
 
            key_value = StaticTuple(key, value, node_refs)
 
168
            key_value = key, value, node_refs
170
169
        else:
171
 
            key_value = StaticTuple(key, value)
 
170
            key_value = key, value
172
171
        for subkey in key[:-1]:
173
172
            key_dict = key_dict.setdefault(subkey, {})
174
173
        key_dict[key[-1]] = key_value
190
189
                                This may contain duplicates if the same key is
191
190
                                referenced in multiple lists.
192
191
        """
193
 
        as_st = StaticTuple.from_sequence
194
192
        self._check_key(key)
195
193
        if _newline_null_re.search(value) is not None:
196
194
            raise errors.BadIndexValue(value)
205
203
                if reference not in self._nodes:
206
204
                    self._check_key(reference)
207
205
                    absent_references.append(reference)
208
 
            reference_list = as_st([as_st(ref).intern()
209
 
                                    for ref in reference_list])
210
 
            node_refs.append(reference_list)
211
 
        return as_st(node_refs), absent_references
 
206
            # TODO: StaticTuple
 
207
            node_refs.append(tuple(reference_list))
 
208
        # TODO: StaticTuple
 
209
        return tuple(node_refs), absent_references
212
210
 
213
211
    def add_node(self, key, value, references=()):
214
212
        """Add a node to the index.
229
227
            # There may be duplicates, but I don't think it is worth worrying
230
228
            # about
231
229
            self._nodes[reference] = ('a', (), '')
232
 
        self._absent_keys.update(absent_references)
233
 
        self._absent_keys.discard(key)
234
230
        self._nodes[key] = ('', node_refs, value)
 
231
        self._keys.add(key)
235
232
        if self._nodes_by_key is not None and self._key_length > 1:
236
233
            self._update_nodes_by_key(key, value, node_refs)
237
234
 
246
243
        lines = [_SIGNATURE]
247
244
        lines.append(_OPTION_NODE_REFS + str(self.reference_lists) + '\n')
248
245
        lines.append(_OPTION_KEY_ELEMENTS + str(self._key_length) + '\n')
249
 
        key_count = len(self._nodes) - len(self._absent_keys)
250
 
        lines.append(_OPTION_LEN + str(key_count) + '\n')
 
246
        lines.append(_OPTION_LEN + str(len(self._keys)) + '\n')
251
247
        prefix_length = sum(len(x) for x in lines)
252
248
        # references are byte offsets. To avoid having to do nasty
253
249
        # polynomial work to resolve offsets (references to later in the
455
451
        trailers = 0
456
452
        pos = stream.tell()
457
453
        lines = stream.read().split('\n')
458
 
        stream.close()
459
454
        del lines[-1]
460
455
        _, _, _, trailers = self._parse_lines(lines, pos)
461
456
        for key, absent, references, value in self._keys_by_offset.itervalues():
468
463
                node_value = value
469
464
            self._nodes[key] = node_value
470
465
        # cache the keys for quick set intersections
 
466
        self._keys = set(self._nodes)
471
467
        if trailers != 1:
472
468
            # there must be one line - the empty trailer line.
473
469
            raise errors.BadIndexData(self)
488
484
            raise ValueError('No ref list %d, index has %d ref lists'
489
485
                % (ref_list_num, self.node_ref_lists))
490
486
        refs = set()
491
 
        nodes = self._nodes
492
 
        for key, (value, ref_lists) in nodes.iteritems():
 
487
        for key, (value, ref_lists) in self._nodes.iteritems():
493
488
            ref_list = ref_lists[ref_list_num]
494
 
            refs.update([ref for ref in ref_list if ref not in nodes])
495
 
        return refs
 
489
            refs.update(ref_list)
 
490
        return refs - self._keys
496
491
 
497
492
    def _get_nodes_by_key(self):
498
493
        if self._nodes_by_key is None:
625
620
 
626
621
    def _iter_entries_from_total_buffer(self, keys):
627
622
        """Iterate over keys when the entire index is parsed."""
628
 
        # Note: See the note in BTreeBuilder.iter_entries for why we don't use
629
 
        #       .intersection() here
630
 
        nodes = self._nodes
631
 
        keys = [key for key in keys if key in nodes]
 
623
        keys = keys.intersection(self._keys)
632
624
        if self.node_ref_lists:
633
625
            for key in keys:
634
 
                value, node_refs = nodes[key]
 
626
                value, node_refs = self._nodes[key]
635
627
                yield self, key, value, node_refs
636
628
        else:
637
629
            for key in keys:
638
 
                yield self, key, nodes[key]
 
630
                yield self, key, self._nodes[key]
639
631
 
640
632
    def iter_entries(self, keys):
641
633
        """Iterate over keys within the index.
1515
1507
            defined order for the result iteration - it will be in the most
1516
1508
            efficient order for the index (keys iteration order in this case).
1517
1509
        """
1518
 
        # Note: See BTreeBuilder.iter_entries for an explanation of why we
1519
 
        #       aren't using set().intersection() here
1520
 
        nodes = self._nodes
1521
 
        keys = [key for key in keys if key in nodes]
 
1510
        keys = set(keys)
1522
1511
        if self.reference_lists:
1523
 
            for key in keys:
1524
 
                node = nodes[key]
 
1512
            for key in keys.intersection(self._keys):
 
1513
                node = self._nodes[key]
1525
1514
                if not node[0]:
1526
1515
                    yield self, key, node[2], node[1]
1527
1516
        else:
1528
 
            for key in keys:
1529
 
                node = nodes[key]
 
1517
            for key in keys.intersection(self._keys):
 
1518
                node = self._nodes[key]
1530
1519
                if not node[0]:
1531
1520
                    yield self, key, node[2]
1532
1521
 
1606
1595
 
1607
1596
        For InMemoryGraphIndex the estimate is exact.
1608
1597
        """
1609
 
        return len(self._nodes) - len(self._absent_keys)
 
1598
        return len(self._keys)
1610
1599
 
1611
1600
    def validate(self):
1612
1601
        """In memory index's have no known corruption at the moment."""