/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

  • Committer: Robert Collins
  • Date: 2009-05-23 20:57:12 UTC
  • mfrom: (4371 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4441.
  • Revision ID: robertc@robertcollins.net-20090523205712-lcwbfqk6vwavinuv
MergeĀ .dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Knit versionedfile implementation.
18
18
 
299
299
            if self._network_bytes is None:
300
300
                self._create_network_bytes()
301
301
            return self._network_bytes
 
302
        if ('-ft-' in self.storage_kind and
 
303
            storage_kind in ('chunked', 'fulltext')):
 
304
            adapter_key = (self.storage_kind, 'fulltext')
 
305
            adapter_factory = adapter_registry.get(adapter_key)
 
306
            adapter = adapter_factory(None)
 
307
            bytes = adapter.get_bytes(self)
 
308
            if storage_kind == 'chunked':
 
309
                return [bytes]
 
310
            else:
 
311
                return bytes
302
312
        if self._knit is not None:
 
313
            # Not redundant with direct conversion above - that only handles
 
314
            # fulltext cases.
303
315
            if storage_kind == 'chunked':
304
316
                return self._knit.get_lines(self.key[0])
305
317
            elif storage_kind == 'fulltext':
943
955
                lines[-1] = lines[-1] + '\n'
944
956
                line_bytes += '\n'
945
957
 
946
 
        for element in key:
 
958
        for element in key[:-1]:
947
959
            if type(element) != str:
948
960
                raise TypeError("key contains non-strings: %r" % (key,))
 
961
        if key[-1] is None:
 
962
            key = key[:-1] + ('sha1:' + digest,)
 
963
        elif type(key[-1]) != str:
 
964
                raise TypeError("key contains non-strings: %r" % (key,))
949
965
        # Knit hunks are still last-element only
950
966
        version_id = key[-1]
951
967
        content = self._factory.make(lines, version_id)
1010
1026
    def _check_add(self, key, lines, random_id, check_content):
1011
1027
        """check that version_id and lines are safe to add."""
1012
1028
        version_id = key[-1]
1013
 
        if contains_whitespace(version_id):
1014
 
            raise InvalidRevisionId(version_id, self)
1015
 
        self.check_not_reserved_id(version_id)
 
1029
        if version_id is not None:
 
1030
            if contains_whitespace(version_id):
 
1031
                raise InvalidRevisionId(version_id, self)
 
1032
            self.check_not_reserved_id(version_id)
1016
1033
        # TODO: If random_id==False and the key is already present, we should
1017
1034
        # probably check that the existing content is identical to what is
1018
1035
        # being inserted, and otherwise raise an exception.  This would make
1597
1614
                # KnitVersionedFiles doesn't permit deltas (_max_delta_chain ==
1598
1615
                # 0) or because it depends on a base only present in the
1599
1616
                # fallback kvfs.
 
1617
                self._access.flush()
1600
1618
                try:
1601
1619
                    # Try getting a fulltext directly from the record.
1602
1620
                    bytes = record.get_bytes_as('fulltext')
1662
1680
         * If a requested key did not change any lines (or didn't have any
1663
1681
           lines), it may not be mentioned at all in the result.
1664
1682
 
 
1683
        :param pb: Progress bar supplied by caller.
1665
1684
        :return: An iterator over (line, key).
1666
1685
        """
1667
1686
        if pb is None:
2669
2688
        return key[:-1], key[-1]
2670
2689
 
2671
2690
 
 
2691
class _KeyRefs(object):
 
2692
 
 
2693
    def __init__(self):
 
2694
        # dict mapping 'key' to 'set of keys referring to that key'
 
2695
        self.refs = {}
 
2696
 
 
2697
    def add_references(self, key, refs):
 
2698
        # Record the new references
 
2699
        for referenced in refs:
 
2700
            try:
 
2701
                needed_by = self.refs[referenced]
 
2702
            except KeyError:
 
2703
                needed_by = self.refs[referenced] = set()
 
2704
            needed_by.add(key)
 
2705
        # Discard references satisfied by the new key
 
2706
        self.add_key(key)
 
2707
 
 
2708
    def get_unsatisfied_refs(self):
 
2709
        return self.refs.iterkeys()
 
2710
 
 
2711
    def add_key(self, key):
 
2712
        try:
 
2713
            del self.refs[key]
 
2714
        except KeyError:
 
2715
            # No keys depended on this key.  That's ok.
 
2716
            pass
 
2717
 
 
2718
    def add_keys(self, keys):
 
2719
        for key in keys:
 
2720
            self.add_key(key)
 
2721
 
 
2722
    def get_referrers(self):
 
2723
        result = set()
 
2724
        for referrers in self.refs.itervalues():
 
2725
            result.update(referrers)
 
2726
        return result
 
2727
 
 
2728
 
2672
2729
class _KnitGraphIndex(object):
2673
2730
    """A KnitVersionedFiles index layered on GraphIndex."""
2674
2731
 
2675
2732
    def __init__(self, graph_index, is_locked, deltas=False, parents=True,
2676
 
        add_callback=None):
 
2733
        add_callback=None, track_external_parent_refs=False):
2677
2734
        """Construct a KnitGraphIndex on a graph_index.
2678
2735
 
2679
2736
        :param graph_index: An implementation of bzrlib.index.GraphIndex.
2687
2744
            [(node, value, node_refs), ...]
2688
2745
        :param is_locked: A callback, returns True if the index is locked and
2689
2746
            thus usable.
 
2747
        :param track_external_parent_refs: If True, record all external parent
 
2748
            references parents from added records.  These can be retrieved
 
2749
            later by calling get_missing_parents().
2690
2750
        """
2691
2751
        self._add_callback = add_callback
2692
2752
        self._graph_index = graph_index
2700
2760
        self.has_graph = parents
2701
2761
        self._is_locked = is_locked
2702
2762
        self._missing_compression_parents = set()
 
2763
        if track_external_parent_refs:
 
2764
            self._key_dependencies = _KeyRefs()
 
2765
        else:
 
2766
            self._key_dependencies = None
2703
2767
 
2704
2768
    def __repr__(self):
2705
2769
        return "%s(%r)" % (self.__class__.__name__, self._graph_index)
2729
2793
 
2730
2794
        keys = {}
2731
2795
        compression_parents = set()
 
2796
        key_dependencies = self._key_dependencies
2732
2797
        for (key, options, access_memo, parents) in records:
2733
2798
            if self._parents:
2734
2799
                parents = tuple(parents)
 
2800
                if key_dependencies is not None:
 
2801
                    key_dependencies.add_references(key, parents)
2735
2802
            index, pos, size = access_memo
2736
2803
            if 'no-eol' in options:
2737
2804
                value = 'N'
2799
2866
            new_missing = graph_index.external_references(ref_list_num=1)
2800
2867
            new_missing.difference_update(self.get_parent_map(new_missing))
2801
2868
            self._missing_compression_parents.update(new_missing)
 
2869
        if self._key_dependencies is not None:
 
2870
            # Add parent refs from graph_index (and discard parent refs that
 
2871
            # the graph_index has).
 
2872
            for node in graph_index.iter_all_entries():
 
2873
                self._key_dependencies.add_references(node[1], node[3][0])
2802
2874
 
2803
2875
    def get_missing_compression_parents(self):
2804
2876
        """Return the keys of missing compression parents.
2808
2880
        """
2809
2881
        return frozenset(self._missing_compression_parents)
2810
2882
 
 
2883
    def get_missing_parents(self):
 
2884
        """Return the keys of missing parents."""
 
2885
        # We may have false positives, so filter those out.
 
2886
        self._key_dependencies.add_keys(
 
2887
            self.get_parent_map(self._key_dependencies.get_unsatisfied_refs()))
 
2888
        return frozenset(self._key_dependencies.get_unsatisfied_refs())
 
2889
 
2811
2890
    def _check_read(self):
2812
2891
        """raise if reads are not permitted."""
2813
2892
        if not self._is_locked():
3036
3115
            result.append((key, base, size))
3037
3116
        return result
3038
3117
 
 
3118
    def flush(self):
 
3119
        """Flush pending writes on this access object.
 
3120
        
 
3121
        For .knit files this is a no-op.
 
3122
        """
 
3123
        pass
 
3124
 
3039
3125
    def get_raw_records(self, memos_for_retrieval):
3040
3126
        """Get the raw bytes for a records.
3041
3127
 
3066
3152
class _DirectPackAccess(object):
3067
3153
    """Access to data in one or more packs with less translation."""
3068
3154
 
3069
 
    def __init__(self, index_to_packs, reload_func=None):
 
3155
    def __init__(self, index_to_packs, reload_func=None, flush_func=None):
3070
3156
        """Create a _DirectPackAccess object.
3071
3157
 
3072
3158
        :param index_to_packs: A dict mapping index objects to the transport
3079
3165
        self._write_index = None
3080
3166
        self._indices = index_to_packs
3081
3167
        self._reload_func = reload_func
 
3168
        self._flush_func = flush_func
3082
3169
 
3083
3170
    def add_raw_records(self, key_sizes, raw_data):
3084
3171
        """Add raw knit bytes to a storage area.
3106
3193
            result.append((self._write_index, p_offset, p_length))
3107
3194
        return result
3108
3195
 
 
3196
    def flush(self):
 
3197
        """Flush pending writes on this access object.
 
3198
 
 
3199
        This will flush any buffered writes to a NewPack.
 
3200
        """
 
3201
        if self._flush_func is not None:
 
3202
            self._flush_func()
 
3203
            
3109
3204
    def get_raw_records(self, memos_for_retrieval):
3110
3205
        """Get the raw bytes for a records.
3111
3206