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

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-12-10 21:06:38 UTC
  • mfrom: (3835.1.18 remote-stacking-graph)
  • Revision ID: pqm@pqm.ubuntu.com-20081210210638-e569azc2bomqq5qx
(abentley) Move RemoteRepository caching to CachingParentsProvider

Show diffs side-by-side

added added

removed removed

Lines of Context:
99
99
 
100
100
 
101
101
class CachingParentsProvider(object):
102
 
    """A parents provider which will cache the revision => parents in a dict.
103
 
 
104
 
    This is useful for providers that have an expensive lookup.
 
102
    """A parents provider which will cache the revision => parents as a dict.
 
103
 
 
104
    This is useful for providers which have an expensive look up.
 
105
 
 
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.
 
109
 
 
110
    The cache is enabled by default, but may be disabled and re-enabled.
105
111
    """
 
112
    def __init__(self, parent_provider=None, get_parent_map=None, debug=False):
 
113
        """Constructor.
106
114
 
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.
 
120
        """
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
 
124
        else:
 
125
            self._get_parent_map = get_parent_map
110
126
        self._cache = {}
 
127
        self._cache_misses = True
 
128
        self._debug = debug
 
129
        if self._debug:
 
130
            self._requested_parents = None
111
131
 
112
132
    def __repr__(self):
113
133
        return "%s(%r)" % (self.__class__.__name__, self._real_provider)
114
134
 
 
135
    def enable_cache(self, cache_misses=True):
 
136
        """Enable cache."""
 
137
        self._cache = {}
 
138
        self._cache_misses = cache_misses
 
139
        if self._debug:
 
140
            self._requested_parents = set()
 
141
 
 
142
    def disable_cache(self):
 
143
        """Disable and clear the cache."""
 
144
        self._cache = None
 
145
        if self._debug:
 
146
            self._requested_parents = None
 
147
 
 
148
    def get_cached_map(self):
 
149
        """Return any cached get_parent_map values."""
 
150
        if self._cache is None:
 
151
            return None
 
152
        return dict((k, v) for k, v in self._cache.items()
 
153
                    if v is not None)
 
154
 
115
155
    def get_parent_map(self, keys):
116
 
        """See _StackedParentsProvider.get_parent_map"""
117
 
        needed = set()
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
120
 
        # key.
121
 
        parent_map = {}
122
 
        cache = self._cache
123
 
        for key in keys:
124
 
            if key in cache:
125
 
                value = cache[key]
126
 
                if value is not None:
127
 
                    parent_map[key] = value
128
 
            else:
129
 
                needed.add(key)
130
 
 
131
 
        if needed:
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))
137
 
        return parent_map
 
156
        """See _StackedParentsProvider.get_parent_map."""
 
157
        # Hack to build up the caching logic.
 
158
        ancestry = self._cache
 
159
        if ancestry is None:
 
160
            # Caching is disabled.
 
161
            missing_revisions = set(keys)
 
162
            ancestry = {}
 
163
        else:
 
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)
 
167
            if self._debug:
 
168
                mutter('re-retrieved revisions: %d of %d',
 
169
                        len(set(ancestry).intersection(parent_map)),
 
170
                        len(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
 
174
                # record misses.
 
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]
 
178
        if self._debug:
 
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)
138
184
 
139
185
 
140
186
class Graph(object):