~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/versionedfile.py

[merge] robert's knit-performance work

Show diffs side-by-side

added added

removed removed

Lines of Context:
78
78
        """Returns whether version is present."""
79
79
        raise NotImplementedError(self.has_version)
80
80
 
81
 
    def add_lines(self, version_id, parents, lines):
 
81
    def add_delta(self, version_id, parents, delta_parent, sha1, noeol, delta):
 
82
        """Add a text to the versioned file via a pregenerated delta.
 
83
 
 
84
        :param version_id: The version id being added.
 
85
        :param parents: The parents of the version_id.
 
86
        :param delta_parent: The parent this delta was created against.
 
87
        :param sha1: The sha1 of the full text.
 
88
        :param delta: The delta instructions. See get_delta for details.
 
89
        """
 
90
        self._check_write_ok()
 
91
        if self.has_version(version_id):
 
92
            raise errors.RevisionAlreadyPresent(version_id, self)
 
93
        return self._add_delta(version_id, parents, delta_parent, sha1, noeol, delta)
 
94
 
 
95
    def _add_delta(self, version_id, parents, delta_parent, sha1, noeol, delta):
 
96
        """Class specific routine to add a delta.
 
97
 
 
98
        This generic version simply applies the delta to the delta_parent and
 
99
        then inserts it.
 
100
        """
 
101
        # strip annotation from delta
 
102
        new_delta = []
 
103
        for start, stop, delta_len, delta_lines in delta:
 
104
            new_delta.append((start, stop, delta_len, [text for origin, text in delta_lines]))
 
105
        if delta_parent is not None:
 
106
            parent_full = self.get_lines(delta_parent)
 
107
        else:
 
108
            parent_full = []
 
109
        new_full = self._apply_delta(parent_full, new_delta)
 
110
        # its impossible to have noeol on an empty file
 
111
        if noeol and new_full[-1][-1] == '\n':
 
112
            new_full[-1] = new_full[-1][:-1]
 
113
        self.add_lines(version_id, parents, new_full)
 
114
 
 
115
    def add_lines(self, version_id, parents, lines, parent_texts=None):
82
116
        """Add a single text on top of the versioned file.
83
117
 
84
118
        Must raise RevisionAlreadyPresent if the new version is
86
120
 
87
121
        Must raise RevisionNotPresent if any of the given parents are
88
122
        not present in file history.
 
123
        :param parent_texts: An optional dictionary containing the opaque 
 
124
                             representations of some or all of the parents of 
 
125
                             version_id to allow delta optimisations. 
 
126
                             VERY IMPORTANT: the texts must be those returned
 
127
                             by add_lines or data corruption can be caused.
 
128
        :return: An opaque representation of the inserted version which can be
 
129
                 provided back to future add_lines calls in the parent_texts
 
130
                 dictionary.
89
131
        """
90
132
        self._check_write_ok()
91
 
        return self._add_lines(version_id, parents, lines)
 
133
        return self._add_lines(version_id, parents, lines, parent_texts)
92
134
 
93
 
    def _add_lines(self, version_id, parents, lines):
 
135
    def _add_lines(self, version_id, parents, lines, parent_texts):
94
136
        """Helper to do the class specific add_lines."""
95
137
        raise NotImplementedError(self.add_lines)
96
138
 
97
 
    def add_lines_with_ghosts(self, version_id, parents, lines):
98
 
        """Add lines to the versioned file, allowing ghosts to be present."""
 
139
    def add_lines_with_ghosts(self, version_id, parents, lines,
 
140
                              parent_texts=None):
 
141
        """Add lines to the versioned file, allowing ghosts to be present.
 
142
        
 
143
        This takes the same parameters as add_lines.
 
144
        """
99
145
        self._check_write_ok()
100
 
        return self._add_lines_with_ghosts(version_id, parents, lines)
 
146
        return self._add_lines_with_ghosts(version_id, parents, lines,
 
147
                                           parent_texts)
101
148
 
102
 
    def _add_lines_with_ghosts(self, version_id, parents, lines):
 
149
    def _add_lines_with_ghosts(self, version_id, parents, lines, parent_texts):
103
150
        """Helper to do class specific add_lines_with_ghosts."""
104
151
        raise NotImplementedError(self.add_lines_with_ghosts)
105
152
 
156
203
        """Helper for fix_parents."""
157
204
        raise NotImplementedError(self.fix_parents)
158
205
 
 
206
    def get_delta(self, version):
 
207
        """Get a delta for constructing version from some other version.
 
208
        
 
209
        :return: (delta_parent, sha1, noeol, delta)
 
210
        Where delta_parent is a version id or None to indicate no parent.
 
211
        """
 
212
        raise NotImplementedError(self.get_delta)
 
213
 
 
214
    def get_deltas(self, versions):
 
215
        """Get multiple deltas at once for constructing versions.
 
216
        
 
217
        :return: dict(version_id:(delta_parent, sha1, noeol, delta))
 
218
        Where delta_parent is a version id or None to indicate no parent, and
 
219
        version_id is the version_id created by that delta.
 
220
        """
 
221
        result = {}
 
222
        for version in versions:
 
223
            result[version] = self.get_delta(version)
 
224
        return result
 
225
 
159
226
    def get_suffixes(self):
160
227
        """Return the file suffixes associated with this versioned file."""
161
228
        raise NotImplementedError(self.get_suffixes)
256
323
    def annotate(self, version_id):
257
324
        return list(self.annotate_iter(version_id))
258
325
 
 
326
    def _apply_delta(self, lines, delta):
 
327
        """Apply delta to lines."""
 
328
        lines = list(lines)
 
329
        offset = 0
 
330
        for start, end, count, delta_lines in delta:
 
331
            lines[offset+start:offset+end] = delta_lines
 
332
            offset = offset + (start - end) + count
 
333
        return lines
 
334
 
259
335
    def join(self, other, pb=None, msg=None, version_ids=None,
260
336
             ignore_missing=False):
261
337
        """Integrate versions from other into this versioned file.
456
532
        graph = self.source.get_graph()
457
533
        order = topo_sort(graph.items())
458
534
        pb = ui.ui_factory.nested_progress_bar()
 
535
        parent_texts = {}
459
536
        try:
 
537
            # TODO for incremental cross-format work:
 
538
            # make a versioned file with the following content:
 
539
            # all revisions we have been asked to join
 
540
            # all their ancestors that are *not* in target already.
 
541
            # the immediate parents of the above two sets, with 
 
542
            # empty parent lists - these versions are in target already
 
543
            # and the incorrect version data will be ignored.
 
544
            # TODO: for all ancestors that are present in target already,
 
545
            # check them for consistent data, this requires moving sha1 from
 
546
            # 
 
547
            # TODO: remove parent texts when they are not relevant any more for 
 
548
            # memory pressure reduction. RBC 20060313
 
549
            # pb.update('Converting versioned data', 0, len(order))
 
550
            # deltas = self.source.get_deltas(order)
460
551
            for index, version in enumerate(order):
461
552
                pb.update('Converting versioned data', index, len(order))
462
 
                target.add_lines(version,
463
 
                                 self.source.get_parents(version),
464
 
                                 self.source.get_lines(version))
 
553
                parent_text = target.add_lines(version,
 
554
                                               self.source.get_parents(version),
 
555
                                               self.source.get_lines(version),
 
556
                                               parent_texts=parent_texts)
 
557
                parent_texts[version] = parent_text
 
558
                #delta_parent, sha1, noeol, delta = deltas[version]
 
559
                #target.add_delta(version,
 
560
                #                 self.source.get_parents(version),
 
561
                #                 delta_parent,
 
562
                #                 sha1,
 
563
                #                 noeol,
 
564
                #                 delta)
 
565
                #target.get_lines(version)
465
566
            
466
567
            # this should hit the native code path for target
467
568
            if target is not self.target: