~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/pack_repo.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-06-05 04:05:05 UTC
  • mfrom: (3473.1.1 ianc-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20080605040505-i9kqxg2fps2qjdi0
Add the 'alias' command (Tim Penhey)

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
from bzrlib.lazy_import import lazy_import
18
18
lazy_import(globals(), """
19
19
from itertools import izip
 
20
import math
 
21
import md5
20
22
import time
21
23
 
22
24
from bzrlib import (
23
 
    debug,
24
 
    graph,
25
 
    osutils,
26
 
    pack,
27
 
    transactions,
28
 
    ui,
29
 
    xml5,
30
 
    xml6,
31
 
    xml7,
32
 
    )
 
25
        debug,
 
26
        graph,
 
27
        pack,
 
28
        ui,
 
29
        )
33
30
from bzrlib.index import (
 
31
    GraphIndex,
 
32
    GraphIndexBuilder,
 
33
    InMemoryGraphIndex,
34
34
    CombinedGraphIndex,
35
 
    GraphIndex,
36
 
    GraphIndexBuilder,
37
35
    GraphIndexPrefixAdapter,
38
 
    InMemoryGraphIndex,
39
 
    )
40
 
from bzrlib.knit import (
41
 
    KnitPlainFactory,
42
 
    KnitVersionedFiles,
43
 
    _KnitGraphIndex,
44
 
    _DirectPackAccess,
45
 
    )
 
36
    )
 
37
from bzrlib.knit import KnitGraphIndex, _PackAccess, _KnitData
 
38
from bzrlib.osutils import rand_chars
 
39
from bzrlib.pack import ContainerWriter
 
40
from bzrlib.store import revision
46
41
from bzrlib import tsort
47
42
""")
48
43
from bzrlib import (
49
44
    bzrdir,
50
45
    errors,
 
46
    knit,
51
47
    lockable_files,
52
48
    lockdir,
 
49
    osutils,
53
50
    symbol_versioning,
 
51
    transactions,
 
52
    xml5,
 
53
    xml6,
 
54
    xml7,
54
55
    )
55
56
 
56
 
from bzrlib.decorators import needs_write_lock
57
 
from bzrlib.btree_index import (
58
 
    BTreeGraphIndex,
59
 
    BTreeBuilder,
60
 
    )
61
 
from bzrlib.index import (
62
 
    GraphIndex,
63
 
    InMemoryGraphIndex,
64
 
    )
 
57
from bzrlib.decorators import needs_read_lock, needs_write_lock
65
58
from bzrlib.repofmt.knitrepo import KnitRepository
66
59
from bzrlib.repository import (
67
60
    CommitBuilder,
 
61
    MetaDirRepository,
68
62
    MetaDirRepositoryFormat,
69
63
    RepositoryFormat,
70
64
    RootCommitBuilder,
71
65
    )
72
66
import bzrlib.revision as _mod_revision
 
67
from bzrlib.store.revision.knit import KnitRevisionStore
 
68
from bzrlib.store.versioned import VersionedFileStore
73
69
from bzrlib.trace import (
74
70
    mutter,
 
71
    mutter_callsite,
 
72
    note,
75
73
    warning,
76
74
    )
77
75
 
92
90
        self._file_graph = graph.Graph(
93
91
            repository._pack_collection.text_index.combined_index)
94
92
 
 
93
    def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
 
94
        return self.repository._pack_collection._add_text_to_weave(file_id,
 
95
            self._new_revision_id, new_lines, parents, nostore_sha,
 
96
            self.random_revid)
 
97
 
95
98
    def _heads(self, file_id, revision_ids):
96
99
        keys = [(file_id, revision_id) for revision_id in revision_ids]
97
100
        return set([key[1] for key in self._file_graph.heads(keys)])
113
116
        self._file_graph = graph.Graph(
114
117
            repository._pack_collection.text_index.combined_index)
115
118
 
 
119
    def _add_text_to_weave(self, file_id, new_lines, parents, nostore_sha):
 
120
        return self.repository._pack_collection._add_text_to_weave(file_id,
 
121
            self._new_revision_id, new_lines, parents, nostore_sha,
 
122
            self.random_revid)
 
123
 
116
124
    def _heads(self, file_id, revision_ids):
117
125
        keys = [(file_id, revision_id) for revision_id in revision_ids]
118
126
        return set([key[1] for key in self._file_graph.heads(keys)])
137
145
        :param text_index: A GraphIndex for determining what file texts
138
146
            are present in the pack and accessing the locations of their
139
147
            texts/deltas (via (fileid, revisionid) tuples).
140
 
        :param signature_index: A GraphIndex for determining what signatures are
 
148
        :param revision_index: A GraphIndex for determining what signatures are
141
149
            present in the Pack and accessing the locations of their texts.
142
150
        """
143
151
        self.revision_index = revision_index
207
215
 
208
216
    def __repr__(self):
209
217
        return "<bzrlib.repofmt.pack_repo.Pack object at 0x%x, %s, %s" % (
210
 
            id(self), self.pack_transport, self.name)
 
218
            id(self), self.transport, self.name)
211
219
 
212
220
 
213
221
class NewPack(Pack):
223
231
        }
224
232
 
225
233
    def __init__(self, upload_transport, index_transport, pack_transport,
226
 
        upload_suffix='', file_mode=None, index_builder_class=None,
227
 
        index_class=None):
 
234
        upload_suffix='', file_mode=None):
228
235
        """Create a NewPack instance.
229
236
 
230
237
        :param upload_transport: A writable transport for the pack to be
237
244
        :param upload_suffix: An optional suffix to be given to any temporary
238
245
            files created during the pack creation. e.g '.autopack'
239
246
        :param file_mode: An optional file mode to create the new files with.
240
 
        :param index_builder_class: Required keyword parameter - the class of
241
 
            index builder to use.
242
 
        :param index_class: Required keyword parameter - the class of index
243
 
            object to use.
244
247
        """
245
248
        # The relative locations of the packs are constrained, but all are
246
249
        # passed in because the caller has them, so as to avoid object churn.
247
250
        Pack.__init__(self,
248
251
            # Revisions: parents list, no text compression.
249
 
            index_builder_class(reference_lists=1),
 
252
            InMemoryGraphIndex(reference_lists=1),
250
253
            # Inventory: We want to map compression only, but currently the
251
254
            # knit code hasn't been updated enough to understand that, so we
252
255
            # have a regular 2-list index giving parents and compression
253
256
            # source.
254
 
            index_builder_class(reference_lists=2),
 
257
            InMemoryGraphIndex(reference_lists=2),
255
258
            # Texts: compression and per file graph, for all fileids - so two
256
259
            # reference lists and two elements in the key tuple.
257
 
            index_builder_class(reference_lists=2, key_elements=2),
 
260
            InMemoryGraphIndex(reference_lists=2, key_elements=2),
258
261
            # Signatures: Just blobs to store, no compression, no parents
259
262
            # listing.
260
 
            index_builder_class(reference_lists=0),
 
263
            InMemoryGraphIndex(reference_lists=0),
261
264
            )
262
 
        # When we make readonly indices, we need this.
263
 
        self.index_class = index_class
264
265
        # where should the new pack be opened
265
266
        self.upload_transport = upload_transport
266
267
        # where are indices written out to
270
271
        # What file mode to upload the pack and indices with.
271
272
        self._file_mode = file_mode
272
273
        # tracks the content written to the .pack file.
273
 
        self._hash = osutils.md5()
 
274
        self._hash = md5.new()
274
275
        # a four-tuple with the length in bytes of the indices, once the pack
275
276
        # is finalised. (rev, inv, text, sigs)
276
277
        self.index_sizes = None
280
281
        # under creation.
281
282
        self._cache_limit = 0
282
283
        # the temporary pack file name.
283
 
        self.random_name = osutils.rand_chars(20) + upload_suffix
 
284
        self.random_name = rand_chars(20) + upload_suffix
284
285
        # when was this pack started ?
285
286
        self.start_time = time.time()
286
287
        # open an output stream for the data added to the pack.
407
408
 
408
409
    def _replace_index_with_readonly(self, index_type):
409
410
        setattr(self, index_type + '_index',
410
 
            self.index_class(self.index_transport,
 
411
            GraphIndex(self.index_transport,
411
412
                self.index_name(index_type, self.name),
412
413
                self.index_sizes[self.index_offset(index_type)]))
413
414
 
452
453
    # XXX: Probably 'can be written to' could/should be separated from 'acts
453
454
    # like a knit index' -- mbp 20071024
454
455
 
455
 
    def __init__(self, reload_func=None):
456
 
        """Create an AggregateIndex.
457
 
 
458
 
        :param reload_func: A function to call if we find we are missing an
459
 
            index. Should have the form reload_func() => True if the list of
460
 
            active pack files has changed.
461
 
        """
462
 
        self._reload_func = reload_func
 
456
    def __init__(self):
 
457
        """Create an AggregateIndex."""
463
458
        self.index_to_pack = {}
464
 
        self.combined_index = CombinedGraphIndex([], reload_func=reload_func)
465
 
        self.data_access = _DirectPackAccess(self.index_to_pack)
466
 
        self.add_callback = None
 
459
        self.combined_index = CombinedGraphIndex([])
 
460
        self.knit_access = _PackAccess(self.index_to_pack)
467
461
 
468
462
    def replace_indices(self, index_to_pack, indices):
469
463
        """Replace the current mappings with fresh ones.
515
509
        # allow writing: queue writes to a new index
516
510
        self.add_index(index, pack)
517
511
        # Updates the index to packs mapping as a side effect,
518
 
        self.data_access.set_writer(pack._writer, index, pack.access_tuple())
 
512
        self.knit_access.set_writer(pack._writer, index, pack.access_tuple())
519
513
        self.add_callback = index.add_nodes
520
514
 
521
515
    def clear(self):
522
516
        """Reset all the aggregate data to nothing."""
523
 
        self.data_access.set_writer(None, None, (None, None))
 
517
        self.knit_access.set_writer(None, None, (None, None))
524
518
        self.index_to_pack.clear()
525
519
        del self.combined_index._indices[:]
526
520
        self.add_callback = None
536
530
        if (self.add_callback is not None and
537
531
            getattr(index, 'add_nodes', None) == self.add_callback):
538
532
            self.add_callback = None
539
 
            self.data_access.set_writer(None, None, (None, None))
 
533
            self.knit_access.set_writer(None, None, (None, None))
540
534
 
541
535
 
542
536
class Packer(object):
595
589
                return None
596
590
            else:
597
591
                self.revision_ids = frozenset(self.revision_ids)
598
 
                self.revision_keys = frozenset((revid,) for revid in
599
 
                    self.revision_ids)
600
592
        if pb is None:
601
593
            self.pb = ui.ui_factory.nested_progress_bar()
602
594
        else:
612
604
        return NewPack(self._pack_collection._upload_transport,
613
605
            self._pack_collection._index_transport,
614
606
            self._pack_collection._pack_transport, upload_suffix=self.suffix,
615
 
            file_mode=self._pack_collection.repo.bzrdir._get_file_mode(),
616
 
            index_builder_class=self._pack_collection._index_builder_class,
617
 
            index_class=self._pack_collection._index_class)
 
607
            file_mode=self._pack_collection.repo.bzrdir._get_file_mode())
618
608
 
619
609
    def _copy_revision_texts(self):
620
610
        """Copy revision data to the new pack."""
773
763
 
774
764
    def _do_copy_nodes(self, nodes, index_map, writer, write_index, pb):
775
765
        # for record verification
776
 
        knit = KnitVersionedFiles(None, None)
 
766
        knit_data = _KnitData(None)
777
767
        # plan a readv on each source pack:
778
768
        # group by pack
779
769
        nodes = sorted(nodes)
805
795
                izip(reader.iter_records(), pack_readv_requests):
806
796
                raw_data = read_func(None)
807
797
                # check the header only
808
 
                df, _ = knit._parse_record_header(key, raw_data)
 
798
                df, _ = knit_data._parse_record_header(key[-1], raw_data)
809
799
                df.close()
810
800
                pos, size = writer.add_bytes_record(raw_data, names)
811
801
                write_index.add_node(key, eol_flag + "%d %d" % (pos, size))
834
824
    def _do_copy_nodes_graph(self, index_map, writer, write_index,
835
825
        output_lines, pb, readv_group_iter, total_items):
836
826
        # for record verification
837
 
        knit = KnitVersionedFiles(None, None)
 
827
        knit_data = _KnitData(None)
838
828
        # for line extraction when requested (inventories only)
839
829
        if output_lines:
840
 
            factory = KnitPlainFactory()
 
830
            factory = knit.KnitPlainFactory()
841
831
        record_index = 0
842
832
        pb.update("Copied record", record_index, total_items)
843
833
        for index, readv_vector, node_vector in readv_group_iter:
847
837
            for (names, read_func), (key, eol_flag, references) in \
848
838
                izip(reader.iter_records(), node_vector):
849
839
                raw_data = read_func(None)
 
840
                version_id = key[-1]
850
841
                if output_lines:
851
842
                    # read the entire thing
852
 
                    content, _ = knit._parse_record(key[-1], raw_data)
 
843
                    content, _ = knit_data._parse_record(version_id, raw_data)
853
844
                    if len(references[-1]) == 0:
854
845
                        line_iterator = factory.get_fulltext_content(content)
855
846
                    else:
856
847
                        line_iterator = factory.get_linedelta_content(content)
857
848
                    for line in line_iterator:
858
 
                        yield line, key
 
849
                        yield line, version_id
859
850
                else:
860
851
                    # check the header only
861
 
                    df, _ = knit._parse_record_header(key, raw_data)
 
852
                    df, _ = knit_data._parse_record_header(version_id, raw_data)
862
853
                    df.close()
863
854
                pos, size = writer.add_bytes_record(raw_data, names)
864
855
                write_index.add_node(key, eol_flag + "%d %d" % (pos, size), references)
920
911
        """Use up the inv_lines generator and setup a text key filter."""
921
912
        repo = self._pack_collection.repo
922
913
        fileid_revisions = repo._find_file_ids_from_xml_inventory_lines(
923
 
            inv_lines, self.revision_keys)
 
914
            inv_lines, self.revision_ids)
924
915
        text_filter = []
925
916
        for fileid, file_revids in fileid_revisions.iteritems():
926
917
            text_filter.extend([(fileid, file_revid) for file_revid in file_revids])
977
968
        # TODO: combine requests in the same index that are in ascending order.
978
969
        return total, requests
979
970
 
980
 
    def open_pack(self):
981
 
        """Open a pack for the pack we are creating."""
982
 
        new_pack = super(OptimisingPacker, self).open_pack()
983
 
        # Turn on the optimization flags for all the index builders.
984
 
        new_pack.revision_index.set_optimize(for_size=True)
985
 
        new_pack.inventory_index.set_optimize(for_size=True)
986
 
        new_pack.text_index.set_optimize(for_size=True)
987
 
        new_pack.signature_index.set_optimize(for_size=True)
988
 
        return new_pack
989
 
 
990
971
 
991
972
class ReconcilePacker(Packer):
992
973
    """A packer which regenerates indices etc as it copies.
1083
1064
            self.new_pack.text_index,
1084
1065
            ('blank', ), 1,
1085
1066
            add_nodes_callback=self.new_pack.text_index.add_nodes)
1086
 
        data_access = _DirectPackAccess(
1087
 
                {self.new_pack.text_index:self.new_pack.access_tuple()})
1088
 
        data_access.set_writer(self.new_pack._writer, self.new_pack.text_index,
1089
 
            self.new_pack.access_tuple())
1090
 
        output_texts = KnitVersionedFiles(
1091
 
            _KnitGraphIndex(self.new_pack.text_index,
1092
 
                add_callback=self.new_pack.text_index.add_nodes,
1093
 
                deltas=True, parents=True, is_locked=repo.is_locked),
1094
 
            data_access=data_access, max_delta_chain=200)
 
1067
        knit_index = KnitGraphIndex(file_id_index,
 
1068
            add_callback=file_id_index.add_nodes,
 
1069
            deltas=True, parents=True)
 
1070
        output_knit = knit.KnitVersionedFile('reconcile-texts',
 
1071
            self._pack_collection.transport,
 
1072
            index=knit_index,
 
1073
            access_method=_PackAccess(
 
1074
                {self.new_pack.text_index:self.new_pack.access_tuple()},
 
1075
                (self.new_pack._writer, self.new_pack.text_index)),
 
1076
            factory=knit.KnitPlainFactory())
1095
1077
        for key, parent_keys in bad_texts:
1096
1078
            # We refer to the new pack to delta data being output.
1097
1079
            # A possible improvement would be to catch errors on short reads
1104
1086
                    raise errors.BzrError('Mismatched key parent %r:%r' %
1105
1087
                        (key, parent_keys))
1106
1088
                parents.append(parent_key[1])
1107
 
            text_lines = osutils.split_lines(repo.texts.get_record_stream(
1108
 
                [key], 'unordered', True).next().get_bytes_as('fulltext'))
1109
 
            output_texts.add_lines(key, parent_keys, text_lines,
1110
 
                random_id=True, check_content=False)
 
1089
            source_weave = repo.weave_store.get_weave(key[0], transaction)
 
1090
            text_lines = source_weave.get_lines(key[1])
 
1091
            # adapt the 'knit' to the current file_id.
 
1092
            file_id_index = GraphIndexPrefixAdapter(
 
1093
                self.new_pack.text_index,
 
1094
                (key[0], ), 1,
 
1095
                add_nodes_callback=self.new_pack.text_index.add_nodes)
 
1096
            knit_index._graph_index = file_id_index
 
1097
            knit_index._add_callback = file_id_index.add_nodes
 
1098
            output_knit.add_lines_with_ghosts(
 
1099
                key[1], parents, text_lines, random_id=True, check_content=False)
1111
1100
        # 5) check that nothing inserted has a reference outside the keyspace.
1112
1101
        missing_text_keys = self.new_pack._external_compression_parents_of_texts()
1113
1102
        if missing_text_keys:
1131
1120
 
1132
1121
 
1133
1122
class RepositoryPackCollection(object):
1134
 
    """Management of packs within a repository.
1135
 
    
1136
 
    :ivar _names: map of {pack_name: (index_size,)}
1137
 
    """
 
1123
    """Management of packs within a repository."""
1138
1124
 
1139
1125
    def __init__(self, repo, transport, index_transport, upload_transport,
1140
 
                 pack_transport, index_builder_class, index_class):
 
1126
                 pack_transport):
1141
1127
        """Create a new RepositoryPackCollection.
1142
1128
 
1143
1129
        :param transport: Addresses the repository base directory 
1146
1132
        :param upload_transport: Addresses the directory into which packs are written
1147
1133
            while they're being created.
1148
1134
        :param pack_transport: Addresses the directory of existing complete packs.
1149
 
        :param index_builder_class: The index builder class to use.
1150
 
        :param index_class: The index class to use.
1151
1135
        """
1152
1136
        self.repo = repo
1153
1137
        self.transport = transport
1154
1138
        self._index_transport = index_transport
1155
1139
        self._upload_transport = upload_transport
1156
1140
        self._pack_transport = pack_transport
1157
 
        self._index_builder_class = index_builder_class
1158
 
        self._index_class = index_class
1159
1141
        self._suffix_offsets = {'.rix': 0, '.iix': 1, '.tix': 2, '.six': 3}
1160
1142
        self.packs = []
1161
1143
        # name:Pack mapping
1165
1147
        # when a pack is being created by this object, the state of that pack.
1166
1148
        self._new_pack = None
1167
1149
        # aggregated revision index data
1168
 
        self.revision_index = AggregateIndex(self.reload_pack_names)
1169
 
        self.inventory_index = AggregateIndex(self.reload_pack_names)
1170
 
        self.text_index = AggregateIndex(self.reload_pack_names)
1171
 
        self.signature_index = AggregateIndex(self.reload_pack_names)
 
1150
        self.revision_index = AggregateIndex()
 
1151
        self.inventory_index = AggregateIndex()
 
1152
        self.text_index = AggregateIndex()
 
1153
        self.signature_index = AggregateIndex()
1172
1154
 
1173
1155
    def add_pack_to_memory(self, pack):
1174
1156
        """Make a Pack object available to the repository to satisfy queries.
1184
1166
        self.text_index.add_index(pack.text_index, pack)
1185
1167
        self.signature_index.add_index(pack.signature_index, pack)
1186
1168
        
 
1169
    def _add_text_to_weave(self, file_id, revision_id, new_lines, parents,
 
1170
        nostore_sha, random_revid):
 
1171
        file_id_index = GraphIndexPrefixAdapter(
 
1172
            self.text_index.combined_index,
 
1173
            (file_id, ), 1,
 
1174
            add_nodes_callback=self.text_index.add_callback)
 
1175
        self.repo._text_knit._index._graph_index = file_id_index
 
1176
        self.repo._text_knit._index._add_callback = file_id_index.add_nodes
 
1177
        return self.repo._text_knit.add_lines_with_ghosts(
 
1178
            revision_id, parents, new_lines, nostore_sha=nostore_sha,
 
1179
            random_id=random_revid, check_content=False)[0:2]
 
1180
 
1187
1181
    def all_packs(self):
1188
1182
        """Return a list of all the Pack objects this repository has.
1189
1183
 
1312
1306
        # plan out what packs to keep, and what to reorganise
1313
1307
        while len(existing_packs):
1314
1308
            # take the largest pack, and if its less than the head of the
1315
 
            # distribution chart we will include its contents in the new pack
1316
 
            # for that position. If its larger, we remove its size from the
 
1309
            # distribution chart we will include its contents in the new pack for
 
1310
            # that position. If its larger, we remove its size from the
1317
1311
            # distribution chart
1318
1312
            next_pack_rev_count, next_pack = existing_packs.pop(0)
1319
1313
            if next_pack_rev_count >= pack_distribution[0]:
1336
1330
                    # this pack is used up, shift left.
1337
1331
                    del pack_distribution[0]
1338
1332
                    pack_operations.append([0, []])
1339
 
        # Now that we know which pack files we want to move, shove them all
1340
 
        # into a single pack file.
1341
 
        final_rev_count = 0
1342
 
        final_pack_list = []
1343
 
        for num_revs, pack_files in pack_operations:
1344
 
            final_rev_count += num_revs
1345
 
            final_pack_list.extend(pack_files)
1346
 
        if len(final_pack_list) == 1:
1347
 
            raise AssertionError('We somehow generated an autopack with a'
1348
 
                ' single pack file being moved.')
1349
 
            return []
1350
 
        return [[final_rev_count, final_pack_list]]
 
1333
        
 
1334
        return pack_operations
1351
1335
 
1352
1336
    def ensure_loaded(self):
1353
1337
        # NB: if you see an assertion error here, its probably access against
1406
1390
        detect updates from others during our write operation.
1407
1391
        :return: An iterator of the index contents.
1408
1392
        """
1409
 
        return self._index_class(self.transport, 'pack-names', None
 
1393
        return GraphIndex(self.transport, 'pack-names', None
1410
1394
                ).iter_all_entries()
1411
1395
 
1412
1396
    def _make_index(self, name, suffix):
1413
1397
        size_offset = self._suffix_offsets[suffix]
1414
1398
        index_name = name + suffix
1415
1399
        index_size = self._names[name][size_offset]
1416
 
        return self._index_class(
 
1400
        return GraphIndex(
1417
1401
            self._index_transport, index_name, index_size)
1418
1402
 
1419
1403
    def _max_pack_count(self, total_revisions):
1485
1469
        self._names.pop(pack.name)
1486
1470
        self._packs_by_name.pop(pack.name)
1487
1471
        self._remove_pack_indices(pack)
1488
 
        self.packs.remove(pack)
1489
1472
 
1490
1473
    def _remove_pack_indices(self, pack):
1491
1474
        """Remove the indices for pack from the aggregated indices."""
1570
1553
        """Release the mutex around the pack-names index."""
1571
1554
        self.repo.control_files.unlock()
1572
1555
 
1573
 
    def _diff_pack_names(self):
1574
 
        """Read the pack names from disk, and compare it to the one in memory.
1575
 
 
1576
 
        :return: (disk_nodes, deleted_nodes, new_nodes)
1577
 
            disk_nodes    The final set of nodes that should be referenced
1578
 
            deleted_nodes Nodes which have been removed from when we started
1579
 
            new_nodes     Nodes that are newly introduced
1580
 
        """
1581
 
        # load the disk nodes across
1582
 
        disk_nodes = set()
1583
 
        for index, key, value in self._iter_disk_pack_index():
1584
 
            disk_nodes.add((key, value))
1585
 
 
1586
 
        # do a two-way diff against our original content
1587
 
        current_nodes = set()
1588
 
        for name, sizes in self._names.iteritems():
1589
 
            current_nodes.add(
1590
 
                ((name, ), ' '.join(str(size) for size in sizes)))
1591
 
 
1592
 
        # Packs no longer present in the repository, which were present when we
1593
 
        # locked the repository
1594
 
        deleted_nodes = self._packs_at_load - current_nodes
1595
 
        # Packs which this process is adding
1596
 
        new_nodes = current_nodes - self._packs_at_load
1597
 
 
1598
 
        # Update the disk_nodes set to include the ones we are adding, and
1599
 
        # remove the ones which were removed by someone else
1600
 
        disk_nodes.difference_update(deleted_nodes)
1601
 
        disk_nodes.update(new_nodes)
1602
 
 
1603
 
        return disk_nodes, deleted_nodes, new_nodes
1604
 
 
1605
 
    def _syncronize_pack_names_from_disk_nodes(self, disk_nodes):
1606
 
        """Given the correct set of pack files, update our saved info.
1607
 
 
1608
 
        :return: (removed, added, modified)
1609
 
            removed     pack names removed from self._names
1610
 
            added       pack names added to self._names
1611
 
            modified    pack names that had changed value
1612
 
        """
1613
 
        removed = []
1614
 
        added = []
1615
 
        modified = []
1616
 
        ## self._packs_at_load = disk_nodes
 
1556
    def _save_pack_names(self, clear_obsolete_packs=False):
 
1557
        """Save the list of packs.
 
1558
 
 
1559
        This will take out the mutex around the pack names list for the
 
1560
        duration of the method call. If concurrent updates have been made, a
 
1561
        three-way merge between the current list and the current in memory list
 
1562
        is performed.
 
1563
 
 
1564
        :param clear_obsolete_packs: If True, clear out the contents of the
 
1565
            obsolete_packs directory.
 
1566
        """
 
1567
        self.lock_names()
 
1568
        try:
 
1569
            builder = GraphIndexBuilder()
 
1570
            # load the disk nodes across
 
1571
            disk_nodes = set()
 
1572
            for index, key, value in self._iter_disk_pack_index():
 
1573
                disk_nodes.add((key, value))
 
1574
            # do a two-way diff against our original content
 
1575
            current_nodes = set()
 
1576
            for name, sizes in self._names.iteritems():
 
1577
                current_nodes.add(
 
1578
                    ((name, ), ' '.join(str(size) for size in sizes)))
 
1579
            deleted_nodes = self._packs_at_load - current_nodes
 
1580
            new_nodes = current_nodes - self._packs_at_load
 
1581
            disk_nodes.difference_update(deleted_nodes)
 
1582
            disk_nodes.update(new_nodes)
 
1583
            # TODO: handle same-name, index-size-changes here - 
 
1584
            # e.g. use the value from disk, not ours, *unless* we're the one
 
1585
            # changing it.
 
1586
            for key, value in disk_nodes:
 
1587
                builder.add_node(key, value)
 
1588
            self.transport.put_file('pack-names', builder.finish(),
 
1589
                mode=self.repo.bzrdir._get_file_mode())
 
1590
            # move the baseline forward
 
1591
            self._packs_at_load = disk_nodes
 
1592
            if clear_obsolete_packs:
 
1593
                self._clear_obsolete_packs()
 
1594
        finally:
 
1595
            self._unlock_names()
 
1596
        # synchronise the memory packs list with what we just wrote:
1617
1597
        new_names = dict(disk_nodes)
1618
1598
        # drop no longer present nodes
1619
1599
        for pack in self.all_packs():
1620
1600
            if (pack.name,) not in new_names:
1621
 
                removed.append(pack.name)
1622
1601
                self._remove_pack_from_memory(pack)
1623
1602
        # add new nodes/refresh existing ones
1624
1603
        for key, value in disk_nodes:
1638
1617
                    self._remove_pack_from_memory(self.get_pack_by_name(name))
1639
1618
                    self._names[name] = sizes
1640
1619
                    self.get_pack_by_name(name)
1641
 
                    modified.append(name)
1642
1620
            else:
1643
1621
                # new
1644
1622
                self._names[name] = sizes
1645
1623
                self.get_pack_by_name(name)
1646
 
                added.append(name)
1647
 
        return removed, added, modified
1648
 
 
1649
 
    def _save_pack_names(self, clear_obsolete_packs=False):
1650
 
        """Save the list of packs.
1651
 
 
1652
 
        This will take out the mutex around the pack names list for the
1653
 
        duration of the method call. If concurrent updates have been made, a
1654
 
        three-way merge between the current list and the current in memory list
1655
 
        is performed.
1656
 
 
1657
 
        :param clear_obsolete_packs: If True, clear out the contents of the
1658
 
            obsolete_packs directory.
1659
 
        """
1660
 
        self.lock_names()
1661
 
        try:
1662
 
            builder = self._index_builder_class()
1663
 
            disk_nodes, deleted_nodes, new_nodes = self._diff_pack_names()
1664
 
            # TODO: handle same-name, index-size-changes here - 
1665
 
            # e.g. use the value from disk, not ours, *unless* we're the one
1666
 
            # changing it.
1667
 
            for key, value in disk_nodes:
1668
 
                builder.add_node(key, value)
1669
 
            self.transport.put_file('pack-names', builder.finish(),
1670
 
                mode=self.repo.bzrdir._get_file_mode())
1671
 
            # move the baseline forward
1672
 
            self._packs_at_load = disk_nodes
1673
 
            if clear_obsolete_packs:
1674
 
                self._clear_obsolete_packs()
1675
 
        finally:
1676
 
            self._unlock_names()
1677
 
        # synchronise the memory packs list with what we just wrote:
1678
 
        self._syncronize_pack_names_from_disk_nodes(disk_nodes)
1679
 
 
1680
 
    def reload_pack_names(self):
1681
 
        """Sync our pack listing with what is present in the repository.
1682
 
 
1683
 
        This should be called when we find out that something we thought was
1684
 
        present is now missing. This happens when another process re-packs the
1685
 
        repository, etc.
1686
 
        """
1687
 
        # This is functionally similar to _save_pack_names, but we don't write
1688
 
        # out the new value.
1689
 
        disk_nodes, _, _ = self._diff_pack_names()
1690
 
        self._packs_at_load = disk_nodes
1691
 
        (removed, added,
1692
 
         modified) = self._syncronize_pack_names_from_disk_nodes(disk_nodes)
1693
 
        if removed or added or modified:
1694
 
            return True
1695
 
        return False
1696
1624
 
1697
1625
    def _clear_obsolete_packs(self):
1698
1626
        """Delete everything from the obsolete-packs directory.
1710
1638
            raise errors.NotWriteLocked(self)
1711
1639
        self._new_pack = NewPack(self._upload_transport, self._index_transport,
1712
1640
            self._pack_transport, upload_suffix='.pack',
1713
 
            file_mode=self.repo.bzrdir._get_file_mode(),
1714
 
            index_builder_class=self._index_builder_class,
1715
 
            index_class=self._index_class)
 
1641
            file_mode=self.repo.bzrdir._get_file_mode())
1716
1642
        # allow writing: queue writes to a new index
1717
1643
        self.revision_index.add_writable_index(self._new_pack.revision_index,
1718
1644
            self._new_pack)
1723
1649
        self.signature_index.add_writable_index(self._new_pack.signature_index,
1724
1650
            self._new_pack)
1725
1651
 
1726
 
        self.repo.inventories._index._add_callback = self.inventory_index.add_callback
1727
 
        self.repo.revisions._index._add_callback = self.revision_index.add_callback
1728
 
        self.repo.signatures._index._add_callback = self.signature_index.add_callback
1729
 
        self.repo.texts._index._add_callback = self.text_index.add_callback
 
1652
        # reused revision and signature knits may need updating
 
1653
        #
 
1654
        # "Hysterical raisins. client code in bzrlib grabs those knits outside
 
1655
        # of write groups and then mutates it inside the write group."
 
1656
        if self.repo._revision_knit is not None:
 
1657
            self.repo._revision_knit._index._add_callback = \
 
1658
                self.revision_index.add_callback
 
1659
        if self.repo._signature_knit is not None:
 
1660
            self.repo._signature_knit._index._add_callback = \
 
1661
                self.signature_index.add_callback
 
1662
        # create a reused knit object for text addition in commit.
 
1663
        self.repo._text_knit = self.repo.weave_store.get_weave_or_empty(
 
1664
            'all-texts', None)
1730
1665
 
1731
1666
    def _abort_write_group(self):
1732
1667
        # FIXME: just drop the transient index.
1754
1689
        self.repo._text_knit = None
1755
1690
 
1756
1691
 
 
1692
class KnitPackRevisionStore(KnitRevisionStore):
 
1693
    """An object to adapt access from RevisionStore's to use KnitPacks.
 
1694
 
 
1695
    This class works by replacing the original RevisionStore.
 
1696
    We need to do this because the KnitPackRevisionStore is less
 
1697
    isolated in its layering - it uses services from the repo.
 
1698
    """
 
1699
 
 
1700
    def __init__(self, repo, transport, revisionstore):
 
1701
        """Create a KnitPackRevisionStore on repo with revisionstore.
 
1702
 
 
1703
        This will store its state in the Repository, use the
 
1704
        indices to provide a KnitGraphIndex,
 
1705
        and at the end of transactions write new indices.
 
1706
        """
 
1707
        KnitRevisionStore.__init__(self, revisionstore.versioned_file_store)
 
1708
        self.repo = repo
 
1709
        self._serializer = revisionstore._serializer
 
1710
        self.transport = transport
 
1711
 
 
1712
    def get_revision_file(self, transaction):
 
1713
        """Get the revision versioned file object."""
 
1714
        if getattr(self.repo, '_revision_knit', None) is not None:
 
1715
            return self.repo._revision_knit
 
1716
        self.repo._pack_collection.ensure_loaded()
 
1717
        add_callback = self.repo._pack_collection.revision_index.add_callback
 
1718
        # setup knit specific objects
 
1719
        knit_index = KnitGraphIndex(
 
1720
            self.repo._pack_collection.revision_index.combined_index,
 
1721
            add_callback=add_callback)
 
1722
        self.repo._revision_knit = knit.KnitVersionedFile(
 
1723
            'revisions', self.transport.clone('..'),
 
1724
            self.repo.bzrdir._get_file_mode(),
 
1725
            create=False,
 
1726
            index=knit_index, delta=False, factory=knit.KnitPlainFactory(),
 
1727
            access_method=self.repo._pack_collection.revision_index.knit_access)
 
1728
        return self.repo._revision_knit
 
1729
 
 
1730
    def get_signature_file(self, transaction):
 
1731
        """Get the signature versioned file object."""
 
1732
        if getattr(self.repo, '_signature_knit', None) is not None:
 
1733
            return self.repo._signature_knit
 
1734
        self.repo._pack_collection.ensure_loaded()
 
1735
        add_callback = self.repo._pack_collection.signature_index.add_callback
 
1736
        # setup knit specific objects
 
1737
        knit_index = KnitGraphIndex(
 
1738
            self.repo._pack_collection.signature_index.combined_index,
 
1739
            add_callback=add_callback, parents=False)
 
1740
        self.repo._signature_knit = knit.KnitVersionedFile(
 
1741
            'signatures', self.transport.clone('..'),
 
1742
            self.repo.bzrdir._get_file_mode(),
 
1743
            create=False,
 
1744
            index=knit_index, delta=False, factory=knit.KnitPlainFactory(),
 
1745
            access_method=self.repo._pack_collection.signature_index.knit_access)
 
1746
        return self.repo._signature_knit
 
1747
 
 
1748
 
 
1749
class KnitPackTextStore(VersionedFileStore):
 
1750
    """Presents a TextStore abstraction on top of packs.
 
1751
 
 
1752
    This class works by replacing the original VersionedFileStore.
 
1753
    We need to do this because the KnitPackRevisionStore is less
 
1754
    isolated in its layering - it uses services from the repo and shares them
 
1755
    with all the data written in a single write group.
 
1756
    """
 
1757
 
 
1758
    def __init__(self, repo, transport, weavestore):
 
1759
        """Create a KnitPackTextStore on repo with weavestore.
 
1760
 
 
1761
        This will store its state in the Repository, use the
 
1762
        indices FileNames to provide a KnitGraphIndex,
 
1763
        and at the end of transactions write new indices.
 
1764
        """
 
1765
        # don't call base class constructor - it's not suitable.
 
1766
        # no transient data stored in the transaction
 
1767
        # cache.
 
1768
        self._precious = False
 
1769
        self.repo = repo
 
1770
        self.transport = transport
 
1771
        self.weavestore = weavestore
 
1772
        # XXX for check() which isn't updated yet
 
1773
        self._transport = weavestore._transport
 
1774
 
 
1775
    def get_weave_or_empty(self, file_id, transaction):
 
1776
        """Get a 'Knit' backed by the .tix indices.
 
1777
 
 
1778
        The transaction parameter is ignored.
 
1779
        """
 
1780
        self.repo._pack_collection.ensure_loaded()
 
1781
        add_callback = self.repo._pack_collection.text_index.add_callback
 
1782
        # setup knit specific objects
 
1783
        file_id_index = GraphIndexPrefixAdapter(
 
1784
            self.repo._pack_collection.text_index.combined_index,
 
1785
            (file_id, ), 1, add_nodes_callback=add_callback)
 
1786
        knit_index = KnitGraphIndex(file_id_index,
 
1787
            add_callback=file_id_index.add_nodes,
 
1788
            deltas=True, parents=True)
 
1789
        return knit.KnitVersionedFile('text:' + file_id,
 
1790
            self.transport.clone('..'),
 
1791
            None,
 
1792
            index=knit_index,
 
1793
            access_method=self.repo._pack_collection.text_index.knit_access,
 
1794
            factory=knit.KnitPlainFactory())
 
1795
 
 
1796
    get_weave = get_weave_or_empty
 
1797
 
 
1798
    def __iter__(self):
 
1799
        """Generate a list of the fileids inserted, for use by check."""
 
1800
        self.repo._pack_collection.ensure_loaded()
 
1801
        ids = set()
 
1802
        for index, key, value, refs in \
 
1803
            self.repo._pack_collection.text_index.combined_index.iter_all_entries():
 
1804
            ids.add(key[0])
 
1805
        return iter(ids)
 
1806
 
 
1807
 
 
1808
class InventoryKnitThunk(object):
 
1809
    """An object to manage thunking get_inventory_weave to pack based knits."""
 
1810
 
 
1811
    def __init__(self, repo, transport):
 
1812
        """Create an InventoryKnitThunk for repo at transport.
 
1813
 
 
1814
        This will store its state in the Repository, use the
 
1815
        indices FileNames to provide a KnitGraphIndex,
 
1816
        and at the end of transactions write a new index..
 
1817
        """
 
1818
        self.repo = repo
 
1819
        self.transport = transport
 
1820
 
 
1821
    def get_weave(self):
 
1822
        """Get a 'Knit' that contains inventory data."""
 
1823
        self.repo._pack_collection.ensure_loaded()
 
1824
        add_callback = self.repo._pack_collection.inventory_index.add_callback
 
1825
        # setup knit specific objects
 
1826
        knit_index = KnitGraphIndex(
 
1827
            self.repo._pack_collection.inventory_index.combined_index,
 
1828
            add_callback=add_callback, deltas=True, parents=True)
 
1829
        return knit.KnitVersionedFile(
 
1830
            'inventory', self.transport.clone('..'),
 
1831
            self.repo.bzrdir._get_file_mode(),
 
1832
            create=False,
 
1833
            index=knit_index, delta=True, factory=knit.KnitPlainFactory(),
 
1834
            access_method=self.repo._pack_collection.inventory_index.knit_access)
 
1835
 
 
1836
 
1757
1837
class KnitPackRepository(KnitRepository):
1758
 
    """Repository with knit objects stored inside pack containers.
1759
 
    
1760
 
    The layering for a KnitPackRepository is:
1761
 
 
1762
 
    Graph        |  HPSS    | Repository public layer |
1763
 
    ===================================================
1764
 
    Tuple based apis below, string based, and key based apis above
1765
 
    ---------------------------------------------------
1766
 
    KnitVersionedFiles
1767
 
      Provides .texts, .revisions etc
1768
 
      This adapts the N-tuple keys to physical knit records which only have a
1769
 
      single string identifier (for historical reasons), which in older formats
1770
 
      was always the revision_id, and in the mapped code for packs is always
1771
 
      the last element of key tuples.
1772
 
    ---------------------------------------------------
1773
 
    GraphIndex
1774
 
      A separate GraphIndex is used for each of the
1775
 
      texts/inventories/revisions/signatures contained within each individual
1776
 
      pack file. The GraphIndex layer works in N-tuples and is unaware of any
1777
 
      semantic value.
1778
 
    ===================================================
1779
 
    
1780
 
    """
1781
 
 
1782
 
    def __init__(self, _format, a_bzrdir, control_files, _commit_builder_class,
1783
 
        _serializer):
 
1838
    """Repository with knit objects stored inside pack containers."""
 
1839
 
 
1840
    def __init__(self, _format, a_bzrdir, control_files, _revision_store,
 
1841
        control_store, text_store, _commit_builder_class, _serializer):
1784
1842
        KnitRepository.__init__(self, _format, a_bzrdir, control_files,
1785
 
            _commit_builder_class, _serializer)
 
1843
            _revision_store, control_store, text_store, _commit_builder_class,
 
1844
            _serializer)
1786
1845
        index_transport = self._transport.clone('indices')
1787
 
        self._pack_collection = RepositoryPackCollection(self, self._transport,
 
1846
        self._pack_collection = RepositoryPackCollection(self,
 
1847
            self._transport,
1788
1848
            index_transport,
1789
1849
            self._transport.clone('upload'),
1790
 
            self._transport.clone('packs'),
1791
 
            _format.index_builder_class,
1792
 
            _format.index_class)
1793
 
        self.inventories = KnitVersionedFiles(
1794
 
            _KnitGraphIndex(self._pack_collection.inventory_index.combined_index,
1795
 
                add_callback=self._pack_collection.inventory_index.add_callback,
1796
 
                deltas=True, parents=True, is_locked=self.is_locked),
1797
 
            data_access=self._pack_collection.inventory_index.data_access,
1798
 
            max_delta_chain=200)
1799
 
        self.revisions = KnitVersionedFiles(
1800
 
            _KnitGraphIndex(self._pack_collection.revision_index.combined_index,
1801
 
                add_callback=self._pack_collection.revision_index.add_callback,
1802
 
                deltas=False, parents=True, is_locked=self.is_locked),
1803
 
            data_access=self._pack_collection.revision_index.data_access,
1804
 
            max_delta_chain=0)
1805
 
        self.signatures = KnitVersionedFiles(
1806
 
            _KnitGraphIndex(self._pack_collection.signature_index.combined_index,
1807
 
                add_callback=self._pack_collection.signature_index.add_callback,
1808
 
                deltas=False, parents=False, is_locked=self.is_locked),
1809
 
            data_access=self._pack_collection.signature_index.data_access,
1810
 
            max_delta_chain=0)
1811
 
        self.texts = KnitVersionedFiles(
1812
 
            _KnitGraphIndex(self._pack_collection.text_index.combined_index,
1813
 
                add_callback=self._pack_collection.text_index.add_callback,
1814
 
                deltas=True, parents=True, is_locked=self.is_locked),
1815
 
            data_access=self._pack_collection.text_index.data_access,
1816
 
            max_delta_chain=200)
 
1850
            self._transport.clone('packs'))
 
1851
        self._revision_store = KnitPackRevisionStore(self, index_transport, self._revision_store)
 
1852
        self.weave_store = KnitPackTextStore(self, index_transport, self.weave_store)
 
1853
        self._inv_thunk = InventoryKnitThunk(self, index_transport)
1817
1854
        # True when the repository object is 'write locked' (as opposed to the
1818
1855
        # physical lock only taken out around changes to the pack-names list.) 
1819
1856
        # Another way to represent this would be a decorator around the control
1825
1862
        self._reconcile_does_inventory_gc = True
1826
1863
        self._reconcile_fixes_text_parents = True
1827
1864
        self._reconcile_backsup_inventory = False
1828
 
        self._fetch_order = 'unordered'
1829
 
 
1830
 
    def _warn_if_deprecated(self):
1831
 
        # This class isn't deprecated, but one sub-format is
1832
 
        if isinstance(self._format, RepositoryFormatKnitPack5RichRootBroken):
1833
 
            from bzrlib import repository
1834
 
            if repository._deprecation_warning_done:
1835
 
                return
1836
 
            repository._deprecation_warning_done = True
1837
 
            warning("Format %s for %s is deprecated - please use"
1838
 
                    " 'bzr upgrade --1.6.1-rich-root'"
1839
 
                    % (self._format, self.bzrdir.transport.base))
1840
1865
 
1841
1866
    def _abort_write_group(self):
1842
1867
        self._pack_collection._abort_write_group()
1887
1912
        parent_map = self.get_parent_map(revision_ids)
1888
1913
        return [parent_map.get(r, None) for r in revision_ids]
1889
1914
 
 
1915
    def get_parent_map(self, keys):
 
1916
        """See graph._StackedParentsProvider.get_parent_map
 
1917
 
 
1918
        This implementation accesses the combined revision index to provide
 
1919
        answers.
 
1920
        """
 
1921
        self._pack_collection.ensure_loaded()
 
1922
        index = self._pack_collection.revision_index.combined_index
 
1923
        keys = set(keys)
 
1924
        if None in keys:
 
1925
            raise ValueError('get_parent_map(None) is not valid')
 
1926
        if _mod_revision.NULL_REVISION in keys:
 
1927
            keys.discard(_mod_revision.NULL_REVISION)
 
1928
            found_parents = {_mod_revision.NULL_REVISION:()}
 
1929
        else:
 
1930
            found_parents = {}
 
1931
        search_keys = set((revision_id,) for revision_id in keys)
 
1932
        for index, key, value, refs in index.iter_entries(search_keys):
 
1933
            parents = refs[0]
 
1934
            if not parents:
 
1935
                parents = (_mod_revision.NULL_REVISION,)
 
1936
            else:
 
1937
                parents = tuple(parent[0] for parent in parents)
 
1938
            found_parents[key[0]] = parents
 
1939
        return found_parents
 
1940
 
 
1941
    def has_revisions(self, revision_ids):
 
1942
        """See Repository.has_revisions()."""
 
1943
        revision_ids = set(revision_ids)
 
1944
        result = revision_ids.intersection(
 
1945
            set([None, _mod_revision.NULL_REVISION]))
 
1946
        revision_ids.difference_update(result)
 
1947
        index = self._pack_collection.revision_index.combined_index
 
1948
        keys = [(revision_id,) for revision_id in revision_ids]
 
1949
        result.update(node[1][0] for node in index.iter_entries(keys))
 
1950
        return result
 
1951
 
1890
1952
    def _make_parents_provider(self):
1891
1953
        return graph.CachingParentsProvider(self)
1892
1954
 
1906
1968
    def _commit_write_group(self):
1907
1969
        return self._pack_collection._commit_write_group()
1908
1970
 
 
1971
    def get_inventory_weave(self):
 
1972
        return self._inv_thunk.get_weave()
 
1973
 
1909
1974
    def get_transaction(self):
1910
1975
        if self._write_lock_count:
1911
1976
            return self._transaction
1923
1988
            raise errors.ReadOnlyError(self)
1924
1989
        self._write_lock_count += 1
1925
1990
        if self._write_lock_count == 1:
 
1991
            from bzrlib import transactions
1926
1992
            self._transaction = transactions.WriteTransaction()
1927
 
            for repo in self._fallback_repositories:
1928
 
                # Writes don't affect fallback repos
1929
 
                repo.lock_read()
1930
1993
        self._refresh_data()
1931
1994
 
1932
1995
    def lock_read(self):
1934
1997
            self._write_lock_count += 1
1935
1998
        else:
1936
1999
            self.control_files.lock_read()
1937
 
            for repo in self._fallback_repositories:
1938
 
                # Writes don't affect fallback repos
1939
 
                repo.lock_read()
1940
2000
        self._refresh_data()
1941
2001
 
1942
2002
    def leave_lock_in_place(self):
1978
2038
                transaction = self._transaction
1979
2039
                self._transaction = None
1980
2040
                transaction.finish()
1981
 
                for repo in self._fallback_repositories:
1982
 
                    repo.unlock()
1983
2041
        else:
1984
2042
            self.control_files.unlock()
1985
 
            for repo in self._fallback_repositories:
1986
 
                repo.unlock()
1987
2043
 
1988
2044
 
1989
2045
class RepositoryFormatPack(MetaDirRepositoryFormat):
2013
2069
    _serializer = None
2014
2070
    # External references are not supported in pack repositories yet.
2015
2071
    supports_external_lookups = False
2016
 
    # What index classes to use
2017
 
    index_builder_class = None
2018
 
    index_class = None
 
2072
 
 
2073
    def _get_control_store(self, repo_transport, control_files):
 
2074
        """Return the control store for this repository."""
 
2075
        return VersionedFileStore(
 
2076
            repo_transport,
 
2077
            prefixed=False,
 
2078
            file_mode=control_files._file_mode,
 
2079
            versionedfile_class=knit.make_file_knit,
 
2080
            versionedfile_kwargs={'factory': knit.KnitPlainFactory()},
 
2081
            )
 
2082
 
 
2083
    def _get_revision_store(self, repo_transport, control_files):
 
2084
        """See RepositoryFormat._get_revision_store()."""
 
2085
        versioned_file_store = VersionedFileStore(
 
2086
            repo_transport,
 
2087
            file_mode=control_files._file_mode,
 
2088
            prefixed=False,
 
2089
            precious=True,
 
2090
            versionedfile_class=knit.make_file_knit,
 
2091
            versionedfile_kwargs={'delta': False,
 
2092
                                  'factory': knit.KnitPlainFactory(),
 
2093
                                 },
 
2094
            escaped=True,
 
2095
            )
 
2096
        return KnitRevisionStore(versioned_file_store)
 
2097
 
 
2098
    def _get_text_store(self, transport, control_files):
 
2099
        """See RepositoryFormat._get_text_store()."""
 
2100
        return self._get_versioned_file_store('knits',
 
2101
                                  transport,
 
2102
                                  control_files,
 
2103
                                  versionedfile_class=knit.make_file_knit,
 
2104
                                  versionedfile_kwargs={
 
2105
                                      'create_parent_dir': True,
 
2106
                                      'delay_create': True,
 
2107
                                      'dir_mode': control_files._dir_mode,
 
2108
                                  },
 
2109
                                  escaped=True)
2019
2110
 
2020
2111
    def initialize(self, a_bzrdir, shared=False):
2021
2112
        """Create a pack based repository.
2027
2118
        """
2028
2119
        mutter('creating repository in %s.', a_bzrdir.transport.base)
2029
2120
        dirs = ['indices', 'obsolete_packs', 'packs', 'upload']
2030
 
        builder = self.index_builder_class()
 
2121
        builder = GraphIndexBuilder()
2031
2122
        files = [('pack-names', builder.finish())]
2032
2123
        utf8_files = [('format', self.get_format_string())]
2033
2124
        
2048
2139
        else:
2049
2140
            repo_transport = a_bzrdir.get_repository_transport(None)
2050
2141
        control_files = lockable_files.LockableFiles(repo_transport,
2051
 
                                'lock', lockdir.LockDir)
 
2142
            'lock', lockdir.LockDir)
 
2143
        text_store = self._get_text_store(repo_transport, control_files)
 
2144
        control_store = self._get_control_store(repo_transport, control_files)
 
2145
        _revision_store = self._get_revision_store(repo_transport, control_files)
2052
2146
        return self.repository_class(_format=self,
2053
2147
                              a_bzrdir=a_bzrdir,
2054
2148
                              control_files=control_files,
 
2149
                              _revision_store=_revision_store,
 
2150
                              control_store=control_store,
 
2151
                              text_store=text_store,
2055
2152
                              _commit_builder_class=self._commit_builder_class,
2056
2153
                              _serializer=self._serializer)
2057
2154
 
2064
2161
 
2065
2162
    repository_class = KnitPackRepository
2066
2163
    _commit_builder_class = PackCommitBuilder
2067
 
    @property
2068
 
    def _serializer(self):
2069
 
        return xml5.serializer_v5
2070
 
    # What index classes to use
2071
 
    index_builder_class = InMemoryGraphIndex
2072
 
    index_class = GraphIndex
 
2164
    _serializer = xml5.serializer_v5
2073
2165
 
2074
2166
    def _get_matching_bzrdir(self):
2075
2167
        return bzrdir.format_registry.make_bzrdir('pack-0.92')
2105
2197
    _commit_builder_class = PackRootCommitBuilder
2106
2198
    rich_root_data = True
2107
2199
    supports_tree_reference = True
2108
 
    @property
2109
 
    def _serializer(self):
2110
 
        return xml7.serializer_v7
2111
 
    # What index classes to use
2112
 
    index_builder_class = InMemoryGraphIndex
2113
 
    index_class = GraphIndex
 
2200
    _serializer = xml7.serializer_v7
2114
2201
 
2115
2202
    def _get_matching_bzrdir(self):
2116
2203
        return bzrdir.format_registry.make_bzrdir(
2151
2238
    _commit_builder_class = PackRootCommitBuilder
2152
2239
    rich_root_data = True
2153
2240
    supports_tree_reference = False
2154
 
    @property
2155
 
    def _serializer(self):
2156
 
        return xml6.serializer_v6
2157
 
    # What index classes to use
2158
 
    index_builder_class = InMemoryGraphIndex
2159
 
    index_class = GraphIndex
 
2241
    _serializer = xml6.serializer_v6
2160
2242
 
2161
2243
    def _get_matching_bzrdir(self):
2162
2244
        return bzrdir.format_registry.make_bzrdir(
2182
2264
        return "Packs containing knits with rich root support\n"
2183
2265
 
2184
2266
 
2185
 
class RepositoryFormatKnitPack5(RepositoryFormatPack):
2186
 
    """Repository that supports external references to allow stacking.
2187
 
 
2188
 
    New in release 1.6.
2189
 
 
2190
 
    Supports external lookups, which results in non-truncated ghosts after
2191
 
    reconcile compared to pack-0.92 formats.
2192
 
    """
2193
 
 
2194
 
    repository_class = KnitPackRepository
2195
 
    _commit_builder_class = PackCommitBuilder
2196
 
    supports_external_lookups = True
2197
 
    # What index classes to use
2198
 
    index_builder_class = InMemoryGraphIndex
2199
 
    index_class = GraphIndex
2200
 
 
2201
 
    @property
2202
 
    def _serializer(self):
2203
 
        return xml5.serializer_v5
2204
 
 
2205
 
    def _get_matching_bzrdir(self):
2206
 
        return bzrdir.format_registry.make_bzrdir('1.6')
2207
 
 
2208
 
    def _ignore_setting_bzrdir(self, format):
2209
 
        pass
2210
 
 
2211
 
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
2212
 
 
2213
 
    def get_format_string(self):
2214
 
        """See RepositoryFormat.get_format_string()."""
2215
 
        return "Bazaar RepositoryFormatKnitPack5 (bzr 1.6)\n"
2216
 
 
2217
 
    def get_format_description(self):
2218
 
        """See RepositoryFormat.get_format_description()."""
2219
 
        return "Packs 5 (adds stacking support, requires bzr 1.6)"
2220
 
 
2221
 
    def check_conversion_target(self, target_format):
2222
 
        pass
2223
 
 
2224
 
 
2225
 
class RepositoryFormatKnitPack5RichRoot(RepositoryFormatPack):
2226
 
    """A repository with rich roots and stacking.
2227
 
 
2228
 
    New in release 1.6.1.
2229
 
 
2230
 
    Supports stacking on other repositories, allowing data to be accessed
2231
 
    without being stored locally.
2232
 
    """
2233
 
 
2234
 
    repository_class = KnitPackRepository
2235
 
    _commit_builder_class = PackRootCommitBuilder
2236
 
    rich_root_data = True
2237
 
    supports_tree_reference = False # no subtrees
2238
 
    supports_external_lookups = True
2239
 
    # What index classes to use
2240
 
    index_builder_class = InMemoryGraphIndex
2241
 
    index_class = GraphIndex
2242
 
 
2243
 
    @property
2244
 
    def _serializer(self):
2245
 
        return xml6.serializer_v6
2246
 
 
2247
 
    def _get_matching_bzrdir(self):
2248
 
        return bzrdir.format_registry.make_bzrdir(
2249
 
            '1.6.1-rich-root')
2250
 
 
2251
 
    def _ignore_setting_bzrdir(self, format):
2252
 
        pass
2253
 
 
2254
 
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
2255
 
 
2256
 
    def check_conversion_target(self, target_format):
2257
 
        if not target_format.rich_root_data:
2258
 
            raise errors.BadConversionTarget(
2259
 
                'Does not support rich root data.', target_format)
2260
 
 
2261
 
    def get_format_string(self):
2262
 
        """See RepositoryFormat.get_format_string()."""
2263
 
        return "Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6.1)\n"
2264
 
 
2265
 
    def get_format_description(self):
2266
 
        return "Packs 5 rich-root (adds stacking support, requires bzr 1.6.1)"
2267
 
 
2268
 
 
2269
 
class RepositoryFormatKnitPack5RichRootBroken(RepositoryFormatPack):
2270
 
    """A repository with rich roots and external references.
2271
 
 
2272
 
    New in release 1.6.
2273
 
 
2274
 
    Supports external lookups, which results in non-truncated ghosts after
2275
 
    reconcile compared to pack-0.92 formats.
2276
 
 
2277
 
    This format was deprecated because the serializer it uses accidentally
2278
 
    supported subtrees, when the format was not intended to. This meant that
2279
 
    someone could accidentally fetch from an incorrect repository.
2280
 
    """
2281
 
 
2282
 
    repository_class = KnitPackRepository
2283
 
    _commit_builder_class = PackRootCommitBuilder
2284
 
    rich_root_data = True
2285
 
    supports_tree_reference = False # no subtrees
2286
 
 
2287
 
    supports_external_lookups = True
2288
 
    # What index classes to use
2289
 
    index_builder_class = InMemoryGraphIndex
2290
 
    index_class = GraphIndex
2291
 
 
2292
 
    @property
2293
 
    def _serializer(self):
2294
 
        return xml7.serializer_v7
2295
 
 
2296
 
    def _get_matching_bzrdir(self):
2297
 
        return bzrdir.format_registry.make_bzrdir(
2298
 
            '1.6.1-rich-root')
2299
 
 
2300
 
    def _ignore_setting_bzrdir(self, format):
2301
 
        pass
2302
 
 
2303
 
    _matchingbzrdir = property(_get_matching_bzrdir, _ignore_setting_bzrdir)
2304
 
 
2305
 
    def check_conversion_target(self, target_format):
2306
 
        if not target_format.rich_root_data:
2307
 
            raise errors.BadConversionTarget(
2308
 
                'Does not support rich root data.', target_format)
2309
 
 
2310
 
    def get_format_string(self):
2311
 
        """See RepositoryFormat.get_format_string()."""
2312
 
        return "Bazaar RepositoryFormatKnitPack5RichRoot (bzr 1.6)\n"
2313
 
 
2314
 
    def get_format_description(self):
2315
 
        return ("Packs 5 rich-root (adds stacking support, requires bzr 1.6)"
2316
 
                " (deprecated)")
2317
 
 
2318
 
 
2319
 
class RepositoryFormatPackDevelopment2(RepositoryFormatPack):
 
2267
class RepositoryFormatPackDevelopment0(RepositoryFormatPack):
2320
2268
    """A no-subtrees development repository.
2321
2269
 
2322
 
    This format should be retained until the second release after bzr 1.7.
 
2270
    This format should be retained until the second release after bzr 1.0.
2323
2271
 
2324
 
    This is pack-1.6.1 with B+Tree indices.
 
2272
    No changes to the disk behaviour from pack-0.92.
2325
2273
    """
2326
2274
 
2327
2275
    repository_class = KnitPackRepository
2328
2276
    _commit_builder_class = PackCommitBuilder
2329
 
    supports_external_lookups = True
2330
 
    # What index classes to use
2331
 
    index_builder_class = BTreeBuilder
2332
 
    index_class = BTreeGraphIndex
2333
 
 
2334
 
    @property
2335
 
    def _serializer(self):
2336
 
        return xml5.serializer_v5
 
2277
    _serializer = xml5.serializer_v5
2337
2278
 
2338
2279
    def _get_matching_bzrdir(self):
2339
 
        return bzrdir.format_registry.make_bzrdir('development2')
 
2280
        return bzrdir.format_registry.make_bzrdir('development0')
2340
2281
 
2341
2282
    def _ignore_setting_bzrdir(self, format):
2342
2283
        pass
2345
2286
 
2346
2287
    def get_format_string(self):
2347
2288
        """See RepositoryFormat.get_format_string()."""
2348
 
        return "Bazaar development format 2 (needs bzr.dev from before 1.8)\n"
 
2289
        return "Bazaar development format 0 (needs bzr.dev from before 1.3)\n"
2349
2290
 
2350
2291
    def get_format_description(self):
2351
2292
        """See RepositoryFormat.get_format_description()."""
2352
2293
        return ("Development repository format, currently the same as "
2353
 
            "1.6.1 with B+Trees.\n")
 
2294
            "pack-0.92\n")
2354
2295
 
2355
2296
    def check_conversion_target(self, target_format):
2356
2297
        pass
2357
2298
 
2358
2299
 
2359
 
class RepositoryFormatPackDevelopment2Subtree(RepositoryFormatPack):
 
2300
class RepositoryFormatPackDevelopment0Subtree(RepositoryFormatPack):
2360
2301
    """A subtrees development repository.
2361
2302
 
2362
 
    This format should be retained until the second release after bzr 1.7.
 
2303
    This format should be retained until the second release after bzr 1.0.
2363
2304
 
2364
 
    1.6.1-subtree[as it might have been] with B+Tree indices.
 
2305
    No changes to the disk behaviour from pack-0.92-subtree.
2365
2306
    """
2366
2307
 
2367
2308
    repository_class = KnitPackRepository
2368
2309
    _commit_builder_class = PackRootCommitBuilder
2369
2310
    rich_root_data = True
2370
2311
    supports_tree_reference = True
2371
 
    supports_external_lookups = True
2372
 
    # What index classes to use
2373
 
    index_builder_class = BTreeBuilder
2374
 
    index_class = BTreeGraphIndex
2375
 
 
2376
 
    @property
2377
 
    def _serializer(self):
2378
 
        return xml7.serializer_v7
 
2312
    _serializer = xml7.serializer_v7
2379
2313
 
2380
2314
    def _get_matching_bzrdir(self):
2381
2315
        return bzrdir.format_registry.make_bzrdir(
2382
 
            'development2-subtree')
 
2316
            'development0-subtree')
2383
2317
 
2384
2318
    def _ignore_setting_bzrdir(self, format):
2385
2319
        pass
2396
2330
            
2397
2331
    def get_format_string(self):
2398
2332
        """See RepositoryFormat.get_format_string()."""
2399
 
        return ("Bazaar development format 2 with subtree support "
2400
 
            "(needs bzr.dev from before 1.8)\n")
 
2333
        return ("Bazaar development format 0 with subtree support "
 
2334
            "(needs bzr.dev from before 1.3)\n")
2401
2335
 
2402
2336
    def get_format_description(self):
2403
2337
        """See RepositoryFormat.get_format_description()."""
2404
2338
        return ("Development repository format, currently the same as "
2405
 
            "1.6.1-subtree with B+Tree indices.\n")
 
2339
            "pack-0.92-subtree\n")
 
2340
 
 
2341