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