/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: Alexander Belchenko
  • Date: 2007-09-22 17:29:16 UTC
  • mfrom: (2846 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2864.
  • Revision ID: bialix@ukr.net-20070922172916-yzl05wpf8ye852gw
Bug #140419 fixed by Robert Collins

Show diffs side-by-side

added added

removed removed

Lines of Context:
100
100
    RevisionNotPresent,
101
101
    RevisionAlreadyPresent,
102
102
    )
103
 
from bzrlib.tuned_gzip import GzipFile
 
103
from bzrlib.tuned_gzip import GzipFile, bytes_to_gzip
104
104
from bzrlib.osutils import (
105
105
    contains_whitespace,
106
106
    contains_linebreaks,
534
534
        return KnitVersionedFile(name, transport, factory=self.factory,
535
535
                                 delta=self.delta, create=True)
536
536
    
537
 
    def _fix_parents(self, version_id, new_parents):
538
 
        """Fix the parents list for version.
539
 
        
540
 
        This is done by appending a new version to the index
541
 
        with identical data except for the parents list.
542
 
        the parents list must be a superset of the current
543
 
        list.
544
 
        """
545
 
        current_values = self._index._cache[version_id]
546
 
        assert set(current_values[4]).difference(set(new_parents)) == set()
547
 
        self._index.add_version(version_id,
548
 
                                current_values[1],
549
 
                                (None, current_values[2], current_values[3]),
550
 
                                new_parents)
551
 
 
552
537
    def get_data_stream(self, required_versions):
553
538
        """Get a data stream for the specified versions.
554
539
 
835
820
        """See VersionedFile.add_lines_with_ghosts()."""
836
821
        self._check_add(version_id, lines, random_id, check_content)
837
822
        return self._add(version_id, lines, parents, self.delta,
838
 
            parent_texts, None, nostore_sha)
 
823
            parent_texts, None, nostore_sha, random_id)
839
824
 
840
825
    def _add_lines(self, version_id, parents, lines, parent_texts,
841
826
        left_matching_blocks, nostore_sha, random_id, check_content):
843
828
        self._check_add(version_id, lines, random_id, check_content)
844
829
        self._check_versions_present(parents)
845
830
        return self._add(version_id, lines[:], parents, self.delta,
846
 
            parent_texts, left_matching_blocks, nostore_sha)
 
831
            parent_texts, left_matching_blocks, nostore_sha, random_id)
847
832
 
848
833
    def _check_add(self, version_id, lines, random_id, check_content):
849
834
        """check that version_id and lines are safe to add."""
861
846
            self._check_lines_are_lines(lines)
862
847
 
863
848
    def _add(self, version_id, lines, parents, delta, parent_texts,
864
 
             left_matching_blocks, nostore_sha):
 
849
        left_matching_blocks, nostore_sha, random_id):
865
850
        """Add a set of lines on top of version specified by parents.
866
851
 
867
852
        If delta is true, compress the text as a line-delta against
928
913
            store_lines = self.factory.lower_fulltext(content)
929
914
 
930
915
        access_memo = self._data.add_record(version_id, digest, store_lines)
931
 
        self._index.add_version(version_id, options, access_memo, parents)
 
916
        self._index.add_versions(
 
917
            ((version_id, options, access_memo, parents),), random_id=random_id)
932
918
        return digest, text_length, content
933
919
 
934
920
    def check(self, progress_bar=None):
1037
1023
            text_map[version_id] = text
1038
1024
        return text_map, final_content
1039
1025
 
 
1026
    @staticmethod
 
1027
    def _apply_delta(lines, delta):
 
1028
        """Apply delta to lines."""
 
1029
        lines = list(lines)
 
1030
        offset = 0
 
1031
        for start, end, count, delta_lines in delta:
 
1032
            lines[offset+start:offset+end] = delta_lines
 
1033
            offset = offset + (start - end) + count
 
1034
        return lines
 
1035
 
1040
1036
    def iter_lines_added_or_present_in_versions(self, version_ids=None, 
1041
1037
                                                pb=None):
1042
1038
        """See VersionedFile.iter_lines_added_or_present_in_versions()."""
1374
1370
        """Add a version record to the index."""
1375
1371
        self.add_versions(((version_id, options, index_memo, parents),))
1376
1372
 
1377
 
    def add_versions(self, versions):
 
1373
    def add_versions(self, versions, random_id=False):
1378
1374
        """Add multiple versions to the index.
1379
1375
        
1380
1376
        :param versions: a list of tuples:
1381
1377
                         (version_id, options, pos, size, parents).
 
1378
        :param random_id: If True the ids being added were randomly generated
 
1379
            and no check for existence will be performed.
1382
1380
        """
1383
1381
        lines = []
1384
1382
        orig_history = self._history[:]
1714
1712
        """Add a version record to the index."""
1715
1713
        return self.add_versions(((version_id, options, access_memo, parents),))
1716
1714
 
1717
 
    def add_versions(self, versions):
 
1715
    def add_versions(self, versions, random_id=False):
1718
1716
        """Add multiple versions to the index.
1719
1717
        
1720
1718
        This function does not insert data into the Immutable GraphIndex
1724
1722
 
1725
1723
        :param versions: a list of tuples:
1726
1724
                         (version_id, options, pos, size, parents).
 
1725
        :param random_id: If True the ids being added were randomly generated
 
1726
            and no check for existence will be performed.
1727
1727
        """
1728
1728
        if not self._add_callback:
1729
1729
            raise errors.ReadOnlyError(self)
1758
1758
                        "in parentless index.")
1759
1759
                node_refs = ()
1760
1760
            keys[key] = (value, node_refs)
1761
 
        present_nodes = self._get_entries(keys)
1762
 
        for (index, key, value, node_refs) in present_nodes:
1763
 
            if (value, node_refs) != keys[key]:
1764
 
                raise KnitCorrupt(self, "inconsistent details in add_versions"
1765
 
                    ": %s %s" % ((value, node_refs), keys[key]))
1766
 
            del keys[key]
 
1761
        if not random_id:
 
1762
            present_nodes = self._get_entries(keys)
 
1763
            for (index, key, value, node_refs) in present_nodes:
 
1764
                if (value, node_refs) != keys[key]:
 
1765
                    raise KnitCorrupt(self, "inconsistent details in add_versions"
 
1766
                        ": %s %s" % ((value, node_refs), keys[key]))
 
1767
                del keys[key]
1767
1768
        result = []
1768
1769
        if self._parents:
1769
1770
            for key, (value, node_refs) in keys.iteritems():
1983
1984
        
1984
1985
        :return: (len, a StringIO instance with the raw data ready to read.)
1985
1986
        """
1986
 
        sio = StringIO()
1987
 
        data_file = GzipFile(None, mode='wb', fileobj=sio,
1988
 
            compresslevel=Z_DEFAULT_COMPRESSION)
1989
 
 
1990
 
        assert isinstance(version_id, str)
1991
 
        data_file.writelines(chain(
 
1987
        bytes = (''.join(chain(
1992
1988
            ["version %s %d %s\n" % (version_id,
1993
1989
                                     len(lines),
1994
1990
                                     digest)],
1995
1991
            lines,
1996
 
            ["end %s\n" % version_id]))
1997
 
        data_file.close()
1998
 
        length= sio.tell()
1999
 
 
2000
 
        sio.seek(0)
2001
 
        return length, sio
 
1992
            ["end %s\n" % version_id])))
 
1993
        assert bytes.__class__ == str
 
1994
        compressed_bytes = bytes_to_gzip(bytes)
 
1995
        return len(compressed_bytes), compressed_bytes
2002
1996
 
2003
1997
    def add_raw_records(self, sizes, raw_data):
2004
1998
        """Append a prepared record to the data file.
2016
2010
        
2017
2011
        Returns index data for retrieving it later, as per add_raw_records.
2018
2012
        """
2019
 
        size, sio = self._record_to_data(version_id, digest, lines)
2020
 
        result = self.add_raw_records([size], sio.getvalue())
 
2013
        size, bytes = self._record_to_data(version_id, digest, lines)
 
2014
        result = self.add_raw_records([size], bytes)
2021
2015
        if self._do_cache:
2022
 
            self._cache[version_id] = sio.getvalue()
 
2016
            self._cache[version_id] = bytes
2023
2017
        return result[0]
2024
2018
 
2025
2019
    def _parse_record_header(self, version_id, raw_data):
2201
2195
    
2202
2196
            self.source_ancestry = set(self.source.get_ancestry(version_ids))
2203
2197
            this_versions = set(self.target._index.get_versions())
 
2198
            # XXX: For efficiency we should not look at the whole index,
 
2199
            #      we only need to consider the referenced revisions - they
 
2200
            #      must all be present, or the method must be full-text.
 
2201
            #      TODO, RBC 20070919
2204
2202
            needed_versions = self.source_ancestry - this_versions
2205
 
            cross_check_versions = self.source_ancestry.intersection(this_versions)
2206
 
            mismatched_versions = set()
2207
 
            for version in cross_check_versions:
2208
 
                # scan to include needed parents.
2209
 
                n1 = set(self.target.get_parents_with_ghosts(version))
2210
 
                n2 = set(self.source.get_parents_with_ghosts(version))
2211
 
                if n1 != n2:
2212
 
                    # FIXME TEST this check for cycles being introduced works
2213
 
                    # the logic is we have a cycle if in our graph we are an
2214
 
                    # ancestor of any of the n2 revisions.
2215
 
                    for parent in n2:
2216
 
                        if parent in n1:
2217
 
                            # safe
2218
 
                            continue
2219
 
                        else:
2220
 
                            parent_ancestors = self.source.get_ancestry(parent)
2221
 
                            if version in parent_ancestors:
2222
 
                                raise errors.GraphCycleError([parent, version])
2223
 
                    # ensure this parent will be available later.
2224
 
                    new_parents = n2.difference(n1)
2225
 
                    needed_versions.update(new_parents.difference(this_versions))
2226
 
                    mismatched_versions.add(version)
2227
2203
    
2228
 
            if not needed_versions and not mismatched_versions:
 
2204
            if not needed_versions:
2229
2205
                return 0
2230
2206
            full_list = topo_sort(self.source.get_graph())
2231
2207
    
2268
2244
                raw_records.append((version_id, options, parents, len(raw_data)))
2269
2245
                raw_datum.append(raw_data)
2270
2246
            self.target._add_raw_records(raw_records, ''.join(raw_datum))
2271
 
 
2272
 
            for version in mismatched_versions:
2273
 
                # FIXME RBC 20060309 is this needed?
2274
 
                n1 = set(self.target.get_parents_with_ghosts(version))
2275
 
                n2 = set(self.source.get_parents_with_ghosts(version))
2276
 
                # write a combined record to our history preserving the current 
2277
 
                # parents as first in the list
2278
 
                new_parents = self.target.get_parents_with_ghosts(version) + list(n2.difference(n1))
2279
 
                self.target.fix_parents(version, new_parents)
2280
2247
            return count
2281
2248
        finally:
2282
2249
            pb.finished()
2317
2284
            self.source_ancestry = set(self.source.get_ancestry(version_ids))
2318
2285
            this_versions = set(self.target._index.get_versions())
2319
2286
            needed_versions = self.source_ancestry - this_versions
2320
 
            cross_check_versions = self.source_ancestry.intersection(this_versions)
2321
 
            mismatched_versions = set()
2322
 
            for version in cross_check_versions:
2323
 
                # scan to include needed parents.
2324
 
                n1 = set(self.target.get_parents_with_ghosts(version))
2325
 
                n2 = set(self.source.get_parents(version))
2326
 
                # if all of n2's parents are in n1, then its fine.
2327
 
                if n2.difference(n1):
2328
 
                    # FIXME TEST this check for cycles being introduced works
2329
 
                    # the logic is we have a cycle if in our graph we are an
2330
 
                    # ancestor of any of the n2 revisions.
2331
 
                    for parent in n2:
2332
 
                        if parent in n1:
2333
 
                            # safe
2334
 
                            continue
2335
 
                        else:
2336
 
                            parent_ancestors = self.source.get_ancestry(parent)
2337
 
                            if version in parent_ancestors:
2338
 
                                raise errors.GraphCycleError([parent, version])
2339
 
                    # ensure this parent will be available later.
2340
 
                    new_parents = n2.difference(n1)
2341
 
                    needed_versions.update(new_parents.difference(this_versions))
2342
 
                    mismatched_versions.add(version)
2343
2287
    
2344
 
            if not needed_versions and not mismatched_versions:
 
2288
            if not needed_versions:
2345
2289
                return 0
2346
2290
            full_list = topo_sort(self.source.get_graph())
2347
2291
    
2361
2305
                self.target.add_lines(
2362
2306
                    version_id, parents, self.source.get_lines(version_id))
2363
2307
                count = count + 1
2364
 
 
2365
 
            for version in mismatched_versions:
2366
 
                # FIXME RBC 20060309 is this needed?
2367
 
                n1 = set(self.target.get_parents_with_ghosts(version))
2368
 
                n2 = set(self.source.get_parents(version))
2369
 
                # write a combined record to our history preserving the current 
2370
 
                # parents as first in the list
2371
 
                new_parents = self.target.get_parents_with_ghosts(version) + list(n2.difference(n1))
2372
 
                self.target.fix_parents(version, new_parents)
2373
2308
            return count
2374
2309
        finally:
2375
2310
            pb.finished()