101
101
class CachingParentsProvider(object):
102
"""A parents provider which will cache the revision => parents in a dict.
104
This is useful for providers that have an expensive lookup.
102
"""A parents provider which will cache the revision => parents as a dict.
104
This is useful for providers which have an expensive look up.
106
Either a ParentsProvider or a get_parent_map-like callback may be
107
supplied. If it provides extra un-asked-for parents, they will be cached,
108
but filtered out of get_parent_map.
110
The cache is enabled by default, but may be disabled and re-enabled.
112
def __init__(self, parent_provider=None, get_parent_map=None, debug=False):
107
def __init__(self, parent_provider):
115
:param parent_provider: The ParentProvider to use. It or
116
get_parent_map must be supplied.
117
:param get_parent_map: The get_parent_map callback to use. It or
118
parent_provider must be supplied.
119
:param debug: If true, mutter debugging messages.
108
121
self._real_provider = parent_provider
109
# Theoretically we could use an LRUCache here
122
if get_parent_map is None:
123
self._get_parent_map = self._real_provider.get_parent_map
125
self._get_parent_map = get_parent_map
127
self._cache_misses = True
130
self._requested_parents = None
112
132
def __repr__(self):
113
133
return "%s(%r)" % (self.__class__.__name__, self._real_provider)
135
def enable_cache(self, cache_misses=True):
138
self._cache_misses = cache_misses
140
self._requested_parents = set()
142
def disable_cache(self):
143
"""Disable and clear the cache."""
146
self._requested_parents = None
148
def get_cached_map(self):
149
"""Return any cached get_parent_map values."""
150
if self._cache is None:
152
return dict((k, v) for k, v in self._cache.items()
115
155
def get_parent_map(self, keys):
116
"""See _StackedParentsProvider.get_parent_map"""
118
# If the _real_provider doesn't have a key, we cache a value of None,
119
# which we then later use to realize we cannot provide a value for that
126
if value is not None:
127
parent_map[key] = value
132
new_parents = self._real_provider.get_parent_map(needed)
133
cache.update(new_parents)
134
parent_map.update(new_parents)
135
needed.difference_update(new_parents)
136
cache.update(dict.fromkeys(needed, None))
156
"""See _StackedParentsProvider.get_parent_map."""
157
# Hack to build up the caching logic.
158
ancestry = self._cache
160
# Caching is disabled.
161
missing_revisions = set(keys)
164
missing_revisions = set(key for key in keys if key not in ancestry)
165
if missing_revisions:
166
parent_map = self._get_parent_map(missing_revisions)
168
mutter('re-retrieved revisions: %d of %d',
169
len(set(ancestry).intersection(parent_map)),
171
ancestry.update(parent_map)
172
if self._cache_misses:
173
# None is never a valid parents list, so it can be used to
175
ancestry.update(dict((k, None) for k in missing_revisions
176
if k not in parent_map))
177
present_keys = [k for k in keys if ancestry.get(k) is not None]
179
if self._requested_parents is not None and len(ancestry) != 0:
180
self._requested_parents.update(present_keys)
181
mutter('Current hit rate: %d%%',
182
100.0 * len(self._requested_parents) / len(ancestry))
183
return dict((k, ancestry[k]) for k in present_keys)
140
186
class Graph(object):