~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/index.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
    'CombinedGraphIndex',
21
21
    'GraphIndex',
22
22
    'GraphIndexBuilder',
 
23
    'GraphIndexPrefixAdapter',
23
24
    'InMemoryGraphIndex',
24
25
    ]
25
26
 
313
314
            self._buffer_all()
314
315
        if self.node_ref_lists:
315
316
            for key, (value, node_ref_lists) in self._nodes.iteritems():
316
 
                yield key, value, node_ref_lists
 
317
                yield self, key, value, node_ref_lists
317
318
        else:
318
319
            for key, value in self._nodes.iteritems():
319
 
                yield key, value
 
320
                yield self, key, value
320
321
 
321
322
    def _read_prefix(self, stream):
322
323
        signature = stream.read(len(self._signature()))
354
355
        if self.node_ref_lists:
355
356
            for key in keys:
356
357
                value, node_refs = self._nodes[key]
357
 
                yield key, value, node_refs
 
358
                yield self, key, value, node_refs
358
359
        else:
359
360
            for key in keys:
360
 
                yield key, self._nodes[key]
 
361
                yield self, key, self._nodes[key]
361
362
 
362
363
    def iter_entries_prefix(self, keys):
363
364
        """Iterate over keys within the index using prefix matching.
391
392
                    raise errors.BadIndexKey(key)
392
393
                if self.node_ref_lists:
393
394
                    value, node_refs = self._nodes[key]
394
 
                    yield key, value, node_refs
 
395
                    yield self, key, value, node_refs
395
396
                else:
396
 
                    yield key, self._nodes[key]
 
397
                    yield self, key, self._nodes[key]
397
398
            return
398
399
        for key in keys:
399
400
            # sanity check
426
427
                        for value in key_dict.itervalues():
427
428
                            # each value is the key:value:node refs tuple
428
429
                            # ready to yield.
429
 
                            yield value
 
430
                            yield (self, ) + value
430
431
            else:
431
432
                # the last thing looked up was a terminal element
432
 
                yield key_dict
 
433
                yield (self, ) + key_dict
433
434
 
434
435
    def _signature(self):
435
436
        """The file signature for this index type."""
483
484
        seen_keys = set()
484
485
        for index in self._indices:
485
486
            for node in index.iter_all_entries():
486
 
                if node[0] not in seen_keys:
 
487
                if node[1] not in seen_keys:
487
488
                    yield node
488
 
                    seen_keys.add(node[0])
 
489
                    seen_keys.add(node[1])
489
490
 
490
491
    def iter_entries(self, keys):
491
492
        """Iterate over keys within the index.
503
504
            if not keys:
504
505
                return
505
506
            for node in index.iter_entries(keys):
506
 
                keys.remove(node[0])
 
507
                keys.remove(node[1])
507
508
                yield node
508
509
 
509
510
    def iter_entries_prefix(self, keys):
532
533
        seen_keys = set()
533
534
        for index in self._indices:
534
535
            for node in index.iter_entries_prefix(keys):
535
 
                if node[0] in seen_keys:
 
536
                if node[1] in seen_keys:
536
537
                    continue
537
 
                seen_keys.add(node[0])
 
538
                seen_keys.add(node[1])
538
539
                yield node
539
540
 
540
541
    def validate(self):
573
574
        if self.reference_lists:
574
575
            for key, (absent, references, value) in self._nodes.iteritems():
575
576
                if not absent:
576
 
                    yield key, value, references
 
577
                    yield self, key, value, references
577
578
        else:
578
579
            for key, (absent, references, value) in self._nodes.iteritems():
579
580
                if not absent:
580
 
                    yield key, value
 
581
                    yield self, key, value
581
582
 
582
583
    def iter_entries(self, keys):
583
584
        """Iterate over keys within the index.
592
593
            for key in keys.intersection(self._nodes):
593
594
                node = self._nodes[key]
594
595
                if not node[0]:
595
 
                    yield key, node[2], node[1]
 
596
                    yield self, key, node[2], node[1]
596
597
        else:
597
598
            for key in keys.intersection(self._nodes):
598
599
                node = self._nodes[key]
599
600
                if not node[0]:
600
 
                    yield key, node[2]
 
601
                    yield self, key, node[2]
601
602
 
602
603
    def iter_entries_prefix(self, keys):
603
604
        """Iterate over keys within the index using prefix matching.
632
633
                if node[0]:
633
634
                    continue 
634
635
                if self.reference_lists:
635
 
                    yield key, node[2], node[1]
 
636
                    yield self, key, node[2], node[1]
636
637
                else:
637
 
                    yield key, node[2]
 
638
                    yield self ,key, node[2]
638
639
            return
639
640
        for key in keys:
640
641
            # sanity check
665
666
                    else:
666
667
                        # yield keys
667
668
                        for value in key_dict.itervalues():
668
 
                            yield value
 
669
                            yield (self, ) + value
669
670
            else:
670
 
                yield key_dict
 
671
                yield (self, ) + key_dict
671
672
 
672
673
    def validate(self):
673
674
        """In memory index's have no known corruption at the moment."""
 
675
 
 
676
 
 
677
class GraphIndexPrefixAdapter(object):
 
678
    """An adapter between GraphIndex with different key lengths.
 
679
 
 
680
    Queries against this will emit queries against the adapted Graph with the
 
681
    prefix added, queries for all items use iter_entries_prefix. The returned
 
682
    nodes will have their keys and node references adjusted to remove the 
 
683
    prefix. Finally, an add_nodes_callback can be supplied - when called the
 
684
    nodes and references being added will have prefix prepended.
 
685
    """
 
686
 
 
687
    def __init__(self, adapted, prefix, missing_key_length, add_nodes_callback=None):
 
688
        """Construct an adapter against adapted with prefix."""
 
689
        self.adapted = adapted
 
690
        self.prefix = prefix + (None,)*missing_key_length
 
691
        self.prefix_key = prefix
 
692
        self.prefix_len = len(prefix)
 
693
        self.add_nodes_callback = add_nodes_callback
 
694
 
 
695
    def add_nodes(self, nodes):
 
696
        """Add nodes to the index.
 
697
 
 
698
        :param nodes: An iterable of (key, node_refs, value) entries to add.
 
699
        """
 
700
        # save nodes in case its an iterator
 
701
        nodes = tuple(nodes)
 
702
        translated_nodes = []
 
703
        try:
 
704
            for (key, value, node_refs) in nodes:
 
705
                adjusted_references = (
 
706
                    tuple(tuple(self.prefix_key + ref_node for ref_node in ref_list)
 
707
                        for ref_list in node_refs))
 
708
                translated_nodes.append((self.prefix_key + key, value,
 
709
                    adjusted_references))
 
710
        except ValueError:
 
711
            # XXX: TODO add an explicit interface for getting the reference list
 
712
            # status, to handle this bit of user-friendliness in the API more 
 
713
            # explicitly.
 
714
            for (key, value) in nodes:
 
715
                translated_nodes.append((self.prefix_key + key, value))
 
716
        self.add_nodes_callback(translated_nodes)
 
717
 
 
718
    def add_node(self, key, value, references=()):
 
719
        """Add a node to the index.
 
720
 
 
721
        :param key: The key. keys are non-empty tuples containing
 
722
            as many whitespace-free utf8 bytestrings as the key length
 
723
            defined for this index.
 
724
        :param references: An iterable of iterables of keys. Each is a
 
725
            reference to another key.
 
726
        :param value: The value to associate with the key. It may be any
 
727
            bytes as long as it does not contain \0 or \n.
 
728
        """
 
729
        self.add_nodes(((key, value, references), ))
 
730
 
 
731
    def _strip_prefix(self, an_iter):
 
732
        """Strip prefix data from nodes and return it."""
 
733
        for node in an_iter:
 
734
            # cross checks
 
735
            if node[1][:self.prefix_len] != self.prefix_key:
 
736
                raise errors.BadIndexData(self)
 
737
            for ref_list in node[3]:
 
738
                for ref_node in ref_list:
 
739
                    if ref_node[:self.prefix_len] != self.prefix_key:
 
740
                        raise errors.BadIndexData(self)
 
741
            yield node[0], node[1][self.prefix_len:], node[2], (
 
742
                tuple(tuple(ref_node[self.prefix_len:] for ref_node in ref_list)
 
743
                for ref_list in node[3]))
 
744
 
 
745
    def iter_all_entries(self):
 
746
        """Iterate over all keys within the index
 
747
 
 
748
        iter_all_entries is implemented against the adapted index using
 
749
        iter_entries_prefix.
 
750
 
 
751
        :return: An iterable of (key, reference_lists, value). There is no
 
752
            defined order for the result iteration - it will be in the most
 
753
            efficient order for the index (in this case dictionary hash order).
 
754
        """
 
755
        return self._strip_prefix(self.adapted.iter_entries_prefix([self.prefix]))
 
756
 
 
757
    def iter_entries(self, keys):
 
758
        """Iterate over keys within the index.
 
759
 
 
760
        :param keys: An iterable providing the keys to be retrieved.
 
761
        :return: An iterable of (key, reference_lists, value). There is no
 
762
            defined order for the result iteration - it will be in the most
 
763
            efficient order for the index (keys iteration order in this case).
 
764
        """
 
765
        return self._strip_prefix(self.adapted.iter_entries(
 
766
            self.prefix_key + key for key in keys))
 
767
 
 
768
    def iter_entries_prefix(self, keys):
 
769
        """Iterate over keys within the index using prefix matching.
 
770
 
 
771
        Prefix matching is applied within the tuple of a key, not to within
 
772
        the bytestring of each key element. e.g. if you have the keys ('foo',
 
773
        'bar'), ('foobar', 'gam') and do a prefix search for ('foo', None) then
 
774
        only the former key is returned.
 
775
 
 
776
        :param keys: An iterable providing the key prefixes to be retrieved.
 
777
            Each key prefix takes the form of a tuple the length of a key, but
 
778
            with the last N elements 'None' rather than a regular bytestring.
 
779
            The first element cannot be 'None'.
 
780
        :return: An iterable as per iter_all_entries, but restricted to the
 
781
            keys with a matching prefix to those supplied. No additional keys
 
782
            will be returned, and every match that is in the index will be
 
783
            returned.
 
784
        """
 
785
        return self._strip_prefix(self.adapted.iter_entries_prefix(
 
786
            self.prefix_key + key for key in keys))
 
787
 
 
788
    def validate(self):
 
789
        """Call the adapted's validate."""
 
790
        self.adapted.validate()