~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/chk_map.py

  • Committer: Robert Collins
  • Date: 2010-01-29 15:18:58 UTC
  • mto: (4797.2.8 2.1)
  • mto: This revision was merged to the branch mainline in revision 4998.
  • Revision ID: robertc@robertcollins.net-20100129151858-0c1m88b013wluaxn
Introduce a threading.local to isolate the chk_map page cache from other threads.

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
"""
39
39
 
40
40
import heapq
 
41
import threading
41
42
 
42
43
from bzrlib import lazy_import
43
44
lazy_import.lazy_import(globals(), """
59
60
# If each line is 50 bytes, and you have 255 internal pages, with 255-way fan
60
61
# out, it takes 3.1MB to cache the layer.
61
62
_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)
 
63
# Per thread caches for 2 reasons:
 
64
# - in the server we may be serving very different content, so we get less
 
65
#   cache thrashing.
 
66
# - we avoid locking on every cache lookup.
 
67
_thread_caches = threading.local()
 
68
# The page cache.
 
69
_thread_caches.page_cache = None
 
70
 
 
71
def _get_cache():
 
72
    """Get the per-thread page cache.
 
73
 
 
74
    We need a function to do this because in a new thread the _thread_caches
 
75
    threading.local object does not have the cache initialized yet.
 
76
    """
 
77
    page_cache = getattr(_thread_caches, 'page_cache', None)
 
78
    if page_cache is None:
 
79
        # We are caching bytes so len(value) is perfectly accurate
 
80
        page_cache = lru_cache.LRUSizeCache(_PAGE_CACHE_SIZE)
 
81
        _thread_caches.page_cache = page_cache
 
82
    return page_cache
 
83
 
64
84
 
65
85
def clear_cache():
66
 
    _page_cache.clear()
 
86
    _get_cache().clear()
 
87
 
67
88
 
68
89
# If a ChildNode falls below this many bytes, we check for a remap
69
90
_INTERESTING_NEW_SIZE = 50
161
182
 
162
183
    def _read_bytes(self, key):
163
184
        try:
164
 
            return _page_cache[key]
 
185
            return _get_cache()[key]
165
186
        except KeyError:
166
187
            stream = self._store.get_record_stream([key], 'unordered', True)
167
188
            bytes = stream.next().get_bytes_as('fulltext')
168
 
            _page_cache[key] = bytes
 
189
            _get_cache()[key] = bytes
169
190
            return bytes
170
191
 
171
192
    def _dump_tree(self, include_keys=False):
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().add(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().add(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().add(self._key, ''.join(lines))
1304
1325
        yield self._key
1305
1326
 
1306
1327
    def _search_key(self, key):
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: