~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-02 20:16:03 UTC
  • mto: This revision was merged to the branch mainline in revision 5694.
  • Revision ID: gzlist@googlemail.com-20110302201603-4tf70q41xu1756lh
Gut smart.message._translate_error as it duplicates logic in remote

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
 
2340
2363
        return self._write_lock_count
2341
2364
 
2342
2365
    def lock_write(self, token=None):
 
2366
        """Lock the repository for writes.
 
2367
 
 
2368
        :return: A bzrlib.repository.RepositoryWriteLockResult.
 
2369
        """
2343
2370
        locked = self.is_locked()
2344
2371
        if not self._write_lock_count and locked:
2345
2372
            raise errors.ReadOnlyError(self)
2354
2381
                # Writes don't affect fallback repos
2355
2382
                repo.lock_read()
2356
2383
            self._refresh_data()
 
2384
        return RepositoryWriteLockResult(self.unlock, None)
2357
2385
 
2358
2386
    def lock_read(self):
 
2387
        """Lock the repository for reads.
 
2388
 
 
2389
        :return: A bzrlib.lock.LogicalLockResult.
 
2390
        """
2359
2391
        locked = self.is_locked()
2360
2392
        if self._write_lock_count:
2361
2393
            self._write_lock_count += 1
2368
2400
            for repo in self._fallback_repositories:
2369
2401
                repo.lock_read()
2370
2402
            self._refresh_data()
 
2403
        return LogicalLockResult(self.unlock)
2371
2404
 
2372
2405
    def leave_lock_in_place(self):
2373
2406
        # not supported - raise an error
2442
2475
        from_repo = self.from_repository
2443
2476
        parent_ids = from_repo._find_parent_ids_of_revisions(revision_ids)
2444
2477
        parent_keys = [(p,) for p in parent_ids]
2445
 
        find_text_keys = from_repo._find_text_key_references_from_xml_inventory_lines
 
2478
        find_text_keys = from_repo._serializer._find_text_key_references
2446
2479
        parent_text_keys = set(find_text_keys(
2447
2480
            from_repo._inventory_xml_lines_for_keys(parent_keys)))
2448
2481
        content_text_keys = set()
2817
2850
    _commit_builder_class = PackCommitBuilder
2818
2851
    supports_external_lookups = True
2819
2852
    # What index classes to use
2820
 
    index_builder_class = BTreeBuilder
2821
 
    index_class = BTreeGraphIndex
 
2853
    index_builder_class = btree_index.BTreeBuilder
 
2854
    index_class = btree_index.BTreeGraphIndex
2822
2855
 
2823
2856
    @property
2824
2857
    def _serializer(self):
2853
2886
    supports_tree_reference = False # no subtrees
2854
2887
    supports_external_lookups = True
2855
2888
    # What index classes to use
2856
 
    index_builder_class = BTreeBuilder
2857
 
    index_class = BTreeGraphIndex
 
2889
    index_builder_class = btree_index.BTreeBuilder
 
2890
    index_class = btree_index.BTreeGraphIndex
2858
2891
 
2859
2892
    @property
2860
2893
    def _serializer(self):
2880
2913
class RepositoryFormatPackDevelopment2Subtree(RepositoryFormatPack):
2881
2914
    """A subtrees development repository.
2882
2915
 
2883
 
    This format should be retained until the second release after bzr 1.7.
 
2916
    This format should be retained in 2.3, to provide an upgrade path from this
 
2917
    to RepositoryFormat2aSubtree.  It can be removed in later releases.
2884
2918
 
2885
2919
    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
2920
    """
2890
2921
 
2891
2922
    repository_class = KnitPackRepository
2895
2926
    supports_tree_reference = True
2896
2927
    supports_external_lookups = True
2897
2928
    # What index classes to use
2898
 
    index_builder_class = BTreeBuilder
2899
 
    index_class = BTreeGraphIndex
 
2929
    index_builder_class = btree_index.BTreeBuilder
 
2930
    index_class = btree_index.BTreeGraphIndex
2900
2931
 
2901
2932
    @property
2902
2933
    def _serializer(self):
2904
2935
 
2905
2936
    def _get_matching_bzrdir(self):
2906
2937
        return bzrdir.format_registry.make_bzrdir(
2907
 
            'development-subtree')
 
2938
            'development5-subtree')
2908
2939
 
2909
2940
    def _ignore_setting_bzrdir(self, format):
2910
2941
        pass
2921
2952
        return ("Development repository format, currently the same as "
2922
2953
            "1.6.1-subtree with B+Tree indices.\n")
2923
2954
 
 
2955
 
 
2956
class RetryPackOperations(errors.RetryWithNewPacks):
 
2957
    """Raised when we are packing and we find a missing file.
 
2958
 
 
2959
    Meant as a signaling exception, to tell the RepositoryPackCollection.pack
 
2960
    code it should try again.
 
2961
    """
 
2962
 
 
2963
    internal_error = True
 
2964
 
 
2965
    _fmt = ("Pack files have changed, reload and try pack again."
 
2966
            " context: %(context)s %(orig_error)s")
 
2967
 
 
2968