~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/knit.py

  • Committer: John Arbash Meinel
  • Date: 2009-02-23 15:29:35 UTC
  • mfrom: (3943.7.7 bzr.code_style_cleanup)
  • mto: This revision was merged to the branch mainline in revision 4033.
  • Revision ID: john@arbash-meinel.com-20090223152935-oel9m92mwcc6nb4h
Merge the removal of all trailing whitespace, and resolve conflicts.

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:
130
130
 
131
131
    def __init__(self, basis_vf):
132
132
        """Create an adapter which accesses full texts from basis_vf.
133
 
        
 
133
 
134
134
        :param basis_vf: A versioned file to access basis texts of deltas from.
135
135
            May be None for adapters that do not need to access basis texts.
136
136
        """
240
240
 
241
241
class KnitContentFactory(ContentFactory):
242
242
    """Content factory for streaming from knits.
243
 
    
 
243
 
244
244
    :seealso ContentFactory:
245
245
    """
246
246
 
247
247
    def __init__(self, key, parents, build_details, sha1, raw_record,
248
248
        annotated, knit=None, network_bytes=None):
249
249
        """Create a KnitContentFactory for key.
250
 
        
 
250
 
251
251
        :param key: The key.
252
252
        :param parents: The parents.
253
253
        :param build_details: The build details as returned from
314
314
 
315
315
    def __init__(self, key, parents, generator, first):
316
316
        """Create a LazyKnitContentFactory.
317
 
        
 
317
 
318
318
        :param key: The key of the record.
319
319
        :param parents: The parents of the record.
320
320
        :param generator: A _ContentMapGenerator containing the record for this
395
395
 
396
396
class KnitContent(object):
397
397
    """Content of a knit version to which deltas can be applied.
398
 
    
 
398
 
399
399
    This is always stored in memory as a list of lines with \n at the end,
400
 
    plus a flag saying if the final ending is really there or not, because that 
 
400
    plus a flag saying if the final ending is really there or not, because that
401
401
    corresponds to the on-disk knit representation.
402
402
    """
403
403
 
492
492
 
493
493
class PlainKnitContent(KnitContent):
494
494
    """Unannotated content.
495
 
    
 
495
 
496
496
    When annotate[_iter] is called on this content, the same version is reported
497
497
    for all lines. Generally, annotate[_iter] is not useful on PlainKnitContent
498
498
    objects.
753
753
 
754
754
    This is only functional enough to run interface tests, it doesn't try to
755
755
    provide a full pack environment.
756
 
    
 
756
 
757
757
    :param annotated: knit annotations are wanted.
758
758
    :param mapper: The mapper from keys to paths.
759
759
    """
769
769
 
770
770
    This is only functional enough to run interface tests, it doesn't try to
771
771
    provide a full pack environment.
772
 
    
 
772
 
773
773
    :param graph: Store a graph.
774
774
    :param delta: Delta compress contents.
775
775
    :param keylength: How long should keys be.
811
811
 
812
812
    Backend storage is managed by indices and data objects.
813
813
 
814
 
    :ivar _index: A _KnitGraphIndex or similar that can describe the 
815
 
        parents, graph, compression and data location of entries in this 
816
 
        KnitVersionedFiles.  Note that this is only the index for 
 
814
    :ivar _index: A _KnitGraphIndex or similar that can describe the
 
815
        parents, graph, compression and data location of entries in this
 
816
        KnitVersionedFiles.  Note that this is only the index for
817
817
        *this* vfs; if there are fallbacks they must be queried separately.
818
818
    """
819
819
 
997
997
 
998
998
    def _check_header_version(self, rec, version_id):
999
999
        """Checks the header version on original format knit records.
1000
 
        
 
1000
 
1001
1001
        These have the last component of the key embedded in the record.
1002
1002
        """
1003
1003
        if rec[1] != version_id:
1082
1082
            if missing and not allow_missing:
1083
1083
                raise errors.RevisionNotPresent(missing.pop(), self)
1084
1084
        return component_data
1085
 
       
 
1085
 
1086
1086
    def _get_content(self, key, parent_texts={}):
1087
1087
        """Returns a content object that makes up the specified
1088
1088
        version."""
1129
1129
 
1130
1130
    def _get_record_map(self, keys, allow_missing=False):
1131
1131
        """Produce a dictionary of knit records.
1132
 
        
 
1132
 
1133
1133
        :return: {key:(record, record_details, digest, next)}
1134
1134
            record
1135
1135
                data returned from read_records (a KnitContentobject)
1141
1141
                build-parent of the version, i.e. the leftmost ancestor.
1142
1142
                Will be None if the record is not a delta.
1143
1143
        :param keys: The keys to build a map for
1144
 
        :param allow_missing: If some records are missing, rather than 
 
1144
        :param allow_missing: If some records are missing, rather than
1145
1145
            error, just return the data that could be generated.
1146
1146
        """
1147
1147
        raw_map = self._get_record_map_unparsed(keys,
1150
1150
 
1151
1151
    def _raw_map_to_record_map(self, raw_map):
1152
1152
        """Parse the contents of _get_record_map_unparsed.
1153
 
        
 
1153
 
1154
1154
        :return: see _get_record_map.
1155
1155
        """
1156
1156
        result = {}
1162
1162
 
1163
1163
    def _get_record_map_unparsed(self, keys, allow_missing=False):
1164
1164
        """Get the raw data for reconstructing keys without parsing it.
1165
 
        
 
1165
 
1166
1166
        :return: A dict suitable for parsing via _raw_map_to_record_map.
1167
1167
            key-> raw_bytes, (method, noeol), compression_parent
1168
1168
        """
1380
1380
    def insert_record_stream(self, stream):
1381
1381
        """Insert a record stream into this container.
1382
1382
 
1383
 
        :param stream: A stream of records to insert. 
 
1383
        :param stream: A stream of records to insert.
1384
1384
        :return: None
1385
1385
        :seealso VersionedFiles.get_record_stream:
1386
1386
        """
1594
1594
                        # fulltext
1595
1595
                        line_iterator = self._factory.get_fulltext_content(data)
1596
1596
                    else:
1597
 
                        # Delta 
 
1597
                        # Delta
1598
1598
                        line_iterator = self._factory.get_linedelta_content(data)
1599
1599
                    # Now that we are yielding the data for this key, remove it
1600
1600
                    # from the list
1611
1611
        # If there are still keys we've not yet found, we look in the fallback
1612
1612
        # vfs, and hope to find them there.  Note that if the keys are found
1613
1613
        # but had no changes or no content, the fallback may not return
1614
 
        # anything.  
 
1614
        # anything.
1615
1615
        if keys and not self._fallback_vfs:
1616
1616
            # XXX: strictly the second parameter is meant to be the file id
1617
1617
            # but it's not easily accessible here.
1639
1639
                           delta=None, annotated=None,
1640
1640
                           left_matching_blocks=None):
1641
1641
        """Merge annotations for content and generate deltas.
1642
 
        
 
1642
 
1643
1643
        This is done by comparing the annotations based on changes to the text
1644
1644
        and generating a delta on the resulting full texts. If annotations are
1645
1645
        not being created then a simple delta is created.
1727
1727
                                 rec[1], record_contents))
1728
1728
        if last_line != 'end %s\n' % rec[1]:
1729
1729
            raise KnitCorrupt(self,
1730
 
                              'unexpected version end line %r, wanted %r' 
 
1730
                              'unexpected version end line %r, wanted %r'
1731
1731
                              % (last_line, rec[1]))
1732
1732
        df.close()
1733
1733
        return rec, record_contents
1750
1750
        if not needed_records:
1751
1751
            return
1752
1752
 
1753
 
        # The transport optimizes the fetching as well 
 
1753
        # The transport optimizes the fetching as well
1754
1754
        # (ie, reads continuous ranges.)
1755
1755
        raw_data = self._access.get_raw_records(
1756
1756
            [index_memo for key, index_memo in needed_records])
1797
1797
 
1798
1798
    def _record_to_data(self, key, digest, lines, dense_lines=None):
1799
1799
        """Convert key, digest, lines into a raw data block.
1800
 
        
 
1800
 
1801
1801
        :param key: The key of the record. Currently keys are always serialised
1802
1802
            using just the trailing component.
1803
1803
        :param dense_lines: The bytes of lines but in a denser form. For
1866
1866
 
1867
1867
    def _work(self):
1868
1868
        """Produce maps of text and KnitContents as dicts.
1869
 
        
 
1869
 
1870
1870
        :return: (text_map, content_map) where text_map contains the texts for
1871
1871
            the requested versions and content_map contains the KnitContents.
1872
1872
        """
1919
1919
                self._raw_record_map)
1920
1920
        record_map = self._record_map
1921
1921
        # raw_record_map is key:
1922
 
        # Have read and parsed records at this point. 
 
1922
        # Have read and parsed records at this point.
1923
1923
        for key in self.keys:
1924
1924
            if key in self.nonlocal_keys:
1925
1925
                # already handled
2025
2025
    def __init__(self, versioned_files, keys, nonlocal_keys=None,
2026
2026
        global_map=None, raw_record_map=None):
2027
2027
        """Create a _ContentMapGenerator.
2028
 
        
 
2028
 
2029
2029
        :param versioned_files: The versioned files that the texts are being
2030
2030
            extracted from.
2031
2031
        :param keys: The keys to produce content maps for.
2172
2172
 
2173
2173
    Duplicate entries may be written to the index for a single version id
2174
2174
    if this is done then the latter one completely replaces the former:
2175
 
    this allows updates to correct version and parent information. 
 
2175
    this allows updates to correct version and parent information.
2176
2176
    Note that the two entries may share the delta, and that successive
2177
2177
    annotations and references MUST point to the first entry.
2178
2178
 
2179
2179
    The index file on disc contains a header, followed by one line per knit
2180
2180
    record. The same revision can be present in an index file more than once.
2181
 
    The first occurrence gets assigned a sequence number starting from 0. 
2182
 
    
 
2181
    The first occurrence gets assigned a sequence number starting from 0.
 
2182
 
2183
2183
    The format of a single line is
2184
2184
    REVISION_ID FLAGS BYTE_OFFSET LENGTH( PARENT_ID|PARENT_SEQUENCE_ID)* :\n
2185
2185
    REVISION_ID is a utf8-encoded revision id
2186
 
    FLAGS is a comma separated list of flags about the record. Values include 
 
2186
    FLAGS is a comma separated list of flags about the record. Values include
2187
2187
        no-eol, line-delta, fulltext.
2188
2188
    BYTE_OFFSET is the ascii representation of the byte offset in the data file
2189
2189
        that the the compressed data starts at.
2193
2193
    PARENT_SEQUENCE_ID the ascii representation of the sequence number of a
2194
2194
        revision id already in the knit that is a parent of REVISION_ID.
2195
2195
    The ' :' marker is the end of record marker.
2196
 
    
 
2196
 
2197
2197
    partial writes:
2198
2198
    when a write is interrupted to the index file, it will result in a line
2199
2199
    that does not end in ' :'. If the ' :' is not present at the end of a line,
2226
2226
 
2227
2227
    def add_records(self, records, random_id=False, missing_compression_parents=False):
2228
2228
        """Add multiple records to the index.
2229
 
        
 
2229
 
2230
2230
        :param records: a list of tuples:
2231
2231
                         (key, options, access_memo, parents).
2232
2232
        :param random_id: If True the ids being added were randomly generated
2288
2288
        # Because kndx files do not support atomic insertion via separate index
2289
2289
        # files, they do not support this method.
2290
2290
        raise NotImplementedError(self.get_missing_compression_parents)
2291
 
    
 
2291
 
2292
2292
    def _cache_key(self, key, options, pos, size, parent_keys):
2293
2293
        """Cache a version record in the history array and index cache.
2294
2294
 
2427
2427
 
2428
2428
    def get_position(self, key):
2429
2429
        """Return details needed to access the version.
2430
 
        
 
2430
 
2431
2431
        :return: a tuple (key, data position, size) to hand to the access
2432
2432
            logic to get the record.
2433
2433
        """
2437
2437
        return key, entry[2], entry[3]
2438
2438
 
2439
2439
    has_key = _mod_index._has_key_from_parent_map
2440
 
    
 
2440
 
2441
2441
    def _init_index(self, path, extra_lines=[]):
2442
2442
        """Initialize an index."""
2443
2443
        sio = StringIO()
2452
2452
 
2453
2453
    def keys(self):
2454
2454
        """Get all the keys in the collection.
2455
 
        
 
2455
 
2456
2456
        The keys are not ordered.
2457
2457
        """
2458
2458
        result = set()
2471
2471
            for suffix in self._kndx_cache[prefix][1]:
2472
2472
                result.add(prefix + (suffix,))
2473
2473
        return result
2474
 
    
 
2474
 
2475
2475
    def _load_prefixes(self, prefixes):
2476
2476
        """Load the indices for prefixes."""
2477
2477
        self._check_read()
2515
2515
 
2516
2516
    def _dictionary_compress(self, keys):
2517
2517
        """Dictionary compress keys.
2518
 
        
 
2518
 
2519
2519
        :param keys: The keys to generate references to.
2520
2520
        :return: A string representation of keys. keys which are present are
2521
2521
            dictionary compressed, and others are emitted as fulltext with a
2585
2585
        :param is_locked: A callback to check whether the object should answer
2586
2586
            queries.
2587
2587
        :param deltas: Allow delta-compressed records.
2588
 
        :param parents: If True, record knits parents, if not do not record 
 
2588
        :param parents: If True, record knits parents, if not do not record
2589
2589
            parents.
2590
2590
        :param add_callback: If not None, allow additions to the index and call
2591
2591
            this callback with a list of added GraphIndex nodes:
2612
2612
    def add_records(self, records, random_id=False,
2613
2613
        missing_compression_parents=False):
2614
2614
        """Add multiple records to the index.
2615
 
        
 
2615
 
2616
2616
        This function does not insert data into the Immutable GraphIndex
2617
2617
        backing the KnitGraphIndex, instead it prepares data for insertion by
2618
2618
        the caller and checks that it is safe to insert then calls
2690
2690
            self._missing_compression_parents.update(compression_parents)
2691
2691
        # Adding records may have satisfied missing compression parents.
2692
2692
        self._missing_compression_parents.difference_update(keys)
2693
 
        
 
2693
 
2694
2694
    def scan_unvalidated_index(self, graph_index):
2695
2695
        """Inform this _KnitGraphIndex that there is an unvalidated index.
2696
2696
 
2778
2778
 
2779
2779
    def _get_entries(self, keys, check_present=False):
2780
2780
        """Get the entries for keys.
2781
 
        
 
2781
 
2782
2782
        :param keys: An iterable of index key tuples.
2783
2783
        """
2784
2784
        keys = set(keys)
2846
2846
 
2847
2847
    def get_position(self, key):
2848
2848
        """Return details needed to access the version.
2849
 
        
 
2849
 
2850
2850
        :return: a tuple (index, data position, size) to hand to the access
2851
2851
            logic to get the record.
2852
2852
        """
2857
2857
 
2858
2858
    def keys(self):
2859
2859
        """Get all the keys in the collection.
2860
 
        
 
2860
 
2861
2861
        The keys are not ordered.
2862
2862
        """
2863
2863
        self._check_read()
2864
2864
        return [node[1] for node in self._graph_index.iter_all_entries()]
2865
 
    
 
2865
 
2866
2866
    missing_keys = _mod_index._missing_keys_from_parent_map
2867
2867
 
2868
2868
    def _node_to_position(self, node):
3012
3012
    def get_raw_records(self, memos_for_retrieval):
3013
3013
        """Get the raw bytes for a records.
3014
3014
 
3015
 
        :param memos_for_retrieval: An iterable containing the (index, pos, 
 
3015
        :param memos_for_retrieval: An iterable containing the (index, pos,
3016
3016
            length) memo for retrieving the bytes. The Pack access method
3017
3017
            looks up the pack to use for a given record in its index_to_pack
3018
3018
            map.