~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repofmt/pack_repo.py

  • Committer: Martin
  • Date: 2011-03-20 18:58:43 UTC
  • mto: This revision was merged to the branch mainline in revision 5731.
  • Revision ID: gzlist@googlemail.com-20110320185843-qn8g96slbc33yw9h
Non-code fixes noticed looking at full diff

Show diffs side-by-side

added added

removed removed

Lines of Context:
49
49
""")
50
50
from bzrlib import (
51
51
    bzrdir,
 
52
    btree_index,
52
53
    errors,
53
54
    lockable_files,
54
55
    lockdir,
56
57
    )
57
58
 
58
59
from bzrlib.decorators import needs_write_lock, only_raises
59
 
from bzrlib.btree_index import (
60
 
    BTreeGraphIndex,
61
 
    BTreeBuilder,
62
 
    )
63
60
from bzrlib.index import (
64
61
    GraphIndex,
65
62
    InMemoryGraphIndex,
66
63
    )
 
64
from bzrlib.lock import LogicalLockResult
67
65
from bzrlib.repofmt.knitrepo import KnitRepository
68
66
from bzrlib.repository import (
69
67
    CommitBuilder,
70
68
    MetaDirRepositoryFormat,
71
69
    RepositoryFormat,
 
70
    RepositoryWriteLockResult,
72
71
    RootCommitBuilder,
73
72
    StreamSource,
74
73
    )
229
228
        unlimited_cache = False
230
229
        if index_type == 'chk':
231
230
            unlimited_cache = True
232
 
        setattr(self, index_type + '_index',
233
 
            self.index_class(self.index_transport,
234
 
                self.index_name(index_type, self.name),
235
 
                self.index_sizes[self.index_offset(index_type)],
236
 
                unlimited_cache=unlimited_cache))
 
231
        index = self.index_class(self.index_transport,
 
232
                    self.index_name(index_type, self.name),
 
233
                    self.index_sizes[self.index_offset(index_type)],
 
234
                    unlimited_cache=unlimited_cache)
 
235
        if index_type == 'chk':
 
236
            index._leaf_factory = btree_index._gcchk_factory
 
237
        setattr(self, index_type + '_index', index)
237
238
 
238
239
 
239
240
class ExistingPack(Pack):
721
722
        :return: A Pack object, or None if nothing was copied.
722
723
        """
723
724
        # open a pack - using the same name as the last temporary file
724
 
        # - which has already been flushed, so its safe.
 
725
        # - which has already been flushed, so it's safe.
725
726
        # XXX: - duplicate code warning with start_write_group; fix before
726
727
        #      considering 'done'.
727
728
        if self._pack_collection._new_pack is not None:
1221
1222
    def _process_inventory_lines(self, inv_lines):
1222
1223
        """Generate a text key reference map rather for reconciling with."""
1223
1224
        repo = self._pack_collection.repo
1224
 
        refs = repo._find_text_key_references_from_xml_inventory_lines(
1225
 
            inv_lines)
 
1225
        refs = repo._serializer._find_text_key_references(inv_lines)
1226
1226
        self._text_refs = refs
1227
1227
        # during reconcile we:
1228
1228
        #  - convert unreferenced texts to full texts
1291
1291
        # reinserted, and if d3 has incorrect parents it will also be
1292
1292
        # reinserted. If we insert d3 first, d2 is present (as it was bulk
1293
1293
        # copied), so we will try to delta, but d2 is not currently able to be
1294
 
        # extracted because it's basis d1 is not present. Topologically sorting
 
1294
        # extracted because its basis d1 is not present. Topologically sorting
1295
1295
        # addresses this. The following generates a sort for all the texts that
1296
1296
        # are being inserted without having to reference the entire text key
1297
1297
        # space (we only topo sort the revisions, which is smaller).
1572
1572
        mutter('Packing repository %s, which has %d pack files, '
1573
1573
            'containing %d revisions with hint %r.', self, total_packs,
1574
1574
            total_revisions, hint)
 
1575
        while True:
 
1576
            try:
 
1577
                self._try_pack_operations(hint)
 
1578
            except RetryPackOperations:
 
1579
                continue
 
1580
            break
 
1581
 
 
1582
        if clean_obsolete_packs:
 
1583
            self._clear_obsolete_packs()
 
1584
 
 
1585
    def _try_pack_operations(self, hint):
 
1586
        """Calculate the pack operations based on the hint (if any), and
 
1587
        execute them.
 
1588
        """
1575
1589
        # determine which packs need changing
1576
1590
        pack_operations = [[0, []]]
1577
1591
        for pack in self.all_packs():
1580
1594
                # or this pack was included in the hint.
1581
1595
                pack_operations[-1][0] += pack.get_revision_count()
1582
1596
                pack_operations[-1][1].append(pack)
1583
 
        self._execute_pack_operations(pack_operations, OptimisingPacker)
1584
 
 
1585
 
        if clean_obsolete_packs:
1586
 
            self._clear_obsolete_packs()
 
1597
        self._execute_pack_operations(pack_operations, OptimisingPacker,
 
1598
            reload_func=self._restart_pack_operations)
1587
1599
 
1588
1600
    def plan_autopack_combinations(self, existing_packs, pack_distribution):
1589
1601
        """Plan a pack operation.
1599
1611
        pack_operations = [[0, []]]
1600
1612
        # plan out what packs to keep, and what to reorganise
1601
1613
        while len(existing_packs):
1602
 
            # take the largest pack, and if its less than the head of the
 
1614
            # take the largest pack, and if it's less than the head of the
1603
1615
            # distribution chart we will include its contents in the new pack
1604
 
            # for that position. If its larger, we remove its size from the
 
1616
            # for that position. If it's larger, we remove its size from the
1605
1617
            # distribution chart
1606
1618
            next_pack_rev_count, next_pack = existing_packs.pop(0)
1607
1619
            if next_pack_rev_count >= pack_distribution[0]:
1642
1654
 
1643
1655
        :return: True if the disk names had not been previously read.
1644
1656
        """
1645
 
        # NB: if you see an assertion error here, its probably access against
 
1657
        # NB: if you see an assertion error here, it's probably access against
1646
1658
        # an unlocked repo. Naughty.
1647
1659
        if not self.repo.is_locked():
1648
1660
            raise errors.ObjectNotLocked(self.repo)
1678
1690
            txt_index = self._make_index(name, '.tix')
1679
1691
            sig_index = self._make_index(name, '.six')
1680
1692
            if self.chk_index is not None:
1681
 
                chk_index = self._make_index(name, '.cix', unlimited_cache=True)
 
1693
                chk_index = self._make_index(name, '.cix', is_chk=True)
1682
1694
            else:
1683
1695
                chk_index = None
1684
1696
            result = ExistingPack(self._pack_transport, name, rev_index,
1704
1716
            sig_index = self._make_index(name, '.six', resume=True)
1705
1717
            if self.chk_index is not None:
1706
1718
                chk_index = self._make_index(name, '.cix', resume=True,
1707
 
                                             unlimited_cache=True)
 
1719
                                             is_chk=True)
1708
1720
            else:
1709
1721
                chk_index = None
1710
1722
            result = self.resumed_pack_factory(name, rev_index, inv_index,
1740
1752
        return self._index_class(self.transport, 'pack-names', None
1741
1753
                ).iter_all_entries()
1742
1754
 
1743
 
    def _make_index(self, name, suffix, resume=False, unlimited_cache=False):
 
1755
    def _make_index(self, name, suffix, resume=False, is_chk=False):
1744
1756
        size_offset = self._suffix_offsets[suffix]
1745
1757
        index_name = name + suffix
1746
1758
        if resume:
1749
1761
        else:
1750
1762
            transport = self._index_transport
1751
1763
            index_size = self._names[name][size_offset]
1752
 
        return self._index_class(transport, index_name, index_size,
1753
 
                                 unlimited_cache=unlimited_cache)
 
1764
        index = self._index_class(transport, index_name, index_size,
 
1765
                                  unlimited_cache=is_chk)
 
1766
        if is_chk and self._index_class is btree_index.BTreeGraphIndex: 
 
1767
            index._leaf_factory = btree_index._gcchk_factory
 
1768
        return index
1754
1769
 
1755
1770
    def _max_pack_count(self, total_revisions):
1756
1771
        """Return the maximum number of packs to use for total revisions.
1942
1957
                    # disk index because the set values are the same, unless
1943
1958
                    # the only index shows up as deleted by the set difference
1944
1959
                    # - which it may. Until there is a specific test for this,
1945
 
                    # assume its broken. RBC 20071017.
 
1960
                    # assume it's broken. RBC 20071017.
1946
1961
                    self._remove_pack_from_memory(self.get_pack_by_name(name))
1947
1962
                    self._names[name] = sizes
1948
1963
                    self.get_pack_by_name(name)
2013
2028
        """
2014
2029
        # The ensure_loaded call is to handle the case where the first call
2015
2030
        # made involving the collection was to reload_pack_names, where we 
2016
 
        # don't have a view of disk contents. Its a bit of a bandaid, and
2017
 
        # causes two reads of pack-names, but its a rare corner case not struck
2018
 
        # with regular push/pull etc.
 
2031
        # don't have a view of disk contents. It's a bit of a bandaid, and
 
2032
        # causes two reads of pack-names, but it's a rare corner case not
 
2033
        # struck with regular push/pull etc.
2019
2034
        first_read = self.ensure_loaded()
2020
2035
        if first_read:
2021
2036
            return True
2040
2055
            raise
2041
2056
        raise errors.RetryAutopack(self.repo, False, sys.exc_info())
2042
2057
 
 
2058
    def _restart_pack_operations(self):
 
2059
        """Reload the pack names list, and restart the autopack code."""
 
2060
        if not self.reload_pack_names():
 
2061
            # Re-raise the original exception, because something went missing
 
2062
            # and a restart didn't find it
 
2063
            raise
 
2064
        raise RetryPackOperations(self.repo, False, sys.exc_info())
 
2065
 
2043
2066
    def _clear_obsolete_packs(self, preserve=None):
2044
2067
        """Delete everything from the obsolete-packs directory.
2045
2068
 
2280
2303
        self._reconcile_fixes_text_parents = True
2281
2304
        self._reconcile_backsup_inventory = False
2282
2305
 
2283
 
    def _warn_if_deprecated(self, branch=None):
2284
 
        # This class isn't deprecated, but one sub-format is
2285
 
        if isinstance(self._format, RepositoryFormatKnitPack5RichRootBroken):
2286
 
            super(KnitPackRepository, self)._warn_if_deprecated(branch)
2287
 
 
2288
2306
    def _abort_write_group(self):
2289
2307
        self.revisions._index._key_dependencies.clear()
2290
2308
        self._pack_collection._abort_write_group()
2340
2358
        return self._write_lock_count
2341
2359
 
2342
2360
    def lock_write(self, token=None):
 
2361
        """Lock the repository for writes.
 
2362
 
 
2363
        :return: A bzrlib.repository.RepositoryWriteLockResult.
 
2364
        """
2343
2365
        locked = self.is_locked()
2344
2366
        if not self._write_lock_count and locked:
2345
2367
            raise errors.ReadOnlyError(self)
2354
2376
                # Writes don't affect fallback repos
2355
2377
                repo.lock_read()
2356
2378
            self._refresh_data()
 
2379
        return RepositoryWriteLockResult(self.unlock, None)
2357
2380
 
2358
2381
    def lock_read(self):
 
2382
        """Lock the repository for reads.
 
2383
 
 
2384
        :return: A bzrlib.lock.LogicalLockResult.
 
2385
        """
2359
2386
        locked = self.is_locked()
2360
2387
        if self._write_lock_count:
2361
2388
            self._write_lock_count += 1
2368
2395
            for repo in self._fallback_repositories:
2369
2396
                repo.lock_read()
2370
2397
            self._refresh_data()
 
2398
        return LogicalLockResult(self.unlock)
2371
2399
 
2372
2400
    def leave_lock_in_place(self):
2373
2401
        # not supported - raise an error
2442
2470
        from_repo = self.from_repository
2443
2471
        parent_ids = from_repo._find_parent_ids_of_revisions(revision_ids)
2444
2472
        parent_keys = [(p,) for p in parent_ids]
2445
 
        find_text_keys = from_repo._find_text_key_references_from_xml_inventory_lines
 
2473
        find_text_keys = from_repo._serializer._find_text_key_references
2446
2474
        parent_text_keys = set(find_text_keys(
2447
2475
            from_repo._inventory_xml_lines_for_keys(parent_keys)))
2448
2476
        content_text_keys = set()
2805
2833
        return ("Packs 5 rich-root (adds stacking support, requires bzr 1.6)"
2806
2834
                " (deprecated)")
2807
2835
 
 
2836
    def is_deprecated(self):
 
2837
        return True
 
2838
 
2808
2839
 
2809
2840
class RepositoryFormatKnitPack6(RepositoryFormatPack):
2810
2841
    """A repository with stacking and btree indexes,
2817
2848
    _commit_builder_class = PackCommitBuilder
2818
2849
    supports_external_lookups = True
2819
2850
    # What index classes to use
2820
 
    index_builder_class = BTreeBuilder
2821
 
    index_class = BTreeGraphIndex
 
2851
    index_builder_class = btree_index.BTreeBuilder
 
2852
    index_class = btree_index.BTreeGraphIndex
2822
2853
 
2823
2854
    @property
2824
2855
    def _serializer(self):
2853
2884
    supports_tree_reference = False # no subtrees
2854
2885
    supports_external_lookups = True
2855
2886
    # What index classes to use
2856
 
    index_builder_class = BTreeBuilder
2857
 
    index_class = BTreeGraphIndex
 
2887
    index_builder_class = btree_index.BTreeBuilder
 
2888
    index_class = btree_index.BTreeGraphIndex
2858
2889
 
2859
2890
    @property
2860
2891
    def _serializer(self):
2880
2911
class RepositoryFormatPackDevelopment2Subtree(RepositoryFormatPack):
2881
2912
    """A subtrees development repository.
2882
2913
 
2883
 
    This format should be retained until the second release after bzr 1.7.
 
2914
    This format should be retained in 2.3, to provide an upgrade path from this
 
2915
    to RepositoryFormat2aSubtree.  It can be removed in later releases.
2884
2916
 
2885
2917
    1.6.1-subtree[as it might have been] with B+Tree indices.
2886
 
 
2887
 
    This is [now] retained until we have a CHK based subtree format in
2888
 
    development.
2889
2918
    """
2890
2919
 
2891
2920
    repository_class = KnitPackRepository
2895
2924
    supports_tree_reference = True
2896
2925
    supports_external_lookups = True
2897
2926
    # What index classes to use
2898
 
    index_builder_class = BTreeBuilder
2899
 
    index_class = BTreeGraphIndex
 
2927
    index_builder_class = btree_index.BTreeBuilder
 
2928
    index_class = btree_index.BTreeGraphIndex
2900
2929
 
2901
2930
    @property
2902
2931
    def _serializer(self):
2904
2933
 
2905
2934
    def _get_matching_bzrdir(self):
2906
2935
        return bzrdir.format_registry.make_bzrdir(
2907
 
            'development-subtree')
 
2936
            'development5-subtree')
2908
2937
 
2909
2938
    def _ignore_setting_bzrdir(self, format):
2910
2939
        pass
2921
2950
        return ("Development repository format, currently the same as "
2922
2951
            "1.6.1-subtree with B+Tree indices.\n")
2923
2952
 
 
2953
 
 
2954
class RetryPackOperations(errors.RetryWithNewPacks):
 
2955
    """Raised when we are packing and we find a missing file.
 
2956
 
 
2957
    Meant as a signaling exception, to tell the RepositoryPackCollection.pack
 
2958
    code it should try again.
 
2959
    """
 
2960
 
 
2961
    internal_error = True
 
2962
 
 
2963
    _fmt = ("Pack files have changed, reload and try pack again."
 
2964
            " context: %(context)s %(orig_error)s")
 
2965
 
 
2966