~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/chk_map.py

  • Committer: Jelmer Vernooij
  • Date: 2010-01-20 22:32:07 UTC
  • mto: This revision was merged to the branch mainline in revision 4977.
  • Revision ID: jelmer@samba.org-20100120223207-pfz89u161ahyzvnt
Add FileTimestampUnavailable exception.

Show diffs side-by-side

added added

removed removed

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