/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
from bzrlib.lazy_import import lazy_import
18
lazy_import(globals(), """
19
from itertools import izip
20
import math
21
import md5
2592.3.91 by Robert Collins
Incrementally closing in on a correct fetch for packs.
22
import time
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
23
24
from bzrlib import (
2592.3.91 by Robert Collins
Incrementally closing in on a correct fetch for packs.
25
        debug,
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
26
        pack,
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
27
        ui,
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
28
        )
29
from bzrlib.index import (
30
    GraphIndex,
31
    GraphIndexBuilder,
32
    InMemoryGraphIndex,
33
    CombinedGraphIndex,
34
    GraphIndexPrefixAdapter,
35
    )
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
36
from bzrlib.knit import KnitGraphIndex, _PackAccess, _KnitData
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
37
from bzrlib.osutils import rand_chars
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
38
from bzrlib.pack import ContainerWriter
39
from bzrlib.store import revision
40
""")
41
from bzrlib import (
42
    bzrdir,
43
    deprecated_graph,
44
    errors,
45
    knit,
46
    lockable_files,
47
    lockdir,
48
    osutils,
49
    transactions,
50
    xml5,
51
    xml7,
52
    )
53
54
from bzrlib.decorators import needs_read_lock, needs_write_lock
2592.3.166 by Robert Collins
Merge KnitRepository3 removal branch.
55
from bzrlib.repofmt.knitrepo import KnitRepository
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
56
from bzrlib.repository import (
2592.3.135 by Robert Collins
Do not create many transient knit objects, saving 4% on commit.
57
    CommitBuilder,
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
58
    MetaDirRepository,
59
    MetaDirRepositoryFormat,
2592.3.135 by Robert Collins
Do not create many transient knit objects, saving 4% on commit.
60
    RootCommitBuilder,
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
61
    )
62
import bzrlib.revision as _mod_revision
63
from bzrlib.store.revision.knit import KnitRevisionStore
64
from bzrlib.store.versioned import VersionedFileStore
65
from bzrlib.trace import mutter, note, warning
66
67
2592.3.135 by Robert Collins
Do not create many transient knit objects, saving 4% on commit.
68
class PackCommitBuilder(CommitBuilder):
69
    """A subclass of CommitBuilder to add texts with pack semantics.
70
    
71
    Specifically this uses one knit object rather than one knit object per
72
    added text, reducing memory and object pressure.
73
    """
74
75
    def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
76
        return self.repository._pack_collection._add_text_to_weave(file_id,
2592.3.135 by Robert Collins
Do not create many transient knit objects, saving 4% on commit.
77
            self._new_revision_id, new_lines, parents, nostore_sha,
78
            self.random_revid)
79
80
81
class PackRootCommitBuilder(RootCommitBuilder):
82
    """A subclass of RootCommitBuilder to add texts with pack semantics.
83
    
84
    Specifically this uses one knit object rather than one knit object per
85
    added text, reducing memory and object pressure.
86
    """
87
88
    def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
89
        return self.repository._pack_collection._add_text_to_weave(file_id,
2592.3.135 by Robert Collins
Do not create many transient knit objects, saving 4% on commit.
90
            self._new_revision_id, new_lines, parents, nostore_sha,
91
            self.random_revid)
92
93
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
94
class Pack(object):
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
95
    """An in memory proxy for a pack and its indices.
96
97
    This is a base class that is not directly used, instead the classes
98
    ExistingPack and NewPack are used.
99
    """
100
2592.3.197 by Robert Collins
Hand over signature index creation to NewPack.
101
    def __init__(self, revision_index, inventory_index, text_index,
102
        signature_index):
2592.3.192 by Robert Collins
Move new revision index management to NewPack.
103
        """Create a pack instance.
104
105
        :param revision_index: A GraphIndex for determining what revisions are
106
            present in the Pack and accessing the locations of their texts.
2592.3.195 by Robert Collins
Move some inventory index logic to NewPack.
107
        :param inventory_index: A GraphIndex for determining what inventories are
2592.3.196 by Robert Collins
Move some text index logic to NewPack.
108
            present in the Pack and accessing the locations of their
109
            texts/deltas.
110
        :param text_index: A GraphIndex for determining what file texts
2592.3.197 by Robert Collins
Hand over signature index creation to NewPack.
111
            are present in the pack and accessing the locations of their
112
            texts/deltas (via (fileid, revisionid) tuples).
113
        :param revision_index: A GraphIndex for determining what signatures are
114
            present in the Pack and accessing the locations of their texts.
2592.3.192 by Robert Collins
Move new revision index management to NewPack.
115
        """
116
        self.revision_index = revision_index
2592.3.195 by Robert Collins
Move some inventory index logic to NewPack.
117
        self.inventory_index = inventory_index
2592.3.196 by Robert Collins
Move some text index logic to NewPack.
118
        self.text_index = text_index
2592.3.197 by Robert Collins
Hand over signature index creation to NewPack.
119
        self.signature_index = signature_index
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
120
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
121
    def access_tuple(self):
122
        """Return a tuple (transport, name) for the pack content."""
123
        return self.pack_transport, self.file_name()
124
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
125
    def file_name(self):
126
        """Get the file name for the pack on disk."""
127
        return self.name + '.pack'
128
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
129
    def get_revision_count(self):
130
        return self.revision_index.key_count()
131
132
    def inventory_index_name(self, name):
133
        """The inv index is the name + .iix."""
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
134
        return self.index_name('inventory', name)
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
135
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
136
    def revision_index_name(self, name):
137
        """The revision index is the name + .rix."""
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
138
        return self.index_name('revision', name)
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
139
140
    def signature_index_name(self, name):
141
        """The signature index is the name + .six."""
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
142
        return self.index_name('signature', name)
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
143
144
    def text_index_name(self, name):
145
        """The text index is the name + .tix."""
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
146
        return self.index_name('text', name)
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
147
148
149
class ExistingPack(Pack):
2592.3.222 by Robert Collins
More review feedback.
150
    """An in memory proxy for an existing .pack and its disk indices."""
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
151
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
152
    def __init__(self, pack_transport, name, revision_index, inventory_index,
2592.3.177 by Robert Collins
Make all parameters to Pack objects mandatory.
153
        text_index, signature_index):
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
154
        """Create an ExistingPack object.
155
156
        :param pack_transport: The transport where the pack file resides.
157
        :param name: The name of the pack on disk in the pack_transport.
158
        """
2592.3.197 by Robert Collins
Hand over signature index creation to NewPack.
159
        Pack.__init__(self, revision_index, inventory_index, text_index,
160
            signature_index)
2592.3.173 by Robert Collins
Basic implementation of all_packs.
161
        self.name = name
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
162
        self.pack_transport = pack_transport
2592.3.177 by Robert Collins
Make all parameters to Pack objects mandatory.
163
        assert None not in (revision_index, inventory_index, text_index,
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
164
            signature_index, name, pack_transport)
2592.3.173 by Robert Collins
Basic implementation of all_packs.
165
166
    def __eq__(self, other):
167
        return self.__dict__ == other.__dict__
168
169
    def __ne__(self, other):
170
        return not self.__eq__(other)
171
172
    def __repr__(self):
173
        return "<bzrlib.repofmt.pack_repo.Pack object at 0x%x, %s, %s" % (
174
            id(self), self.transport, self.name)
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
175
176
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
177
class NewPack(Pack):
178
    """An in memory proxy for a pack which is being created."""
179
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
180
    # A map of index 'type' to the file extension and position in the
181
    # index_sizes array.
2592.3.227 by Martin Pool
Rename NewPack.indices to NewPack.index_definitions
182
    index_definitions = {
2592.3.226 by Martin Pool
formatting and docstrings
183
        'revision': ('.rix', 0),
184
        'inventory': ('.iix', 1),
185
        'text': ('.tix', 2),
186
        'signature': ('.six', 3),
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
187
        }
188
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
189
    def __init__(self, upload_transport, index_transport, pack_transport,
3010.1.11 by Robert Collins
Provide file modes to files created by pack repositories
190
        upload_suffix='', file_mode=None):
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
191
        """Create a NewPack instance.
192
193
        :param upload_transport: A writable transport for the pack to be
194
            incrementally uploaded to.
195
        :param index_transport: A writable transport for the pack's indices to
196
            be written to when the pack is finished.
197
        :param pack_transport: A writable transport for the pack to be renamed
2592.3.206 by Robert Collins
Move pack rename-into-place into NewPack.finish and document hash-collision cases somewhat better.
198
            to when the upload is complete. This *must* be the same as
199
            upload_transport.clone('../packs').
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
200
        :param upload_suffix: An optional suffix to be given to any temporary
201
            files created during the pack creation. e.g '.autopack'
3010.1.11 by Robert Collins
Provide file modes to files created by pack repositories
202
        :param file_mode: An optional file mode to create the new files with.
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
203
        """
2592.3.228 by Martin Pool
docstrings and error messages from review
204
        # The relative locations of the packs are constrained, but all are
205
        # passed in because the caller has them, so as to avoid object churn.
2592.3.195 by Robert Collins
Move some inventory index logic to NewPack.
206
        Pack.__init__(self,
207
            # Revisions: parents list, no text compression.
208
            InMemoryGraphIndex(reference_lists=1),
209
            # Inventory: We want to map compression only, but currently the
210
            # knit code hasn't been updated enough to understand that, so we
211
            # have a regular 2-list index giving parents and compression
212
            # source.
2592.3.196 by Robert Collins
Move some text index logic to NewPack.
213
            InMemoryGraphIndex(reference_lists=2),
214
            # Texts: compression and per file graph, for all fileids - so two
215
            # reference lists and two elements in the key tuple.
216
            InMemoryGraphIndex(reference_lists=2, key_elements=2),
2592.3.197 by Robert Collins
Hand over signature index creation to NewPack.
217
            # Signatures: Just blobs to store, no compression, no parents
218
            # listing.
219
            InMemoryGraphIndex(reference_lists=0),
2592.3.196 by Robert Collins
Move some text index logic to NewPack.
220
            )
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
221
        # where should the new pack be opened
222
        self.upload_transport = upload_transport
223
        # where are indices written out to
224
        self.index_transport = index_transport
225
        # where is the pack renamed to when it is finished?
226
        self.pack_transport = pack_transport
3010.1.11 by Robert Collins
Provide file modes to files created by pack repositories
227
        # What file mode to upload the pack and indices with.
228
        self._file_mode = file_mode
2592.3.193 by Robert Collins
Move hash tracking of new packs into NewPack.
229
        # tracks the content written to the .pack file.
230
        self._hash = md5.new()
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
231
        # a four-tuple with the length in bytes of the indices, once the pack
2592.3.195 by Robert Collins
Move some inventory index logic to NewPack.
232
        # is finalised. (rev, inv, text, sigs)
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
233
        self.index_sizes = None
2592.3.203 by Robert Collins
Teach NewPack how to buffer for pack operations.
234
        # How much data to cache when writing packs. Note that this is not
2592.3.222 by Robert Collins
More review feedback.
235
        # synchronised with reads, because it's not in the transport layer, so
2592.3.203 by Robert Collins
Teach NewPack how to buffer for pack operations.
236
        # is not safe unless the client knows it won't be reading from the pack
237
        # under creation.
238
        self._cache_limit = 0
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
239
        # the temporary pack file name.
240
        self.random_name = rand_chars(20) + upload_suffix
241
        # when was this pack started ?
242
        self.start_time = time.time()
2592.3.202 by Robert Collins
Move write stream management into NewPack.
243
        # open an output stream for the data added to the pack.
244
        self.write_stream = self.upload_transport.open_write_stream(
3010.1.11 by Robert Collins
Provide file modes to files created by pack repositories
245
            self.random_name, mode=self._file_mode)
2592.3.234 by Martin Pool
Use -Dpack not -Dfetch for pack traces
246
        if 'pack' in debug.debug_flags:
2592.3.202 by Robert Collins
Move write stream management into NewPack.
247
            mutter('%s: create_pack: pack stream open: %s%s t+%6.3fs',
248
                time.ctime(), self.upload_transport.base, self.random_name,
249
                time.time() - self.start_time)
2592.3.233 by Martin Pool
Review cleanups
250
        # A list of byte sequences to be written to the new pack, and the 
251
        # aggregate size of them.  Stored as a list rather than separate 
252
        # variables so that the _write_data closure below can update them.
2592.3.203 by Robert Collins
Teach NewPack how to buffer for pack operations.
253
        self._buffer = [[], 0]
2592.3.233 by Martin Pool
Review cleanups
254
        # create a callable for adding data 
255
        #
256
        # robertc says- this is a closure rather than a method on the object
257
        # so that the variables are locals, and faster than accessing object
258
        # members.
2592.3.203 by Robert Collins
Teach NewPack how to buffer for pack operations.
259
        def _write_data(bytes, flush=False, _buffer=self._buffer,
260
            _write=self.write_stream.write, _update=self._hash.update):
261
            _buffer[0].append(bytes)
262
            _buffer[1] += len(bytes)
2592.3.222 by Robert Collins
More review feedback.
263
            # buffer cap
2592.3.203 by Robert Collins
Teach NewPack how to buffer for pack operations.
264
            if _buffer[1] > self._cache_limit or flush:
265
                bytes = ''.join(_buffer[0])
266
                _write(bytes)
267
                _update(bytes)
268
                _buffer[:] = [[], 0]
2592.3.202 by Robert Collins
Move write stream management into NewPack.
269
        # expose this on self, for the occasion when clients want to add data.
270
        self._write_data = _write_data
2592.3.205 by Robert Collins
Move the pack ContainerWriter instance into NewPack.
271
        # a pack writer object to serialise pack records.
272
        self._writer = pack.ContainerWriter(self._write_data)
273
        self._writer.begin()
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
274
        # what state is the pack in? (open, finished, aborted)
275
        self._state = 'open'
2592.3.202 by Robert Collins
Move write stream management into NewPack.
276
277
    def abort(self):
278
        """Cancel creating this pack."""
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
279
        self._state = 'aborted'
2938.1.1 by Robert Collins
trivial fix for packs@win32: explicitly close file before deleting
280
        self.write_stream.close()
2592.3.202 by Robert Collins
Move write stream management into NewPack.
281
        # Remove the temporary pack file.
282
        self.upload_transport.delete(self.random_name)
283
        # The indices have no state on disk.
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
284
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
285
    def access_tuple(self):
286
        """Return a tuple (transport, name) for the pack content."""
287
        assert self._state in ('open', 'finished')
288
        if self._state == 'finished':
289
            return Pack.access_tuple(self)
290
        else:
291
            return self.upload_transport, self.random_name
292
2592.3.198 by Robert Collins
Factor out data_inserted to reduce code duplication in detecting empty packs.
293
    def data_inserted(self):
294
        """True if data has been added to this pack."""
2592.3.233 by Martin Pool
Review cleanups
295
        return bool(self.get_revision_count() or
296
            self.inventory_index.key_count() or
297
            self.text_index.key_count() or
298
            self.signature_index.key_count())
2592.3.198 by Robert Collins
Factor out data_inserted to reduce code duplication in detecting empty packs.
299
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
300
    def finish(self):
301
        """Finish the new pack.
302
303
        This:
304
         - finalises the content
305
         - assigns a name (the md5 of the content, currently)
306
         - writes out the associated indices
307
         - renames the pack into place.
308
         - stores the index size tuple for the pack in the index_sizes
309
           attribute.
310
        """
2592.3.205 by Robert Collins
Move the pack ContainerWriter instance into NewPack.
311
        self._writer.end()
2592.3.203 by Robert Collins
Teach NewPack how to buffer for pack operations.
312
        if self._buffer[1]:
313
            self._write_data('', flush=True)
2592.3.199 by Robert Collins
Store the name of a NewPack in the object upon finish().
314
        self.name = self._hash.hexdigest()
2592.3.203 by Robert Collins
Teach NewPack how to buffer for pack operations.
315
        # write indices
2592.3.233 by Martin Pool
Review cleanups
316
        # XXX: It'd be better to write them all to temporary names, then
317
        # rename them all into place, so that the window when only some are
318
        # visible is smaller.  On the other hand none will be seen until
319
        # they're in the names list.
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
320
        self.index_sizes = [None, None, None, None]
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
321
        self._write_index('revision', self.revision_index, 'revision')
322
        self._write_index('inventory', self.inventory_index, 'inventory')
323
        self._write_index('text', self.text_index, 'file texts')
324
        self._write_index('signature', self.signature_index,
325
            'revision signatures')
2592.3.202 by Robert Collins
Move write stream management into NewPack.
326
        self.write_stream.close()
2592.3.206 by Robert Collins
Move pack rename-into-place into NewPack.finish and document hash-collision cases somewhat better.
327
        # Note that this will clobber an existing pack with the same name,
328
        # without checking for hash collisions. While this is undesirable this
329
        # is something that can be rectified in a subsequent release. One way
330
        # to rectify it may be to leave the pack at the original name, writing
331
        # its pack-names entry as something like 'HASH: index-sizes
332
        # temporary-name'. Allocate that and check for collisions, if it is
333
        # collision free then rename it into place. If clients know this scheme
334
        # they can handle missing-file errors by:
335
        #  - try for HASH.pack
336
        #  - try for temporary-name
337
        #  - refresh the pack-list to see if the pack is now absent
338
        self.upload_transport.rename(self.random_name,
339
                '../packs/' + self.name + '.pack')
2592.3.211 by Robert Collins
Pack inventory index management cleaned up.
340
        self._state = 'finished'
2592.3.234 by Martin Pool
Use -Dpack not -Dfetch for pack traces
341
        if 'pack' in debug.debug_flags:
2592.3.219 by Robert Collins
Review feedback.
342
            # XXX: size might be interesting?
343
            mutter('%s: create_pack: pack renamed into place: %s%s->%s%s t+%6.3fs',
344
                time.ctime(), self.upload_transport.base, self.random_name,
345
                self.pack_transport, self.name,
346
                time.time() - self.start_time)
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
347
348
    def index_name(self, index_type, name):
349
        """Get the disk name of an index type for pack name 'name'."""
2592.3.227 by Martin Pool
Rename NewPack.indices to NewPack.index_definitions
350
        return name + NewPack.index_definitions[index_type][0]
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
351
352
    def index_offset(self, index_type):
353
        """Get the position in a index_size array for a given index type."""
2592.3.227 by Martin Pool
Rename NewPack.indices to NewPack.index_definitions
354
        return NewPack.index_definitions[index_type][1]
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
355
2592.3.233 by Martin Pool
Review cleanups
356
    def _replace_index_with_readonly(self, index_type):
357
        setattr(self, index_type + '_index',
358
            GraphIndex(self.index_transport,
359
                self.index_name(index_type, self.name),
360
                self.index_sizes[self.index_offset(index_type)]))
361
2592.3.203 by Robert Collins
Teach NewPack how to buffer for pack operations.
362
    def set_write_cache_size(self, size):
363
        self._cache_limit = size
364
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
365
    def _write_index(self, index_type, index, label):
2592.3.196 by Robert Collins
Move some text index logic to NewPack.
366
        """Write out an index.
367
2592.3.222 by Robert Collins
More review feedback.
368
        :param index_type: The type of index to write - e.g. 'revision'.
2592.3.196 by Robert Collins
Move some text index logic to NewPack.
369
        :param index: The index object to serialise.
370
        :param label: What label to give the index e.g. 'revision'.
371
        """
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
372
        index_name = self.index_name(index_type, self.name)
373
        self.index_sizes[self.index_offset(index_type)] = \
3010.1.11 by Robert Collins
Provide file modes to files created by pack repositories
374
            self.index_transport.put_file(index_name, index.finish(),
375
            mode=self._file_mode)
2592.3.234 by Martin Pool
Use -Dpack not -Dfetch for pack traces
376
        if 'pack' in debug.debug_flags:
2592.3.196 by Robert Collins
Move some text index logic to NewPack.
377
            # XXX: size might be interesting?
378
            mutter('%s: create_pack: wrote %s index: %s%s t+%6.3fs',
379
                time.ctime(), label, self.upload_transport.base,
380
                self.random_name, time.time() - self.start_time)
2592.3.233 by Martin Pool
Review cleanups
381
        # Replace the writable index on this object with a readonly, 
382
        # presently unloaded index. We should alter
383
        # the index layer to make its finish() error if add_node is
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
384
        # subsequently used. RBC
2592.3.233 by Martin Pool
Review cleanups
385
        self._replace_index_with_readonly(index_type)
2592.3.195 by Robert Collins
Move some inventory index logic to NewPack.
386
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
387
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
388
class AggregateIndex(object):
389
    """An aggregated index for the RepositoryPackCollection.
390
391
    AggregateIndex is reponsible for managing the PackAccess object,
392
    Index-To-Pack mapping, and all indices list for a specific type of index
393
    such as 'revision index'.
2592.3.228 by Martin Pool
docstrings and error messages from review
394
395
    A CombinedIndex provides an index on a single key space built up
396
    from several on-disk indices.  The AggregateIndex builds on this 
397
    to provide a knit access layer, and allows having up to one writable
398
    index within the collection.
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
399
    """
2592.3.235 by Martin Pool
Review cleanups
400
    # XXX: Probably 'can be written to' could/should be separated from 'acts
401
    # like a knit index' -- mbp 20071024
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
402
403
    def __init__(self):
404
        """Create an AggregateIndex."""
405
        self.index_to_pack = {}
406
        self.combined_index = CombinedGraphIndex([])
407
        self.knit_access = _PackAccess(self.index_to_pack)
408
409
    def replace_indices(self, index_to_pack, indices):
410
        """Replace the current mappings with fresh ones.
411
412
        This should probably not be used eventually, rather incremental add and
413
        removal of indices. It has been added during refactoring of existing
414
        code.
415
416
        :param index_to_pack: A mapping from index objects to
417
            (transport, name) tuples for the pack file data.
418
        :param indices: A list of indices.
419
        """
420
        # refresh the revision pack map dict without replacing the instance.
421
        self.index_to_pack.clear()
422
        self.index_to_pack.update(index_to_pack)
423
        # XXX: API break - clearly a 'replace' method would be good?
424
        self.combined_index._indices[:] = indices
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
425
        # the current add nodes callback for the current writable index if
426
        # there is one.
427
        self.add_callback = None
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
428
429
    def add_index(self, index, pack):
430
        """Add index to the aggregate, which is an index for Pack pack.
2592.3.226 by Martin Pool
formatting and docstrings
431
432
        Future searches on the aggregate index will seach this new index
433
        before all previously inserted indices.
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
434
        
2592.3.226 by Martin Pool
formatting and docstrings
435
        :param index: An Index for the pack.
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
436
        :param pack: A Pack instance.
437
        """
438
        # expose it to the index map
439
        self.index_to_pack[index] = pack.access_tuple()
440
        # put it at the front of the linear index list
441
        self.combined_index.insert_index(0, index)
442
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
443
    def add_writable_index(self, index, pack):
444
        """Add an index which is able to have data added to it.
2592.3.235 by Martin Pool
Review cleanups
445
446
        There can be at most one writable index at any time.  Any
447
        modifications made to the knit are put into this index.
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
448
        
449
        :param index: An index from the pack parameter.
450
        :param pack: A Pack instance.
451
        """
2592.3.228 by Martin Pool
docstrings and error messages from review
452
        assert self.add_callback is None, \
453
            "%s already has a writable index through %s" % \
454
            (self, self.add_callback)
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
455
        # allow writing: queue writes to a new index
456
        self.add_index(index, pack)
457
        # Updates the index to packs mapping as a side effect,
458
        self.knit_access.set_writer(pack._writer, index, pack.access_tuple())
459
        self.add_callback = index.add_nodes
460
461
    def clear(self):
462
        """Reset all the aggregate data to nothing."""
463
        self.knit_access.set_writer(None, None, (None, None))
464
        self.index_to_pack.clear()
465
        del self.combined_index._indices[:]
466
        self.add_callback = None
467
468
    def remove_index(self, index, pack):
469
        """Remove index from the indices used to answer queries.
470
        
471
        :param index: An index from the pack parameter.
472
        :param pack: A Pack instance.
473
        """
474
        del self.index_to_pack[index]
475
        self.combined_index._indices.remove(index)
476
        if (self.add_callback is not None and
477
            getattr(index, 'add_nodes', None) == self.add_callback):
478
            self.add_callback = None
479
            self.knit_access.set_writer(None, None, (None, None))
480
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
481
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
482
class Packer(object):
483
    """Create a pack from packs."""
484
485
    def __init__(self, pack_collection, packs, suffix, revision_ids=None):
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
486
        """Create a Packer.
487
488
        :param pack_collection: A RepositoryPackCollection object where the
489
            new pack is being written to.
490
        :param packs: The packs to combine.
491
        :param suffix: The suffix to use on the temporary files for the pack.
492
        :param revision_ids: Revision ids to limit the pack to.
493
        """
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
494
        self.packs = packs
495
        self.suffix = suffix
496
        self.revision_ids = revision_ids
497
        self._pack_collection = pack_collection
498
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
499
    def pack(self, pb=None):
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
500
        """Create a new pack by reading data from other packs.
501
502
        This does little more than a bulk copy of data. One key difference
503
        is that data with the same item key across multiple packs is elided
504
        from the output. The new pack is written into the current pack store
505
        along with its indices, and the name added to the pack names. The 
2592.3.182 by Robert Collins
Eliminate the need to use a transport,name tuple to represent a pack during fetch.
506
        source packs are not altered and are not required to be in the current
507
        pack collection.
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
508
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
509
        :param pb: An optional progress bar to use. A nested bar is created if
510
            this is None.
2592.3.91 by Robert Collins
Incrementally closing in on a correct fetch for packs.
511
        :return: A Pack object, or None if nothing was copied.
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
512
        """
513
        # open a pack - using the same name as the last temporary file
514
        # - which has already been flushed, so its safe.
515
        # XXX: - duplicate code warning with start_write_group; fix before
516
        #      considering 'done'.
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
517
        if self._pack_collection._new_pack is not None:
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
518
            raise errors.BzrError('call to create_pack_from_packs while '
519
                'another pack is being written.')
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
520
        if self.revision_ids is not None:
521
            if len(self.revision_ids) == 0:
2947.1.3 by Robert Collins
Unbreak autopack. Doh.
522
                # silly fetch request.
523
                return None
524
            else:
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
525
                self.revision_ids = frozenset(self.revision_ids)
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
526
        if pb is None:
527
            self.pb = ui.ui_factory.nested_progress_bar()
528
        else:
529
            self.pb = pb
2947.1.4 by Robert Collins
* A progress bar has been added for knitpack -> knitpack fetching.
530
        try:
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
531
            return self._create_pack_from_packs()
2947.1.4 by Robert Collins
* A progress bar has been added for knitpack -> knitpack fetching.
532
        finally:
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
533
            if pb is None:
534
                self.pb.finished()
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
535
536
    def open_pack(self):
537
        """Open a pack for the pack we are creating."""
538
        return NewPack(self._pack_collection._upload_transport,
539
            self._pack_collection._index_transport,
3010.1.11 by Robert Collins
Provide file modes to files created by pack repositories
540
            self._pack_collection._pack_transport, upload_suffix=self.suffix,
541
            file_mode=self._pack_collection.repo.control_files._file_mode)
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
542
543
    def _create_pack_from_packs(self):
544
        self.pb.update("Opening pack", 0, 5)
545
        new_pack = self.open_pack()
2592.3.203 by Robert Collins
Teach NewPack how to buffer for pack operations.
546
        # buffer data - we won't be reading-back during the pack creation and
547
        # this makes a significant difference on sftp pushes.
548
        new_pack.set_write_cache_size(1024*1024)
2592.3.234 by Martin Pool
Use -Dpack not -Dfetch for pack traces
549
        if 'pack' in debug.debug_flags:
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
550
            plain_pack_list = ['%s%s' % (a_pack.pack_transport.base, a_pack.name)
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
551
                for a_pack in self.packs]
552
            if self.revision_ids is not None:
553
                rev_count = len(self.revision_ids)
2592.3.112 by Robert Collins
Various fixups found dogfooding.
554
            else:
555
                rev_count = 'all'
556
            mutter('%s: create_pack: creating pack from source packs: '
557
                '%s%s %s revisions wanted %s t=0',
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
558
                time.ctime(), self._pack_collection._upload_transport.base, new_pack.random_name,
2592.3.112 by Robert Collins
Various fixups found dogfooding.
559
                plain_pack_list, rev_count)
2592.3.93 by Robert Collins
Steps toward filtering revisions/inventories/texts during fetch.
560
        # select revisions
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
561
        if self.revision_ids:
562
            revision_keys = [(revision_id,) for revision_id in self.revision_ids]
2592.3.93 by Robert Collins
Steps toward filtering revisions/inventories/texts during fetch.
563
        else:
564
            revision_keys = None
2592.3.179 by Robert Collins
Generate the revision_index_map for packing during the core operation, from the pack objects.
565
566
        # select revision keys
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
567
        revision_index_map = self._pack_collection._packs_list_to_pack_map_and_index_list(
568
            self.packs, 'revision_index')[0]
569
        revision_nodes = self._pack_collection._index_contents(revision_index_map, revision_keys)
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
570
        # copy revision keys and adjust values
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
571
        self.pb.update("Copying revision texts", 1)
2592.3.205 by Robert Collins
Move the pack ContainerWriter instance into NewPack.
572
        list(self._copy_nodes_graph(revision_nodes, revision_index_map,
573
            new_pack._writer, new_pack.revision_index))
2592.3.234 by Martin Pool
Use -Dpack not -Dfetch for pack traces
574
        if 'pack' in debug.debug_flags:
2592.3.91 by Robert Collins
Incrementally closing in on a correct fetch for packs.
575
            mutter('%s: create_pack: revisions copied: %s%s %d items t+%6.3fs',
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
576
                time.ctime(), self._pack_collection._upload_transport.base, new_pack.random_name,
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
577
                new_pack.revision_index.key_count(),
578
                time.time() - new_pack.start_time)
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
579
        # select inventory keys
2592.3.145 by Robert Collins
Fix test_fetch_missing_text_other_location_fails for pack repositories.
580
        inv_keys = revision_keys # currently the same keyspace, and note that
581
        # querying for keys here could introduce a bug where an inventory item
582
        # is missed, so do not change it to query separately without cross
583
        # checking like the text key check below.
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
584
        inventory_index_map = self._pack_collection._packs_list_to_pack_map_and_index_list(
585
            self.packs, 'inventory_index')[0]
586
        inv_nodes = self._pack_collection._index_contents(inventory_index_map, inv_keys)
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
587
        # copy inventory keys and adjust values
2592.3.104 by Robert Collins
hackish fix, but all tests passing again.
588
        # XXX: Should be a helper function to allow different inv representation
589
        # at this point.
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
590
        self.pb.update("Copying inventory texts", 2)
2592.3.104 by Robert Collins
hackish fix, but all tests passing again.
591
        inv_lines = self._copy_nodes_graph(inv_nodes, inventory_index_map,
2592.3.205 by Robert Collins
Move the pack ContainerWriter instance into NewPack.
592
            new_pack._writer, new_pack.inventory_index, output_lines=True)
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
593
        if self.revision_ids:
594
            fileid_revisions = self._pack_collection.repo._find_file_ids_from_xml_inventory_lines(
595
                inv_lines, self.revision_ids)
2592.3.110 by Robert Collins
Filter out texts and signatures not referenced by the revisions being copied during pack to pack fetching.
596
            text_filter = []
597
            for fileid, file_revids in fileid_revisions.iteritems():
598
                text_filter.extend(
599
                    [(fileid, file_revid) for file_revid in file_revids])
600
        else:
2592.3.145 by Robert Collins
Fix test_fetch_missing_text_other_location_fails for pack repositories.
601
            # eat the iterator to cause it to execute.
2592.3.110 by Robert Collins
Filter out texts and signatures not referenced by the revisions being copied during pack to pack fetching.
602
            list(inv_lines)
603
            text_filter = None
2592.3.234 by Martin Pool
Use -Dpack not -Dfetch for pack traces
604
        if 'pack' in debug.debug_flags:
2592.3.91 by Robert Collins
Incrementally closing in on a correct fetch for packs.
605
            mutter('%s: create_pack: inventories copied: %s%s %d items t+%6.3fs',
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
606
                time.ctime(), self._pack_collection._upload_transport.base, new_pack.random_name,
2592.3.195 by Robert Collins
Move some inventory index logic to NewPack.
607
                new_pack.inventory_index.key_count(),
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
608
                time.time() - new_pack.start_time)
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
609
        # select text keys
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
610
        text_index_map = self._pack_collection._packs_list_to_pack_map_and_index_list(
611
            self.packs, 'text_index')[0]
612
        text_nodes = self._pack_collection._index_contents(text_index_map, text_filter)
2592.3.149 by Robert Collins
Unbreak pack to pack fetching properly, with missing-text detection really working.
613
        if text_filter is not None:
614
            # We could return the keys copied as part of the return value from
615
            # _copy_nodes_graph but this doesn't work all that well with the
616
            # need to get line output too, so we check separately, and as we're
617
            # going to buffer everything anyway, we check beforehand, which
618
            # saves reading knit data over the wire when we know there are
619
            # mising records.
620
            text_nodes = set(text_nodes)
621
            present_text_keys = set(_node[1] for _node in text_nodes)
622
            missing_text_keys = set(text_filter) - present_text_keys
623
            if missing_text_keys:
624
                # TODO: raise a specific error that can handle many missing
625
                # keys.
626
                a_missing_key = missing_text_keys.pop()
627
                raise errors.RevisionNotPresent(a_missing_key[1],
628
                    a_missing_key[0])
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
629
        # copy text keys and adjust values
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
630
        self.pb.update("Copying content texts", 3)
2592.3.205 by Robert Collins
Move the pack ContainerWriter instance into NewPack.
631
        list(self._copy_nodes_graph(text_nodes, text_index_map,
632
            new_pack._writer, new_pack.text_index))
2592.3.234 by Martin Pool
Use -Dpack not -Dfetch for pack traces
633
        if 'pack' in debug.debug_flags:
2592.3.91 by Robert Collins
Incrementally closing in on a correct fetch for packs.
634
            mutter('%s: create_pack: file texts copied: %s%s %d items t+%6.3fs',
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
635
                time.ctime(), self._pack_collection._upload_transport.base, new_pack.random_name,
2592.3.196 by Robert Collins
Move some text index logic to NewPack.
636
                new_pack.text_index.key_count(),
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
637
                time.time() - new_pack.start_time)
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
638
        # select signature keys
2592.3.110 by Robert Collins
Filter out texts and signatures not referenced by the revisions being copied during pack to pack fetching.
639
        signature_filter = revision_keys # same keyspace
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
640
        signature_index_map = self._pack_collection._packs_list_to_pack_map_and_index_list(
641
            self.packs, 'signature_index')[0]
642
        signature_nodes = self._pack_collection._index_contents(signature_index_map,
2592.3.110 by Robert Collins
Filter out texts and signatures not referenced by the revisions being copied during pack to pack fetching.
643
            signature_filter)
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
644
        # copy signature keys and adjust values
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
645
        self.pb.update("Copying signature texts", 4)
2592.3.205 by Robert Collins
Move the pack ContainerWriter instance into NewPack.
646
        self._copy_nodes(signature_nodes, signature_index_map, new_pack._writer,
647
            new_pack.signature_index)
2592.3.234 by Martin Pool
Use -Dpack not -Dfetch for pack traces
648
        if 'pack' in debug.debug_flags:
2592.3.91 by Robert Collins
Incrementally closing in on a correct fetch for packs.
649
            mutter('%s: create_pack: revision signatures copied: %s%s %d items t+%6.3fs',
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
650
                time.ctime(), self._pack_collection._upload_transport.base, new_pack.random_name,
2592.3.197 by Robert Collins
Hand over signature index creation to NewPack.
651
                new_pack.signature_index.key_count(),
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
652
                time.time() - new_pack.start_time)
2592.3.203 by Robert Collins
Teach NewPack how to buffer for pack operations.
653
        if not new_pack.data_inserted():
654
            new_pack.abort()
655
            return None
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
656
        self.pb.update("Finishing pack", 5)
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
657
        new_pack.finish()
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
658
        self._pack_collection.allocate(new_pack)
2592.3.206 by Robert Collins
Move pack rename-into-place into NewPack.finish and document hash-collision cases somewhat better.
659
        return new_pack
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
660
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
661
    def _copy_nodes(self, nodes, index_map, writer, write_index):
662
        """Copy knit nodes between packs with no graph references."""
663
        pb = ui.ui_factory.nested_progress_bar()
664
        try:
665
            return self._do_copy_nodes(nodes, index_map, writer,
666
                write_index, pb)
667
        finally:
668
            pb.finished()
669
670
    def _do_copy_nodes(self, nodes, index_map, writer, write_index, pb):
671
        # for record verification
672
        knit_data = _KnitData(None)
673
        # plan a readv on each source pack:
674
        # group by pack
675
        nodes = sorted(nodes)
676
        # how to map this into knit.py - or knit.py into this?
677
        # we don't want the typical knit logic, we want grouping by pack
678
        # at this point - perhaps a helper library for the following code 
679
        # duplication points?
680
        request_groups = {}
681
        for index, key, value in nodes:
682
            if index not in request_groups:
683
                request_groups[index] = []
684
            request_groups[index].append((key, value))
685
        record_index = 0
686
        pb.update("Copied record", record_index, len(nodes))
687
        for index, items in request_groups.iteritems():
688
            pack_readv_requests = []
689
            for key, value in items:
690
                # ---- KnitGraphIndex.get_position
691
                bits = value[1:].split(' ')
692
                offset, length = int(bits[0]), int(bits[1])
693
                pack_readv_requests.append((offset, length, (key, value[0])))
694
            # linear scan up the pack
695
            pack_readv_requests.sort()
696
            # copy the data
697
            transport, path = index_map[index]
698
            reader = pack.make_readv_reader(transport, path,
699
                [offset[0:2] for offset in pack_readv_requests])
700
            for (names, read_func), (_1, _2, (key, eol_flag)) in \
701
                izip(reader.iter_records(), pack_readv_requests):
702
                raw_data = read_func(None)
703
                # check the header only
704
                df, _ = knit_data._parse_record_header(key[-1], raw_data)
705
                df.close()
706
                pos, size = writer.add_bytes_record(raw_data, names)
707
                write_index.add_node(key, eol_flag + "%d %d" % (pos, size))
708
                pb.update("Copied record", record_index)
709
                record_index += 1
710
711
    def _copy_nodes_graph(self, nodes, index_map, writer, write_index,
712
        output_lines=False):
713
        """Copy knit nodes between packs.
714
715
        :param output_lines: Return lines present in the copied data as
2975.3.1 by Robert Collins
Change (without backwards compatibility) the
716
            an iterator of line,version_id.
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
717
        """
718
        pb = ui.ui_factory.nested_progress_bar()
719
        try:
720
            return self._do_copy_nodes_graph(nodes, index_map, writer,
721
                write_index, output_lines, pb)
722
        finally:
723
            pb.finished()
724
725
    def _do_copy_nodes_graph(self, nodes, index_map, writer, write_index,
726
        output_lines, pb):
727
        # for record verification
728
        knit_data = _KnitData(None)
729
        # for line extraction when requested (inventories only)
730
        if output_lines:
731
            factory = knit.KnitPlainFactory()
732
        # plan a readv on each source pack:
733
        # group by pack
734
        nodes = sorted(nodes)
735
        # how to map this into knit.py - or knit.py into this?
736
        # we don't want the typical knit logic, we want grouping by pack
737
        # at this point - perhaps a helper library for the following code 
738
        # duplication points?
739
        request_groups = {}
740
        record_index = 0
741
        pb.update("Copied record", record_index, len(nodes))
742
        for index, key, value, references in nodes:
743
            if index not in request_groups:
744
                request_groups[index] = []
745
            request_groups[index].append((key, value, references))
746
        for index, items in request_groups.iteritems():
747
            pack_readv_requests = []
748
            for key, value, references in items:
749
                # ---- KnitGraphIndex.get_position
750
                bits = value[1:].split(' ')
751
                offset, length = int(bits[0]), int(bits[1])
752
                pack_readv_requests.append((offset, length, (key, value[0], references)))
753
            # linear scan up the pack
754
            pack_readv_requests.sort()
755
            # copy the data
756
            transport, path = index_map[index]
757
            reader = pack.make_readv_reader(transport, path,
758
                [offset[0:2] for offset in pack_readv_requests])
759
            for (names, read_func), (_1, _2, (key, eol_flag, references)) in \
760
                izip(reader.iter_records(), pack_readv_requests):
761
                raw_data = read_func(None)
2975.3.2 by Robert Collins
Review feedback - document the API change and improve readability in pack's _do_copy_nodes.
762
                version_id = key[-1]
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
763
                if output_lines:
764
                    # read the entire thing
2975.3.2 by Robert Collins
Review feedback - document the API change and improve readability in pack's _do_copy_nodes.
765
                    content, _ = knit_data._parse_record(version_id, raw_data)
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
766
                    if len(references[-1]) == 0:
767
                        line_iterator = factory.get_fulltext_content(content)
768
                    else:
769
                        line_iterator = factory.get_linedelta_content(content)
770
                    for line in line_iterator:
2975.3.2 by Robert Collins
Review feedback - document the API change and improve readability in pack's _do_copy_nodes.
771
                        yield line, version_id
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
772
                else:
773
                    # check the header only
2975.3.2 by Robert Collins
Review feedback - document the API change and improve readability in pack's _do_copy_nodes.
774
                    df, _ = knit_data._parse_record_header(version_id, raw_data)
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
775
                    df.close()
776
                pos, size = writer.add_bytes_record(raw_data, names)
777
                write_index.add_node(key, eol_flag + "%d %d" % (pos, size), references)
778
                pb.update("Copied record", record_index)
779
                record_index += 1
780
781
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
782
class ReconcilePacker(Packer):
783
    """A packer which regenerates indices etc as it copies.
784
    
785
    This is used by ``bzr reconcile`` to cause parent text pointers to be
786
    regenerated.
787
    """
788
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
789
790
class RepositoryPackCollection(object):
791
    """Management of packs within a repository."""
792
793
    def __init__(self, repo, transport, index_transport, upload_transport,
794
                 pack_transport):
795
        """Create a new RepositoryPackCollection.
796
797
        :param transport: Addresses the repository base directory 
798
            (typically .bzr/repository/).
799
        :param index_transport: Addresses the directory containing indices.
800
        :param upload_transport: Addresses the directory into which packs are written
801
            while they're being created.
802
        :param pack_transport: Addresses the directory of existing complete packs.
803
        """
804
        self.repo = repo
805
        self.transport = transport
806
        self._index_transport = index_transport
807
        self._upload_transport = upload_transport
808
        self._pack_transport = pack_transport
809
        self._suffix_offsets = {'.rix': 0, '.iix': 1, '.tix': 2, '.six': 3}
810
        self.packs = []
811
        # name:Pack mapping
812
        self._packs_by_name = {}
813
        # the previous pack-names content
814
        self._packs_at_load = None
815
        # when a pack is being created by this object, the state of that pack.
816
        self._new_pack = None
817
        # aggregated revision index data
818
        self.revision_index = AggregateIndex()
819
        self.inventory_index = AggregateIndex()
820
        self.text_index = AggregateIndex()
821
        self.signature_index = AggregateIndex()
822
823
    def add_pack_to_memory(self, pack):
824
        """Make a Pack object available to the repository to satisfy queries.
825
        
826
        :param pack: A Pack object.
827
        """
828
        assert pack.name not in self._packs_by_name
829
        self.packs.append(pack)
830
        self._packs_by_name[pack.name] = pack
831
        self.revision_index.add_index(pack.revision_index, pack)
832
        self.inventory_index.add_index(pack.inventory_index, pack)
833
        self.text_index.add_index(pack.text_index, pack)
834
        self.signature_index.add_index(pack.signature_index, pack)
835
        
836
    def _add_text_to_weave(self, file_id, revision_id, new_lines, parents,
837
        nostore_sha, random_revid):
838
        file_id_index = GraphIndexPrefixAdapter(
839
            self.text_index.combined_index,
840
            (file_id, ), 1,
841
            add_nodes_callback=self.text_index.add_callback)
842
        self.repo._text_knit._index._graph_index = file_id_index
843
        self.repo._text_knit._index._add_callback = file_id_index.add_nodes
844
        return self.repo._text_knit.add_lines_with_ghosts(
845
            revision_id, parents, new_lines, nostore_sha=nostore_sha,
846
            random_id=random_revid, check_content=False)[0:2]
847
848
    def all_packs(self):
849
        """Return a list of all the Pack objects this repository has.
850
851
        Note that an in-progress pack being created is not returned.
852
853
        :return: A list of Pack objects for all the packs in the repository.
854
        """
855
        result = []
856
        for name in self.names():
857
            result.append(self.get_pack_by_name(name))
858
        return result
859
860
    def autopack(self):
861
        """Pack the pack collection incrementally.
862
        
863
        This will not attempt global reorganisation or recompression,
864
        rather it will just ensure that the total number of packs does
865
        not grow without bound. It uses the _max_pack_count method to
866
        determine if autopacking is needed, and the pack_distribution
867
        method to determine the number of revisions in each pack.
868
869
        If autopacking takes place then the packs name collection will have
870
        been flushed to disk - packing requires updating the name collection
871
        in synchronisation with certain steps. Otherwise the names collection
872
        is not flushed.
873
874
        :return: True if packing took place.
875
        """
876
        # XXX: Should not be needed when the management of indices is sane.
877
        total_revisions = self.revision_index.combined_index.key_count()
878
        total_packs = len(self._names)
879
        if self._max_pack_count(total_revisions) >= total_packs:
880
            return False
881
        # XXX: the following may want to be a class, to pack with a given
882
        # policy.
883
        mutter('Auto-packing repository %s, which has %d pack files, '
884
            'containing %d revisions into %d packs.', self, total_packs,
885
            total_revisions, self._max_pack_count(total_revisions))
886
        # determine which packs need changing
887
        pack_distribution = self.pack_distribution(total_revisions)
888
        existing_packs = []
889
        for pack in self.all_packs():
890
            revision_count = pack.get_revision_count()
891
            if revision_count == 0:
892
                # revision less packs are not generated by normal operation,
893
                # only by operations like sign-my-commits, and thus will not
894
                # tend to grow rapdily or without bound like commit containing
895
                # packs do - leave them alone as packing them really should
896
                # group their data with the relevant commit, and that may
897
                # involve rewriting ancient history - which autopack tries to
898
                # avoid. Alternatively we could not group the data but treat
899
                # each of these as having a single revision, and thus add 
900
                # one revision for each to the total revision count, to get
901
                # a matching distribution.
902
                continue
903
            existing_packs.append((revision_count, pack))
904
        pack_operations = self.plan_autopack_combinations(
905
            existing_packs, pack_distribution)
906
        self._execute_pack_operations(pack_operations)
907
        return True
908
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
909
    def _execute_pack_operations(self, pack_operations):
910
        """Execute a series of pack operations.
911
912
        :param pack_operations: A list of [revision_count, packs_to_combine].
913
        :return: None.
914
        """
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
915
        for revision_count, packs in pack_operations:
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
916
            # we may have no-ops from the setup logic
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
917
            if len(packs) == 0:
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
918
                continue
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
919
            Packer(self, packs, '.autopack').pack()
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
920
            for pack in packs:
2592.3.236 by Martin Pool
Make RepositoryPackCollection.remove_pack_from_memory private
921
                self._remove_pack_from_memory(pack)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
922
        # record the newly available packs and stop advertising the old
923
        # packs
2948.1.1 by Robert Collins
* Obsolete packs are now cleaned up by pack and autopack operations.
924
        self._save_pack_names(clear_obsolete_packs=True)
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
925
        # Move the old packs out of the way now they are no longer referenced.
926
        for revision_count, packs in pack_operations:
927
            self._obsolete_packs(packs)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
928
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
929
    def lock_names(self):
930
        """Acquire the mutex around the pack-names index.
931
        
932
        This cannot be used in the middle of a read-only transaction on the
933
        repository.
934
        """
935
        self.repo.control_files.lock_write()
936
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
937
    def pack(self):
938
        """Pack the pack collection totally."""
939
        self.ensure_loaded()
2592.3.213 by Robert Collins
Retain packs and indices in memory within a lock, even when write groups are entered and exited.
940
        total_packs = len(self._names)
941
        if total_packs < 2:
942
            return
943
        total_revisions = self.revision_index.combined_index.key_count()
944
        # XXX: the following may want to be a class, to pack with a given
945
        # policy.
946
        mutter('Packing repository %s, which has %d pack files, '
947
            'containing %d revisions into 1 packs.', self, total_packs,
948
            total_revisions)
949
        # determine which packs need changing
950
        pack_distribution = [1]
951
        pack_operations = [[0, []]]
952
        for pack in self.all_packs():
953
            revision_count = pack.get_revision_count()
954
            pack_operations[-1][0] += revision_count
955
            pack_operations[-1][1].append(pack)
956
        self._execute_pack_operations(pack_operations)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
957
958
    def plan_autopack_combinations(self, existing_packs, pack_distribution):
2592.3.176 by Robert Collins
Various pack refactorings.
959
        """Plan a pack operation.
960
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
961
        :param existing_packs: The packs to pack. (A list of (revcount, Pack)
962
            tuples).
2592.3.235 by Martin Pool
Review cleanups
963
        :param pack_distribution: A list with the number of revisions desired
2592.3.176 by Robert Collins
Various pack refactorings.
964
            in each pack.
965
        """
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
966
        if len(existing_packs) <= len(pack_distribution):
967
            return []
968
        existing_packs.sort(reverse=True)
969
        pack_operations = [[0, []]]
970
        # plan out what packs to keep, and what to reorganise
971
        while len(existing_packs):
972
            # take the largest pack, and if its less than the head of the
973
            # distribution chart we will include its contents in the new pack for
974
            # that position. If its larger, we remove its size from the
975
            # distribution chart
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
976
            next_pack_rev_count, next_pack = existing_packs.pop(0)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
977
            if next_pack_rev_count >= pack_distribution[0]:
978
                # this is already packed 'better' than this, so we can
979
                # not waste time packing it.
980
                while next_pack_rev_count > 0:
981
                    next_pack_rev_count -= pack_distribution[0]
982
                    if next_pack_rev_count >= 0:
983
                        # more to go
984
                        del pack_distribution[0]
985
                    else:
986
                        # didn't use that entire bucket up
987
                        pack_distribution[0] = -next_pack_rev_count
988
            else:
989
                # add the revisions we're going to add to the next output pack
990
                pack_operations[-1][0] += next_pack_rev_count
991
                # allocate this pack to the next pack sub operation
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
992
                pack_operations[-1][1].append(next_pack)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
993
                if pack_operations[-1][0] >= pack_distribution[0]:
994
                    # this pack is used up, shift left.
995
                    del pack_distribution[0]
996
                    pack_operations.append([0, []])
997
        
998
        return pack_operations
999
1000
    def ensure_loaded(self):
2592.3.214 by Robert Collins
Merge bzr.dev.
1001
        # NB: if you see an assertion error here, its probably access against
1002
        # an unlocked repo. Naughty.
1003
        assert self.repo.is_locked()
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1004
        if self._names is None:
2592.3.118 by Robert Collins
Record the size of the index files in the pack-names index.
1005
            self._names = {}
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1006
            self._packs_at_load = set()
1007
            for index, key, value in self._iter_disk_pack_index():
2592.3.118 by Robert Collins
Record the size of the index files in the pack-names index.
1008
                name = key[0]
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1009
                self._names[name] = self._parse_index_sizes(value)
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1010
                self._packs_at_load.add((key, value))
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1011
        # populate all the metadata.
1012
        self.all_packs()
1013
1014
    def _parse_index_sizes(self, value):
1015
        """Parse a string of index sizes."""
1016
        return tuple([int(digits) for digits in value.split(' ')])
2592.3.118 by Robert Collins
Record the size of the index files in the pack-names index.
1017
2592.3.176 by Robert Collins
Various pack refactorings.
1018
    def get_pack_by_name(self, name):
1019
        """Get a Pack object by name.
1020
1021
        :param name: The name of the pack - e.g. '123456'
1022
        :return: A Pack object.
1023
        """
1024
        try:
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1025
            return self._packs_by_name[name]
2592.3.176 by Robert Collins
Various pack refactorings.
1026
        except KeyError:
1027
            rev_index = self._make_index(name, '.rix')
1028
            inv_index = self._make_index(name, '.iix')
1029
            txt_index = self._make_index(name, '.tix')
1030
            sig_index = self._make_index(name, '.six')
2592.3.191 by Robert Collins
Give Pack responsibility for index naming, and two concrete classes - NewPack for new packs and ExistingPack for packs we read from disk.
1031
            result = ExistingPack(self._pack_transport, name, rev_index,
1032
                inv_index, txt_index, sig_index)
2592.3.178 by Robert Collins
Add pack objects to the api for PackCollection.create_pack_from_packs.
1033
            self.add_pack_to_memory(result)
2592.3.176 by Robert Collins
Various pack refactorings.
1034
            return result
1035
2592.3.201 by Robert Collins
Cleanup RepositoryPackCollection.allocate.
1036
    def allocate(self, a_new_pack):
2592.3.118 by Robert Collins
Record the size of the index files in the pack-names index.
1037
        """Allocate name in the list of packs.
1038
2592.3.201 by Robert Collins
Cleanup RepositoryPackCollection.allocate.
1039
        :param a_new_pack: A NewPack instance to be added to the collection of
1040
            packs for this repository.
2592.3.118 by Robert Collins
Record the size of the index files in the pack-names index.
1041
        """
2592.3.91 by Robert Collins
Incrementally closing in on a correct fetch for packs.
1042
        self.ensure_loaded()
2592.3.201 by Robert Collins
Cleanup RepositoryPackCollection.allocate.
1043
        if a_new_pack.name in self._names:
2592.3.206 by Robert Collins
Move pack rename-into-place into NewPack.finish and document hash-collision cases somewhat better.
1044
            # a collision with the packs we know about (not the only possible
1045
            # collision, see NewPack.finish() for some discussion). Remove our
1046
            # prior reference to it.
2592.3.236 by Martin Pool
Make RepositoryPackCollection.remove_pack_from_memory private
1047
            self._remove_pack_from_memory(a_new_pack)
2592.3.201 by Robert Collins
Cleanup RepositoryPackCollection.allocate.
1048
        self._names[a_new_pack.name] = tuple(a_new_pack.index_sizes)
1049
        self.add_pack_to_memory(a_new_pack)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1050
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1051
    def _iter_disk_pack_index(self):
1052
        """Iterate over the contents of the pack-names index.
1053
        
1054
        This is used when loading the list from disk, and before writing to
1055
        detect updates from others during our write operation.
1056
        :return: An iterator of the index contents.
1057
        """
1058
        return GraphIndex(self.transport, 'pack-names', None
1059
                ).iter_all_entries()
1060
2592.3.176 by Robert Collins
Various pack refactorings.
1061
    def _make_index(self, name, suffix):
1062
        size_offset = self._suffix_offsets[suffix]
1063
        index_name = name + suffix
1064
        index_size = self._names[name][size_offset]
1065
        return GraphIndex(
1066
            self._index_transport, index_name, index_size)
2592.5.5 by Martin Pool
Make RepositoryPackCollection remember the index transport, and responsible for getting a map of indexes
1067
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1068
    def _max_pack_count(self, total_revisions):
1069
        """Return the maximum number of packs to use for total revisions.
1070
        
1071
        :param total_revisions: The total number of revisions in the
1072
            repository.
1073
        """
1074
        if not total_revisions:
1075
            return 1
1076
        digits = str(total_revisions)
1077
        result = 0
1078
        for digit in digits:
1079
            result += int(digit)
1080
        return result
1081
1082
    def names(self):
1083
        """Provide an order to the underlying names."""
2592.3.118 by Robert Collins
Record the size of the index files in the pack-names index.
1084
        return sorted(self._names.keys())
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1085
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
1086
    def _obsolete_packs(self, packs):
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1087
        """Move a number of packs which have been obsoleted out of the way.
1088
1089
        Each pack and its associated indices are moved out of the way.
1090
1091
        Note: for correctness this function should only be called after a new
1092
        pack names index has been written without these pack names, and with
1093
        the names of packs that contain the data previously available via these
1094
        packs.
1095
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
1096
        :param packs: The packs to obsolete.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1097
        :param return: None.
1098
        """
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
1099
        for pack in packs:
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
1100
            pack.pack_transport.rename(pack.file_name(),
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
1101
                '../obsolete_packs/' + pack.file_name())
2592.3.226 by Martin Pool
formatting and docstrings
1102
            # TODO: Probably needs to know all possible indices for this pack
1103
            # - or maybe list the directory and move all indices matching this
2592.5.13 by Martin Pool
Clean up duplicate index_transport variables
1104
            # name whether we recognize it or not?
2592.3.187 by Robert Collins
Finish cleaning up the packing logic to take Pack objects - all tests pass.
1105
            for suffix in ('.iix', '.six', '.tix', '.rix'):
1106
                self._index_transport.rename(pack.name + suffix,
1107
                    '../obsolete_packs/' + pack.name + suffix)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1108
1109
    def pack_distribution(self, total_revisions):
1110
        """Generate a list of the number of revisions to put in each pack.
1111
1112
        :param total_revisions: The total number of revisions in the
1113
            repository.
1114
        """
1115
        if total_revisions == 0:
1116
            return [0]
1117
        digits = reversed(str(total_revisions))
1118
        result = []
1119
        for exponent, count in enumerate(digits):
1120
            size = 10 ** exponent
1121
            for pos in range(int(count)):
1122
                result.append(size)
1123
        return list(reversed(result))
1124
2592.5.12 by Martin Pool
Move pack_transport and pack_name onto RepositoryPackCollection
1125
    def _pack_tuple(self, name):
1126
        """Return a tuple with the transport and file name for a pack name."""
1127
        return self._pack_transport, name + '.pack'
1128
2592.3.236 by Martin Pool
Make RepositoryPackCollection.remove_pack_from_memory private
1129
    def _remove_pack_from_memory(self, pack):
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1130
        """Remove pack from the packs accessed by this repository.
1131
        
1132
        Only affects memory state, until self._save_pack_names() is invoked.
1133
        """
1134
        self._names.pop(pack.name)
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1135
        self._packs_by_name.pop(pack.name)
2592.3.213 by Robert Collins
Retain packs and indices in memory within a lock, even when write groups are entered and exited.
1136
        self._remove_pack_indices(pack)
1137
1138
    def _remove_pack_indices(self, pack):
1139
        """Remove the indices for pack from the aggregated indices."""
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1140
        self.revision_index.remove_index(pack.revision_index, pack)
2592.3.211 by Robert Collins
Pack inventory index management cleaned up.
1141
        self.inventory_index.remove_index(pack.inventory_index, pack)
2592.3.212 by Robert Collins
Cleanup text index management in packs.
1142
        self.text_index.remove_index(pack.text_index, pack)
2592.3.210 by Robert Collins
Signature index management looking sane for packs.
1143
        self.signature_index.remove_index(pack.signature_index, pack)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1144
1145
    def reset(self):
2592.3.190 by Robert Collins
Move flush and reset operations to the pack collection rather than the thunk layers.
1146
        """Clear all cached data."""
1147
        # cached revision data
1148
        self.repo._revision_knit = None
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1149
        self.revision_index.clear()
2592.3.190 by Robert Collins
Move flush and reset operations to the pack collection rather than the thunk layers.
1150
        # cached signature data
1151
        self.repo._signature_knit = None
2592.3.210 by Robert Collins
Signature index management looking sane for packs.
1152
        self.signature_index.clear()
2592.3.212 by Robert Collins
Cleanup text index management in packs.
1153
        # cached file text data
1154
        self.text_index.clear()
2592.3.190 by Robert Collins
Move flush and reset operations to the pack collection rather than the thunk layers.
1155
        self.repo._text_knit = None
2592.3.211 by Robert Collins
Pack inventory index management cleaned up.
1156
        # cached inventory data
1157
        self.inventory_index.clear()
2592.3.192 by Robert Collins
Move new revision index management to NewPack.
1158
        # remove the open pack
1159
        self._new_pack = None
2592.3.190 by Robert Collins
Move flush and reset operations to the pack collection rather than the thunk layers.
1160
        # information about packs.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1161
        self._names = None
2592.3.90 by Robert Collins
Slightly broken, but branch and fetch performance is now roughly on par (for bzr.dev) with knits - should be much faster for large repos.
1162
        self.packs = []
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1163
        self._packs_by_name = {}
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1164
        self._packs_at_load = None
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1165
2592.3.207 by Robert Collins
Start removing the dependency on RepositoryPackCollection._make_index_map.
1166
    def _make_index_map(self, index_suffix):
2592.3.226 by Martin Pool
formatting and docstrings
1167
        """Return information on existing indices.
2592.3.207 by Robert Collins
Start removing the dependency on RepositoryPackCollection._make_index_map.
1168
1169
        :param suffix: Index suffix added to pack name.
1170
1171
        :returns: (pack_map, indices) where indices is a list of GraphIndex 
1172
        objects, and pack_map is a mapping from those objects to the 
1173
        pack tuple they describe.
1174
        """
1175
        # TODO: stop using this; it creates new indices unnecessarily.
2592.3.176 by Robert Collins
Various pack refactorings.
1176
        self.ensure_loaded()
2592.3.226 by Martin Pool
formatting and docstrings
1177
        suffix_map = {'.rix': 'revision_index',
1178
            '.six': 'signature_index',
1179
            '.iix': 'inventory_index',
1180
            '.tix': 'text_index',
2592.3.207 by Robert Collins
Start removing the dependency on RepositoryPackCollection._make_index_map.
1181
        }
1182
        return self._packs_list_to_pack_map_and_index_list(self.all_packs(),
1183
            suffix_map[index_suffix])
2592.5.15 by Martin Pool
Split out common code for making index maps
1184
2592.3.179 by Robert Collins
Generate the revision_index_map for packing during the core operation, from the pack objects.
1185
    def _packs_list_to_pack_map_and_index_list(self, packs, index_attribute):
1186
        """Convert a list of packs to an index pack map and index list.
1187
1188
        :param packs: The packs list to process.
1189
        :param index_attribute: The attribute that the desired index is found
1190
            on.
1191
        :return: A tuple (map, list) where map contains the dict from
1192
            index:pack_tuple, and lsit contains the indices in the same order
1193
            as the packs list.
1194
        """
1195
        indices = []
1196
        pack_map = {}
1197
        for pack in packs:
1198
            index = getattr(pack, index_attribute)
1199
            indices.append(index)
2592.3.200 by Robert Collins
Make NewPack reopen the index files, separating out the task of refreshing the index maps in the repository and managing the completion of writing a single pack to disk.
1200
            pack_map[index] = (pack.pack_transport, pack.file_name())
2592.3.179 by Robert Collins
Generate the revision_index_map for packing during the core operation, from the pack objects.
1201
        return pack_map, indices
1202
2592.3.93 by Robert Collins
Steps toward filtering revisions/inventories/texts during fetch.
1203
    def _index_contents(self, pack_map, key_filter=None):
1204
        """Get an iterable of the index contents from a pack_map.
1205
1206
        :param pack_map: A map from indices to pack details.
1207
        :param key_filter: An optional filter to limit the
1208
            keys returned.
1209
        """
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1210
        indices = [index for index in pack_map.iterkeys()]
1211
        all_index = CombinedGraphIndex(indices)
2592.3.93 by Robert Collins
Steps toward filtering revisions/inventories/texts during fetch.
1212
        if key_filter is None:
1213
            return all_index.iter_all_entries()
1214
        else:
1215
            return all_index.iter_entries(key_filter)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1216
2592.3.237 by Martin Pool
Rename RepositoryPackCollection.release_names to _unlock_names
1217
    def _unlock_names(self):
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1218
        """Release the mutex around the pack-names index."""
1219
        self.repo.control_files.unlock()
1220
2948.1.1 by Robert Collins
* Obsolete packs are now cleaned up by pack and autopack operations.
1221
    def _save_pack_names(self, clear_obsolete_packs=False):
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1222
        """Save the list of packs.
1223
1224
        This will take out the mutex around the pack names list for the
1225
        duration of the method call. If concurrent updates have been made, a
1226
        three-way merge between the current list and the current in memory list
1227
        is performed.
2948.1.1 by Robert Collins
* Obsolete packs are now cleaned up by pack and autopack operations.
1228
1229
        :param clear_obsolete_packs: If True, clear out the contents of the
1230
            obsolete_packs directory.
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1231
        """
1232
        self.lock_names()
1233
        try:
1234
            builder = GraphIndexBuilder()
1235
            # load the disk nodes across
1236
            disk_nodes = set()
1237
            for index, key, value in self._iter_disk_pack_index():
1238
                disk_nodes.add((key, value))
1239
            # do a two-way diff against our original content
1240
            current_nodes = set()
1241
            for name, sizes in self._names.iteritems():
1242
                current_nodes.add(
1243
                    ((name, ), ' '.join(str(size) for size in sizes)))
1244
            deleted_nodes = self._packs_at_load - current_nodes
1245
            new_nodes = current_nodes - self._packs_at_load
1246
            disk_nodes.difference_update(deleted_nodes)
1247
            disk_nodes.update(new_nodes)
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1248
            # TODO: handle same-name, index-size-changes here - 
1249
            # e.g. use the value from disk, not ours, *unless* we're the one
1250
            # changing it.
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1251
            for key, value in disk_nodes:
1252
                builder.add_node(key, value)
3010.1.11 by Robert Collins
Provide file modes to files created by pack repositories
1253
            self.transport.put_file('pack-names', builder.finish(),
1254
                mode=self.repo.control_files._file_mode)
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1255
            # move the baseline forward
1256
            self._packs_at_load = disk_nodes
2948.1.1 by Robert Collins
* Obsolete packs are now cleaned up by pack and autopack operations.
1257
            # now clear out the obsolete packs directory
1258
            if clear_obsolete_packs:
1259
                self.transport.clone('obsolete_packs').delete_multi(
1260
                    self.transport.list_dir('obsolete_packs'))
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1261
        finally:
2592.3.237 by Martin Pool
Rename RepositoryPackCollection.release_names to _unlock_names
1262
            self._unlock_names()
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1263
        # synchronise the memory packs list with what we just wrote:
1264
        new_names = dict(disk_nodes)
1265
        # drop no longer present nodes
1266
        for pack in self.all_packs():
1267
            if (pack.name,) not in new_names:
2592.3.236 by Martin Pool
Make RepositoryPackCollection.remove_pack_from_memory private
1268
                self._remove_pack_from_memory(pack)
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1269
        # add new nodes/refresh existing ones
1270
        for key, value in disk_nodes:
1271
            name = key[0]
1272
            sizes = self._parse_index_sizes(value)
1273
            if name in self._names:
1274
                # existing
1275
                if sizes != self._names[name]:
1276
                    # the pack for name has had its indices replaced - rare but
1277
                    # important to handle. XXX: probably can never happen today
1278
                    # because the three-way merge code above does not handle it
1279
                    # - you may end up adding the same key twice to the new
1280
                    # disk index because the set values are the same, unless
1281
                    # the only index shows up as deleted by the set difference
1282
                    # - which it may. Until there is a specific test for this,
1283
                    # assume its broken. RBC 20071017.
2592.3.236 by Martin Pool
Make RepositoryPackCollection.remove_pack_from_memory private
1284
                    self._remove_pack_from_memory(self.get_pack_by_name(name))
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1285
                    self._names[name] = sizes
1286
                    self.get_pack_by_name(name)
1287
            else:
1288
                # new
1289
                self._names[name] = sizes
1290
                self.get_pack_by_name(name)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1291
2592.3.202 by Robert Collins
Move write stream management into NewPack.
1292
    def _start_write_group(self):
2592.3.190 by Robert Collins
Move flush and reset operations to the pack collection rather than the thunk layers.
1293
        # Do not permit preparation for writing if we're not in a 'write lock'.
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1294
        if not self.repo.is_write_locked():
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1295
            raise errors.NotWriteLocked(self)
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
1296
        self._new_pack = NewPack(self._upload_transport, self._index_transport,
3010.1.11 by Robert Collins
Provide file modes to files created by pack repositories
1297
            self._pack_transport, upload_suffix='.pack',
1298
            file_mode=self.repo.control_files._file_mode)
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1299
        # allow writing: queue writes to a new index
1300
        self.revision_index.add_writable_index(self._new_pack.revision_index,
1301
            self._new_pack)
2592.3.211 by Robert Collins
Pack inventory index management cleaned up.
1302
        self.inventory_index.add_writable_index(self._new_pack.inventory_index,
1303
            self._new_pack)
2592.3.212 by Robert Collins
Cleanup text index management in packs.
1304
        self.text_index.add_writable_index(self._new_pack.text_index,
1305
            self._new_pack)
2592.3.210 by Robert Collins
Signature index management looking sane for packs.
1306
        self.signature_index.add_writable_index(self._new_pack.signature_index,
1307
            self._new_pack)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1308
2592.3.213 by Robert Collins
Retain packs and indices in memory within a lock, even when write groups are entered and exited.
1309
        # reused revision and signature knits may need updating
2592.3.238 by Martin Pool
Pack doc updates
1310
        #
1311
        # "Hysterical raisins. client code in bzrlib grabs those knits outside
1312
        # of write groups and then mutates it inside the write group."
2592.3.213 by Robert Collins
Retain packs and indices in memory within a lock, even when write groups are entered and exited.
1313
        if self.repo._revision_knit is not None:
1314
            self.repo._revision_knit._index._add_callback = \
1315
                self.revision_index.add_callback
1316
        if self.repo._signature_knit is not None:
1317
            self.repo._signature_knit._index._add_callback = \
1318
                self.signature_index.add_callback
1319
        # create a reused knit object for text addition in commit.
1320
        self.repo._text_knit = self.repo.weave_store.get_weave_or_empty(
1321
            'all-texts', None)
2592.5.9 by Martin Pool
Move some more bits that seem to belong in RepositoryPackCollection into there
1322
2592.5.8 by Martin Pool
Delegate abort_write_group to RepositoryPackCollection
1323
    def _abort_write_group(self):
1324
        # FIXME: just drop the transient index.
1325
        # forget what names there are
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1326
        self._new_pack.abort()
2592.3.213 by Robert Collins
Retain packs and indices in memory within a lock, even when write groups are entered and exited.
1327
        self._remove_pack_indices(self._new_pack)
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1328
        self._new_pack = None
2592.3.213 by Robert Collins
Retain packs and indices in memory within a lock, even when write groups are entered and exited.
1329
        self.repo._text_knit = None
2592.5.6 by Martin Pool
Move pack repository start_write_group to pack collection object
1330
2592.5.7 by Martin Pool
move commit_write_group to RepositoryPackCollection
1331
    def _commit_write_group(self):
2592.3.213 by Robert Collins
Retain packs and indices in memory within a lock, even when write groups are entered and exited.
1332
        self._remove_pack_indices(self._new_pack)
2592.3.198 by Robert Collins
Factor out data_inserted to reduce code duplication in detecting empty packs.
1333
        if self._new_pack.data_inserted():
2592.3.209 by Robert Collins
Revision index management looking sane for packs.
1334
            # get all the data to disk and read to use
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
1335
            self._new_pack.finish()
2592.3.201 by Robert Collins
Cleanup RepositoryPackCollection.allocate.
1336
            self.allocate(self._new_pack)
2592.3.194 by Robert Collins
Output the revision index from NewPack.finish
1337
            self._new_pack = None
2592.5.7 by Martin Pool
move commit_write_group to RepositoryPackCollection
1338
            if not self.autopack():
2592.3.201 by Robert Collins
Cleanup RepositoryPackCollection.allocate.
1339
                # when autopack takes no steps, the names list is still
1340
                # unsaved.
2592.5.10 by Martin Pool
Rename RepositoryPackCollection.save to _save_pack_names
1341
                self._save_pack_names()
2592.5.7 by Martin Pool
move commit_write_group to RepositoryPackCollection
1342
        else:
2592.3.202 by Robert Collins
Move write stream management into NewPack.
1343
            self._new_pack.abort()
2951.1.1 by Robert Collins
(robertc) Fix data-refresh logic for packs not to refresh mid-transaction when a names write lock is held. (Robert Collins)
1344
            self._new_pack = None
2592.3.213 by Robert Collins
Retain packs and indices in memory within a lock, even when write groups are entered and exited.
1345
        self.repo._text_knit = None
2592.5.8 by Martin Pool
Delegate abort_write_group to RepositoryPackCollection
1346
1347
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1348
class KnitPackRevisionStore(KnitRevisionStore):
1349
    """An object to adapt access from RevisionStore's to use KnitPacks.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1350
1351
    This class works by replacing the original RevisionStore.
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1352
    We need to do this because the KnitPackRevisionStore is less
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1353
    isolated in its layering - it uses services from the repo.
1354
    """
1355
1356
    def __init__(self, repo, transport, revisionstore):
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1357
        """Create a KnitPackRevisionStore on repo with revisionstore.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1358
1359
        This will store its state in the Repository, use the
2592.3.238 by Martin Pool
Pack doc updates
1360
        indices to provide a KnitGraphIndex,
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1361
        and at the end of transactions write new indices.
1362
        """
1363
        KnitRevisionStore.__init__(self, revisionstore.versioned_file_store)
1364
        self.repo = repo
1365
        self._serializer = revisionstore._serializer
1366
        self.transport = transport
1367
1368
    def get_revision_file(self, transaction):
1369
        """Get the revision versioned file object."""
1370
        if getattr(self.repo, '_revision_knit', None) is not None:
1371
            return self.repo._revision_knit
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1372
        self.repo._pack_collection.ensure_loaded()
1373
        add_callback = self.repo._pack_collection.revision_index.add_callback
2592.3.208 by Robert Collins
Start refactoring the knit-pack thunking to be clearer.
1374
        # setup knit specific objects
1375
        knit_index = KnitGraphIndex(
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1376
            self.repo._pack_collection.revision_index.combined_index,
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1377
            add_callback=add_callback)
1378
        self.repo._revision_knit = knit.KnitVersionedFile(
1379
            'revisions', self.transport.clone('..'),
1380
            self.repo.control_files._file_mode,
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1381
            create=False, access_mode=self.repo._access_mode(),
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1382
            index=knit_index, delta=False, factory=knit.KnitPlainFactory(),
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1383
            access_method=self.repo._pack_collection.revision_index.knit_access)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1384
        return self.repo._revision_knit
1385
1386
    def get_signature_file(self, transaction):
1387
        """Get the signature versioned file object."""
1388
        if getattr(self.repo, '_signature_knit', None) is not None:
1389
            return self.repo._signature_knit
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1390
        self.repo._pack_collection.ensure_loaded()
1391
        add_callback = self.repo._pack_collection.signature_index.add_callback
2592.3.210 by Robert Collins
Signature index management looking sane for packs.
1392
        # setup knit specific objects
1393
        knit_index = KnitGraphIndex(
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1394
            self.repo._pack_collection.signature_index.combined_index,
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1395
            add_callback=add_callback, parents=False)
1396
        self.repo._signature_knit = knit.KnitVersionedFile(
1397
            'signatures', self.transport.clone('..'),
1398
            self.repo.control_files._file_mode,
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1399
            create=False, access_mode=self.repo._access_mode(),
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1400
            index=knit_index, delta=False, factory=knit.KnitPlainFactory(),
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1401
            access_method=self.repo._pack_collection.signature_index.knit_access)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1402
        return self.repo._signature_knit
1403
1404
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1405
class KnitPackTextStore(VersionedFileStore):
2592.3.238 by Martin Pool
Pack doc updates
1406
    """Presents a TextStore abstraction on top of packs.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1407
1408
    This class works by replacing the original VersionedFileStore.
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1409
    We need to do this because the KnitPackRevisionStore is less
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1410
    isolated in its layering - it uses services from the repo and shares them
1411
    with all the data written in a single write group.
1412
    """
1413
1414
    def __init__(self, repo, transport, weavestore):
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1415
        """Create a KnitPackTextStore on repo with weavestore.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1416
1417
        This will store its state in the Repository, use the
1418
        indices FileNames to provide a KnitGraphIndex,
1419
        and at the end of transactions write new indices.
1420
        """
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1421
        # don't call base class constructor - it's not suitable.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1422
        # no transient data stored in the transaction
1423
        # cache.
1424
        self._precious = False
1425
        self.repo = repo
1426
        self.transport = transport
1427
        self.weavestore = weavestore
1428
        # XXX for check() which isn't updated yet
1429
        self._transport = weavestore._transport
1430
2592.3.212 by Robert Collins
Cleanup text index management in packs.
1431
    def get_weave_or_empty(self, file_id, transaction):
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1432
        """Get a 'Knit' backed by the .tix indices.
1433
1434
        The transaction parameter is ignored.
1435
        """
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1436
        self.repo._pack_collection.ensure_loaded()
1437
        add_callback = self.repo._pack_collection.text_index.add_callback
2592.3.212 by Robert Collins
Cleanup text index management in packs.
1438
        # setup knit specific objects
1439
        file_id_index = GraphIndexPrefixAdapter(
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1440
            self.repo._pack_collection.text_index.combined_index,
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1441
            (file_id, ), 1, add_nodes_callback=add_callback)
1442
        knit_index = KnitGraphIndex(file_id_index,
1443
            add_callback=file_id_index.add_nodes,
1444
            deltas=True, parents=True)
2592.3.159 by Robert Collins
Provide a transport for KnitVersionedFile's __repr__ in pack repositories.
1445
        return knit.KnitVersionedFile('text:' + file_id,
1446
            self.transport.clone('..'),
2592.3.130 by Robert Collins
Reduce object creation volume during commit.
1447
            None,
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1448
            index=knit_index,
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1449
            access_method=self.repo._pack_collection.text_index.knit_access,
2592.3.160 by Robert Collins
Change the packs format to be unannotated.
1450
            factory=knit.KnitPlainFactory())
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1451
1452
    get_weave = get_weave_or_empty
1453
1454
    def __iter__(self):
1455
        """Generate a list of the fileids inserted, for use by check."""
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1456
        self.repo._pack_collection.ensure_loaded()
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1457
        ids = set()
2592.3.212 by Robert Collins
Cleanup text index management in packs.
1458
        for index, key, value, refs in \
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1459
            self.repo._pack_collection.text_index.combined_index.iter_all_entries():
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1460
            ids.add(key[0])
1461
        return iter(ids)
1462
1463
1464
class InventoryKnitThunk(object):
1465
    """An object to manage thunking get_inventory_weave to pack based knits."""
1466
1467
    def __init__(self, repo, transport):
1468
        """Create an InventoryKnitThunk for repo at transport.
1469
1470
        This will store its state in the Repository, use the
1471
        indices FileNames to provide a KnitGraphIndex,
1472
        and at the end of transactions write a new index..
1473
        """
1474
        self.repo = repo
1475
        self.transport = transport
1476
1477
    def get_weave(self):
1478
        """Get a 'Knit' that contains inventory data."""
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1479
        self.repo._pack_collection.ensure_loaded()
1480
        add_callback = self.repo._pack_collection.inventory_index.add_callback
2592.3.211 by Robert Collins
Pack inventory index management cleaned up.
1481
        # setup knit specific objects
1482
        knit_index = KnitGraphIndex(
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1483
            self.repo._pack_collection.inventory_index.combined_index,
2592.3.211 by Robert Collins
Pack inventory index management cleaned up.
1484
            add_callback=add_callback, deltas=True, parents=True)
1485
        return knit.KnitVersionedFile(
1486
            'inventory', self.transport.clone('..'),
1487
            self.repo.control_files._file_mode,
1488
            create=False, access_mode=self.repo._access_mode(),
1489
            index=knit_index, delta=True, factory=knit.KnitPlainFactory(),
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1490
            access_method=self.repo._pack_collection.inventory_index.knit_access)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1491
1492
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1493
class KnitPackRepository(KnitRepository):
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1494
    """Experimental graph-knit using repository."""
1495
1496
    def __init__(self, _format, a_bzrdir, control_files, _revision_store,
2592.3.166 by Robert Collins
Merge KnitRepository3 removal branch.
1497
        control_store, text_store, _commit_builder_class, _serializer):
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1498
        KnitRepository.__init__(self, _format, a_bzrdir, control_files,
2592.3.166 by Robert Collins
Merge KnitRepository3 removal branch.
1499
            _revision_store, control_store, text_store, _commit_builder_class,
1500
            _serializer)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1501
        index_transport = control_files._transport.clone('indices')
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1502
        self._pack_collection = RepositoryPackCollection(self, control_files._transport,
2592.5.11 by Martin Pool
Move upload_transport from pack repositories to the pack collection
1503
            index_transport,
2592.5.12 by Martin Pool
Move pack_transport and pack_name onto RepositoryPackCollection
1504
            control_files._transport.clone('upload'),
1505
            control_files._transport.clone('packs'))
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1506
        self._revision_store = KnitPackRevisionStore(self, index_transport, self._revision_store)
1507
        self.weave_store = KnitPackTextStore(self, index_transport, self.weave_store)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1508
        self._inv_thunk = InventoryKnitThunk(self, index_transport)
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1509
        # True when the repository object is 'write locked' (as opposed to the
1510
        # physical lock only taken out around changes to the pack-names list.) 
1511
        # Another way to represent this would be a decorator around the control
1512
        # files object that presents logical locks as physical ones - if this
1513
        # gets ugly consider that alternative design. RBC 20071011
1514
        self._write_lock_count = 0
1515
        self._transaction = None
2592.3.96 by Robert Collins
Merge index improvements (includes bzr.dev).
1516
        # for tests
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
1517
        self._reconcile_does_inventory_gc = True
2592.3.214 by Robert Collins
Merge bzr.dev.
1518
        self._reconcile_fixes_text_parents = False
2951.1.3 by Robert Collins
Partial support for native reconcile with packs.
1519
        self._reconcile_backsup_inventory = False
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1520
1521
    def _abort_write_group(self):
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1522
        self._pack_collection._abort_write_group()
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1523
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1524
    def _access_mode(self):
1525
        """Return 'w' or 'r' for depending on whether a write lock is active.
1526
        
1527
        This method is a helper for the Knit-thunking support objects.
1528
        """
1529
        if self.is_write_locked():
1530
            return 'w'
1531
        return 'r'
1532
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
1533
    def _find_inconsistent_revision_parents(self):
1534
        """Find revisions with incorrectly cached parents.
1535
1536
        :returns: an iterator yielding tuples of (revison-id, parents-in-index,
1537
            parents-in-revision).
1538
        """
1539
        assert self.is_locked()
1540
        pb = ui.ui_factory.nested_progress_bar()
2951.1.11 by Robert Collins
Do not try to use try:finally: around a yield for python 2.4.
1541
        result = []
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
1542
        try:
1543
            revision_nodes = self._pack_collection.revision_index \
1544
                .combined_index.iter_all_entries()
1545
            index_positions = []
1546
            # Get the cached index values for all revisions, and also the location
1547
            # in each index of the revision text so we can perform linear IO.
1548
            for index, key, value, refs in revision_nodes:
1549
                pos, length = value[1:].split(' ')
1550
                index_positions.append((index, int(pos), key[0],
1551
                    tuple(parent[0] for parent in refs[0])))
1552
                pb.update("Reading revision index.", 0, 0)
1553
            index_positions.sort()
2951.1.10 by Robert Collins
Peer review feedback with Ian.
1554
            batch_count = len(index_positions) / 1000 + 1
1555
            pb.update("Checking cached revision graph.", 0, batch_count)
1556
            for offset in xrange(batch_count):
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
1557
                pb.update("Checking cached revision graph.", offset)
1558
                to_query = index_positions[offset * 1000:(offset + 1) * 1000]
1559
                if not to_query:
1560
                    break
1561
                rev_ids = [item[2] for item in to_query]
1562
                revs = self.get_revisions(rev_ids)
1563
                for revision, item in zip(revs, to_query):
1564
                    index_parents = item[3]
1565
                    rev_parents = tuple(revision.parent_ids)
1566
                    if index_parents != rev_parents:
2951.1.11 by Robert Collins
Do not try to use try:finally: around a yield for python 2.4.
1567
                        result.append((revision.revision_id, index_parents, rev_parents))
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
1568
        finally:
1569
            pb.finished()
2951.1.11 by Robert Collins
Do not try to use try:finally: around a yield for python 2.4.
1570
        return result
2951.1.2 by Robert Collins
Partial refactoring of pack_repo to create a Packer object for packing.
1571
2592.3.216 by Robert Collins
Implement get_parents and _make_parents_provider for Pack repositories.
1572
    def get_parents(self, revision_ids):
1573
        """See StackedParentsProvider.get_parents.
1574
        
1575
        This implementation accesses the combined revision index to provide
1576
        answers.
1577
        """
2947.1.1 by Robert Collins
(robertc) Fix pack-repository to support get_parents calls as the first call on a repository, and fix full-branch push/pull performance to not suck terribly. (Robert Collins)
1578
        self._pack_collection.ensure_loaded()
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1579
        index = self._pack_collection.revision_index.combined_index
2592.3.216 by Robert Collins
Implement get_parents and _make_parents_provider for Pack repositories.
1580
        search_keys = set()
1581
        for revision_id in revision_ids:
1582
            if revision_id != _mod_revision.NULL_REVISION:
1583
                search_keys.add((revision_id,))
1584
        found_parents = {_mod_revision.NULL_REVISION:[]}
1585
        for index, key, value, refs in index.iter_entries(search_keys):
1586
            parents = refs[0]
1587
            if not parents:
1588
                parents = (_mod_revision.NULL_REVISION,)
1589
            else:
1590
                parents = tuple(parent[0] for parent in parents)
1591
            found_parents[key[0]] = parents
1592
        result = []
1593
        for revision_id in revision_ids:
1594
            try:
1595
                result.append(found_parents[revision_id])
1596
            except KeyError:
1597
                result.append(None)
1598
        return result
1599
1600
    def _make_parents_provider(self):
1601
        return self
1602
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1603
    def _refresh_data(self):
2951.1.1 by Robert Collins
(robertc) Fix data-refresh logic for packs not to refresh mid-transaction when a names write lock is held. (Robert Collins)
1604
        if self._write_lock_count == 1 or (
1605
            self.control_files._lock_count == 1 and
1606
            self.control_files._lock_mode == 'r'):
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1607
            # forget what names there are
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1608
            self._pack_collection.reset()
2592.3.219 by Robert Collins
Review feedback.
1609
            # XXX: Better to do an in-memory merge when acquiring a new lock -
1610
            # factor out code from _save_pack_names.
2949.1.2 by Robert Collins
* Fetch with pack repositories will no longer read the entire history graph.
1611
            self._pack_collection.ensure_loaded()
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1612
1613
    def _start_write_group(self):
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1614
        self._pack_collection._start_write_group()
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1615
1616
    def _commit_write_group(self):
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1617
        return self._pack_collection._commit_write_group()
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1618
1619
    def get_inventory_weave(self):
1620
        return self._inv_thunk.get_weave()
1621
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1622
    def get_transaction(self):
1623
        if self._write_lock_count:
1624
            return self._transaction
1625
        else:
1626
            return self.control_files.get_transaction()
1627
1628
    def is_locked(self):
1629
        return self._write_lock_count or self.control_files.is_locked()
1630
1631
    def is_write_locked(self):
1632
        return self._write_lock_count
1633
1634
    def lock_write(self, token=None):
1635
        if not self._write_lock_count and self.is_locked():
1636
            raise errors.ReadOnlyError(self)
1637
        self._write_lock_count += 1
1638
        if self._write_lock_count == 1:
1639
            from bzrlib import transactions
1640
            self._transaction = transactions.WriteTransaction()
1641
        self._refresh_data()
1642
1643
    def lock_read(self):
1644
        if self._write_lock_count:
1645
            self._write_lock_count += 1
1646
        else:
1647
            self.control_files.lock_read()
1648
        self._refresh_data()
1649
1650
    def leave_lock_in_place(self):
1651
        # not supported - raise an error
1652
        raise NotImplementedError(self.leave_lock_in_place)
1653
1654
    def dont_leave_lock_in_place(self):
1655
        # not supported - raise an error
1656
        raise NotImplementedError(self.dont_leave_lock_in_place)
1657
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1658
    @needs_write_lock
1659
    def pack(self):
1660
        """Compress the data within the repository.
1661
1662
        This will pack all the data to a single pack. In future it may
1663
        recompress deltas or do other such expensive operations.
1664
        """
2592.3.232 by Martin Pool
Disambiguate two member variables called _packs into _packs_by_name and _pack_collection
1665
        self._pack_collection.pack()
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1666
1667
    @needs_write_lock
1668
    def reconcile(self, other=None, thorough=False):
1669
        """Reconcile this repository."""
1670
        from bzrlib.reconcile import PackReconciler
1671
        reconciler = PackReconciler(self, thorough=thorough)
1672
        reconciler.reconcile()
1673
        return reconciler
1674
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1675
    def unlock(self):
1676
        if self._write_lock_count == 1 and self._write_group is not None:
2592.3.244 by Martin Pool
unlock while in a write group now aborts the write group, unlocks, and errors.
1677
            self.abort_write_group()
1678
            self._transaction = None
1679
            self._write_lock_count = 0
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1680
            raise errors.BzrError(
2592.3.244 by Martin Pool
unlock while in a write group now aborts the write group, unlocks, and errors.
1681
                'Must end write group before releasing write lock on %s'
1682
                % self)
2592.3.188 by Robert Collins
Allow pack repositories to have multiple writers active at one time, for greater concurrency.
1683
        if self._write_lock_count:
1684
            self._write_lock_count -= 1
1685
            if not self._write_lock_count:
1686
                transaction = self._transaction
1687
                self._transaction = None
1688
                transaction.finish()
1689
        else:
1690
            self.control_files.unlock()
1691
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1692
1693
class RepositoryFormatPack(MetaDirRepositoryFormat):
1694
    """Format logic for pack structured repositories.
1695
1696
    This repository format has:
1697
     - a list of packs in pack-names
1698
     - packs in packs/NAME.pack
1699
     - indices in indices/NAME.{iix,six,tix,rix}
1700
     - knit deltas in the packs, knit indices mapped to the indices.
1701
     - thunk objects to support the knits programming API.
1702
     - a format marker of its own
1703
     - an optional 'shared-storage' flag
1704
     - an optional 'no-working-trees' flag
1705
     - a LockDir lock
1706
    """
1707
2592.3.166 by Robert Collins
Merge KnitRepository3 removal branch.
1708
    # Set this attribute in derived classes to control the repository class
1709
    # created by open and initialize.
1710
    repository_class = None
1711
    # Set this attribute in derived classes to control the
1712
    # _commit_builder_class that the repository objects will have passed to
1713
    # their constructor.
1714
    _commit_builder_class = None
1715
    # Set this attribute in derived clases to control the _serializer that the
1716
    # repository objects will have passed to their constructor.
1717
    _serializer = None
1718
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1719
    def _get_control_store(self, repo_transport, control_files):
1720
        """Return the control store for this repository."""
1721
        return VersionedFileStore(
1722
            repo_transport,
1723
            prefixed=False,
1724
            file_mode=control_files._file_mode,
1725
            versionedfile_class=knit.KnitVersionedFile,
2592.3.226 by Martin Pool
formatting and docstrings
1726
            versionedfile_kwargs={'factory': knit.KnitPlainFactory()},
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1727
            )
1728
1729
    def _get_revision_store(self, repo_transport, control_files):
1730
        """See RepositoryFormat._get_revision_store()."""
1731
        versioned_file_store = VersionedFileStore(
1732
            repo_transport,
1733
            file_mode=control_files._file_mode,
1734
            prefixed=False,
1735
            precious=True,
1736
            versionedfile_class=knit.KnitVersionedFile,
2592.3.226 by Martin Pool
formatting and docstrings
1737
            versionedfile_kwargs={'delta': False,
1738
                                  'factory': knit.KnitPlainFactory(),
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1739
                                 },
1740
            escaped=True,
1741
            )
1742
        return KnitRevisionStore(versioned_file_store)
1743
1744
    def _get_text_store(self, transport, control_files):
1745
        """See RepositoryFormat._get_text_store()."""
1746
        return self._get_versioned_file_store('knits',
1747
                                  transport,
1748
                                  control_files,
1749
                                  versionedfile_class=knit.KnitVersionedFile,
1750
                                  versionedfile_kwargs={
2592.3.226 by Martin Pool
formatting and docstrings
1751
                                      'create_parent_dir': True,
1752
                                      'delay_create': True,
1753
                                      'dir_mode': control_files._dir_mode,
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1754
                                  },
1755
                                  escaped=True)
1756
1757
    def initialize(self, a_bzrdir, shared=False):
1758
        """Create a pack based repository.
1759
1760
        :param a_bzrdir: bzrdir to contain the new repository; must already
1761
            be initialized.
1762
        :param shared: If true the repository will be initialized as a shared
1763
                       repository.
1764
        """
1765
        mutter('creating repository in %s.', a_bzrdir.transport.base)
1766
        dirs = ['indices', 'obsolete_packs', 'packs', 'upload']
1767
        builder = GraphIndexBuilder()
1768
        files = [('pack-names', builder.finish())]
1769
        utf8_files = [('format', self.get_format_string())]
1770
        
1771
        self._upload_blank_content(a_bzrdir, dirs, files, utf8_files, shared)
1772
        return self.open(a_bzrdir=a_bzrdir, _found=True)
1773
1774
    def open(self, a_bzrdir, _found=False, _override_transport=None):
1775
        """See RepositoryFormat.open().
1776
        
1777
        :param _override_transport: INTERNAL USE ONLY. Allows opening the
1778
                                    repository at a slightly different url
1779
                                    than normal. I.e. during 'upgrade'.
1780
        """
1781
        if not _found:
1782
            format = RepositoryFormat.find_format(a_bzrdir)
1783
            assert format.__class__ ==  self.__class__
1784
        if _override_transport is not None:
1785
            repo_transport = _override_transport
1786
        else:
1787
            repo_transport = a_bzrdir.get_repository_transport(None)
1788
        control_files = lockable_files.LockableFiles(repo_transport,
1789
                                'lock', lockdir.LockDir)
1790
        text_store = self._get_text_store(repo_transport, control_files)
1791
        control_store = self._get_control_store(repo_transport, control_files)
1792
        _revision_store = self._get_revision_store(repo_transport, control_files)
1793
        return self.repository_class(_format=self,
1794
                              a_bzrdir=a_bzrdir,
1795
                              control_files=control_files,
1796
                              _revision_store=_revision_store,
1797
                              control_store=control_store,
2592.3.166 by Robert Collins
Merge KnitRepository3 removal branch.
1798
                              text_store=text_store,
1799
                              _commit_builder_class=self._commit_builder_class,
1800
                              _serializer=self._serializer)
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1801
1802
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1803
class RepositoryFormatKnitPack1(RepositoryFormatPack):
2592.3.215 by Robert Collins
Review feedback.
1804
    """A no-subtrees parameterised Pack repository.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1805
2939.2.1 by Ian Clatworthy
use 'knitpack' naming instead of 'experimental' for pack formats
1806
    This format was introduced in 0.92.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1807
    """
1808
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1809
    repository_class = KnitPackRepository
2592.3.166 by Robert Collins
Merge KnitRepository3 removal branch.
1810
    _commit_builder_class = PackCommitBuilder
1811
    _serializer = xml5.serializer_v5
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1812
1813
    def _get_matching_bzrdir(self):
3010.3.2 by Martin Pool
Rename pack0.92 to pack-0.92
1814
        return bzrdir.format_registry.make_bzrdir('pack-0.92')
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1815
1816
    def _ignore_setting_bzrdir(self, format):
1817
        pass
1818
1819
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
1820
1821
    def get_format_string(self):
1822
        """See RepositoryFormat.get_format_string()."""
2939.2.6 by Ian Clatworthy
more review feedback from lifeless and poolie
1823
        return "Bazaar pack repository format 1 (needs bzr 0.92)\n"
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1824
1825
    def get_format_description(self):
1826
        """See RepositoryFormat.get_format_description()."""
2939.2.1 by Ian Clatworthy
use 'knitpack' naming instead of 'experimental' for pack formats
1827
        return "Packs containing knits without subtree support"
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1828
1829
    def check_conversion_target(self, target_format):
1830
        pass
1831
1832
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1833
class RepositoryFormatKnitPack3(RepositoryFormatPack):
2592.3.215 by Robert Collins
Review feedback.
1834
    """A subtrees parameterised Pack repository.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1835
2592.3.215 by Robert Collins
Review feedback.
1836
    This repository format uses the xml7 serializer to get:
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1837
     - support for recording full info about the tree root
1838
     - support for recording tree-references
2592.3.215 by Robert Collins
Review feedback.
1839
2939.2.1 by Ian Clatworthy
use 'knitpack' naming instead of 'experimental' for pack formats
1840
    This format was introduced in 0.92.
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1841
    """
1842
2592.3.224 by Martin Pool
Rename GraphKnitRepository etc to KnitPackRepository
1843
    repository_class = KnitPackRepository
2592.3.166 by Robert Collins
Merge KnitRepository3 removal branch.
1844
    _commit_builder_class = PackRootCommitBuilder
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1845
    rich_root_data = True
1846
    supports_tree_reference = True
2592.3.166 by Robert Collins
Merge KnitRepository3 removal branch.
1847
    _serializer = xml7.serializer_v7
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1848
1849
    def _get_matching_bzrdir(self):
2939.2.5 by Ian Clatworthy
review feedback from lifeless
1850
        return bzrdir.format_registry.make_bzrdir(
3010.3.2 by Martin Pool
Rename pack0.92 to pack-0.92
1851
            'pack-0.92-subtree')
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1852
1853
    def _ignore_setting_bzrdir(self, format):
1854
        pass
1855
1856
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
1857
1858
    def check_conversion_target(self, target_format):
1859
        if not target_format.rich_root_data:
1860
            raise errors.BadConversionTarget(
1861
                'Does not support rich root data.', target_format)
1862
        if not getattr(target_format, 'supports_tree_reference', False):
1863
            raise errors.BadConversionTarget(
1864
                'Does not support nested trees', target_format)
1865
            
1866
    def get_format_string(self):
1867
        """See RepositoryFormat.get_format_string()."""
2939.2.6 by Ian Clatworthy
more review feedback from lifeless and poolie
1868
        return "Bazaar pack repository format 1 with subtree support (needs bzr 0.92)\n"
2592.3.88 by Robert Collins
Move Pack repository logic to bzrlib.repofmt.pack_repo.
1869
1870
    def get_format_description(self):
1871
        """See RepositoryFormat.get_format_description()."""
2939.2.1 by Ian Clatworthy
use 'knitpack' naming instead of 'experimental' for pack formats
1872
        return "Packs containing knits with subtree support\n"