/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
    )
49
from bzrlib import ui
50
51
52
def open_pack(self):
53
    return self._pack_collection.pack_factory(self._pack_collection._upload_transport,
54
        self._pack_collection._index_transport,
55
        self._pack_collection._pack_transport, upload_suffix=self.suffix,
56
        file_mode=self._pack_collection.repo.bzrdir._get_file_mode())
57
58
59
Packer.open_pack = open_pack
60
61
62
class GCPack(NewPack):
63
64
    def __init__(self, upload_transport, index_transport, pack_transport,
65
        upload_suffix='', file_mode=None):
66
        """Create a NewPack instance.
67
68
        :param upload_transport: A writable transport for the pack to be
69
            incrementally uploaded to.
70
        :param index_transport: A writable transport for the pack's indices to
71
            be written to when the pack is finished.
72
        :param pack_transport: A writable transport for the pack to be renamed
73
            to when the upload is complete. This *must* be the same as
74
            upload_transport.clone('../packs').
75
        :param upload_suffix: An optional suffix to be given to any temporary
76
            files created during the pack creation. e.g '.autopack'
77
        :param file_mode: An optional file mode to create the new files with.
78
        """
79
        # The relative locations of the packs are constrained, but all are
80
        # passed in because the caller has them, so as to avoid object churn.
81
        Pack.__init__(self,
82
            # Revisions: parents list, no text compression.
83
            BTreeBuilder(reference_lists=1),
84
            # Inventory: compressed, with graph for compatibility with other
85
            # existing bzrlib code.
86
            BTreeBuilder(reference_lists=1),
87
            # Texts: per file graph:
88
            BTreeBuilder(reference_lists=1, key_elements=2),
89
            # Signatures: Just blobs to store, no compression, no parents
90
            # listing.
91
            BTreeBuilder(reference_lists=0),
92
            )
93
        # where should the new pack be opened
94
        self.upload_transport = upload_transport
95
        # where are indices written out to
96
        self.index_transport = index_transport
97
        # where is the pack renamed to when it is finished?
98
        self.pack_transport = pack_transport
99
        # What file mode to upload the pack and indices with.
100
        self._file_mode = file_mode
101
        # tracks the content written to the .pack file.
102
        self._hash = md5.new()
103
        # a four-tuple with the length in bytes of the indices, once the pack
104
        # is finalised. (rev, inv, text, sigs)
105
        self.index_sizes = None
106
        # How much data to cache when writing packs. Note that this is not
107
        # synchronised with reads, because it's not in the transport layer, so
108
        # is not safe unless the client knows it won't be reading from the pack
109
        # under creation.
110
        self._cache_limit = 0
111
        # the temporary pack file name.
112
        self.random_name = rand_chars(20) + upload_suffix
113
        # when was this pack started ?
114
        self.start_time = time.time()
115
        # open an output stream for the data added to the pack.
116
        self.write_stream = self.upload_transport.open_write_stream(
117
            self.random_name, mode=self._file_mode)
118
        if 'pack' in debug.debug_flags:
119
            mutter('%s: create_pack: pack stream open: %s%s t+%6.3fs',
120
                time.ctime(), self.upload_transport.base, self.random_name,
121
                time.time() - self.start_time)
122
        # A list of byte sequences to be written to the new pack, and the 
123
        # aggregate size of them.  Stored as a list rather than separate 
124
        # variables so that the _write_data closure below can update them.
125
        self._buffer = [[], 0]
126
        # create a callable for adding data 
127
        #
128
        # robertc says- this is a closure rather than a method on the object
129
        # so that the variables are locals, and faster than accessing object
130
        # members.
131
        def _write_data(bytes, flush=False, _buffer=self._buffer,
132
            _write=self.write_stream.write, _update=self._hash.update):
133
            _buffer[0].append(bytes)
134
            _buffer[1] += len(bytes)
135
            # buffer cap
136
            if _buffer[1] > self._cache_limit or flush:
137
                bytes = ''.join(_buffer[0])
138
                _write(bytes)
139
                _update(bytes)
140
                _buffer[:] = [[], 0]
141
        # expose this on self, for the occasion when clients want to add data.
142
        self._write_data = _write_data
143
        # a pack writer object to serialise pack records.
144
        self._writer = pack.ContainerWriter(self._write_data)
145
        self._writer.begin()
146
        # what state is the pack in? (open, finished, aborted)
147
        self._state = 'open'
148
149
    def _replace_index_with_readonly(self, index_type):
150
        setattr(self, index_type + '_index',
151
            BTreeGraphIndex(self.index_transport,
152
                self.index_name(index_type, self.name),
153
                self.index_sizes[self.index_offset(index_type)]))
154
155
156
RepositoryPackCollection.pack_factory = NewPack
157
158
class GCRepositoryPackCollection(RepositoryPackCollection):
159
160
    pack_factory = GCPack
161
162
    def _make_index(self, name, suffix):
163
        """Overridden to use BTreeGraphIndex objects."""
164
        size_offset = self._suffix_offsets[suffix]
165
        index_name = name + suffix
166
        index_size = self._names[name][size_offset]
167
        return BTreeGraphIndex(
168
            self._index_transport, index_name, index_size)
169
170
    def _start_write_group(self):
171
        # Do not permit preparation for writing if we're not in a 'write lock'.
172
        if not self.repo.is_write_locked():
173
            raise errors.NotWriteLocked(self)
174
        self._new_pack = self.pack_factory(self._upload_transport, self._index_transport,
175
            self._pack_transport, upload_suffix='.pack',
176
            file_mode=self.repo.bzrdir._get_file_mode())
177
        # allow writing: queue writes to a new index
178
        self.revision_index.add_writable_index(self._new_pack.revision_index,
179
            self._new_pack)
180
        self.inventory_index.add_writable_index(self._new_pack.inventory_index,
181
            self._new_pack)
182
        self.text_index.add_writable_index(self._new_pack.text_index,
183
            self._new_pack)
184
        self.signature_index.add_writable_index(self._new_pack.signature_index,
185
            self._new_pack)
186
187
        self.repo.inventories._index._add_callback = self.inventory_index.add_callback
188
        self.repo.revisions._index._add_callback = self.revision_index.add_callback
189
        self.repo.signatures._index._add_callback = self.signature_index.add_callback
190
        self.repo.texts._index._add_callback = self.text_index.add_callback
191
192
193
194
class GCPackRepository(KnitPackRepository):
195
    """GC customisation of KnitPackRepository."""
196
197
    def __init__(self, _format, a_bzrdir, control_files, _commit_builder_class,
198
        _serializer):
199
        """Overridden to change pack collection class."""
200
        KnitPackRepository.__init__(self, _format, a_bzrdir, control_files,
201
            _commit_builder_class, _serializer)
202
        # and now replace everything it did :)
203
        index_transport = self._transport.clone('indices')
204
        self._pack_collection = GCRepositoryPackCollection(self,
205
            self._transport, index_transport,
206
            self._transport.clone('upload'),
207
            self._transport.clone('packs'))
208
        self.inventories = GroupCompressVersionedFiles(
209
            _GCGraphIndex(self._pack_collection.inventory_index.combined_index,
210
                add_callback=self._pack_collection.inventory_index.add_callback,
211
                parents=True, is_locked=self.is_locked),
212
            access=self._pack_collection.inventory_index.data_access)
213
        self.revisions = GroupCompressVersionedFiles(
214
            _GCGraphIndex(self._pack_collection.revision_index.combined_index,
215
                add_callback=self._pack_collection.revision_index.add_callback,
216
                parents=True, is_locked=self.is_locked),
217
            access=self._pack_collection.revision_index.data_access,
218
            delta=False)
219
        self.signatures = GroupCompressVersionedFiles(
220
            _GCGraphIndex(self._pack_collection.signature_index.combined_index,
221
                add_callback=self._pack_collection.signature_index.add_callback,
222
                parents=False, is_locked=self.is_locked),
223
            access=self._pack_collection.signature_index.data_access,
224
            delta=False)
225
        self.texts = GroupCompressVersionedFiles(
226
            _GCGraphIndex(self._pack_collection.text_index.combined_index,
227
                add_callback=self._pack_collection.text_index.add_callback,
228
                parents=True, is_locked=self.is_locked),
229
            access=self._pack_collection.text_index.data_access)
230
        # True when the repository object is 'write locked' (as opposed to the
231
        # physical lock only taken out around changes to the pack-names list.) 
232
        # Another way to represent this would be a decorator around the control
233
        # files object that presents logical locks as physical ones - if this
234
        # gets ugly consider that alternative design. RBC 20071011
235
        self._write_lock_count = 0
236
        self._transaction = None
237
        # for tests
238
        self._reconcile_does_inventory_gc = True
239
        self._reconcile_fixes_text_parents = True
240
        self._reconcile_backsup_inventory = False
241
242
0.17.21 by Robert Collins
Update groupcompress to bzrlib 1.10.
243
class RepositoryFormatPackGCPlain(RepositoryFormatPackDevelopment2):
0.17.9 by Robert Collins
Initial stab at repository format support.
244
    """A B+Tree index using pack repository."""
245
246
    repository_class = GCPackRepository
247
248
    def get_format_string(self):
249
        """See RepositoryFormat.get_format_string()."""
250
        return ("Bazaar development format - btree+gc "
251
            "(needs bzr.dev from 1.6)\n")
252
253
    def get_format_description(self):
254
        """See RepositoryFormat.get_format_description()."""
255
        return ("Development repository format - btree+groupcompress "
256
            ", interoperates with pack-0.92\n")
257
258
259
class RepositoryFormatPackGCRichRoot(RepositoryFormatKnitPack4):
260
    """A B+Tree index using pack repository."""
261
262
    repository_class = GCPackRepository
263
264
    def get_format_string(self):
265
        """See RepositoryFormat.get_format_string()."""
266
        return ("Bazaar development format - btree+gc-rich-root "
267
            "(needs bzr.dev from 1.6)\n")
268
269
    def get_format_description(self):
270
        """See RepositoryFormat.get_format_description()."""
271
        return ("Development repository format - btree+groupcompress "
272
            ", interoperates with rich-root-pack\n")
273
274
0.17.21 by Robert Collins
Update groupcompress to bzrlib 1.10.
275
class RepositoryFormatPackGCSubtrees(RepositoryFormatPackDevelopment2Subtree):
0.17.9 by Robert Collins
Initial stab at repository format support.
276
    """A B+Tree index using pack repository."""
277
278
    repository_class = GCPackRepository
279
280
    def get_format_string(self):
281
        """See RepositoryFormat.get_format_string()."""
282
        return ("Bazaar development format - btree+gc-subtrees "
283
            "(needs bzr.dev from 1.6)\n")
284
285
    def get_format_description(self):
286
        """See RepositoryFormat.get_format_description()."""
287
        return ("Development repository format - btree+groupcompress "
288
            ", interoperates with pack-0.92-subtrees\n")
289
290
291
def pack_incompatible(source, target, orig_method=InterPackRepo.is_compatible):
292
    formats = (RepositoryFormatPackGCPlain, RepositoryFormatPackGCRichRoot,
293
        RepositoryFormatPackGCSubtrees)
0.17.10 by Robert Collins
Correct optimiser disabling.
294
    if isinstance(source._format, formats) or isinstance(target._format, formats):
0.17.9 by Robert Collins
Initial stab at repository format support.
295
        return False
296
    else:
297
        return orig_method(source, target)
298
299
300
InterPackRepo.is_compatible = staticmethod(pack_incompatible)