~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/chk_map.py

(jelmer) Use the absolute_import feature everywhere in bzrlib,
 and add a source test to make sure it's used everywhere. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2008, 2009 Canonical Ltd
 
1
# Copyright (C) 2008-2011 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
37
37
 
38
38
"""
39
39
 
 
40
from __future__ import absolute_import
 
41
 
40
42
import heapq
 
43
import threading
41
44
 
42
45
from bzrlib import lazy_import
43
46
lazy_import.lazy_import(globals(), """
44
47
from bzrlib import (
45
48
    errors,
46
 
    versionedfile,
47
49
    )
48
50
""")
49
51
from bzrlib import (
 
52
    errors,
50
53
    lru_cache,
51
54
    osutils,
52
55
    registry,
59
62
# If each line is 50 bytes, and you have 255 internal pages, with 255-way fan
60
63
# out, it takes 3.1MB to cache the layer.
61
64
_PAGE_CACHE_SIZE = 4*1024*1024
62
 
# We are caching bytes so len(value) is perfectly accurate
63
 
_page_cache = lru_cache.LRUSizeCache(_PAGE_CACHE_SIZE)
 
65
# Per thread caches for 2 reasons:
 
66
# - in the server we may be serving very different content, so we get less
 
67
#   cache thrashing.
 
68
# - we avoid locking on every cache lookup.
 
69
_thread_caches = threading.local()
 
70
# The page cache.
 
71
_thread_caches.page_cache = None
 
72
 
 
73
def _get_cache():
 
74
    """Get the per-thread page cache.
 
75
 
 
76
    We need a function to do this because in a new thread the _thread_caches
 
77
    threading.local object does not have the cache initialized yet.
 
78
    """
 
79
    page_cache = getattr(_thread_caches, 'page_cache', None)
 
80
    if page_cache is None:
 
81
        # We are caching bytes so len(value) is perfectly accurate
 
82
        page_cache = lru_cache.LRUSizeCache(_PAGE_CACHE_SIZE)
 
83
        _thread_caches.page_cache = page_cache
 
84
    return page_cache
 
85
 
64
86
 
65
87
def clear_cache():
66
 
    _page_cache.clear()
 
88
    _get_cache().clear()
 
89
 
67
90
 
68
91
# If a ChildNode falls below this many bytes, we check for a remap
69
92
_INTERESTING_NEW_SIZE = 50
70
93
# If a ChildNode shrinks by more than this amount, we check for a remap
71
94
_INTERESTING_SHRINKAGE_LIMIT = 20
72
 
# If we delete more than this many nodes applying a delta, we check for a remap
73
 
_INTERESTING_DELETES_LIMIT = 5
74
95
 
75
96
 
76
97
def _search_key_plain(key):
114
135
            into the map; if old_key is not None, then the old mapping
115
136
            of old_key is removed.
116
137
        """
117
 
        delete_count = 0
 
138
        has_deletes = False
118
139
        # Check preconditions first.
119
140
        as_st = StaticTuple.from_sequence
120
141
        new_items = set([as_st(key) for (old, key, value) in delta
127
148
        for old, new, value in delta:
128
149
            if old is not None and old != new:
129
150
                self.unmap(old, check_remap=False)
130
 
                delete_count += 1
 
151
                has_deletes = True
131
152
        for old, new, value in delta:
132
153
            if new is not None:
133
154
                self.map(new, value)
134
 
        if delete_count > _INTERESTING_DELETES_LIMIT:
135
 
            trace.mutter("checking remap as %d deletions", delete_count)
 
155
        if has_deletes:
136
156
            self._check_remap()
137
157
        return self._save()
138
158
 
161
181
 
162
182
    def _read_bytes(self, key):
163
183
        try:
164
 
            return _page_cache[key]
 
184
            return _get_cache()[key]
165
185
        except KeyError:
166
186
            stream = self._store.get_record_stream([key], 'unordered', True)
167
187
            bytes = stream.next().get_bytes_as('fulltext')
168
 
            _page_cache[key] = bytes
 
188
            _get_cache()[key] = bytes
169
189
            return bytes
170
190
 
171
191
    def _dump_tree(self, include_keys=False):
552
572
        """Check if nodes can be collapsed."""
553
573
        self._ensure_root()
554
574
        if type(self._root_node) is InternalNode:
555
 
            self._root_node._check_remap(self._store)
 
575
            self._root_node = self._root_node._check_remap(self._store)
556
576
 
557
577
    def _save(self):
558
578
        """Save the map completely.
671
691
        the key/value pairs.
672
692
    """
673
693
 
674
 
    __slots__ = ('_common_serialised_prefix', '_serialise_key')
 
694
    __slots__ = ('_common_serialised_prefix',)
675
695
 
676
696
    def __init__(self, search_key_func=None):
677
697
        Node.__init__(self)
678
698
        # All of the keys in this leaf node share this common prefix
679
699
        self._common_serialised_prefix = None
680
 
        self._serialise_key = '\x00'.join
681
700
        if search_key_func is None:
682
701
            self._search_key_func = _search_key_plain
683
702
        else:
867
886
                raise AssertionError('%r must be known' % self._search_prefix)
868
887
            return self._search_prefix, [("", self)]
869
888
 
 
889
    _serialise_key = '\x00'.join
 
890
 
870
891
    def serialise(self, store):
871
892
        """Serialise the LeafNode to store.
872
893
 
901
922
        bytes = ''.join(lines)
902
923
        if len(bytes) != self._current_size():
903
924
            raise AssertionError('Invalid _current_size')
904
 
        _page_cache.add(self._key, bytes)
 
925
        _get_cache()[self._key] = bytes
905
926
        return [self._key]
906
927
 
907
928
    def refs(self):
1143
1164
            found_keys = set()
1144
1165
            for key in keys:
1145
1166
                try:
1146
 
                    bytes = _page_cache[key]
 
1167
                    bytes = _get_cache()[key]
1147
1168
                except KeyError:
1148
1169
                    continue
1149
1170
                else:
1174
1195
                    prefix, node_key_filter = keys[record.key]
1175
1196
                    node_and_filters.append((node, node_key_filter))
1176
1197
                    self._items[prefix] = node
1177
 
                    _page_cache.add(record.key, bytes)
 
1198
                    _get_cache()[record.key] = bytes
1178
1199
                for info in node_and_filters:
1179
1200
                    yield info
1180
1201
 
1300
1321
            lines.append(serialised[prefix_len:])
1301
1322
        sha1, _, _ = store.add_lines((None,), (), lines)
1302
1323
        self._key = StaticTuple("sha1:" + sha1,).intern()
1303
 
        _page_cache.add(self._key, ''.join(lines))
 
1324
        _get_cache()[self._key] = ''.join(lines)
1304
1325
        yield self._key
1305
1326
 
1306
1327
    def _search_key(self, key):
1350
1371
        return self._search_prefix
1351
1372
 
1352
1373
    def unmap(self, store, key, check_remap=True):
1353
 
        """Remove key from this node and it's children."""
 
1374
        """Remove key from this node and its children."""
1354
1375
        if not len(self._items):
1355
1376
            raise AssertionError("can't unmap in an empty InternalNode.")
1356
1377
        children = [node for node, _
1489
1510
        self._state = None
1490
1511
 
1491
1512
    def _read_nodes_from_store(self, keys):
1492
 
        # We chose not to use _page_cache, because we think in terms of records
1493
 
        # to be yielded. Also, we expect to touch each page only 1 time during
1494
 
        # this code. (We may want to evaluate saving the raw bytes into the
1495
 
        # page cache, which would allow a working tree update after the fetch
1496
 
        # to not have to read the bytes again.)
 
1513
        # We chose not to use _get_cache(), because we think in
 
1514
        # terms of records to be yielded. Also, we expect to touch each page
 
1515
        # only 1 time during this code. (We may want to evaluate saving the
 
1516
        # raw bytes into the page cache, which would allow a working tree
 
1517
        # update after the fetch to not have to read the bytes again.)
1497
1518
        as_st = StaticTuple.from_sequence
1498
1519
        stream = self._store.get_record_stream(keys, 'unordered', True)
1499
1520
        for record in stream:
1705
1726
 
1706
1727
try:
1707
1728
    from bzrlib._chk_map_pyx import (
 
1729
        _bytes_to_text_key,
1708
1730
        _search_key_16,
1709
1731
        _search_key_255,
1710
1732
        _deserialise_leaf_node,
1713
1735
except ImportError, e:
1714
1736
    osutils.failed_to_load_extension(e)
1715
1737
    from bzrlib._chk_map_py import (
 
1738
        _bytes_to_text_key,
1716
1739
        _search_key_16,
1717
1740
        _search_key_255,
1718
1741
        _deserialise_leaf_node,