~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/weaverepo.py

  • Committer: John Arbash Meinel
  • Date: 2007-05-04 18:59:36 UTC
  • mto: This revision was merged to the branch mainline in revision 2643.
  • Revision ID: john@arbash-meinel.com-20070504185936-1mjdoqmtz74xe5mg
A C implementation of _fields_to_entry_0_parents drops the time from 400ms to 330ms for a 21k-entry tree

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
 
"""Deprecated weave-based repository formats.
18
17
 
19
 
Weave based formats scaled linearly with history size and could not represent
20
 
ghosts.
21
 
"""
 
18
"""Old weave-based repository formats"""
22
19
 
23
20
from StringIO import StringIO
24
21
 
25
22
from bzrlib import (
26
23
    bzrdir,
27
 
    debug,
28
 
    errors,
29
24
    lockable_files,
30
25
    lockdir,
31
 
    osutils,
32
 
    revision as _mod_revision,
33
26
    weave,
34
27
    weavefile,
35
28
    xml5,
36
29
    )
37
30
from bzrlib.decorators import needs_read_lock, needs_write_lock
38
31
from bzrlib.repository import (
39
 
    CommitBuilder,
40
32
    MetaDirRepository,
41
33
    MetaDirRepositoryFormat,
42
34
    Repository,
43
35
    RepositoryFormat,
44
36
    )
45
37
from bzrlib.store.text import TextStore
46
 
from bzrlib.symbol_versioning import deprecated_method, one_four
47
38
from bzrlib.trace import mutter
48
39
 
49
40
 
67
58
                              prefixed=prefixed, compressed=compressed,
68
59
                              dir_mode=dir_mode,
69
60
                              file_mode=file_mode)
 
61
            #if self._transport.should_cache():
 
62
            #    cache_path = os.path.join(self.cache_root, name)
 
63
            #    os.mkdir(cache_path)
 
64
            #    store = bzrlib.store.CachedStore(store, cache_path)
70
65
            return store
71
66
 
72
67
        # not broken out yet because the controlweaves|inventory_store
78
73
            text_store = get_store('text-store')
79
74
        super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files, _revision_store, control_store, text_store)
80
75
 
81
 
    @needs_read_lock
82
 
    def _all_possible_ids(self):
83
 
        """Return all the possible revisions that we could find."""
84
 
        if 'evil' in debug.debug_flags:
85
 
            mutter_callsite(3, "_all_possible_ids scales with size of history.")
86
 
        return self.get_inventory_weave().versions()
87
 
 
88
 
    @needs_read_lock
89
 
    def _all_revision_ids(self):
90
 
        """Returns a list of all the revision ids in the repository. 
91
 
 
92
 
        These are in as much topological order as the underlying store can 
93
 
        present: for weaves ghosts may lead to a lack of correctness until
94
 
        the reweave updates the parents list.
95
 
        """
96
 
        if self._revision_store.text_store.listable():
97
 
            return self._revision_store.all_revision_ids(self.get_transaction())
98
 
        result = self._all_possible_ids()
99
 
        # TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
100
 
        #       ids. (It should, since _revision_store's API should change to
101
 
        #       return utf8 revision_ids)
102
 
        return self._eliminate_revisions_not_present(result)
103
 
 
104
 
    def _check_revision_parents(self, revision, inventory):
105
 
        """Private to Repository and Fetch.
106
 
        
107
 
        This checks the parentage of revision in an inventory weave for 
108
 
        consistency and is only applicable to inventory-weave-for-ancestry
109
 
        using repository formats & fetchers.
110
 
        """
111
 
        weave_parents = inventory.get_parent_map(
112
 
            [revision.revision_id])[revision.revision_id]
113
 
        parent_map = inventory.get_parent_map(revision.parent_ids)
114
 
        for parent_id in revision.parent_ids:
115
 
            if parent_id in parent_map:
116
 
                # this parent must not be a ghost.
117
 
                if not parent_id in weave_parents:
118
 
                    # but it is a ghost
119
 
                    raise errors.CorruptRepository(self)
120
 
 
121
76
    def get_commit_builder(self, branch, parents, config, timestamp=None,
122
77
                           timezone=None, committer=None, revprops=None,
123
78
                           revision_id=None):
124
79
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
125
 
        result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
126
 
                              committer, revprops, revision_id)
127
 
        self.start_write_group()
128
 
        return result
129
 
 
130
 
    @needs_read_lock
131
 
    def get_revisions(self, revision_ids):
132
 
        revs = self._get_revisions(revision_ids)
133
 
        # weave corruption can lead to absent revision markers that should be
134
 
        # present.
135
 
        # the following test is reasonably cheap (it needs a single weave read)
136
 
        # and the weave is cached in read transactions. In write transactions
137
 
        # it is not cached but typically we only read a small number of
138
 
        # revisions. For knits when they are introduced we will probably want
139
 
        # to ensure that caching write transactions are in use.
140
 
        inv = self.get_inventory_weave()
141
 
        for rev in revs:
142
 
            self._check_revision_parents(rev, inv)
143
 
        return revs
144
 
 
145
 
    @deprecated_method(one_four)
146
 
    @needs_read_lock
147
 
    def get_revision_graph(self, revision_id=None):
148
 
        """Return a dictionary containing the revision graph.
149
 
        
150
 
        :param revision_id: The revision_id to get a graph from. If None, then
151
 
        the entire revision graph is returned. This is a deprecated mode of
152
 
        operation and will be removed in the future.
153
 
        :return: a dictionary of revision_id->revision_parents_list.
154
 
        """
155
 
        if 'evil' in debug.debug_flags:
156
 
            mutter_callsite(2,
157
 
                "get_revision_graph scales with size of history.")
158
 
        # special case NULL_REVISION
159
 
        if revision_id == _mod_revision.NULL_REVISION:
160
 
            return {}
161
 
        a_weave = self.get_inventory_weave()
162
 
        all_revisions = self._eliminate_revisions_not_present(
163
 
                                a_weave.versions())
164
 
        entire_graph = a_weave.get_parent_map(all_revisions)
165
 
        if revision_id is None:
166
 
            return entire_graph
167
 
        elif revision_id not in entire_graph:
168
 
            raise errors.NoSuchRevision(self, revision_id)
169
 
        else:
170
 
            # add what can be reached from revision_id
171
 
            result = {}
172
 
            pending = set([revision_id])
173
 
            while len(pending) > 0:
174
 
                node = pending.pop()
175
 
                result[node] = entire_graph[node]
176
 
                for revision_id in result[node]:
177
 
                    if revision_id not in result:
178
 
                        pending.add(revision_id)
179
 
            return result
180
 
 
181
 
    def has_revisions(self, revision_ids):
182
 
        """See Repository.has_revisions()."""
183
 
        result = set()
184
 
        transaction = self.get_transaction()
185
 
        for revision_id in revision_ids:
186
 
            if self._revision_store.has_revision_id(revision_id, transaction):
187
 
                result.add(revision_id)
188
 
        return result
 
80
        return Repository.get_commit_builder(self, branch, parents, config,
 
81
            timestamp, timezone, committer, revprops, revision_id)
189
82
 
190
83
    @needs_read_lock
191
84
    def is_shared(self):
208
101
        """Returns the policy for making working trees on new branches."""
209
102
        return True
210
103
 
211
 
    def revision_graph_can_have_wrong_parents(self):
212
 
        # XXX: This is an old format that we don't support full checking on, so
213
 
        # just claim that checking for this inconsistency is not required.
214
 
        return False
215
 
 
216
104
 
217
105
class WeaveMetaDirRepository(MetaDirRepository):
218
106
    """A subclass of MetaDirRepository to set weave specific policy."""
219
107
 
220
108
    _serializer = xml5.serializer_v5
221
109
 
222
 
    @needs_read_lock
223
 
    def _all_possible_ids(self):
224
 
        """Return all the possible revisions that we could find."""
225
 
        if 'evil' in debug.debug_flags:
226
 
            mutter_callsite(3, "_all_possible_ids scales with size of history.")
227
 
        return self.get_inventory_weave().versions()
228
 
 
229
 
    @needs_read_lock
230
 
    def _all_revision_ids(self):
231
 
        """Returns a list of all the revision ids in the repository. 
232
 
 
233
 
        These are in as much topological order as the underlying store can 
234
 
        present: for weaves ghosts may lead to a lack of correctness until
235
 
        the reweave updates the parents list.
236
 
        """
237
 
        if self._revision_store.text_store.listable():
238
 
            return self._revision_store.all_revision_ids(self.get_transaction())
239
 
        result = self._all_possible_ids()
240
 
        # TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
241
 
        #       ids. (It should, since _revision_store's API should change to
242
 
        #       return utf8 revision_ids)
243
 
        return self._eliminate_revisions_not_present(result)
244
 
 
245
 
    def _check_revision_parents(self, revision, inventory):
246
 
        """Private to Repository and Fetch.
247
 
        
248
 
        This checks the parentage of revision in an inventory weave for 
249
 
        consistency and is only applicable to inventory-weave-for-ancestry
250
 
        using repository formats & fetchers.
251
 
        """
252
 
        weave_parents = inventory.get_parent_map(
253
 
            [revision.revision_id])[revision.revision_id]
254
 
        parent_map = inventory.get_parent_map(revision.parent_ids)
255
 
        for parent_id in revision.parent_ids:
256
 
            if parent_id in parent_map:
257
 
                # this parent must not be a ghost.
258
 
                if not parent_id in weave_parents:
259
 
                    # but it is a ghost
260
 
                    raise errors.CorruptRepository(self)
261
 
 
262
110
    def get_commit_builder(self, branch, parents, config, timestamp=None,
263
111
                           timezone=None, committer=None, revprops=None,
264
112
                           revision_id=None):
265
113
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
266
 
        result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
267
 
                              committer, revprops, revision_id)
268
 
        self.start_write_group()
269
 
        return result
270
 
 
271
 
    @needs_read_lock
272
 
    def get_revision(self, revision_id):
273
 
        """Return the Revision object for a named revision"""
274
 
        # TODO: jam 20070210 get_revision_reconcile should do this for us
275
 
        r = self.get_revision_reconcile(revision_id)
276
 
        # weave corruption can lead to absent revision markers that should be
277
 
        # present.
278
 
        # the following test is reasonably cheap (it needs a single weave read)
279
 
        # and the weave is cached in read transactions. In write transactions
280
 
        # it is not cached but typically we only read a small number of
281
 
        # revisions. For knits when they are introduced we will probably want
282
 
        # to ensure that caching write transactions are in use.
283
 
        inv = self.get_inventory_weave()
284
 
        self._check_revision_parents(r, inv)
285
 
        return r
286
 
 
287
 
    @deprecated_method(one_four)
288
 
    @needs_read_lock
289
 
    def get_revision_graph(self, revision_id=None):
290
 
        """Return a dictionary containing the revision graph.
291
 
        
292
 
        :param revision_id: The revision_id to get a graph from. If None, then
293
 
        the entire revision graph is returned. This is a deprecated mode of
294
 
        operation and will be removed in the future.
295
 
        :return: a dictionary of revision_id->revision_parents_list.
296
 
        """
297
 
        if 'evil' in debug.debug_flags:
298
 
            mutter_callsite(3,
299
 
                "get_revision_graph scales with size of history.")
300
 
        # special case NULL_REVISION
301
 
        if revision_id == _mod_revision.NULL_REVISION:
302
 
            return {}
303
 
        a_weave = self.get_inventory_weave()
304
 
        all_revisions = self._eliminate_revisions_not_present(
305
 
                                a_weave.versions())
306
 
        entire_graph = a_weave.get_parent_map(all_revisions)
307
 
        if revision_id is None:
308
 
            return entire_graph
309
 
        elif revision_id not in entire_graph:
310
 
            raise errors.NoSuchRevision(self, revision_id)
311
 
        else:
312
 
            # add what can be reached from revision_id
313
 
            result = {}
314
 
            pending = set([revision_id])
315
 
            while len(pending) > 0:
316
 
                node = pending.pop()
317
 
                result[node] = entire_graph[node]
318
 
                for revision_id in result[node]:
319
 
                    if revision_id not in result:
320
 
                        pending.add(revision_id)
321
 
            return result
322
 
 
323
 
    def has_revisions(self, revision_ids):
324
 
        """See Repository.has_revisions()."""
325
 
        result = set()
326
 
        transaction = self.get_transaction()
327
 
        for revision_id in revision_ids:
328
 
            if self._revision_store.has_revision_id(revision_id, transaction):
329
 
                result.add(revision_id)
330
 
        return result
331
 
 
332
 
    def revision_graph_can_have_wrong_parents(self):
333
 
        # XXX: This is an old format that we don't support full checking on, so
334
 
        # just claim that checking for this inconsistency is not required.
335
 
        return False
 
114
        return MetaDirRepository.get_commit_builder(self, branch, parents,
 
115
            config, timestamp, timezone, committer, revprops, revision_id)
336
116
 
337
117
 
338
118
class PreSplitOutRepositoryFormat(RepositoryFormat):
340
120
 
341
121
    rich_root_data = False
342
122
    supports_tree_reference = False
343
 
    supports_ghosts = False
344
 
    supports_external_lookups = False
345
123
 
346
124
    def initialize(self, a_bzrdir, shared=False, _internal=False):
347
 
        """Create a weave repository."""
 
125
        """Create a weave repository.
 
126
        
 
127
        TODO: when creating split out bzr branch formats, move this to a common
 
128
        base for Format5, Format6. or something like that.
 
129
        """
348
130
        if shared:
349
131
            raise errors.IncompatibleFormat(self, a_bzrdir._format)
350
132
 
525
307
        """See RepositoryFormat._get_text_store()."""
526
308
        return self._get_versioned_file_store('weaves', transport, control_files)
527
309
 
 
310
 
528
311
class RepositoryFormat7(MetaDirRepositoryFormat):
529
312
    """Bzr repository 7.
530
313
 
538
321
    """
539
322
 
540
323
    _versionedfile_class = weave.WeaveFile
541
 
    supports_ghosts = False
542
324
 
543
325
    def _get_control_store(self, repo_transport, control_files):
544
326
        """Return the control store for this repository."""
620
402
            text_store=text_store)
621
403
 
622
404
 
623
 
class WeaveCommitBuilder(CommitBuilder):
624
 
    """A builder for weave based repos that don't support ghosts."""
625
 
 
626
 
    def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
627
 
        versionedfile = self.repository.weave_store.get_weave_or_empty(
628
 
            file_id, self.repository.get_transaction())
629
 
        result = versionedfile.add_lines(
630
 
            self._new_revision_id, parents, new_lines,
631
 
            nostore_sha=nostore_sha)[0:2]
632
 
        versionedfile.clear_cache()
633
 
        return result
634
 
 
635
 
 
636
405
_legacy_formats = [RepositoryFormat4(),
637
406
                   RepositoryFormat5(),
638
407
                   RepositoryFormat6()]