/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/chk_map.py

  • Committer: John Arbash Meinel
  • Date: 2009-07-08 14:37:25 UTC
  • mfrom: (4516 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4517.
  • Revision ID: john@arbash-meinel.com-20090708143725-sc9sjy3mz4cxwxzz
Merge bzr.dev 4516

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2008 Canonical Ltd
 
1
# Copyright (C) 2008, 2009 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
38
38
"""
39
39
 
40
40
import heapq
41
 
import time
42
41
 
43
42
from bzrlib import lazy_import
44
43
lazy_import.lazy_import(globals(), """
45
44
from bzrlib import versionedfile
46
45
""")
47
46
from bzrlib import (
48
 
    errors,
49
47
    lru_cache,
50
48
    osutils,
51
49
    registry,
121
119
 
122
120
    def _ensure_root(self):
123
121
        """Ensure that the root node is an object not a key."""
124
 
        if type(self._root_node) == tuple:
 
122
        if type(self._root_node) is tuple:
125
123
            # Demand-load the root
126
124
            self._root_node = self._get_node(self._root_node)
127
125
 
135
133
        :param node: A tuple key or node object.
136
134
        :return: A node object.
137
135
        """
138
 
        if type(node) == tuple:
 
136
        if type(node) is tuple:
139
137
            bytes = self._read_bytes(node)
140
138
            return _deserialise(bytes, node,
141
139
                search_key_func=self._search_key_func)
203
201
            multiple pages.
204
202
        :return: The root chk of the resulting CHKMap.
205
203
        """
206
 
        result = CHKMap(store, None, search_key_func=search_key_func)
 
204
        root_key = klass._create_directly(store, initial_value,
 
205
            maximum_size=maximum_size, key_width=key_width,
 
206
            search_key_func=search_key_func)
 
207
        return root_key
 
208
 
 
209
    @classmethod
 
210
    def _create_via_map(klass, store, initial_value, maximum_size=0,
 
211
                        key_width=1, search_key_func=None):
 
212
        result = klass(store, None, search_key_func=search_key_func)
207
213
        result._root_node.set_maximum_size(maximum_size)
208
214
        result._root_node._key_width = key_width
209
215
        delta = []
210
216
        for key, value in initial_value.items():
211
217
            delta.append((None, key, value))
212
 
        return result.apply_delta(delta)
 
218
        root_key = result.apply_delta(delta)
 
219
        return root_key
 
220
 
 
221
    @classmethod
 
222
    def _create_directly(klass, store, initial_value, maximum_size=0,
 
223
                         key_width=1, search_key_func=None):
 
224
        node = LeafNode(search_key_func=search_key_func)
 
225
        node.set_maximum_size(maximum_size)
 
226
        node._key_width = key_width
 
227
        node._items = dict(initial_value)
 
228
        node._raw_size = sum([node._key_value_len(key, value)
 
229
                              for key,value in initial_value.iteritems()])
 
230
        node._len = len(node._items)
 
231
        node._compute_search_prefix()
 
232
        node._compute_serialised_prefix()
 
233
        if (node._len > 1
 
234
            and maximum_size
 
235
            and node._current_size() > maximum_size):
 
236
            prefix, node_details = node._split(store)
 
237
            if len(node_details) == 1:
 
238
                raise AssertionError('Failed to split using node._split')
 
239
            node = InternalNode(prefix, search_key_func=search_key_func)
 
240
            node.set_maximum_size(maximum_size)
 
241
            node._key_width = key_width
 
242
            for split, subnode in node_details:
 
243
                node.add_node(split, subnode)
 
244
        keys = list(node.serialise(store))
 
245
        return keys[-1]
213
246
 
214
247
    def iter_changes(self, basis):
215
248
        """Iterate over the changes between basis and self.
465
498
 
466
499
    def _node_key(self, node):
467
500
        """Get the key for a node whether it's a tuple or node."""
468
 
        if type(node) == tuple:
 
501
        if type(node) is tuple:
469
502
            return node
470
503
        else:
471
504
            return node._key
491
524
 
492
525
        :return: The key of the root node.
493
526
        """
494
 
        if type(self._root_node) == tuple:
 
527
        if type(self._root_node) is tuple:
495
528
            # Already saved.
496
529
            return self._root_node
497
530
        keys = list(self._root_node.serialise(self._store))
764
797
                result[prefix] = node
765
798
            else:
766
799
                node = result[prefix]
767
 
            node.map(store, key, value)
 
800
            sub_prefix, node_details = node.map(store, key, value)
 
801
            if len(node_details) > 1:
 
802
                if prefix != sub_prefix:
 
803
                    # This node has been split and is now found via a different
 
804
                    # path
 
805
                    result.pop(prefix)
 
806
                new_node = InternalNode(sub_prefix,
 
807
                    search_key_func=self._search_key_func)
 
808
                new_node.set_maximum_size(self._maximum_size)
 
809
                new_node._key_width = self._key_width
 
810
                for split, node in node_details:
 
811
                    new_node.add_node(split, node)
 
812
                result[prefix] = new_node
768
813
        return common_prefix, result.items()
769
814
 
770
815
    def map(self, store, key, value):
955
1000
        # prefix is the key in self._items to use, key_filter is the key_filter
956
1001
        # entries that would match this node
957
1002
        keys = {}
 
1003
        shortcut = False
958
1004
        if key_filter is None:
 
1005
            # yielding all nodes, yield whatever we have, and queue up a read
 
1006
            # for whatever we are missing
 
1007
            shortcut = True
959
1008
            for prefix, node in self._items.iteritems():
960
 
                if type(node) == tuple:
 
1009
                if node.__class__ is tuple:
961
1010
                    keys[node] = (prefix, None)
962
1011
                else:
963
1012
                    yield node, None
964
 
        else:
965
 
            # XXX defaultdict ?
 
1013
        elif len(key_filter) == 1:
 
1014
            # Technically, this path could also be handled by the first check
 
1015
            # in 'self._node_width' in length_filters. However, we can handle
 
1016
            # this case without spending any time building up the
 
1017
            # prefix_to_keys, etc state.
 
1018
 
 
1019
            # This is a bit ugly, but TIMEIT showed it to be by far the fastest
 
1020
            # 0.626us   list(key_filter)[0]
 
1021
            #       is a func() for list(), 2 mallocs, and a getitem
 
1022
            # 0.489us   [k for k in key_filter][0]
 
1023
            #       still has the mallocs, avoids the func() call
 
1024
            # 0.350us   iter(key_filter).next()
 
1025
            #       has a func() call, and mallocs an iterator
 
1026
            # 0.125us   for key in key_filter: pass
 
1027
            #       no func() overhead, might malloc an iterator
 
1028
            # 0.105us   for key in key_filter: break
 
1029
            #       no func() overhead, might malloc an iterator, probably
 
1030
            #       avoids checking an 'else' clause as part of the for
 
1031
            for key in key_filter:
 
1032
                break
 
1033
            search_prefix = self._search_prefix_filter(key)
 
1034
            if len(search_prefix) == self._node_width:
 
1035
                # This item will match exactly, so just do a dict lookup, and
 
1036
                # see what we can return
 
1037
                shortcut = True
 
1038
                try:
 
1039
                    node = self._items[search_prefix]
 
1040
                except KeyError:
 
1041
                    # A given key can only match 1 child node, if it isn't
 
1042
                    # there, then we can just return nothing
 
1043
                    return
 
1044
                if node.__class__ is tuple:
 
1045
                    keys[node] = (search_prefix, [key])
 
1046
                else:
 
1047
                    # This is loaded, and the only thing that can match,
 
1048
                    # return
 
1049
                    yield node, [key]
 
1050
                    return
 
1051
        if not shortcut:
 
1052
            # First, convert all keys into a list of search prefixes
 
1053
            # Aggregate common prefixes, and track the keys they come from
966
1054
            prefix_to_keys = {}
967
1055
            length_filters = {}
968
1056
            for key in key_filter:
969
 
                search_key = self._search_prefix_filter(key)
 
1057
                search_prefix = self._search_prefix_filter(key)
970
1058
                length_filter = length_filters.setdefault(
971
 
                                    len(search_key), set())
972
 
                length_filter.add(search_key)
973
 
                prefix_to_keys.setdefault(search_key, []).append(key)
974
 
            length_filters = length_filters.items()
975
 
            for prefix, node in self._items.iteritems():
976
 
                node_key_filter = []
977
 
                for length, length_filter in length_filters:
978
 
                    sub_prefix = prefix[:length]
979
 
                    if sub_prefix in length_filter:
980
 
                        node_key_filter.extend(prefix_to_keys[sub_prefix])
981
 
                if node_key_filter: # this key matched something, yield it
982
 
                    if type(node) == tuple:
983
 
                        keys[node] = (prefix, node_key_filter)
 
1059
                                    len(search_prefix), set())
 
1060
                length_filter.add(search_prefix)
 
1061
                prefix_to_keys.setdefault(search_prefix, []).append(key)
 
1062
 
 
1063
            if (self._node_width in length_filters
 
1064
                and len(length_filters) == 1):
 
1065
                # all of the search prefixes match exactly _node_width. This
 
1066
                # means that everything is an exact match, and we can do a
 
1067
                # lookup into self._items, rather than iterating over the items
 
1068
                # dict.
 
1069
                search_prefixes = length_filters[self._node_width]
 
1070
                for search_prefix in search_prefixes:
 
1071
                    try:
 
1072
                        node = self._items[search_prefix]
 
1073
                    except KeyError:
 
1074
                        # We can ignore this one
 
1075
                        continue
 
1076
                    node_key_filter = prefix_to_keys[search_prefix]
 
1077
                    if node.__class__ is tuple:
 
1078
                        keys[node] = (search_prefix, node_key_filter)
984
1079
                    else:
985
1080
                        yield node, node_key_filter
 
1081
            else:
 
1082
                # The slow way. We walk every item in self._items, and check to
 
1083
                # see if there are any matches
 
1084
                length_filters = length_filters.items()
 
1085
                for prefix, node in self._items.iteritems():
 
1086
                    node_key_filter = []
 
1087
                    for length, length_filter in length_filters:
 
1088
                        sub_prefix = prefix[:length]
 
1089
                        if sub_prefix in length_filter:
 
1090
                            node_key_filter.extend(prefix_to_keys[sub_prefix])
 
1091
                    if node_key_filter: # this key matched something, yield it
 
1092
                        if node.__class__ is tuple:
 
1093
                            keys[node] = (prefix, node_key_filter)
 
1094
                        else:
 
1095
                            yield node, node_key_filter
986
1096
        if keys:
987
1097
            # Look in the page cache for some more bytes
988
1098
            found_keys = set()
1117
1227
        :return: An iterable of the keys inserted by this operation.
1118
1228
        """
1119
1229
        for node in self._items.itervalues():
1120
 
            if type(node) == tuple:
 
1230
            if type(node) is tuple:
1121
1231
                # Never deserialised.
1122
1232
                continue
1123
1233
            if node._key is not None:
1134
1244
        lines.append('%s\n' % (self._search_prefix,))
1135
1245
        prefix_len = len(self._search_prefix)
1136
1246
        for prefix, node in sorted(self._items.items()):
1137
 
            if type(node) == tuple:
 
1247
            if type(node) is tuple:
1138
1248
                key = node[0]
1139
1249
            else:
1140
1250
                key = node._key[0]
1179
1289
            raise AssertionError("unserialised nodes have no refs.")
1180
1290
        refs = []
1181
1291
        for value in self._items.itervalues():
1182
 
            if type(value) == tuple:
 
1292
            if type(value) is tuple:
1183
1293
                refs.append(value)
1184
1294
            else:
1185
1295
                refs.append(value.key())
1292
1402
    chks_to_read = uninteresting_keys.union(interesting_keys)
1293
1403
    next_uninteresting = set()
1294
1404
    next_interesting = set()
 
1405
    next_interesting_intersection = None
1295
1406
    uninteresting_items = set()
1296
1407
    interesting_items = set()
1297
1408
    interesting_to_yield = []
1313
1424
        else:
1314
1425
            interesting_to_yield.append(record.key)
1315
1426
            if type(node) is InternalNode:
 
1427
                if next_interesting_intersection is None:
 
1428
                    next_interesting_intersection = set(node.refs())
 
1429
                else:
 
1430
                    next_interesting_intersection = \
 
1431
                        next_interesting_intersection.intersection(node.refs())
1316
1432
                next_interesting.update(node.refs())
1317
1433
            else:
1318
1434
                interesting_items.update(node.iteritems(None))
1319
1435
    return (next_uninteresting, uninteresting_items,
1320
 
            next_interesting, interesting_to_yield, interesting_items)
 
1436
            next_interesting, interesting_to_yield, interesting_items,
 
1437
            next_interesting_intersection)
1321
1438
 
1322
1439
 
1323
1440
def _find_all_uninteresting(store, interesting_root_keys,
1338
1455
    # uninteresting set
1339
1456
    (uninteresting_keys, uninteresting_items,
1340
1457
     interesting_keys, interesting_to_yield,
1341
 
     interesting_items) = _find_children_info(store, interesting_root_keys,
 
1458
     interesting_items, interesting_intersection,
 
1459
     ) = _find_children_info(store, interesting_root_keys,
1342
1460
                                              uninteresting_root_keys,
1343
1461
                                              pb=pb)
1344
1462
    all_uninteresting_chks.update(uninteresting_keys)
1345
1463
    all_uninteresting_items.update(uninteresting_items)
1346
1464
    del uninteresting_items
1347
 
    # Note: Exact matches between interesting and uninteresting do not need
1348
 
    #       to be search further. Non-exact matches need to be searched in case
1349
 
    #       there is a future exact-match
1350
 
    uninteresting_keys.difference_update(interesting_keys)
 
1465
    # Do not examine in detail pages common to all interesting trees.
 
1466
    # Pages that are common to all interesting trees will have their
 
1467
    # older versions found via the uninteresting tree traversal. Some pages
 
1468
    # found via the interesting trees traversal will be uninteresting for
 
1469
    # other of the interesting trees, which is why we require the pages to be
 
1470
    # common for us to trim them.
 
1471
    if interesting_intersection is not None:
 
1472
        uninteresting_keys.difference_update(interesting_intersection)
1351
1473
 
1352
1474
    # Second, find the full set of uninteresting bits reachable by the
1353
1475
    # uninteresting roots