~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

remove all trailing whitespace from bzr source

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
updates.
21
21
 
22
22
Knit file layout:
23
 
lifeless: the data file is made up of "delta records".  each delta record has a delta header 
24
 
that contains; (1) a version id, (2) the size of the delta (in lines), and (3)  the digest of 
25
 
the -expanded data- (ie, the delta applied to the parent).  the delta also ends with a 
 
23
lifeless: the data file is made up of "delta records".  each delta record has a delta header
 
24
that contains; (1) a version id, (2) the size of the delta (in lines), and (3)  the digest of
 
25
the -expanded data- (ie, the delta applied to the parent).  the delta also ends with a
26
26
end-marker; simply "end VERSION"
27
27
 
28
28
delta can be line or full contents.a
35
35
130,130,2
36
36
8         if elt.get('executable') == 'yes':
37
37
8             ie.executable = True
38
 
end robertc@robertcollins.net-20051003014215-ee2990904cc4c7ad 
 
38
end robertc@robertcollins.net-20051003014215-ee2990904cc4c7ad
39
39
 
40
40
 
41
41
whats in an index:
54
54
# TODOS:
55
55
# 10:16 < lifeless> make partial index writes safe
56
56
# 10:16 < lifeless> implement 'knit.check()' like weave.check()
57
 
# 10:17 < lifeless> record known ghosts so we can detect when they are filled in rather than the current 'reweave 
 
57
# 10:17 < lifeless> record known ghosts so we can detect when they are filled in rather than the current 'reweave
58
58
#                    always' approach.
59
59
# move sha1 out of the content so that join is faster at verifying parents
60
60
# record content length ?
61
 
                  
 
61
 
62
62
 
63
63
from cStringIO import StringIO
64
64
from itertools import izip, chain
138
138
 
139
139
    def __init__(self, basis_vf):
140
140
        """Create an adapter which accesses full texts from basis_vf.
141
 
        
 
141
 
142
142
        :param basis_vf: A versioned file to access basis texts of deltas from.
143
143
            May be None for adapters that do not need to access basis texts.
144
144
        """
242
242
 
243
243
class KnitContentFactory(ContentFactory):
244
244
    """Content factory for streaming from knits.
245
 
    
 
245
 
246
246
    :seealso ContentFactory:
247
247
    """
248
248
 
249
249
    def __init__(self, key, parents, build_details, sha1, raw_record,
250
250
        annotated, knit=None):
251
251
        """Create a KnitContentFactory for key.
252
 
        
 
252
 
253
253
        :param key: The key.
254
254
        :param parents: The parents.
255
255
        :param build_details: The build details as returned from
289
289
 
290
290
class KnitContent(object):
291
291
    """Content of a knit version to which deltas can be applied.
292
 
    
 
292
 
293
293
    This is always stored in memory as a list of lines with \n at the end,
294
 
    plus a flag saying if the final ending is really there or not, because that 
 
294
    plus a flag saying if the final ending is really there or not, because that
295
295
    corresponds to the on-disk knit representation.
296
296
    """
297
297
 
386
386
 
387
387
class PlainKnitContent(KnitContent):
388
388
    """Unannotated content.
389
 
    
 
389
 
390
390
    When annotate[_iter] is called on this content, the same version is reported
391
391
    for all lines. Generally, annotate[_iter] is not useful on PlainKnitContent
392
392
    objects.
647
647
 
648
648
    This is only functional enough to run interface tests, it doesn't try to
649
649
    provide a full pack environment.
650
 
    
 
650
 
651
651
    :param annotated: knit annotations are wanted.
652
652
    :param mapper: The mapper from keys to paths.
653
653
    """
663
663
 
664
664
    This is only functional enough to run interface tests, it doesn't try to
665
665
    provide a full pack environment.
666
 
    
 
666
 
667
667
    :param graph: Store a graph.
668
668
    :param delta: Delta compress contents.
669
669
    :param keylength: How long should keys be.
705
705
 
706
706
    Backend storage is managed by indices and data objects.
707
707
 
708
 
    :ivar _index: A _KnitGraphIndex or similar that can describe the 
709
 
        parents, graph, compression and data location of entries in this 
710
 
        KnitVersionedFiles.  Note that this is only the index for 
 
708
    :ivar _index: A _KnitGraphIndex or similar that can describe the
 
709
        parents, graph, compression and data location of entries in this
 
710
        KnitVersionedFiles.  Note that this is only the index for
711
711
        *this* vfs; if there are fallbacks they must be queried separately.
712
712
    """
713
713
 
891
891
 
892
892
    def _check_header_version(self, rec, version_id):
893
893
        """Checks the header version on original format knit records.
894
 
        
 
894
 
895
895
        These have the last component of the key embedded in the record.
896
896
        """
897
897
        if rec[1] != version_id:
976
976
            if missing and not allow_missing:
977
977
                raise errors.RevisionNotPresent(missing.pop(), self)
978
978
        return component_data
979
 
       
 
979
 
980
980
    def _get_content(self, key, parent_texts={}):
981
981
        """Returns a content object that makes up the specified
982
982
        version."""
991
991
 
992
992
    def _get_content_maps(self, keys, nonlocal_keys=None):
993
993
        """Produce maps of text and KnitContents
994
 
        
 
994
 
995
995
        :param keys: The keys to produce content maps for.
996
996
        :param nonlocal_keys: An iterable of keys(possibly intersecting keys)
997
997
            which are known to not be in this knit, but rather in one of the
1102
1102
 
1103
1103
    def _get_record_map(self, keys, allow_missing=False):
1104
1104
        """Produce a dictionary of knit records.
1105
 
        
 
1105
 
1106
1106
        :return: {key:(record, record_details, digest, next)}
1107
1107
            record
1108
1108
                data returned from read_records
1114
1114
                build-parent of the version, i.e. the leftmost ancestor.
1115
1115
                Will be None if the record is not a delta.
1116
1116
        :param keys: The keys to build a map for
1117
 
        :param allow_missing: If some records are missing, rather than 
 
1117
        :param allow_missing: If some records are missing, rather than
1118
1118
            error, just return the data that could be generated.
1119
1119
        """
1120
1120
        # This retries the whole request if anything fails. Potentially we
1330
1330
    def insert_record_stream(self, stream):
1331
1331
        """Insert a record stream into this container.
1332
1332
 
1333
 
        :param stream: A stream of records to insert. 
 
1333
        :param stream: A stream of records to insert.
1334
1334
        :return: None
1335
1335
        :seealso VersionedFiles.get_record_stream:
1336
1336
        """
1528
1528
                        # fulltext
1529
1529
                        line_iterator = self._factory.get_fulltext_content(data)
1530
1530
                    else:
1531
 
                        # Delta 
 
1531
                        # Delta
1532
1532
                        line_iterator = self._factory.get_linedelta_content(data)
1533
1533
                    # Now that we are yielding the data for this key, remove it
1534
1534
                    # from the list
1545
1545
        # If there are still keys we've not yet found, we look in the fallback
1546
1546
        # vfs, and hope to find them there.  Note that if the keys are found
1547
1547
        # but had no changes or no content, the fallback may not return
1548
 
        # anything.  
 
1548
        # anything.
1549
1549
        if keys and not self._fallback_vfs:
1550
1550
            # XXX: strictly the second parameter is meant to be the file id
1551
1551
            # but it's not easily accessible here.
1573
1573
                           delta=None, annotated=None,
1574
1574
                           left_matching_blocks=None):
1575
1575
        """Merge annotations for content and generate deltas.
1576
 
        
 
1576
 
1577
1577
        This is done by comparing the annotations based on changes to the text
1578
1578
        and generating a delta on the resulting full texts. If annotations are
1579
1579
        not being created then a simple delta is created.
1661
1661
                                 rec[1], record_contents))
1662
1662
        if last_line != 'end %s\n' % rec[1]:
1663
1663
            raise KnitCorrupt(self,
1664
 
                              'unexpected version end line %r, wanted %r' 
 
1664
                              'unexpected version end line %r, wanted %r'
1665
1665
                              % (last_line, rec[1]))
1666
1666
        df.close()
1667
1667
        return rec, record_contents
1684
1684
        if not needed_records:
1685
1685
            return
1686
1686
 
1687
 
        # The transport optimizes the fetching as well 
 
1687
        # The transport optimizes the fetching as well
1688
1688
        # (ie, reads continuous ranges.)
1689
1689
        raw_data = self._access.get_raw_records(
1690
1690
            [index_memo for key, index_memo in needed_records])
1720
1720
 
1721
1721
    def _record_to_data(self, key, digest, lines, dense_lines=None):
1722
1722
        """Convert key, digest, lines into a raw data block.
1723
 
        
 
1723
 
1724
1724
        :param key: The key of the record. Currently keys are always serialised
1725
1725
            using just the trailing component.
1726
1726
        :param dense_lines: The bytes of lines but in a denser form. For
1785
1785
 
1786
1786
    Duplicate entries may be written to the index for a single version id
1787
1787
    if this is done then the latter one completely replaces the former:
1788
 
    this allows updates to correct version and parent information. 
 
1788
    this allows updates to correct version and parent information.
1789
1789
    Note that the two entries may share the delta, and that successive
1790
1790
    annotations and references MUST point to the first entry.
1791
1791
 
1792
1792
    The index file on disc contains a header, followed by one line per knit
1793
1793
    record. The same revision can be present in an index file more than once.
1794
 
    The first occurrence gets assigned a sequence number starting from 0. 
1795
 
    
 
1794
    The first occurrence gets assigned a sequence number starting from 0.
 
1795
 
1796
1796
    The format of a single line is
1797
1797
    REVISION_ID FLAGS BYTE_OFFSET LENGTH( PARENT_ID|PARENT_SEQUENCE_ID)* :\n
1798
1798
    REVISION_ID is a utf8-encoded revision id
1799
 
    FLAGS is a comma separated list of flags about the record. Values include 
 
1799
    FLAGS is a comma separated list of flags about the record. Values include
1800
1800
        no-eol, line-delta, fulltext.
1801
1801
    BYTE_OFFSET is the ascii representation of the byte offset in the data file
1802
1802
        that the the compressed data starts at.
1806
1806
    PARENT_SEQUENCE_ID the ascii representation of the sequence number of a
1807
1807
        revision id already in the knit that is a parent of REVISION_ID.
1808
1808
    The ' :' marker is the end of record marker.
1809
 
    
 
1809
 
1810
1810
    partial writes:
1811
1811
    when a write is interrupted to the index file, it will result in a line
1812
1812
    that does not end in ' :'. If the ' :' is not present at the end of a line,
1839
1839
 
1840
1840
    def add_records(self, records, random_id=False):
1841
1841
        """Add multiple records to the index.
1842
 
        
 
1842
 
1843
1843
        :param records: a list of tuples:
1844
1844
                         (key, options, access_memo, parents).
1845
1845
        :param random_id: If True the ids being added were randomly generated
2019
2019
 
2020
2020
    def get_position(self, key):
2021
2021
        """Return details needed to access the version.
2022
 
        
 
2022
 
2023
2023
        :return: a tuple (key, data position, size) to hand to the access
2024
2024
            logic to get the record.
2025
2025
        """
2029
2029
        return key, entry[2], entry[3]
2030
2030
 
2031
2031
    has_key = _mod_index._has_key_from_parent_map
2032
 
    
 
2032
 
2033
2033
    def _init_index(self, path, extra_lines=[]):
2034
2034
        """Initialize an index."""
2035
2035
        sio = StringIO()
2044
2044
 
2045
2045
    def keys(self):
2046
2046
        """Get all the keys in the collection.
2047
 
        
 
2047
 
2048
2048
        The keys are not ordered.
2049
2049
        """
2050
2050
        result = set()
2063
2063
            for suffix in self._kndx_cache[prefix][1]:
2064
2064
                result.add(prefix + (suffix,))
2065
2065
        return result
2066
 
    
 
2066
 
2067
2067
    def _load_prefixes(self, prefixes):
2068
2068
        """Load the indices for prefixes."""
2069
2069
        self._check_read()
2107
2107
 
2108
2108
    def _dictionary_compress(self, keys):
2109
2109
        """Dictionary compress keys.
2110
 
        
 
2110
 
2111
2111
        :param keys: The keys to generate references to.
2112
2112
        :return: A string representation of keys. keys which are present are
2113
2113
            dictionary compressed, and others are emitted as fulltext with a
2177
2177
        :param is_locked: A callback to check whether the object should answer
2178
2178
            queries.
2179
2179
        :param deltas: Allow delta-compressed records.
2180
 
        :param parents: If True, record knits parents, if not do not record 
 
2180
        :param parents: If True, record knits parents, if not do not record
2181
2181
            parents.
2182
2182
        :param add_callback: If not None, allow additions to the index and call
2183
2183
            this callback with a list of added GraphIndex nodes:
2202
2202
 
2203
2203
    def add_records(self, records, random_id=False):
2204
2204
        """Add multiple records to the index.
2205
 
        
 
2205
 
2206
2206
        This function does not insert data into the Immutable GraphIndex
2207
2207
        backing the KnitGraphIndex, instead it prepares data for insertion by
2208
2208
        the caller and checks that it is safe to insert then calls
2262
2262
            for key, (value, node_refs) in keys.iteritems():
2263
2263
                result.append((key, value))
2264
2264
        self._add_callback(result)
2265
 
        
 
2265
 
2266
2266
    def _check_read(self):
2267
2267
        """raise if reads are not permitted."""
2268
2268
        if not self._is_locked():
2328
2328
 
2329
2329
    def _get_entries(self, keys, check_present=False):
2330
2330
        """Get the entries for keys.
2331
 
        
 
2331
 
2332
2332
        :param keys: An iterable of index key tuples.
2333
2333
        """
2334
2334
        keys = set(keys)
2396
2396
 
2397
2397
    def get_position(self, key):
2398
2398
        """Return details needed to access the version.
2399
 
        
 
2399
 
2400
2400
        :return: a tuple (index, data position, size) to hand to the access
2401
2401
            logic to get the record.
2402
2402
        """
2407
2407
 
2408
2408
    def keys(self):
2409
2409
        """Get all the keys in the collection.
2410
 
        
 
2410
 
2411
2411
        The keys are not ordered.
2412
2412
        """
2413
2413
        self._check_read()
2414
2414
        return [node[1] for node in self._graph_index.iter_all_entries()]
2415
 
    
 
2415
 
2416
2416
    missing_keys = _mod_index._missing_keys_from_parent_map
2417
2417
 
2418
2418
    def _node_to_position(self, node):
2562
2562
    def get_raw_records(self, memos_for_retrieval):
2563
2563
        """Get the raw bytes for a records.
2564
2564
 
2565
 
        :param memos_for_retrieval: An iterable containing the (index, pos, 
 
2565
        :param memos_for_retrieval: An iterable containing the (index, pos,
2566
2566
            length) memo for retrieving the bytes. The Pack access method
2567
2567
            looks up the pack to use for a given record in its index_to_pack
2568
2568
            map.