~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/weaverepo.py

Merge from bzr.dev.

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.
17
18
 
18
 
"""Old weave-based repository formats"""
 
19
Weave based formats scaled linearly with history size and could not represent
 
20
ghosts.
 
21
"""
19
22
 
20
23
from StringIO import StringIO
21
24
 
22
25
from bzrlib import (
23
26
    bzrdir,
 
27
    debug,
 
28
    errors,
24
29
    lockable_files,
25
30
    lockdir,
 
31
    osutils,
 
32
    revision as _mod_revision,
26
33
    weave,
27
34
    weavefile,
28
35
    xml5,
29
36
    )
30
37
from bzrlib.decorators import needs_read_lock, needs_write_lock
31
38
from bzrlib.repository import (
 
39
    CommitBuilder,
32
40
    MetaDirRepository,
33
41
    MetaDirRepositoryFormat,
34
42
    Repository,
69
77
            text_store = get_store('text-store')
70
78
        super(AllInOneRepository, self).__init__(_format, a_bzrdir, a_bzrdir._control_files, _revision_store, control_store, text_store)
71
79
 
 
80
    @needs_read_lock
 
81
    def _all_possible_ids(self):
 
82
        """Return all the possible revisions that we could find."""
 
83
        if 'evil' in debug.debug_flags:
 
84
            mutter_callsite(3, "_all_possible_ids scales with size of history.")
 
85
        return self.get_inventory_weave().versions()
 
86
 
 
87
    @needs_read_lock
 
88
    def _all_revision_ids(self):
 
89
        """Returns a list of all the revision ids in the repository. 
 
90
 
 
91
        These are in as much topological order as the underlying store can 
 
92
        present: for weaves ghosts may lead to a lack of correctness until
 
93
        the reweave updates the parents list.
 
94
        """
 
95
        if self._revision_store.text_store.listable():
 
96
            return self._revision_store.all_revision_ids(self.get_transaction())
 
97
        result = self._all_possible_ids()
 
98
        # TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
 
99
        #       ids. (It should, since _revision_store's API should change to
 
100
        #       return utf8 revision_ids)
 
101
        return self._eliminate_revisions_not_present(result)
 
102
 
 
103
    def _check_revision_parents(self, revision, inventory):
 
104
        """Private to Repository and Fetch.
 
105
        
 
106
        This checks the parentage of revision in an inventory weave for 
 
107
        consistency and is only applicable to inventory-weave-for-ancestry
 
108
        using repository formats & fetchers.
 
109
        """
 
110
        weave_parents = inventory.get_parents(revision.revision_id)
 
111
        weave_names = inventory.versions()
 
112
        for parent_id in revision.parent_ids:
 
113
            if parent_id in weave_names:
 
114
                # this parent must not be a ghost.
 
115
                if not parent_id in weave_parents:
 
116
                    # but it is a ghost
 
117
                    raise errors.CorruptRepository(self)
 
118
 
72
119
    def get_commit_builder(self, branch, parents, config, timestamp=None,
73
120
                           timezone=None, committer=None, revprops=None,
74
121
                           revision_id=None):
75
122
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
76
 
        return Repository.get_commit_builder(self, branch, parents, config,
77
 
            timestamp, timezone, committer, revprops, revision_id)
 
123
        revision_id = osutils.safe_revision_id(revision_id)
 
124
        result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
 
125
                              committer, revprops, revision_id)
 
126
        self.start_write_group()
 
127
        return result
 
128
 
 
129
    @needs_read_lock
 
130
    def get_revisions(self, revision_ids):
 
131
        revs = self._get_revisions(revision_ids)
 
132
        # weave corruption can lead to absent revision markers that should be
 
133
        # present.
 
134
        # the following test is reasonably cheap (it needs a single weave read)
 
135
        # and the weave is cached in read transactions. In write transactions
 
136
        # it is not cached but typically we only read a small number of
 
137
        # revisions. For knits when they are introduced we will probably want
 
138
        # to ensure that caching write transactions are in use.
 
139
        inv = self.get_inventory_weave()
 
140
        for rev in revs:
 
141
            self._check_revision_parents(rev, inv)
 
142
        return revs
 
143
 
 
144
    @needs_read_lock
 
145
    def get_revision_graph(self, revision_id=None):
 
146
        """Return a dictionary containing the revision graph.
 
147
        
 
148
        :param revision_id: The revision_id to get a graph from. If None, then
 
149
        the entire revision graph is returned. This is a deprecated mode of
 
150
        operation and will be removed in the future.
 
151
        :return: a dictionary of revision_id->revision_parents_list.
 
152
        """
 
153
        if 'evil' in debug.debug_flags:
 
154
            mutter_callsite(2,
 
155
                "get_revision_graph scales with size of history.")
 
156
        # special case NULL_REVISION
 
157
        if revision_id == _mod_revision.NULL_REVISION:
 
158
            return {}
 
159
        revision_id = osutils.safe_revision_id(revision_id)
 
160
        a_weave = self.get_inventory_weave()
 
161
        all_revisions = self._eliminate_revisions_not_present(
 
162
                                a_weave.versions())
 
163
        entire_graph = dict([(node, tuple(a_weave.get_parents(node))) for 
 
164
                             node in 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
78
180
 
79
181
    @needs_read_lock
80
182
    def is_shared(self):
103
205
 
104
206
    _serializer = xml5.serializer_v5
105
207
 
 
208
    @needs_read_lock
 
209
    def _all_possible_ids(self):
 
210
        """Return all the possible revisions that we could find."""
 
211
        if 'evil' in debug.debug_flags:
 
212
            mutter_callsite(3, "_all_possible_ids scales with size of history.")
 
213
        return self.get_inventory_weave().versions()
 
214
 
 
215
    @needs_read_lock
 
216
    def _all_revision_ids(self):
 
217
        """Returns a list of all the revision ids in the repository. 
 
218
 
 
219
        These are in as much topological order as the underlying store can 
 
220
        present: for weaves ghosts may lead to a lack of correctness until
 
221
        the reweave updates the parents list.
 
222
        """
 
223
        if self._revision_store.text_store.listable():
 
224
            return self._revision_store.all_revision_ids(self.get_transaction())
 
225
        result = self._all_possible_ids()
 
226
        # TODO: jam 20070210 Ensure that _all_possible_ids returns non-unicode
 
227
        #       ids. (It should, since _revision_store's API should change to
 
228
        #       return utf8 revision_ids)
 
229
        return self._eliminate_revisions_not_present(result)
 
230
 
 
231
    def _check_revision_parents(self, revision, inventory):
 
232
        """Private to Repository and Fetch.
 
233
        
 
234
        This checks the parentage of revision in an inventory weave for 
 
235
        consistency and is only applicable to inventory-weave-for-ancestry
 
236
        using repository formats & fetchers.
 
237
        """
 
238
        weave_parents = inventory.get_parents(revision.revision_id)
 
239
        weave_names = inventory.versions()
 
240
        for parent_id in revision.parent_ids:
 
241
            if parent_id in weave_names:
 
242
                # this parent must not be a ghost.
 
243
                if not parent_id in weave_parents:
 
244
                    # but it is a ghost
 
245
                    raise errors.CorruptRepository(self)
 
246
 
106
247
    def get_commit_builder(self, branch, parents, config, timestamp=None,
107
248
                           timezone=None, committer=None, revprops=None,
108
249
                           revision_id=None):
109
250
        self._check_ascii_revisionid(revision_id, self.get_commit_builder)
110
 
        return MetaDirRepository.get_commit_builder(self, branch, parents,
111
 
            config, timestamp, timezone, committer, revprops, revision_id)
 
251
        revision_id = osutils.safe_revision_id(revision_id)
 
252
        result = WeaveCommitBuilder(self, parents, config, timestamp, timezone,
 
253
                              committer, revprops, revision_id)
 
254
        self.start_write_group()
 
255
        return result
 
256
 
 
257
    @needs_read_lock
 
258
    def get_revision(self, revision_id):
 
259
        """Return the Revision object for a named revision"""
 
260
        # TODO: jam 20070210 get_revision_reconcile should do this for us
 
261
        revision_id = osutils.safe_revision_id(revision_id)
 
262
        r = self.get_revision_reconcile(revision_id)
 
263
        # weave corruption can lead to absent revision markers that should be
 
264
        # present.
 
265
        # the following test is reasonably cheap (it needs a single weave read)
 
266
        # and the weave is cached in read transactions. In write transactions
 
267
        # it is not cached but typically we only read a small number of
 
268
        # revisions. For knits when they are introduced we will probably want
 
269
        # to ensure that caching write transactions are in use.
 
270
        inv = self.get_inventory_weave()
 
271
        self._check_revision_parents(r, inv)
 
272
        return r
 
273
 
 
274
    @needs_read_lock
 
275
    def get_revision_graph(self, revision_id=None):
 
276
        """Return a dictionary containing the revision graph.
 
277
        
 
278
        :param revision_id: The revision_id to get a graph from. If None, then
 
279
        the entire revision graph is returned. This is a deprecated mode of
 
280
        operation and will be removed in the future.
 
281
        :return: a dictionary of revision_id->revision_parents_list.
 
282
        """
 
283
        if 'evil' in debug.debug_flags:
 
284
            mutter_callsite(3,
 
285
                "get_revision_graph scales with size of history.")
 
286
        # special case NULL_REVISION
 
287
        if revision_id == _mod_revision.NULL_REVISION:
 
288
            return {}
 
289
        revision_id = osutils.safe_revision_id(revision_id)
 
290
        a_weave = self.get_inventory_weave()
 
291
        all_revisions = self._eliminate_revisions_not_present(
 
292
                                a_weave.versions())
 
293
        entire_graph = dict([(node, tuple(a_weave.get_parents(node))) for 
 
294
                             node in all_revisions])
 
295
        if revision_id is None:
 
296
            return entire_graph
 
297
        elif revision_id not in entire_graph:
 
298
            raise errors.NoSuchRevision(self, revision_id)
 
299
        else:
 
300
            # add what can be reached from revision_id
 
301
            result = {}
 
302
            pending = set([revision_id])
 
303
            while len(pending) > 0:
 
304
                node = pending.pop()
 
305
                result[node] = entire_graph[node]
 
306
                for revision_id in result[node]:
 
307
                    if revision_id not in result:
 
308
                        pending.add(revision_id)
 
309
            return result
112
310
 
113
311
 
114
312
class PreSplitOutRepositoryFormat(RepositoryFormat):
398
596
            text_store=text_store)
399
597
 
400
598
 
 
599
class WeaveCommitBuilder(CommitBuilder):
 
600
    """A builder for weave based repos that don't support ghosts."""
 
601
 
 
602
    def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
 
603
        versionedfile = self.repository.weave_store.get_weave_or_empty(
 
604
            file_id, self.repository.get_transaction())
 
605
        result = versionedfile.add_lines(
 
606
            self._new_revision_id, parents, new_lines,
 
607
            nostore_sha=nostore_sha)[0:2]
 
608
        versionedfile.clear_cache()
 
609
        return result
 
610
 
 
611
 
401
612
_legacy_formats = [RepositoryFormat4(),
402
613
                   RepositoryFormat5(),
403
614
                   RepositoryFormat6()]