/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
0.17.9 by Robert Collins
Initial stab at repository format support.
1
# groupcompress, a bzr plugin providing improved disk utilisation
2
# Copyright (C) 2008 Canonical Limited.
3
# 
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License version 2 as published
6
# by the Free Software Foundation.
7
# 
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
# 
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
16
# 
17
18
"""Repostory formats using B+Tree indices and groupcompress compression."""
19
20
import md5
21
import time
22
23
from bzrlib import debug, errors, pack, repository
0.17.21 by Robert Collins
Update groupcompress to bzrlib 1.10.
24
from bzrlib.btree_index import (
25
    BTreeBuilder,
26
    BTreeGraphIndex,
27
    )
0.17.9 by Robert Collins
Initial stab at repository format support.
28
from bzrlib.index import GraphIndex, GraphIndexBuilder
29
from bzrlib.repository import InterPackRepo
30
from bzrlib.plugins.groupcompress.groupcompress import (
31
    _GCGraphIndex,
32
    GroupCompressVersionedFiles,
33
    )
34
from bzrlib.osutils import rand_chars
35
from bzrlib.repofmt.pack_repo import (
36
    Pack,
37
    NewPack,
38
    KnitPackRepository,
39
    RepositoryPackCollection,
0.17.21 by Robert Collins
Update groupcompress to bzrlib 1.10.
40
    RepositoryFormatPackDevelopment2,
41
    RepositoryFormatPackDevelopment2Subtree,
0.17.9 by Robert Collins
Initial stab at repository format support.
42
    RepositoryFormatKnitPack1,
43
    RepositoryFormatKnitPack3,
44
    RepositoryFormatKnitPack4,
45
    Packer,
46
    ReconcilePacker,
47
    OptimisingPacker,
48
    )
0.17.25 by Robert Collins
Preliminary --gc-plain-chk support.
49
try:
50
    from bzrlib.repofmt.pack_repo import (
51
    RepositoryFormatPackDevelopment4,
52
    RepositoryFormatPackDevelopment4Subtree,
53
    )
54
    chk_support = True
55
except ImportError:
56
    chk_support = False
0.17.9 by Robert Collins
Initial stab at repository format support.
57
from bzrlib import ui
58
59
60
def open_pack(self):
0.17.22 by Robert Collins
really get gc working with 1.10
61
    return self._pack_collection.pack_factory(self._pack_collection,
62
        upload_suffix=self.suffix,
0.17.9 by Robert Collins
Initial stab at repository format support.
63
        file_mode=self._pack_collection.repo.bzrdir._get_file_mode())
64
65
66
Packer.open_pack = open_pack
67
68
69
class GCPack(NewPack):
70
0.17.22 by Robert Collins
really get gc working with 1.10
71
    def __init__(self, pack_collection, upload_suffix='', file_mode=None):
0.17.9 by Robert Collins
Initial stab at repository format support.
72
        """Create a NewPack instance.
73
74
        :param upload_transport: A writable transport for the pack to be
75
            incrementally uploaded to.
76
        :param index_transport: A writable transport for the pack's indices to
77
            be written to when the pack is finished.
78
        :param pack_transport: A writable transport for the pack to be renamed
79
            to when the upload is complete. This *must* be the same as
80
            upload_transport.clone('../packs').
81
        :param upload_suffix: An optional suffix to be given to any temporary
82
            files created during the pack creation. e.g '.autopack'
83
        :param file_mode: An optional file mode to create the new files with.
84
        """
0.17.25 by Robert Collins
Preliminary --gc-plain-chk support.
85
        # replaced from bzr.dev to:
86
        # - change inventory reference list length to 1
87
        # - change texts reference lists to 1
88
        # TODO: patch this to be parameterised upstream
89
        
0.17.9 by Robert Collins
Initial stab at repository format support.
90
        # The relative locations of the packs are constrained, but all are
91
        # passed in because the caller has them, so as to avoid object churn.
0.17.22 by Robert Collins
really get gc working with 1.10
92
        index_builder_class = pack_collection._index_builder_class
0.17.25 by Robert Collins
Preliminary --gc-plain-chk support.
93
        if chk_support:
94
            # from brisbane-core
95
            if pack_collection.chk_index is not None:
96
                chk_index = index_builder_class(reference_lists=0)
97
            else:
98
                chk_index = None
99
            Pack.__init__(self,
100
                # Revisions: parents list, no text compression.
101
                index_builder_class(reference_lists=1),
102
                # Inventory: We want to map compression only, but currently the
103
                # knit code hasn't been updated enough to understand that, so we
104
                # have a regular 2-list index giving parents and compression
105
                # source.
106
                index_builder_class(reference_lists=1),
107
                # Texts: compression and per file graph, for all fileids - so two
108
                # reference lists and two elements in the key tuple.
109
                index_builder_class(reference_lists=1, key_elements=2),
110
                # Signatures: Just blobs to store, no compression, no parents
111
                # listing.
112
                index_builder_class(reference_lists=0),
113
                # CHK based storage - just blobs, no compression or parents.
114
                chk_index=chk_index
115
                )
116
        else:
117
            # from bzr.dev
118
            Pack.__init__(self,
119
                # Revisions: parents list, no text compression.
120
                index_builder_class(reference_lists=1),
121
                # Inventory: compressed, with graph for compatibility with other
122
                # existing bzrlib code.
123
                index_builder_class(reference_lists=1),
124
                # Texts: per file graph:
125
                index_builder_class(reference_lists=1, key_elements=2),
126
                # Signatures: Just blobs to store, no compression, no parents
127
                # listing.
128
                index_builder_class(reference_lists=0),
129
                )
0.17.22 by Robert Collins
really get gc working with 1.10
130
        self._pack_collection = pack_collection
131
        # When we make readonly indices, we need this.
132
        self.index_class = pack_collection._index_class
0.17.9 by Robert Collins
Initial stab at repository format support.
133
        # where should the new pack be opened
0.17.22 by Robert Collins
really get gc working with 1.10
134
        self.upload_transport = pack_collection._upload_transport
0.17.9 by Robert Collins
Initial stab at repository format support.
135
        # where are indices written out to
0.17.22 by Robert Collins
really get gc working with 1.10
136
        self.index_transport = pack_collection._index_transport
0.17.9 by Robert Collins
Initial stab at repository format support.
137
        # where is the pack renamed to when it is finished?
0.17.22 by Robert Collins
really get gc working with 1.10
138
        self.pack_transport = pack_collection._pack_transport
0.17.9 by Robert Collins
Initial stab at repository format support.
139
        # What file mode to upload the pack and indices with.
140
        self._file_mode = file_mode
141
        # tracks the content written to the .pack file.
142
        self._hash = md5.new()
143
        # a four-tuple with the length in bytes of the indices, once the pack
144
        # is finalised. (rev, inv, text, sigs)
145
        self.index_sizes = None
146
        # How much data to cache when writing packs. Note that this is not
147
        # synchronised with reads, because it's not in the transport layer, so
148
        # is not safe unless the client knows it won't be reading from the pack
149
        # under creation.
150
        self._cache_limit = 0
151
        # the temporary pack file name.
152
        self.random_name = rand_chars(20) + upload_suffix
153
        # when was this pack started ?
154
        self.start_time = time.time()
155
        # open an output stream for the data added to the pack.
156
        self.write_stream = self.upload_transport.open_write_stream(
157
            self.random_name, mode=self._file_mode)
158
        if 'pack' in debug.debug_flags:
159
            mutter('%s: create_pack: pack stream open: %s%s t+%6.3fs',
160
                time.ctime(), self.upload_transport.base, self.random_name,
161
                time.time() - self.start_time)
162
        # A list of byte sequences to be written to the new pack, and the 
163
        # aggregate size of them.  Stored as a list rather than separate 
164
        # variables so that the _write_data closure below can update them.
165
        self._buffer = [[], 0]
166
        # create a callable for adding data 
167
        #
168
        # robertc says- this is a closure rather than a method on the object
169
        # so that the variables are locals, and faster than accessing object
170
        # members.
171
        def _write_data(bytes, flush=False, _buffer=self._buffer,
172
            _write=self.write_stream.write, _update=self._hash.update):
173
            _buffer[0].append(bytes)
174
            _buffer[1] += len(bytes)
175
            # buffer cap
176
            if _buffer[1] > self._cache_limit or flush:
177
                bytes = ''.join(_buffer[0])
178
                _write(bytes)
179
                _update(bytes)
180
                _buffer[:] = [[], 0]
181
        # expose this on self, for the occasion when clients want to add data.
182
        self._write_data = _write_data
183
        # a pack writer object to serialise pack records.
184
        self._writer = pack.ContainerWriter(self._write_data)
185
        self._writer.begin()
186
        # what state is the pack in? (open, finished, aborted)
187
        self._state = 'open'
188
189
190
RepositoryPackCollection.pack_factory = NewPack
191
192
class GCRepositoryPackCollection(RepositoryPackCollection):
193
194
    pack_factory = GCPack
195
196
    def _make_index(self, name, suffix):
197
        """Overridden to use BTreeGraphIndex objects."""
198
        size_offset = self._suffix_offsets[suffix]
199
        index_name = name + suffix
200
        index_size = self._names[name][size_offset]
201
        return BTreeGraphIndex(
202
            self._index_transport, index_name, index_size)
203
204
    def _start_write_group(self):
0.17.25 by Robert Collins
Preliminary --gc-plain-chk support.
205
        # Overridden to add 'self.pack_factory()'
0.17.9 by Robert Collins
Initial stab at repository format support.
206
        # Do not permit preparation for writing if we're not in a 'write lock'.
207
        if not self.repo.is_write_locked():
208
            raise errors.NotWriteLocked(self)
0.17.22 by Robert Collins
really get gc working with 1.10
209
        self._new_pack = self.pack_factory(self, upload_suffix='.pack',
0.17.9 by Robert Collins
Initial stab at repository format support.
210
            file_mode=self.repo.bzrdir._get_file_mode())
211
        # allow writing: queue writes to a new index
212
        self.revision_index.add_writable_index(self._new_pack.revision_index,
213
            self._new_pack)
214
        self.inventory_index.add_writable_index(self._new_pack.inventory_index,
215
            self._new_pack)
216
        self.text_index.add_writable_index(self._new_pack.text_index,
217
            self._new_pack)
218
        self.signature_index.add_writable_index(self._new_pack.signature_index,
219
            self._new_pack)
0.17.25 by Robert Collins
Preliminary --gc-plain-chk support.
220
        if chk_support and self.chk_index is not None:
221
            self.chk_index.add_writable_index(self._new_pack.chk_index,
222
                self._new_pack)
223
            self.repo.chk_bytes._index._add_callback = self.chk_index.add_callback
0.17.9 by Robert Collins
Initial stab at repository format support.
224
225
        self.repo.inventories._index._add_callback = self.inventory_index.add_callback
226
        self.repo.revisions._index._add_callback = self.revision_index.add_callback
227
        self.repo.signatures._index._add_callback = self.signature_index.add_callback
228
        self.repo.texts._index._add_callback = self.text_index.add_callback
229
230
231
232
class GCPackRepository(KnitPackRepository):
233
    """GC customisation of KnitPackRepository."""
234
235
    def __init__(self, _format, a_bzrdir, control_files, _commit_builder_class,
236
        _serializer):
237
        """Overridden to change pack collection class."""
238
        KnitPackRepository.__init__(self, _format, a_bzrdir, control_files,
239
            _commit_builder_class, _serializer)
240
        # and now replace everything it did :)
241
        index_transport = self._transport.clone('indices')
0.17.25 by Robert Collins
Preliminary --gc-plain-chk support.
242
        if chk_support:
243
            self._pack_collection = GCRepositoryPackCollection(self,
244
                self._transport, index_transport,
245
                self._transport.clone('upload'),
246
                self._transport.clone('packs'),
247
                _format.index_builder_class,
248
                _format.index_class,
249
                use_chk_index=self._format.supports_chks,
250
                )
251
        else:
252
            self._pack_collection = GCRepositoryPackCollection(self,
253
                self._transport, index_transport,
254
                self._transport.clone('upload'),
255
                self._transport.clone('packs'),
256
                _format.index_builder_class,
257
                _format.index_class)
0.17.9 by Robert Collins
Initial stab at repository format support.
258
        self.inventories = GroupCompressVersionedFiles(
259
            _GCGraphIndex(self._pack_collection.inventory_index.combined_index,
260
                add_callback=self._pack_collection.inventory_index.add_callback,
261
                parents=True, is_locked=self.is_locked),
262
            access=self._pack_collection.inventory_index.data_access)
263
        self.revisions = GroupCompressVersionedFiles(
264
            _GCGraphIndex(self._pack_collection.revision_index.combined_index,
265
                add_callback=self._pack_collection.revision_index.add_callback,
266
                parents=True, is_locked=self.is_locked),
267
            access=self._pack_collection.revision_index.data_access,
268
            delta=False)
269
        self.signatures = GroupCompressVersionedFiles(
270
            _GCGraphIndex(self._pack_collection.signature_index.combined_index,
271
                add_callback=self._pack_collection.signature_index.add_callback,
272
                parents=False, is_locked=self.is_locked),
273
            access=self._pack_collection.signature_index.data_access,
274
            delta=False)
275
        self.texts = GroupCompressVersionedFiles(
276
            _GCGraphIndex(self._pack_collection.text_index.combined_index,
277
                add_callback=self._pack_collection.text_index.add_callback,
278
                parents=True, is_locked=self.is_locked),
279
            access=self._pack_collection.text_index.data_access)
280
        # True when the repository object is 'write locked' (as opposed to the
281
        # physical lock only taken out around changes to the pack-names list.) 
282
        # Another way to represent this would be a decorator around the control
283
        # files object that presents logical locks as physical ones - if this
284
        # gets ugly consider that alternative design. RBC 20071011
285
        self._write_lock_count = 0
286
        self._transaction = None
287
        # for tests
288
        self._reconcile_does_inventory_gc = True
289
        self._reconcile_fixes_text_parents = True
290
        self._reconcile_backsup_inventory = False
291
292
0.17.21 by Robert Collins
Update groupcompress to bzrlib 1.10.
293
class RepositoryFormatPackGCPlain(RepositoryFormatPackDevelopment2):
0.17.9 by Robert Collins
Initial stab at repository format support.
294
    """A B+Tree index using pack repository."""
295
296
    repository_class = GCPackRepository
297
298
    def get_format_string(self):
299
        """See RepositoryFormat.get_format_string()."""
300
        return ("Bazaar development format - btree+gc "
301
            "(needs bzr.dev from 1.6)\n")
302
303
    def get_format_description(self):
304
        """See RepositoryFormat.get_format_description()."""
305
        return ("Development repository format - btree+groupcompress "
306
            ", interoperates with pack-0.92\n")
307
308
309
class RepositoryFormatPackGCRichRoot(RepositoryFormatKnitPack4):
310
    """A B+Tree index using pack repository."""
311
312
    repository_class = GCPackRepository
313
314
    def get_format_string(self):
315
        """See RepositoryFormat.get_format_string()."""
316
        return ("Bazaar development format - btree+gc-rich-root "
317
            "(needs bzr.dev from 1.6)\n")
318
319
    def get_format_description(self):
320
        """See RepositoryFormat.get_format_description()."""
321
        return ("Development repository format - btree+groupcompress "
322
            ", interoperates with rich-root-pack\n")
323
324
0.17.21 by Robert Collins
Update groupcompress to bzrlib 1.10.
325
class RepositoryFormatPackGCSubtrees(RepositoryFormatPackDevelopment2Subtree):
0.17.9 by Robert Collins
Initial stab at repository format support.
326
    """A B+Tree index using pack repository."""
327
328
    repository_class = GCPackRepository
329
330
    def get_format_string(self):
331
        """See RepositoryFormat.get_format_string()."""
332
        return ("Bazaar development format - btree+gc-subtrees "
333
            "(needs bzr.dev from 1.6)\n")
334
335
    def get_format_description(self):
336
        """See RepositoryFormat.get_format_description()."""
337
        return ("Development repository format - btree+groupcompress "
338
            ", interoperates with pack-0.92-subtrees\n")
339
0.17.25 by Robert Collins
Preliminary --gc-plain-chk support.
340
if chk_support:
341
    'Bazaar development format - 1.9+gc (needs bzr.dev from 1.9)\n',
342
    class RepositoryFormatPackGCPlainCHK(RepositoryFormatPackDevelopment4):
343
        """A CHK+group compress pack repository."""
344
345
        repository_class = GCPackRepository
346
347
        def get_format_string(self):
348
            """See RepositoryFormat.get_format_string()."""
349
            return ('Bazaar development format - chk+gc '
350
                '(needs bzr.dev from 1.12)\n')
351
352
        def get_format_description(self):
353
            """See RepositoryFormat.get_format_description()."""
354
            return ("Development repository format - chk+groupcompress "
355
                ", interoperates with pack-0.92\n")
356
357
358
359
0.17.9 by Robert Collins
Initial stab at repository format support.
360
361
def pack_incompatible(source, target, orig_method=InterPackRepo.is_compatible):
362
    formats = (RepositoryFormatPackGCPlain, RepositoryFormatPackGCRichRoot,
363
        RepositoryFormatPackGCSubtrees)
0.17.10 by Robert Collins
Correct optimiser disabling.
364
    if isinstance(source._format, formats) or isinstance(target._format, formats):
0.17.9 by Robert Collins
Initial stab at repository format support.
365
        return False
366
    else:
367
        return orig_method(source, target)
368
369
370
InterPackRepo.is_compatible = staticmethod(pack_incompatible)