bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
| 
3830.3.12
by Martin Pool
 Review cleanups: unify has_key impls, add missing_keys(), clean up exception blocks  | 
1  | 
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
 | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
2  | 
#
 | 
3  | 
# This program is free software; you can redistribute it and/or modify
 | 
|
4  | 
# it under the terms of the GNU General Public License as published by
 | 
|
5  | 
# the Free Software Foundation; either version 2 of the License, or
 | 
|
6  | 
# (at your option) any later version.
 | 
|
7  | 
#
 | 
|
8  | 
# This program is distributed in the hope that it will be useful,
 | 
|
9  | 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|
10  | 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|
11  | 
# GNU General Public License for more details.
 | 
|
12  | 
#
 | 
|
13  | 
# You should have received a copy of the GNU General Public License
 | 
|
14  | 
# along with this program; if not, write to the Free Software
 | 
|
| 
4183.7.1
by Sabin Iacob
 update FSF mailing address  | 
15  | 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
16  | 
|
17  | 
"""Knit versionedfile implementation.
 | 
|
18  | 
||
19  | 
A knit is a versioned file implementation that supports efficient append only
 | 
|
20  | 
updates.
 | 
|
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
21  | 
|
22  | 
Knit file layout:
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
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
 | 
|
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
26  | 
end-marker; simply "end VERSION"
 | 
27  | 
||
28  | 
delta can be line or full contents.a
 | 
|
29  | 
... the 8's there are the index number of the annotation.
 | 
|
30  | 
version robertc@robertcollins.net-20051003014215-ee2990904cc4c7ad 7 c7d23b2a5bd6ca00e8e266cec0ec228158ee9f9e
 | 
|
31  | 
59,59,3
 | 
|
32  | 
8
 | 
|
33  | 
8         if ie.executable:
 | 
|
34  | 
8             e.set('executable', 'yes')
 | 
|
35  | 
130,130,2
 | 
|
36  | 
8         if elt.get('executable') == 'yes':
 | 
|
37  | 
8             ie.executable = True
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
38  | 
end robertc@robertcollins.net-20051003014215-ee2990904cc4c7ad
 | 
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
39  | 
|
40  | 
||
41  | 
whats in an index:
 | 
|
42  | 
09:33 < jrydberg> lifeless: each index is made up of a tuple of; version id, options, position, size, parents
 | 
|
43  | 
09:33 < jrydberg> lifeless: the parents are currently dictionary compressed
 | 
|
44  | 
09:33 < jrydberg> lifeless: (meaning it currently does not support ghosts)
 | 
|
45  | 
09:33 < lifeless> right
 | 
|
46  | 
09:33 < jrydberg> lifeless: the position and size is the range in the data file
 | 
|
47  | 
||
48  | 
||
49  | 
so the index sequence is the dictionary compressed sequence number used
 | 
|
50  | 
in the deltas to provide line annotation
 | 
|
51  | 
||
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
52  | 
"""
 | 
53  | 
||
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
54  | 
|
| 
1563.2.11
by Robert Collins
 Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.  | 
55  | 
from cStringIO import StringIO  | 
| 
1596.2.28
by Robert Collins
 more knit profile based tuning.  | 
56  | 
from itertools import izip, chain  | 
| 
1756.2.17
by Aaron Bentley
 Fixes suggested by John Meinel  | 
57  | 
import operator  | 
| 
1563.2.6
by Robert Collins
 Start check tests for knits (pending), and remove dead code.  | 
58  | 
import os  | 
| 
3789.2.1
by John Arbash Meinel
 _DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.  | 
59  | 
import sys  | 
| 
1594.2.19
by Robert Collins
 More coalescing tweaks, and knit feedback.  | 
60  | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
61  | 
from bzrlib.lazy_import import lazy_import  | 
62  | 
lazy_import(globals(), """  | 
|
63  | 
from bzrlib import (
 | 
|
| 
2770.1.1
by Aaron Bentley
 Initial implmentation of plain knit annotation  | 
64  | 
    annotate,
 | 
| 
3535.5.1
by John Arbash Meinel
 cleanup a few imports to be lazily loaded.  | 
65  | 
    debug,
 | 
66  | 
    diff,
 | 
|
| 
3224.1.10
by John Arbash Meinel
 Introduce the heads_provider for reannotate.  | 
67  | 
    graph as _mod_graph,
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
68  | 
    index as _mod_index,
 | 
| 
2998.2.2
by John Arbash Meinel
 implement a faster path for copying from packs back to knits.  | 
69  | 
    lru_cache,
 | 
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
70  | 
    pack,
 | 
| 
3535.5.1
by John Arbash Meinel
 cleanup a few imports to be lazily loaded.  | 
71  | 
    progress,
 | 
| 
2745.1.2
by Robert Collins
 Ensure mutter_callsite is not directly called on a lazy_load object, to make the stacklevel parameter work correctly.  | 
72  | 
    trace,
 | 
| 
3224.5.1
by Andrew Bennetts
 Lots of assorted hackery to reduce the number of imports for common operations. Improves 'rocks', 'st' and 'help' times by ~50ms on my laptop.  | 
73  | 
    tsort,
 | 
| 
3535.5.1
by John Arbash Meinel
 cleanup a few imports to be lazily loaded.  | 
74  | 
    tuned_gzip,
 | 
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
75  | 
    )
 | 
76  | 
""")  | 
|
| 
1911.2.3
by John Arbash Meinel
 Moving everything into a new location so that we can cache more than just revision ids  | 
77  | 
from bzrlib import (  | 
78  | 
errors,  | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
79  | 
osutils,  | 
| 
2104.4.2
by John Arbash Meinel
 Small cleanup and NEWS entry about fixing bug #65714  | 
80  | 
patiencediff,  | 
| 
2158.3.1
by Dmitry Vasiliev
 KnitIndex tests/fixes/optimizations  | 
81  | 
    )
 | 
82  | 
from bzrlib.errors import (  | 
|
83  | 
FileExists,  | 
|
84  | 
NoSuchFile,  | 
|
85  | 
KnitError,  | 
|
86  | 
InvalidRevisionId,  | 
|
87  | 
KnitCorrupt,  | 
|
88  | 
KnitHeaderError,  | 
|
89  | 
RevisionNotPresent,  | 
|
90  | 
RevisionAlreadyPresent,  | 
|
| 
3787.1.1
by Robert Collins
 Embed the failed text in sha1 knit errors.  | 
91  | 
SHA1KnitCorrupt,  | 
| 
2158.3.1
by Dmitry Vasiliev
 KnitIndex tests/fixes/optimizations  | 
92  | 
    )
 | 
93  | 
from bzrlib.osutils import (  | 
|
94  | 
contains_whitespace,  | 
|
95  | 
contains_linebreaks,  | 
|
| 
2850.1.1
by Robert Collins
 * ``KnitVersionedFile.add*`` will no longer cache added records even when  | 
96  | 
sha_string,  | 
| 
2158.3.1
by Dmitry Vasiliev
 KnitIndex tests/fixes/optimizations  | 
97  | 
sha_strings,  | 
| 
3350.3.8
by Robert Collins
 Basic stream insertion, no fast path yet for knit to knit.  | 
98  | 
split_lines,  | 
| 
2158.3.1
by Dmitry Vasiliev
 KnitIndex tests/fixes/optimizations  | 
99  | 
    )
 | 
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
100  | 
from bzrlib.versionedfile import (  | 
| 
3350.3.12
by Robert Collins
 Generate streams with absent records.  | 
101  | 
AbsentContentFactory,  | 
| 
3350.3.8
by Robert Collins
 Basic stream insertion, no fast path yet for knit to knit.  | 
102  | 
adapter_registry,  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
103  | 
ConstantMapper,  | 
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
104  | 
ContentFactory,  | 
| 
3890.2.1
by John Arbash Meinel
 Start working on a ChunkedContentFactory.  | 
105  | 
ChunkedContentFactory,  | 
| 
4111.1.1
by Robert Collins
 Add a groupcompress sort order.  | 
106  | 
sort_groupcompress,  | 
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
107  | 
VersionedFile,  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
108  | 
VersionedFiles,  | 
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
109  | 
    )
 | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
110  | 
|
111  | 
||
112  | 
# TODO: Split out code specific to this format into an associated object.
 | 
|
113  | 
||
114  | 
# TODO: Can we put in some kind of value to check that the index and data
 | 
|
115  | 
# files belong together?
 | 
|
116  | 
||
| 
1759.2.1
by Jelmer Vernooij
 Fix some types (found using aspell).  | 
117  | 
# TODO: accommodate binaries, perhaps by storing a byte count
 | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
118  | 
|
119  | 
# TODO: function to check whole file
 | 
|
120  | 
||
121  | 
# TODO: atomically append data, then measure backwards from the cursor
 | 
|
122  | 
# position after writing to work out where it was located.  we may need to
 | 
|
123  | 
# bypass python file buffering.
 | 
|
124  | 
||
125  | 
DATA_SUFFIX = '.knit'  | 
|
126  | 
INDEX_SUFFIX = '.kndx'  | 
|
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
127  | 
_STREAM_MIN_BUFFER_SIZE = 5*1024*1024  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
128  | 
|
129  | 
||
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
130  | 
class KnitAdapter(object):  | 
131  | 
"""Base class for knit record adaption."""  | 
|
132  | 
||
| 
3350.3.7
by Robert Collins
 Create a registry of versioned file record adapters.  | 
133  | 
def __init__(self, basis_vf):  | 
134  | 
"""Create an adapter which accesses full texts from basis_vf.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
135  | 
|
| 
3350.3.7
by Robert Collins
 Create a registry of versioned file record adapters.  | 
136  | 
        :param basis_vf: A versioned file to access basis texts of deltas from.
 | 
137  | 
            May be None for adapters that do not need to access basis texts.
 | 
|
138  | 
        """
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
139  | 
self._data = KnitVersionedFiles(None, None)  | 
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
140  | 
self._annotate_factory = KnitAnnotateFactory()  | 
141  | 
self._plain_factory = KnitPlainFactory()  | 
|
| 
3350.3.7
by Robert Collins
 Create a registry of versioned file record adapters.  | 
142  | 
self._basis_vf = basis_vf  | 
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
143  | 
|
144  | 
||
145  | 
class FTAnnotatedToUnannotated(KnitAdapter):  | 
|
146  | 
"""An adapter from FT annotated knits to unannotated ones."""  | 
|
147  | 
||
| 
4005.3.1
by Robert Collins
 Change the signature on VersionedFiles adapters to allow less typing and more flexability inside adapters.  | 
148  | 
def get_bytes(self, factory):  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
149  | 
annotated_compressed_bytes = factory._raw_record  | 
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
150  | 
rec, contents = \  | 
151  | 
self._data._parse_record_unchecked(annotated_compressed_bytes)  | 
|
152  | 
content = self._annotate_factory.parse_fulltext(contents, rec[1])  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
153  | 
size, bytes = self._data._record_to_data((rec[1],), rec[3], content.text())  | 
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
154  | 
return bytes  | 
155  | 
||
156  | 
||
157  | 
class DeltaAnnotatedToUnannotated(KnitAdapter):  | 
|
158  | 
"""An adapter for deltas from annotated to unannotated."""  | 
|
159  | 
||
| 
4005.3.1
by Robert Collins
 Change the signature on VersionedFiles adapters to allow less typing and more flexability inside adapters.  | 
160  | 
def get_bytes(self, factory):  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
161  | 
annotated_compressed_bytes = factory._raw_record  | 
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
162  | 
rec, contents = \  | 
163  | 
self._data._parse_record_unchecked(annotated_compressed_bytes)  | 
|
164  | 
delta = self._annotate_factory.parse_line_delta(contents, rec[1],  | 
|
165  | 
plain=True)  | 
|
166  | 
contents = self._plain_factory.lower_line_delta(delta)  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
167  | 
size, bytes = self._data._record_to_data((rec[1],), rec[3], contents)  | 
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
168  | 
return bytes  | 
169  | 
||
170  | 
||
171  | 
class FTAnnotatedToFullText(KnitAdapter):  | 
|
172  | 
"""An adapter from FT annotated knits to unannotated ones."""  | 
|
173  | 
||
| 
4005.3.1
by Robert Collins
 Change the signature on VersionedFiles adapters to allow less typing and more flexability inside adapters.  | 
174  | 
def get_bytes(self, factory):  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
175  | 
annotated_compressed_bytes = factory._raw_record  | 
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
176  | 
rec, contents = \  | 
177  | 
self._data._parse_record_unchecked(annotated_compressed_bytes)  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
178  | 
content, delta = self._annotate_factory.parse_record(factory.key[-1],  | 
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
179  | 
contents, factory._build_details, None)  | 
180  | 
return ''.join(content.text())  | 
|
181  | 
||
182  | 
||
183  | 
class DeltaAnnotatedToFullText(KnitAdapter):  | 
|
184  | 
"""An adapter for deltas from annotated to unannotated."""  | 
|
185  | 
||
| 
4005.3.1
by Robert Collins
 Change the signature on VersionedFiles adapters to allow less typing and more flexability inside adapters.  | 
186  | 
def get_bytes(self, factory):  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
187  | 
annotated_compressed_bytes = factory._raw_record  | 
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
188  | 
rec, contents = \  | 
189  | 
self._data._parse_record_unchecked(annotated_compressed_bytes)  | 
|
190  | 
delta = self._annotate_factory.parse_line_delta(contents, rec[1],  | 
|
191  | 
plain=True)  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
192  | 
compression_parent = factory.parents[0]  | 
193  | 
basis_entry = self._basis_vf.get_record_stream(  | 
|
194  | 
[compression_parent], 'unordered', True).next()  | 
|
195  | 
if basis_entry.storage_kind == 'absent':  | 
|
196  | 
raise errors.RevisionNotPresent(compression_parent, self._basis_vf)  | 
|
| 
3890.2.9
by John Arbash Meinel
 Start using osutils.chunks_as_lines rather than osutils.split_lines.  | 
197  | 
basis_chunks = basis_entry.get_bytes_as('chunked')  | 
198  | 
basis_lines = osutils.chunks_to_lines(basis_chunks)  | 
|
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
199  | 
        # Manually apply the delta because we have one annotated content and
 | 
200  | 
        # one plain.
 | 
|
201  | 
basis_content = PlainKnitContent(basis_lines, compression_parent)  | 
|
202  | 
basis_content.apply_delta(delta, rec[1])  | 
|
203  | 
basis_content._should_strip_eol = factory._build_details[1]  | 
|
204  | 
return ''.join(basis_content.text())  | 
|
205  | 
||
206  | 
||
| 
3350.3.5
by Robert Collins
 Create adapters from plain compressed knit content.  | 
207  | 
class FTPlainToFullText(KnitAdapter):  | 
208  | 
"""An adapter from FT plain knits to unannotated ones."""  | 
|
209  | 
||
| 
4005.3.1
by Robert Collins
 Change the signature on VersionedFiles adapters to allow less typing and more flexability inside adapters.  | 
210  | 
def get_bytes(self, factory):  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
211  | 
compressed_bytes = factory._raw_record  | 
| 
3350.3.5
by Robert Collins
 Create adapters from plain compressed knit content.  | 
212  | 
rec, contents = \  | 
213  | 
self._data._parse_record_unchecked(compressed_bytes)  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
214  | 
content, delta = self._plain_factory.parse_record(factory.key[-1],  | 
| 
3350.3.5
by Robert Collins
 Create adapters from plain compressed knit content.  | 
215  | 
contents, factory._build_details, None)  | 
216  | 
return ''.join(content.text())  | 
|
217  | 
||
218  | 
||
219  | 
class DeltaPlainToFullText(KnitAdapter):  | 
|
220  | 
"""An adapter for deltas from annotated to unannotated."""  | 
|
221  | 
||
| 
4005.3.1
by Robert Collins
 Change the signature on VersionedFiles adapters to allow less typing and more flexability inside adapters.  | 
222  | 
def get_bytes(self, factory):  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
223  | 
compressed_bytes = factory._raw_record  | 
| 
3350.3.5
by Robert Collins
 Create adapters from plain compressed knit content.  | 
224  | 
rec, contents = \  | 
225  | 
self._data._parse_record_unchecked(compressed_bytes)  | 
|
226  | 
delta = self._plain_factory.parse_line_delta(contents, rec[1])  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
227  | 
compression_parent = factory.parents[0]  | 
228  | 
        # XXX: string splitting overhead.
 | 
|
229  | 
basis_entry = self._basis_vf.get_record_stream(  | 
|
230  | 
[compression_parent], 'unordered', True).next()  | 
|
231  | 
if basis_entry.storage_kind == 'absent':  | 
|
232  | 
raise errors.RevisionNotPresent(compression_parent, self._basis_vf)  | 
|
| 
3890.2.9
by John Arbash Meinel
 Start using osutils.chunks_as_lines rather than osutils.split_lines.  | 
233  | 
basis_chunks = basis_entry.get_bytes_as('chunked')  | 
234  | 
basis_lines = osutils.chunks_to_lines(basis_chunks)  | 
|
| 
3350.3.5
by Robert Collins
 Create adapters from plain compressed knit content.  | 
235  | 
basis_content = PlainKnitContent(basis_lines, compression_parent)  | 
236  | 
        # Manually apply the delta because we have one annotated content and
 | 
|
237  | 
        # one plain.
 | 
|
238  | 
content, _ = self._plain_factory.parse_record(rec[1], contents,  | 
|
239  | 
factory._build_details, basis_content)  | 
|
240  | 
return ''.join(content.text())  | 
|
241  | 
||
242  | 
||
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
243  | 
class KnitContentFactory(ContentFactory):  | 
244  | 
"""Content factory for streaming from knits.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
245  | 
|
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
246  | 
    :seealso ContentFactory:
 | 
247  | 
    """
 | 
|
248  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
249  | 
def __init__(self, key, parents, build_details, sha1, raw_record,  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
250  | 
annotated, knit=None, network_bytes=None):  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
251  | 
"""Create a KnitContentFactory for key.  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
252  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
253  | 
        :param key: The key.
 | 
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
254  | 
        :param parents: The parents.
 | 
255  | 
        :param build_details: The build details as returned from
 | 
|
256  | 
            get_build_details.
 | 
|
257  | 
        :param sha1: The sha1 expected from the full text of this object.
 | 
|
258  | 
        :param raw_record: The bytes of the knit data from disk.
 | 
|
259  | 
        :param annotated: True if the raw data is annotated.
 | 
|
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
260  | 
        :param network_bytes: None to calculate the network bytes on demand,
 | 
261  | 
            not-none if they are already known.
 | 
|
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
262  | 
        """
 | 
263  | 
ContentFactory.__init__(self)  | 
|
264  | 
self.sha1 = sha1  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
265  | 
self.key = key  | 
266  | 
self.parents = parents  | 
|
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
267  | 
if build_details[0] == 'line-delta':  | 
268  | 
kind = 'delta'  | 
|
269  | 
else:  | 
|
270  | 
kind = 'ft'  | 
|
271  | 
if annotated:  | 
|
272  | 
annotated_kind = 'annotated-'  | 
|
273  | 
else:  | 
|
274  | 
annotated_kind = ''  | 
|
275  | 
self.storage_kind = 'knit-%s%s-gz' % (annotated_kind, kind)  | 
|
276  | 
self._raw_record = raw_record  | 
|
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
277  | 
self._network_bytes = network_bytes  | 
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
278  | 
self._build_details = build_details  | 
279  | 
self._knit = knit  | 
|
280  | 
||
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
281  | 
def _create_network_bytes(self):  | 
282  | 
"""Create a fully serialised network version for transmission."""  | 
|
283  | 
        # storage_kind, key, parents, Noeol, raw_record
 | 
|
284  | 
key_bytes = '\x00'.join(self.key)  | 
|
285  | 
if self.parents is None:  | 
|
286  | 
parent_bytes = 'None:'  | 
|
287  | 
else:  | 
|
288  | 
parent_bytes = '\t'.join('\x00'.join(key) for key in self.parents)  | 
|
289  | 
if self._build_details[1]:  | 
|
290  | 
noeol = 'N'  | 
|
291  | 
else:  | 
|
292  | 
noeol = ' '  | 
|
293  | 
network_bytes = "%s\n%s\n%s\n%s%s" % (self.storage_kind, key_bytes,  | 
|
294  | 
parent_bytes, noeol, self._raw_record)  | 
|
295  | 
self._network_bytes = network_bytes  | 
|
296  | 
||
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
297  | 
def get_bytes_as(self, storage_kind):  | 
298  | 
if storage_kind == self.storage_kind:  | 
|
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
299  | 
if self._network_bytes is None:  | 
300  | 
self._create_network_bytes()  | 
|
301  | 
return self._network_bytes  | 
|
| 
4152.1.2
by Robert Collins
 Add streaming from a stacked branch when the sort order is compatible with doing so.  | 
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  | 
|
| 
3890.2.1
by John Arbash Meinel
 Start working on a ChunkedContentFactory.  | 
312  | 
if self._knit is not None:  | 
| 
4152.1.2
by Robert Collins
 Add streaming from a stacked branch when the sort order is compatible with doing so.  | 
313  | 
            # Not redundant with direct conversion above - that only handles
 | 
314  | 
            # fulltext cases.
 | 
|
| 
3890.2.1
by John Arbash Meinel
 Start working on a ChunkedContentFactory.  | 
315  | 
if storage_kind == 'chunked':  | 
316  | 
return self._knit.get_lines(self.key[0])  | 
|
317  | 
elif storage_kind == 'fulltext':  | 
|
318  | 
return self._knit.get_text(self.key[0])  | 
|
319  | 
raise errors.UnavailableRepresentation(self.key, storage_kind,  | 
|
320  | 
self.storage_kind)  | 
|
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
321  | 
|
322  | 
||
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
323  | 
class LazyKnitContentFactory(ContentFactory):  | 
324  | 
"""A ContentFactory which can either generate full text or a wire form.  | 
|
325  | 
||
326  | 
    :seealso ContentFactory:
 | 
|
327  | 
    """
 | 
|
328  | 
||
329  | 
def __init__(self, key, parents, generator, first):  | 
|
330  | 
"""Create a LazyKnitContentFactory.  | 
|
| 
4032.1.1
by John Arbash Meinel
 Merge the removal of all trailing whitespace, and resolve conflicts.  | 
331  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
332  | 
        :param key: The key of the record.
 | 
333  | 
        :param parents: The parents of the record.
 | 
|
334  | 
        :param generator: A _ContentMapGenerator containing the record for this
 | 
|
335  | 
            key.
 | 
|
336  | 
        :param first: Is this the first content object returned from generator?
 | 
|
337  | 
            if it is, its storage kind is knit-delta-closure, otherwise it is
 | 
|
338  | 
            knit-delta-closure-ref
 | 
|
339  | 
        """
 | 
|
340  | 
self.key = key  | 
|
341  | 
self.parents = parents  | 
|
342  | 
self.sha1 = None  | 
|
343  | 
self._generator = generator  | 
|
344  | 
self.storage_kind = "knit-delta-closure"  | 
|
345  | 
if not first:  | 
|
346  | 
self.storage_kind = self.storage_kind + "-ref"  | 
|
347  | 
self._first = first  | 
|
348  | 
||
349  | 
def get_bytes_as(self, storage_kind):  | 
|
350  | 
if storage_kind == self.storage_kind:  | 
|
351  | 
if self._first:  | 
|
352  | 
return self._generator._wire_bytes()  | 
|
353  | 
else:  | 
|
354  | 
                # all the keys etc are contained in the bytes returned in the
 | 
|
355  | 
                # first record.
 | 
|
356  | 
return ''  | 
|
357  | 
if storage_kind in ('chunked', 'fulltext'):  | 
|
358  | 
chunks = self._generator._get_one_work(self.key).text()  | 
|
359  | 
if storage_kind == 'chunked':  | 
|
360  | 
return chunks  | 
|
361  | 
else:  | 
|
362  | 
return ''.join(chunks)  | 
|
363  | 
raise errors.UnavailableRepresentation(self.key, storage_kind,  | 
|
364  | 
self.storage_kind)  | 
|
365  | 
||
366  | 
||
367  | 
def knit_delta_closure_to_records(storage_kind, bytes, line_end):  | 
|
368  | 
"""Convert a network record to a iterator over stream records.  | 
|
369  | 
||
370  | 
    :param storage_kind: The storage kind of the record.
 | 
|
371  | 
        Must be 'knit-delta-closure'.
 | 
|
372  | 
    :param bytes: The bytes of the record on the network.
 | 
|
373  | 
    """
 | 
|
374  | 
generator = _NetworkContentMapGenerator(bytes, line_end)  | 
|
375  | 
return generator.get_record_stream()  | 
|
376  | 
||
377  | 
||
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
378  | 
def knit_network_to_record(storage_kind, bytes, line_end):  | 
379  | 
"""Convert a network record to a record object.  | 
|
380  | 
||
381  | 
    :param storage_kind: The storage kind of the record.
 | 
|
382  | 
    :param bytes: The bytes of the record on the network.
 | 
|
383  | 
    """
 | 
|
384  | 
start = line_end  | 
|
385  | 
line_end = bytes.find('\n', start)  | 
|
| 
4005.3.3
by Robert Collins
 Test NetworkRecordStream with delta'd texts.  | 
386  | 
key = tuple(bytes[start:line_end].split('\x00'))  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
387  | 
start = line_end + 1  | 
388  | 
line_end = bytes.find('\n', start)  | 
|
389  | 
parent_line = bytes[start:line_end]  | 
|
390  | 
if parent_line == 'None:':  | 
|
391  | 
parents = None  | 
|
392  | 
else:  | 
|
393  | 
parents = tuple(  | 
|
| 
4005.3.3
by Robert Collins
 Test NetworkRecordStream with delta'd texts.  | 
394  | 
[tuple(segment.split('\x00')) for segment in parent_line.split('\t')  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
395  | 
if segment])  | 
396  | 
start = line_end + 1  | 
|
| 
4005.3.3
by Robert Collins
 Test NetworkRecordStream with delta'd texts.  | 
397  | 
noeol = bytes[start] == 'N'  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
398  | 
if 'ft' in storage_kind:  | 
399  | 
method = 'fulltext'  | 
|
400  | 
else:  | 
|
401  | 
method = 'line-delta'  | 
|
402  | 
build_details = (method, noeol)  | 
|
403  | 
start = start + 1  | 
|
404  | 
raw_record = bytes[start:]  | 
|
405  | 
annotated = 'annotated' in storage_kind  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
406  | 
return [KnitContentFactory(key, parents, build_details, None, raw_record,  | 
407  | 
annotated, network_bytes=bytes)]  | 
|
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
408  | 
|
409  | 
||
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
410  | 
class KnitContent(object):  | 
| 
3468.2.4
by Martin Pool
 Test and fix #234748 problems in trailing newline diffs  | 
411  | 
"""Content of a knit version to which deltas can be applied.  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
412  | 
|
| 
3468.2.5
by Martin Pool
 Correct comment and remove overbroad except block  | 
413  | 
    This is always stored in memory as a list of lines with \n at the end,
 | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
414  | 
    plus a flag saying if the final ending is really there or not, because that
 | 
| 
3468.2.5
by Martin Pool
 Correct comment and remove overbroad except block  | 
415  | 
    corresponds to the on-disk knit representation.
 | 
| 
3468.2.4
by Martin Pool
 Test and fix #234748 problems in trailing newline diffs  | 
416  | 
    """
 | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
417  | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
418  | 
def __init__(self):  | 
419  | 
self._should_strip_eol = False  | 
|
420  | 
||
| 
2921.2.1
by Robert Collins
 * Knit text reconstruction now avoids making copies of the lines list for  | 
421  | 
def apply_delta(self, delta, new_version_id):  | 
| 
2921.2.2
by Robert Collins
 Review feedback.  | 
422  | 
"""Apply delta to this object to become new_version_id."""  | 
| 
2921.2.1
by Robert Collins
 * Knit text reconstruction now avoids making copies of the lines list for  | 
423  | 
raise NotImplementedError(self.apply_delta)  | 
424  | 
||
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
425  | 
def line_delta_iter(self, new_lines):  | 
| 
1596.2.32
by Robert Collins
 Reduce re-extraction of texts during weave to knit joins by providing a memoisation facility.  | 
426  | 
"""Generate line-based delta from this content to new_lines."""  | 
| 
2151.1.1
by John Arbash Meinel
 (Dmitry Vasiliev) Tune KnitContent and add tests  | 
427  | 
new_texts = new_lines.text()  | 
428  | 
old_texts = self.text()  | 
|
| 
2781.1.1
by Martin Pool
 merge cpatiencediff from Lukas  | 
429  | 
s = patiencediff.PatienceSequenceMatcher(None, old_texts, new_texts)  | 
| 
2151.1.1
by John Arbash Meinel
 (Dmitry Vasiliev) Tune KnitContent and add tests  | 
430  | 
for tag, i1, i2, j1, j2 in s.get_opcodes():  | 
431  | 
if tag == 'equal':  | 
|
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
432  | 
                continue
 | 
| 
2151.1.1
by John Arbash Meinel
 (Dmitry Vasiliev) Tune KnitContent and add tests  | 
433  | 
            # ofrom, oto, length, data
 | 
434  | 
yield i1, i2, j2 - j1, new_lines._lines[j1:j2]  | 
|
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
435  | 
|
436  | 
def line_delta(self, new_lines):  | 
|
437  | 
return list(self.line_delta_iter(new_lines))  | 
|
438  | 
||
| 
2520.4.41
by Aaron Bentley
 Accelerate mpdiff generation  | 
439  | 
    @staticmethod
 | 
| 
2520.4.48
by Aaron Bentley
 Support getting blocks from knit deltas with no final EOL  | 
440  | 
def get_line_delta_blocks(knit_delta, source, target):  | 
| 
2520.4.41
by Aaron Bentley
 Accelerate mpdiff generation  | 
441  | 
"""Extract SequenceMatcher.get_matching_blocks() from a knit delta"""  | 
| 
2520.4.48
by Aaron Bentley
 Support getting blocks from knit deltas with no final EOL  | 
442  | 
target_len = len(target)  | 
| 
2520.4.41
by Aaron Bentley
 Accelerate mpdiff generation  | 
443  | 
s_pos = 0  | 
444  | 
t_pos = 0  | 
|
445  | 
for s_begin, s_end, t_len, new_text in knit_delta:  | 
|
| 
2520.4.47
by Aaron Bentley
 Fix get_line_delta_blocks with eol  | 
446  | 
true_n = s_begin - s_pos  | 
447  | 
n = true_n  | 
|
| 
2520.4.41
by Aaron Bentley
 Accelerate mpdiff generation  | 
448  | 
if n > 0:  | 
| 
2520.4.48
by Aaron Bentley
 Support getting blocks from knit deltas with no final EOL  | 
449  | 
                # knit deltas do not provide reliable info about whether the
 | 
450  | 
                # last line of a file matches, due to eol handling.
 | 
|
451  | 
if source[s_pos + n -1] != target[t_pos + n -1]:  | 
|
| 
2520.4.47
by Aaron Bentley
 Fix get_line_delta_blocks with eol  | 
452  | 
n-=1  | 
453  | 
if n > 0:  | 
|
454  | 
yield s_pos, t_pos, n  | 
|
455  | 
t_pos += t_len + true_n  | 
|
| 
2520.4.41
by Aaron Bentley
 Accelerate mpdiff generation  | 
456  | 
s_pos = s_end  | 
| 
2520.4.48
by Aaron Bentley
 Support getting blocks from knit deltas with no final EOL  | 
457  | 
n = target_len - t_pos  | 
458  | 
if n > 0:  | 
|
459  | 
if source[s_pos + n -1] != target[t_pos + n -1]:  | 
|
460  | 
n-=1  | 
|
461  | 
if n > 0:  | 
|
462  | 
yield s_pos, t_pos, n  | 
|
| 
2520.4.41
by Aaron Bentley
 Accelerate mpdiff generation  | 
463  | 
yield s_pos + (target_len - t_pos), target_len, 0  | 
464  | 
||
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
465  | 
|
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
466  | 
class AnnotatedKnitContent(KnitContent):  | 
467  | 
"""Annotated content."""  | 
|
468  | 
||
469  | 
def __init__(self, lines):  | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
470  | 
KnitContent.__init__(self)  | 
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
471  | 
self._lines = lines  | 
472  | 
||
| 
3316.2.13
by Robert Collins
 * ``VersionedFile.annotate_iter`` is deprecated. While in principal this  | 
473  | 
def annotate(self):  | 
474  | 
"""Return a list of (origin, text) for each content line."""  | 
|
| 
3468.2.4
by Martin Pool
 Test and fix #234748 problems in trailing newline diffs  | 
475  | 
lines = self._lines[:]  | 
476  | 
if self._should_strip_eol:  | 
|
477  | 
origin, last_line = lines[-1]  | 
|
478  | 
lines[-1] = (origin, last_line.rstrip('\n'))  | 
|
479  | 
return lines  | 
|
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
480  | 
|
| 
2921.2.1
by Robert Collins
 * Knit text reconstruction now avoids making copies of the lines list for  | 
481  | 
def apply_delta(self, delta, new_version_id):  | 
| 
2921.2.2
by Robert Collins
 Review feedback.  | 
482  | 
"""Apply delta to this object to become new_version_id."""  | 
| 
2921.2.1
by Robert Collins
 * Knit text reconstruction now avoids making copies of the lines list for  | 
483  | 
offset = 0  | 
484  | 
lines = self._lines  | 
|
485  | 
for start, end, count, delta_lines in delta:  | 
|
486  | 
lines[offset+start:offset+end] = delta_lines  | 
|
487  | 
offset = offset + (start - end) + count  | 
|
488  | 
||
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
489  | 
def text(self):  | 
| 
2911.1.1
by Martin Pool
 Better messages when problems are detected inside a knit  | 
490  | 
try:  | 
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
491  | 
lines = [text for origin, text in self._lines]  | 
| 
2911.1.1
by Martin Pool
 Better messages when problems are detected inside a knit  | 
492  | 
except ValueError, e:  | 
493  | 
            # most commonly (only?) caused by the internal form of the knit
 | 
|
494  | 
            # missing annotation information because of a bug - see thread
 | 
|
495  | 
            # around 20071015
 | 
|
496  | 
raise KnitCorrupt(self,  | 
|
497  | 
"line in annotated knit missing annotation information: %s"  | 
|
498  | 
% (e,))  | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
499  | 
if self._should_strip_eol:  | 
| 
3350.3.4
by Robert Collins
 Finish adapters for annotated knits to unannotated knits and full texts.  | 
500  | 
lines[-1] = lines[-1].rstrip('\n')  | 
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
501  | 
return lines  | 
502  | 
||
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
503  | 
def copy(self):  | 
504  | 
return AnnotatedKnitContent(self._lines[:])  | 
|
505  | 
||
506  | 
||
507  | 
class PlainKnitContent(KnitContent):  | 
|
| 
2794.1.3
by Robert Collins
 Review feedback.  | 
508  | 
"""Unannotated content.  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
509  | 
|
| 
2794.1.3
by Robert Collins
 Review feedback.  | 
510  | 
    When annotate[_iter] is called on this content, the same version is reported
 | 
511  | 
    for all lines. Generally, annotate[_iter] is not useful on PlainKnitContent
 | 
|
512  | 
    objects.
 | 
|
513  | 
    """
 | 
|
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
514  | 
|
515  | 
def __init__(self, lines, version_id):  | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
516  | 
KnitContent.__init__(self)  | 
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
517  | 
self._lines = lines  | 
518  | 
self._version_id = version_id  | 
|
519  | 
||
| 
3316.2.13
by Robert Collins
 * ``VersionedFile.annotate_iter`` is deprecated. While in principal this  | 
520  | 
def annotate(self):  | 
521  | 
"""Return a list of (origin, text) for each content line."""  | 
|
522  | 
return [(self._version_id, line) for line in self._lines]  | 
|
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
523  | 
|
| 
2921.2.1
by Robert Collins
 * Knit text reconstruction now avoids making copies of the lines list for  | 
524  | 
def apply_delta(self, delta, new_version_id):  | 
| 
2921.2.2
by Robert Collins
 Review feedback.  | 
525  | 
"""Apply delta to this object to become new_version_id."""  | 
| 
2921.2.1
by Robert Collins
 * Knit text reconstruction now avoids making copies of the lines list for  | 
526  | 
offset = 0  | 
527  | 
lines = self._lines  | 
|
528  | 
for start, end, count, delta_lines in delta:  | 
|
529  | 
lines[offset+start:offset+end] = delta_lines  | 
|
530  | 
offset = offset + (start - end) + count  | 
|
531  | 
self._version_id = new_version_id  | 
|
532  | 
||
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
533  | 
def copy(self):  | 
534  | 
return PlainKnitContent(self._lines[:], self._version_id)  | 
|
535  | 
||
536  | 
def text(self):  | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
537  | 
lines = self._lines  | 
538  | 
if self._should_strip_eol:  | 
|
539  | 
lines = lines[:]  | 
|
540  | 
lines[-1] = lines[-1].rstrip('\n')  | 
|
541  | 
return lines  | 
|
542  | 
||
543  | 
||
544  | 
class _KnitFactory(object):  | 
|
545  | 
"""Base class for common Factory functions."""  | 
|
546  | 
||
547  | 
def parse_record(self, version_id, record, record_details,  | 
|
548  | 
base_content, copy_base_content=True):  | 
|
549  | 
"""Parse a record into a full content object.  | 
|
550  | 
||
551  | 
        :param version_id: The official version id for this content
 | 
|
552  | 
        :param record: The data returned by read_records_iter()
 | 
|
553  | 
        :param record_details: Details about the record returned by
 | 
|
554  | 
            get_build_details
 | 
|
555  | 
        :param base_content: If get_build_details returns a compression_parent,
 | 
|
556  | 
            you must return a base_content here, else use None
 | 
|
557  | 
        :param copy_base_content: When building from the base_content, decide
 | 
|
558  | 
            you can either copy it and return a new object, or modify it in
 | 
|
559  | 
            place.
 | 
|
560  | 
        :return: (content, delta) A Content object and possibly a line-delta,
 | 
|
561  | 
            delta may be None
 | 
|
562  | 
        """
 | 
|
563  | 
method, noeol = record_details  | 
|
564  | 
if method == 'line-delta':  | 
|
565  | 
if copy_base_content:  | 
|
566  | 
content = base_content.copy()  | 
|
567  | 
else:  | 
|
568  | 
content = base_content  | 
|
569  | 
delta = self.parse_line_delta(record, version_id)  | 
|
570  | 
content.apply_delta(delta, version_id)  | 
|
571  | 
else:  | 
|
572  | 
content = self.parse_fulltext(record, version_id)  | 
|
573  | 
delta = None  | 
|
574  | 
content._should_strip_eol = noeol  | 
|
575  | 
return (content, delta)  | 
|
576  | 
||
577  | 
||
578  | 
class KnitAnnotateFactory(_KnitFactory):  | 
|
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
579  | 
"""Factory for creating annotated Content objects."""  | 
580  | 
||
581  | 
annotated = True  | 
|
582  | 
||
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
583  | 
def make(self, lines, version_id):  | 
584  | 
num_lines = len(lines)  | 
|
585  | 
return AnnotatedKnitContent(zip([version_id] * num_lines, lines))  | 
|
586  | 
||
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
587  | 
def parse_fulltext(self, content, version_id):  | 
| 
1596.2.7
by Robert Collins
 Remove the requirement for reannotation in knit joins.  | 
588  | 
"""Convert fulltext to internal representation  | 
589  | 
||
590  | 
        fulltext content is of the format
 | 
|
591  | 
        revid(utf8) plaintext\n
 | 
|
592  | 
        internal representation is of the format:
 | 
|
593  | 
        (revid, plaintext)
 | 
|
594  | 
        """
 | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
595  | 
        # TODO: jam 20070209 The tests expect this to be returned as tuples,
 | 
596  | 
        #       but the code itself doesn't really depend on that.
 | 
|
597  | 
        #       Figure out a way to not require the overhead of turning the
 | 
|
598  | 
        #       list back into tuples.
 | 
|
599  | 
lines = [tuple(line.split(' ', 1)) for line in content]  | 
|
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
600  | 
return AnnotatedKnitContent(lines)  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
601  | 
|
602  | 
def parse_line_delta_iter(self, lines):  | 
|
| 
2163.1.2
by John Arbash Meinel
 Don't modify the list during parse_line_delta  | 
603  | 
return iter(self.parse_line_delta(lines))  | 
| 
1628.1.2
by Robert Collins
 More knit micro-optimisations.  | 
604  | 
|
| 
2851.4.2
by Ian Clatworthy
 use factory methods in annotated-to-plain conversion instead of duplicating format knowledge  | 
605  | 
def parse_line_delta(self, lines, version_id, plain=False):  | 
| 
1596.2.7
by Robert Collins
 Remove the requirement for reannotation in knit joins.  | 
606  | 
"""Convert a line based delta into internal representation.  | 
607  | 
||
608  | 
        line delta is in the form of:
 | 
|
609  | 
        intstart intend intcount
 | 
|
610  | 
        1..count lines:
 | 
|
611  | 
        revid(utf8) newline\n
 | 
|
| 
1759.2.1
by Jelmer Vernooij
 Fix some types (found using aspell).  | 
612  | 
        internal representation is
 | 
| 
1596.2.7
by Robert Collins
 Remove the requirement for reannotation in knit joins.  | 
613  | 
        (start, end, count, [1..count tuples (revid, newline)])
 | 
| 
2851.4.2
by Ian Clatworthy
 use factory methods in annotated-to-plain conversion instead of duplicating format knowledge  | 
614  | 
|
615  | 
        :param plain: If True, the lines are returned as a plain
 | 
|
| 
2911.1.1
by Martin Pool
 Better messages when problems are detected inside a knit  | 
616  | 
            list without annotations, not as a list of (origin, content) tuples, i.e.
 | 
| 
2851.4.2
by Ian Clatworthy
 use factory methods in annotated-to-plain conversion instead of duplicating format knowledge  | 
617  | 
            (start, end, count, [1..count newline])
 | 
| 
1596.2.7
by Robert Collins
 Remove the requirement for reannotation in knit joins.  | 
618  | 
        """
 | 
| 
1628.1.2
by Robert Collins
 More knit micro-optimisations.  | 
619  | 
result = []  | 
620  | 
lines = iter(lines)  | 
|
621  | 
next = lines.next  | 
|
| 
2249.5.1
by John Arbash Meinel
 Leave revision-ids in utf-8 when reading.  | 
622  | 
|
| 
2249.5.15
by John Arbash Meinel
 remove get_cached_utf8 checks which were slowing things down.  | 
623  | 
cache = {}  | 
624  | 
def cache_and_return(line):  | 
|
625  | 
origin, text = line.split(' ', 1)  | 
|
626  | 
return cache.setdefault(origin, origin), text  | 
|
627  | 
||
| 
1628.1.2
by Robert Collins
 More knit micro-optimisations.  | 
628  | 
        # walk through the lines parsing.
 | 
| 
2851.4.2
by Ian Clatworthy
 use factory methods in annotated-to-plain conversion instead of duplicating format knowledge  | 
629  | 
        # Note that the plain test is explicitly pulled out of the
 | 
630  | 
        # loop to minimise any performance impact
 | 
|
631  | 
if plain:  | 
|
632  | 
for header in lines:  | 
|
633  | 
start, end, count = [int(n) for n in header.split(',')]  | 
|
634  | 
contents = [next().split(' ', 1)[1] for i in xrange(count)]  | 
|
635  | 
result.append((start, end, count, contents))  | 
|
636  | 
else:  | 
|
637  | 
for header in lines:  | 
|
638  | 
start, end, count = [int(n) for n in header.split(',')]  | 
|
639  | 
contents = [tuple(next().split(' ', 1)) for i in xrange(count)]  | 
|
640  | 
result.append((start, end, count, contents))  | 
|
| 
1628.1.2
by Robert Collins
 More knit micro-optimisations.  | 
641  | 
return result  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
642  | 
|
| 
2163.2.2
by John Arbash Meinel
 Don't deal with annotations when we don't care about them. Saves another 300+ms  | 
643  | 
def get_fulltext_content(self, lines):  | 
644  | 
"""Extract just the content lines from a fulltext."""  | 
|
645  | 
return (line.split(' ', 1)[1] for line in lines)  | 
|
646  | 
||
647  | 
def get_linedelta_content(self, lines):  | 
|
648  | 
"""Extract just the content from a line delta.  | 
|
649  | 
||
650  | 
        This doesn't return all of the extra information stored in a delta.
 | 
|
651  | 
        Only the actual content lines.
 | 
|
652  | 
        """
 | 
|
653  | 
lines = iter(lines)  | 
|
654  | 
next = lines.next  | 
|
655  | 
for header in lines:  | 
|
656  | 
header = header.split(',')  | 
|
657  | 
count = int(header[2])  | 
|
658  | 
for i in xrange(count):  | 
|
659  | 
origin, text = next().split(' ', 1)  | 
|
660  | 
yield text  | 
|
661  | 
||
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
662  | 
def lower_fulltext(self, content):  | 
| 
1596.2.7
by Robert Collins
 Remove the requirement for reannotation in knit joins.  | 
663  | 
"""convert a fulltext content record into a serializable form.  | 
664  | 
||
665  | 
        see parse_fulltext which this inverts.
 | 
|
666  | 
        """
 | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
667  | 
        # TODO: jam 20070209 We only do the caching thing to make sure that
 | 
668  | 
        #       the origin is a valid utf-8 line, eventually we could remove it
 | 
|
| 
2249.5.15
by John Arbash Meinel
 remove get_cached_utf8 checks which were slowing things down.  | 
669  | 
return ['%s %s' % (o, t) for o, t in content._lines]  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
670  | 
|
671  | 
def lower_line_delta(self, delta):  | 
|
| 
1596.2.7
by Robert Collins
 Remove the requirement for reannotation in knit joins.  | 
672  | 
"""convert a delta into a serializable form.  | 
673  | 
||
| 
1628.1.2
by Robert Collins
 More knit micro-optimisations.  | 
674  | 
        See parse_line_delta which this inverts.
 | 
| 
1596.2.7
by Robert Collins
 Remove the requirement for reannotation in knit joins.  | 
675  | 
        """
 | 
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
676  | 
        # TODO: jam 20070209 We only do the caching thing to make sure that
 | 
677  | 
        #       the origin is a valid utf-8 line, eventually we could remove it
 | 
|
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
678  | 
out = []  | 
679  | 
for start, end, c, lines in delta:  | 
|
680  | 
out.append('%d,%d,%d\n' % (start, end, c))  | 
|
| 
2249.5.15
by John Arbash Meinel
 remove get_cached_utf8 checks which were slowing things down.  | 
681  | 
out.extend(origin + ' ' + text  | 
| 
1911.2.1
by John Arbash Meinel
 Cache encode/decode operations, saves memory and time. Especially when committing a new kernel tree with 7.7M new lines to annotate  | 
682  | 
for origin, text in lines)  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
683  | 
return out  | 
684  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
685  | 
def annotate(self, knit, key):  | 
686  | 
content = knit._get_content(key)  | 
|
687  | 
        # adjust for the fact that serialised annotations are only key suffixes
 | 
|
688  | 
        # for this factory.
 | 
|
689  | 
if type(key) == tuple:  | 
|
690  | 
prefix = key[:-1]  | 
|
691  | 
origins = content.annotate()  | 
|
692  | 
result = []  | 
|
693  | 
for origin, line in origins:  | 
|
694  | 
result.append((prefix + (origin,), line))  | 
|
695  | 
return result  | 
|
696  | 
else:  | 
|
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
697  | 
            # XXX: This smells a bit.  Why would key ever be a non-tuple here?
 | 
698  | 
            # Aren't keys defined to be tuples?  -- spiv 20080618
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
699  | 
return content.annotate()  | 
| 
2770.1.1
by Aaron Bentley
 Initial implmentation of plain knit annotation  | 
700  | 
|
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
701  | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
702  | 
class KnitPlainFactory(_KnitFactory):  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
703  | 
"""Factory for creating plain Content objects."""  | 
704  | 
||
705  | 
annotated = False  | 
|
706  | 
||
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
707  | 
def make(self, lines, version_id):  | 
708  | 
return PlainKnitContent(lines, version_id)  | 
|
709  | 
||
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
710  | 
def parse_fulltext(self, content, version_id):  | 
| 
1596.2.7
by Robert Collins
 Remove the requirement for reannotation in knit joins.  | 
711  | 
"""This parses an unannotated fulltext.  | 
712  | 
||
713  | 
        Note that this is not a noop - the internal representation
 | 
|
714  | 
        has (versionid, line) - its just a constant versionid.
 | 
|
715  | 
        """
 | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
716  | 
return self.make(content, version_id)  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
717  | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
718  | 
def parse_line_delta_iter(self, lines, version_id):  | 
| 
2163.1.2
by John Arbash Meinel
 Don't modify the list during parse_line_delta  | 
719  | 
cur = 0  | 
720  | 
num_lines = len(lines)  | 
|
721  | 
while cur < num_lines:  | 
|
722  | 
header = lines[cur]  | 
|
723  | 
cur += 1  | 
|
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
724  | 
start, end, c = [int(n) for n in header.split(',')]  | 
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
725  | 
yield start, end, c, lines[cur:cur+c]  | 
| 
2163.1.2
by John Arbash Meinel
 Don't modify the list during parse_line_delta  | 
726  | 
cur += c  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
727  | 
|
| 
2249.5.12
by John Arbash Meinel
 Change the APIs for VersionedFile, Store, and some of Repository into utf-8  | 
728  | 
def parse_line_delta(self, lines, version_id):  | 
729  | 
return list(self.parse_line_delta_iter(lines, version_id))  | 
|
| 
2158.3.1
by Dmitry Vasiliev
 KnitIndex tests/fixes/optimizations  | 
730  | 
|
| 
2163.2.2
by John Arbash Meinel
 Don't deal with annotations when we don't care about them. Saves another 300+ms  | 
731  | 
def get_fulltext_content(self, lines):  | 
732  | 
"""Extract just the content lines from a fulltext."""  | 
|
733  | 
return iter(lines)  | 
|
734  | 
||
735  | 
def get_linedelta_content(self, lines):  | 
|
736  | 
"""Extract just the content from a line delta.  | 
|
737  | 
||
738  | 
        This doesn't return all of the extra information stored in a delta.
 | 
|
739  | 
        Only the actual content lines.
 | 
|
740  | 
        """
 | 
|
741  | 
lines = iter(lines)  | 
|
742  | 
next = lines.next  | 
|
743  | 
for header in lines:  | 
|
744  | 
header = header.split(',')  | 
|
745  | 
count = int(header[2])  | 
|
746  | 
for i in xrange(count):  | 
|
747  | 
yield next()  | 
|
748  | 
||
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
749  | 
def lower_fulltext(self, content):  | 
750  | 
return content.text()  | 
|
751  | 
||
752  | 
def lower_line_delta(self, delta):  | 
|
753  | 
out = []  | 
|
754  | 
for start, end, c, lines in delta:  | 
|
755  | 
out.append('%d,%d,%d\n' % (start, end, c))  | 
|
| 
2794.1.2
by Robert Collins
 Nuke versioned file add/get delta support, allowing easy simplification of unannotated Content, reducing memory copies and friction during commit on unannotated texts.  | 
756  | 
out.extend(lines)  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
757  | 
return out  | 
758  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
759  | 
def annotate(self, knit, key):  | 
| 
3224.1.7
by John Arbash Meinel
 _StreamIndex also needs to return the proper values for get_build_details.  | 
760  | 
annotator = _KnitAnnotator(knit)  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
761  | 
return annotator.annotate(key)  | 
762  | 
||
763  | 
||
764  | 
||
765  | 
def make_file_factory(annotated, mapper):  | 
|
766  | 
"""Create a factory for creating a file based KnitVersionedFiles.  | 
|
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
767  | 
|
768  | 
    This is only functional enough to run interface tests, it doesn't try to
 | 
|
769  | 
    provide a full pack environment.
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
770  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
771  | 
    :param annotated: knit annotations are wanted.
 | 
772  | 
    :param mapper: The mapper from keys to paths.
 | 
|
773  | 
    """
 | 
|
774  | 
def factory(transport):  | 
|
775  | 
index = _KndxIndex(transport, mapper, lambda:None, lambda:True, lambda:True)  | 
|
776  | 
access = _KnitKeyAccess(transport, mapper)  | 
|
777  | 
return KnitVersionedFiles(index, access, annotated=annotated)  | 
|
778  | 
return factory  | 
|
779  | 
||
780  | 
||
781  | 
def make_pack_factory(graph, delta, keylength):  | 
|
782  | 
"""Create a factory for creating a pack based VersionedFiles.  | 
|
783  | 
||
784  | 
    This is only functional enough to run interface tests, it doesn't try to
 | 
|
785  | 
    provide a full pack environment.
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
786  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
787  | 
    :param graph: Store a graph.
 | 
788  | 
    :param delta: Delta compress contents.
 | 
|
789  | 
    :param keylength: How long should keys be.
 | 
|
790  | 
    """
 | 
|
791  | 
def factory(transport):  | 
|
792  | 
parents = graph or delta  | 
|
793  | 
ref_length = 0  | 
|
794  | 
if graph:  | 
|
795  | 
ref_length += 1  | 
|
796  | 
if delta:  | 
|
797  | 
ref_length += 1  | 
|
798  | 
max_delta_chain = 200  | 
|
799  | 
else:  | 
|
800  | 
max_delta_chain = 0  | 
|
801  | 
graph_index = _mod_index.InMemoryGraphIndex(reference_lists=ref_length,  | 
|
802  | 
key_elements=keylength)  | 
|
803  | 
stream = transport.open_write_stream('newpack')  | 
|
804  | 
writer = pack.ContainerWriter(stream.write)  | 
|
805  | 
writer.begin()  | 
|
806  | 
index = _KnitGraphIndex(graph_index, lambda:True, parents=parents,  | 
|
807  | 
deltas=delta, add_callback=graph_index.add_nodes)  | 
|
808  | 
access = _DirectPackAccess({})  | 
|
809  | 
access.set_writer(writer, graph_index, (transport, 'newpack'))  | 
|
810  | 
result = KnitVersionedFiles(index, access,  | 
|
811  | 
max_delta_chain=max_delta_chain)  | 
|
812  | 
result.stream = stream  | 
|
813  | 
result.writer = writer  | 
|
814  | 
return result  | 
|
815  | 
return factory  | 
|
816  | 
||
817  | 
||
818  | 
def cleanup_pack_knit(versioned_files):  | 
|
819  | 
versioned_files.stream.close()  | 
|
820  | 
versioned_files.writer.end()  | 
|
821  | 
||
822  | 
||
| 
4039.3.5
by John Arbash Meinel
 Add direct tests for _get_total_build_size.  | 
823  | 
def _get_total_build_size(self, keys, positions):  | 
| 
4039.3.4
by John Arbash Meinel
 Properly determine the total number of bytes needed for a given key.  | 
824  | 
"""Determine the total bytes to build these keys.  | 
825  | 
||
826  | 
    (helper function because _KnitGraphIndex and _KndxIndex work the same, but
 | 
|
827  | 
    don't inherit from a common base.)
 | 
|
828  | 
||
829  | 
    :param keys: Keys that we want to build
 | 
|
830  | 
    :param positions: dict of {key, (info, index_memo, comp_parent)} (such
 | 
|
831  | 
        as returned by _get_components_positions)
 | 
|
832  | 
    :return: Number of bytes to build those keys
 | 
|
833  | 
    """
 | 
|
834  | 
all_build_index_memos = {}  | 
|
835  | 
build_keys = keys  | 
|
836  | 
while build_keys:  | 
|
837  | 
next_keys = set()  | 
|
838  | 
for key in build_keys:  | 
|
839  | 
            # This is mostly for the 'stacked' case
 | 
|
840  | 
            # Where we will be getting the data from a fallback
 | 
|
841  | 
if key not in positions:  | 
|
842  | 
                continue
 | 
|
843  | 
_, index_memo, compression_parent = positions[key]  | 
|
844  | 
all_build_index_memos[key] = index_memo  | 
|
845  | 
if compression_parent not in all_build_index_memos:  | 
|
846  | 
next_keys.add(compression_parent)  | 
|
847  | 
build_keys = next_keys  | 
|
848  | 
return sum([index_memo[2] for index_memo  | 
|
849  | 
in all_build_index_memos.itervalues()])  | 
|
850  | 
||
851  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
852  | 
class KnitVersionedFiles(VersionedFiles):  | 
853  | 
"""Storage for many versioned files using knit compression.  | 
|
854  | 
||
855  | 
    Backend storage is managed by indices and data objects.
 | 
|
| 
3582.1.14
by Martin Pool
 Clearer comments about KnitVersionedFile stacking  | 
856  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
857  | 
    :ivar _index: A _KnitGraphIndex or similar that can describe the
 | 
858  | 
        parents, graph, compression and data location of entries in this
 | 
|
859  | 
        KnitVersionedFiles.  Note that this is only the index for
 | 
|
| 
3582.1.16
by Martin Pool
 Review feedback and news entry  | 
860  | 
        *this* vfs; if there are fallbacks they must be queried separately.
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
861  | 
    """
 | 
862  | 
||
863  | 
def __init__(self, index, data_access, max_delta_chain=200,  | 
|
| 
3789.2.1
by John Arbash Meinel
 _DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.  | 
864  | 
annotated=False, reload_func=None):  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
865  | 
"""Create a KnitVersionedFiles with index and data_access.  | 
866  | 
||
867  | 
        :param index: The index for the knit data.
 | 
|
868  | 
        :param data_access: The access object to store and retrieve knit
 | 
|
869  | 
            records.
 | 
|
870  | 
        :param max_delta_chain: The maximum number of deltas to permit during
 | 
|
871  | 
            insertion. Set to 0 to prohibit the use of deltas.
 | 
|
872  | 
        :param annotated: Set to True to cause annotations to be calculated and
 | 
|
873  | 
            stored during insertion.
 | 
|
| 
3789.2.1
by John Arbash Meinel
 _DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.  | 
874  | 
        :param reload_func: An function that can be called if we think we need
 | 
875  | 
            to reload the pack listing and try again. See
 | 
|
876  | 
            'bzrlib.repofmt.pack_repo.AggregateIndex' for the signature.
 | 
|
| 
1563.2.25
by Robert Collins
 Merge in upstream.  | 
877  | 
        """
 | 
| 
3316.2.3
by Robert Collins
 Remove manual notification of transaction finishing on versioned files.  | 
878  | 
self._index = index  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
879  | 
self._access = data_access  | 
880  | 
self._max_delta_chain = max_delta_chain  | 
|
881  | 
if annotated:  | 
|
882  | 
self._factory = KnitAnnotateFactory()  | 
|
883  | 
else:  | 
|
884  | 
self._factory = KnitPlainFactory()  | 
|
| 
3350.8.1
by Robert Collins
 KnitVersionedFiles.add_fallback_versioned_files exists.  | 
885  | 
self._fallback_vfs = []  | 
| 
3789.2.1
by John Arbash Meinel
 _DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.  | 
886  | 
self._reload_func = reload_func  | 
| 
3350.8.1
by Robert Collins
 KnitVersionedFiles.add_fallback_versioned_files exists.  | 
887  | 
|
| 
3702.1.1
by Martin Pool
 Add repr for KnitVersionedFiles  | 
888  | 
def __repr__(self):  | 
889  | 
return "%s(%r, %r)" % (  | 
|
890  | 
self.__class__.__name__,  | 
|
891  | 
self._index,  | 
|
892  | 
self._access)  | 
|
893  | 
||
| 
3350.8.1
by Robert Collins
 KnitVersionedFiles.add_fallback_versioned_files exists.  | 
894  | 
def add_fallback_versioned_files(self, a_versioned_files):  | 
895  | 
"""Add a source of texts for texts not present in this knit.  | 
|
896  | 
||
897  | 
        :param a_versioned_files: A VersionedFiles object.
 | 
|
898  | 
        """
 | 
|
899  | 
self._fallback_vfs.append(a_versioned_files)  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
900  | 
|
901  | 
def add_lines(self, key, parents, lines, parent_texts=None,  | 
|
902  | 
left_matching_blocks=None, nostore_sha=None, random_id=False,  | 
|
903  | 
check_content=True):  | 
|
904  | 
"""See VersionedFiles.add_lines()."""  | 
|
905  | 
self._index._check_write_ok()  | 
|
906  | 
self._check_add(key, lines, random_id, check_content)  | 
|
907  | 
if parents is None:  | 
|
| 
3350.6.11
by Martin Pool
 Review cleanups and documentation from Robert's mail on 2080618  | 
908  | 
            # The caller might pass None if there is no graph data, but kndx
 | 
909  | 
            # indexes can't directly store that, so we give them
 | 
|
910  | 
            # an empty tuple instead.
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
911  | 
parents = ()  | 
912  | 
return self._add(key, lines, parents,  | 
|
913  | 
parent_texts, left_matching_blocks, nostore_sha, random_id)  | 
|
914  | 
||
915  | 
def _add(self, key, lines, parents, parent_texts,  | 
|
916  | 
left_matching_blocks, nostore_sha, random_id):  | 
|
917  | 
"""Add a set of lines on top of version specified by parents.  | 
|
918  | 
||
919  | 
        Any versions not present will be converted into ghosts.
 | 
|
920  | 
        """
 | 
|
921  | 
        # first thing, if the content is something we don't need to store, find
 | 
|
922  | 
        # that out.
 | 
|
923  | 
line_bytes = ''.join(lines)  | 
|
924  | 
digest = sha_string(line_bytes)  | 
|
925  | 
if nostore_sha == digest:  | 
|
926  | 
raise errors.ExistingContent  | 
|
927  | 
||
928  | 
present_parents = []  | 
|
929  | 
if parent_texts is None:  | 
|
930  | 
parent_texts = {}  | 
|
| 
3830.3.9
by Martin Pool
 Simplify kvf insert_record_stream; add has_key shorthand methods; update stacking effort tests  | 
931  | 
        # Do a single query to ascertain parent presence; we only compress
 | 
932  | 
        # against parents in the same kvf.
 | 
|
933  | 
present_parent_map = self._index.get_parent_map(parents)  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
934  | 
for parent in parents:  | 
935  | 
if parent in present_parent_map:  | 
|
936  | 
present_parents.append(parent)  | 
|
937  | 
||
938  | 
        # Currently we can only compress against the left most present parent.
 | 
|
939  | 
if (len(present_parents) == 0 or  | 
|
940  | 
present_parents[0] != parents[0]):  | 
|
941  | 
delta = False  | 
|
942  | 
else:  | 
|
943  | 
            # To speed the extract of texts the delta chain is limited
 | 
|
944  | 
            # to a fixed number of deltas.  This should minimize both
 | 
|
945  | 
            # I/O and the time spend applying deltas.
 | 
|
946  | 
delta = self._check_should_delta(present_parents[0])  | 
|
947  | 
||
948  | 
text_length = len(line_bytes)  | 
|
949  | 
options = []  | 
|
950  | 
if lines:  | 
|
951  | 
if lines[-1][-1] != '\n':  | 
|
952  | 
                # copy the contents of lines.
 | 
|
953  | 
lines = lines[:]  | 
|
954  | 
options.append('no-eol')  | 
|
955  | 
lines[-1] = lines[-1] + '\n'  | 
|
956  | 
line_bytes += '\n'  | 
|
957  | 
||
| 
4241.4.1
by Ian Clatworthy
 add sha generation support to versionedfiles  | 
958  | 
for element in key[:-1]:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
959  | 
if type(element) != str:  | 
960  | 
raise TypeError("key contains non-strings: %r" % (key,))  | 
|
| 
4241.4.1
by Ian Clatworthy
 add sha generation support to versionedfiles  | 
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,))  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
965  | 
        # Knit hunks are still last-element only
 | 
966  | 
version_id = key[-1]  | 
|
967  | 
content = self._factory.make(lines, version_id)  | 
|
968  | 
if 'no-eol' in options:  | 
|
969  | 
            # Hint to the content object that its text() call should strip the
 | 
|
970  | 
            # EOL.
 | 
|
971  | 
content._should_strip_eol = True  | 
|
972  | 
if delta or (self._factory.annotated and len(present_parents) > 0):  | 
|
973  | 
            # Merge annotations from parent texts if needed.
 | 
|
974  | 
delta_hunks = self._merge_annotations(content, present_parents,  | 
|
975  | 
parent_texts, delta, self._factory.annotated,  | 
|
976  | 
left_matching_blocks)  | 
|
977  | 
||
978  | 
if delta:  | 
|
979  | 
options.append('line-delta')  | 
|
980  | 
store_lines = self._factory.lower_line_delta(delta_hunks)  | 
|
981  | 
size, bytes = self._record_to_data(key, digest,  | 
|
982  | 
store_lines)  | 
|
983  | 
else:  | 
|
984  | 
options.append('fulltext')  | 
|
985  | 
            # isinstance is slower and we have no hierarchy.
 | 
|
| 
4088.3.1
by Benjamin Peterson
 compare types with 'is' not ==  | 
986  | 
if self._factory.__class__ is KnitPlainFactory:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
987  | 
                # Use the already joined bytes saving iteration time in
 | 
988  | 
                # _record_to_data.
 | 
|
989  | 
size, bytes = self._record_to_data(key, digest,  | 
|
990  | 
lines, [line_bytes])  | 
|
991  | 
else:  | 
|
992  | 
                # get mixed annotation + content and feed it into the
 | 
|
993  | 
                # serialiser.
 | 
|
994  | 
store_lines = self._factory.lower_fulltext(content)  | 
|
995  | 
size, bytes = self._record_to_data(key, digest,  | 
|
996  | 
store_lines)  | 
|
997  | 
||
998  | 
access_memo = self._access.add_raw_records([(key, size)], bytes)[0]  | 
|
999  | 
self._index.add_records(  | 
|
1000  | 
((key, options, access_memo, parents),),  | 
|
1001  | 
random_id=random_id)  | 
|
1002  | 
return digest, text_length, content  | 
|
1003  | 
||
1004  | 
def annotate(self, key):  | 
|
1005  | 
"""See VersionedFiles.annotate."""  | 
|
1006  | 
return self._factory.annotate(self, key)  | 
|
1007  | 
||
1008  | 
def check(self, progress_bar=None):  | 
|
1009  | 
"""See VersionedFiles.check()."""  | 
|
1010  | 
        # This doesn't actually test extraction of everything, but that will
 | 
|
1011  | 
        # impact 'bzr check' substantially, and needs to be integrated with
 | 
|
1012  | 
        # care. However, it does check for the obvious problem of a delta with
 | 
|
1013  | 
        # no basis.
 | 
|
| 
3517.4.14
by Martin Pool
 KnitVersionedFiles.check should just check its own keys then recurse into fallbacks  | 
1014  | 
keys = self._index.keys()  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1015  | 
parent_map = self.get_parent_map(keys)  | 
1016  | 
for key in keys:  | 
|
1017  | 
if self._index.get_method(key) != 'fulltext':  | 
|
1018  | 
compression_parent = parent_map[key][0]  | 
|
1019  | 
if compression_parent not in parent_map:  | 
|
1020  | 
raise errors.KnitCorrupt(self,  | 
|
1021  | 
"Missing basis parent %s for %s" % (  | 
|
1022  | 
compression_parent, key))  | 
|
| 
3517.4.14
by Martin Pool
 KnitVersionedFiles.check should just check its own keys then recurse into fallbacks  | 
1023  | 
for fallback_vfs in self._fallback_vfs:  | 
1024  | 
fallback_vfs.check()  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1025  | 
|
1026  | 
def _check_add(self, key, lines, random_id, check_content):  | 
|
1027  | 
"""check that version_id and lines are safe to add."""  | 
|
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
1028  | 
version_id = key[-1]  | 
| 
4241.4.1
by Ian Clatworthy
 add sha generation support to versionedfiles  | 
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)  | 
|
| 
3350.6.11
by Martin Pool
 Review cleanups and documentation from Robert's mail on 2080618  | 
1033  | 
        # TODO: If random_id==False and the key is already present, we should
 | 
1034  | 
        # probably check that the existing content is identical to what is
 | 
|
1035  | 
        # being inserted, and otherwise raise an exception.  This would make
 | 
|
1036  | 
        # the bundle code simpler.
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1037  | 
if check_content:  | 
1038  | 
self._check_lines_not_unicode(lines)  | 
|
1039  | 
self._check_lines_are_lines(lines)  | 
|
1040  | 
||
1041  | 
def _check_header(self, key, line):  | 
|
1042  | 
rec = self._split_header(line)  | 
|
1043  | 
self._check_header_version(rec, key[-1])  | 
|
1044  | 
return rec  | 
|
1045  | 
||
1046  | 
def _check_header_version(self, rec, version_id):  | 
|
1047  | 
"""Checks the header version on original format knit records.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1048  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1049  | 
        These have the last component of the key embedded in the record.
 | 
1050  | 
        """
 | 
|
1051  | 
if rec[1] != version_id:  | 
|
1052  | 
raise KnitCorrupt(self,  | 
|
1053  | 
'unexpected version, wanted %r, got %r' % (version_id, rec[1]))  | 
|
1054  | 
||
1055  | 
def _check_should_delta(self, parent):  | 
|
| 
2147.1.1
by John Arbash Meinel
 Factor the common knit delta selection into a helper func, and allow the fulltext to be chosen based on cumulative delta size  | 
1056  | 
"""Iterate back through the parent listing, looking for a fulltext.  | 
1057  | 
||
1058  | 
        This is used when we want to decide whether to add a delta or a new
 | 
|
1059  | 
        fulltext. It searches for _max_delta_chain parents. When it finds a
 | 
|
1060  | 
        fulltext parent, it sees if the total size of the deltas leading up to
 | 
|
1061  | 
        it is large enough to indicate that we want a new full text anyway.
 | 
|
1062  | 
||
1063  | 
        Return True if we should create a new delta, False if we should use a
 | 
|
1064  | 
        full text.
 | 
|
1065  | 
        """
 | 
|
1066  | 
delta_size = 0  | 
|
1067  | 
fulltext_size = None  | 
|
| 
2147.1.2
by John Arbash Meinel
 Simplify the knit max-chain detection code.  | 
1068  | 
for count in xrange(self._max_delta_chain):  | 
| 
3350.8.9
by Robert Collins
 define behaviour for add_lines with stacked storage.  | 
1069  | 
try:  | 
| 
3582.1.14
by Martin Pool
 Clearer comments about KnitVersionedFile stacking  | 
1070  | 
                # Note that this only looks in the index of this particular
 | 
1071  | 
                # KnitVersionedFiles, not in the fallbacks.  This ensures that
 | 
|
1072  | 
                # we won't store a delta spanning physical repository
 | 
|
1073  | 
                # boundaries.
 | 
|
| 
3915.3.1
by John Arbash Meinel
 As part of _check_should_delta, use the get_build_details api.  | 
1074  | 
build_details = self._index.get_build_details([parent])  | 
1075  | 
parent_details = build_details[parent]  | 
|
| 
3973.1.1
by John Arbash Meinel
 Trivially fix a bug in _check_should_delta when a parent is not present.  | 
1076  | 
except (RevisionNotPresent, KeyError), e:  | 
| 
3915.3.1
by John Arbash Meinel
 As part of _check_should_delta, use the get_build_details api.  | 
1077  | 
                # Some basis is not locally present: always fulltext
 | 
| 
3350.8.9
by Robert Collins
 define behaviour for add_lines with stacked storage.  | 
1078  | 
return False  | 
| 
3915.3.1
by John Arbash Meinel
 As part of _check_should_delta, use the get_build_details api.  | 
1079  | 
index_memo, compression_parent, _, _ = parent_details  | 
1080  | 
_, _, size = index_memo  | 
|
1081  | 
if compression_parent is None:  | 
|
| 
2147.1.1
by John Arbash Meinel
 Factor the common knit delta selection into a helper func, and allow the fulltext to be chosen based on cumulative delta size  | 
1082  | 
fulltext_size = size  | 
1083  | 
                break
 | 
|
1084  | 
delta_size += size  | 
|
| 
3350.6.11
by Martin Pool
 Review cleanups and documentation from Robert's mail on 2080618  | 
1085  | 
            # We don't explicitly check for presence because this is in an
 | 
1086  | 
            # inner loop, and if it's missing it'll fail anyhow.
 | 
|
| 
3915.3.1
by John Arbash Meinel
 As part of _check_should_delta, use the get_build_details api.  | 
1087  | 
parent = compression_parent  | 
| 
2147.1.2
by John Arbash Meinel
 Simplify the knit max-chain detection code.  | 
1088  | 
else:  | 
1089  | 
            # We couldn't find a fulltext, so we must create a new one
 | 
|
| 
2147.1.1
by John Arbash Meinel
 Factor the common knit delta selection into a helper func, and allow the fulltext to be chosen based on cumulative delta size  | 
1090  | 
return False  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1091  | 
        # Simple heuristic - if the total I/O wold be greater as a delta than
 | 
1092  | 
        # the originally installed fulltext, we create a new fulltext.
 | 
|
| 
2147.1.2
by John Arbash Meinel
 Simplify the knit max-chain detection code.  | 
1093  | 
return fulltext_size > delta_size  | 
| 
2147.1.1
by John Arbash Meinel
 Factor the common knit delta selection into a helper func, and allow the fulltext to be chosen based on cumulative delta size  | 
1094  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1095  | 
def _build_details_to_components(self, build_details):  | 
1096  | 
"""Convert a build_details tuple to a position tuple."""  | 
|
1097  | 
        # record_details, access_memo, compression_parent
 | 
|
1098  | 
return build_details[3], build_details[0], build_details[1]  | 
|
1099  | 
||
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
1100  | 
def _get_components_positions(self, keys, allow_missing=False):  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1101  | 
"""Produce a map of position data for the components of keys.  | 
1102  | 
||
1103  | 
        This data is intended to be used for retrieving the knit records.
 | 
|
1104  | 
||
1105  | 
        A dict of key to (record_details, index_memo, next, parents) is
 | 
|
1106  | 
        returned.
 | 
|
1107  | 
        method is the way referenced data should be applied.
 | 
|
1108  | 
        index_memo is the handle to pass to the data access to actually get the
 | 
|
1109  | 
            data
 | 
|
1110  | 
        next is the build-parent of the version, or None for fulltexts.
 | 
|
1111  | 
        parents is the version_ids of the parents of this version
 | 
|
1112  | 
||
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
1113  | 
        :param allow_missing: If True do not raise an error on a missing component,
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1114  | 
            just ignore it.
 | 
1115  | 
        """
 | 
|
1116  | 
component_data = {}  | 
|
1117  | 
pending_components = keys  | 
|
1118  | 
while pending_components:  | 
|
1119  | 
build_details = self._index.get_build_details(pending_components)  | 
|
1120  | 
current_components = set(pending_components)  | 
|
1121  | 
pending_components = set()  | 
|
1122  | 
for key, details in build_details.iteritems():  | 
|
1123  | 
(index_memo, compression_parent, parents,  | 
|
1124  | 
record_details) = details  | 
|
1125  | 
method = record_details[0]  | 
|
1126  | 
if compression_parent is not None:  | 
|
1127  | 
pending_components.add(compression_parent)  | 
|
1128  | 
component_data[key] = self._build_details_to_components(details)  | 
|
1129  | 
missing = current_components.difference(build_details)  | 
|
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
1130  | 
if missing and not allow_missing:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1131  | 
raise errors.RevisionNotPresent(missing.pop(), self)  | 
1132  | 
return component_data  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1133  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1134  | 
def _get_content(self, key, parent_texts={}):  | 
1135  | 
"""Returns a content object that makes up the specified  | 
|
1136  | 
        version."""
 | 
|
1137  | 
cached_version = parent_texts.get(key, None)  | 
|
1138  | 
if cached_version is not None:  | 
|
1139  | 
            # Ensure the cache dict is valid.
 | 
|
1140  | 
if not self.get_parent_map([key]):  | 
|
1141  | 
raise RevisionNotPresent(key, self)  | 
|
1142  | 
return cached_version  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1143  | 
generator = _VFContentMapGenerator(self, [key])  | 
1144  | 
return generator._get_content(key)  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1145  | 
|
1146  | 
def get_parent_map(self, keys):  | 
|
| 
3517.4.17
by Martin Pool
 Redo base Repository.get_parent_map to use .revisions graph  | 
1147  | 
"""Get a map of the graph parents of keys.  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1148  | 
|
1149  | 
        :param keys: The keys to look up parents for.
 | 
|
1150  | 
        :return: A mapping from keys to parents. Absent keys are absent from
 | 
|
1151  | 
            the mapping.
 | 
|
1152  | 
        """
 | 
|
| 
3350.8.14
by Robert Collins
 Review feedback.  | 
1153  | 
return self._get_parent_map_with_sources(keys)[0]  | 
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1154  | 
|
| 
3350.8.14
by Robert Collins
 Review feedback.  | 
1155  | 
def _get_parent_map_with_sources(self, keys):  | 
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1156  | 
"""Get a map of the parents of keys.  | 
1157  | 
||
1158  | 
        :param keys: The keys to look up parents for.
 | 
|
1159  | 
        :return: A tuple. The first element is a mapping from keys to parents.
 | 
|
1160  | 
            Absent keys are absent from the mapping. The second element is a
 | 
|
1161  | 
            list with the locations each key was found in. The first element
 | 
|
1162  | 
            is the in-this-knit parents, the second the first fallback source,
 | 
|
1163  | 
            and so on.
 | 
|
1164  | 
        """
 | 
|
| 
3350.8.2
by Robert Collins
 stacked get_parent_map.  | 
1165  | 
result = {}  | 
1166  | 
sources = [self._index] + self._fallback_vfs  | 
|
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1167  | 
source_results = []  | 
| 
3350.8.2
by Robert Collins
 stacked get_parent_map.  | 
1168  | 
missing = set(keys)  | 
1169  | 
for source in sources:  | 
|
1170  | 
if not missing:  | 
|
1171  | 
                break
 | 
|
1172  | 
new_result = source.get_parent_map(missing)  | 
|
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1173  | 
source_results.append(new_result)  | 
| 
3350.8.2
by Robert Collins
 stacked get_parent_map.  | 
1174  | 
result.update(new_result)  | 
1175  | 
missing.difference_update(set(new_result))  | 
|
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1176  | 
return result, source_results  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1177  | 
|
| 
3350.8.3
by Robert Collins
 VF.get_sha1s needed changing to be stackable.  | 
1178  | 
def _get_record_map(self, keys, allow_missing=False):  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1179  | 
"""Produce a dictionary of knit records.  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1180  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1181  | 
        :return: {key:(record, record_details, digest, next)}
 | 
1182  | 
            record
 | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1183  | 
                data returned from read_records (a KnitContentobject)
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1184  | 
            record_details
 | 
1185  | 
                opaque information to pass to parse_record
 | 
|
1186  | 
            digest
 | 
|
1187  | 
                SHA1 digest of the full text after all steps are done
 | 
|
1188  | 
            next
 | 
|
1189  | 
                build-parent of the version, i.e. the leftmost ancestor.
 | 
|
1190  | 
                Will be None if the record is not a delta.
 | 
|
| 
3350.8.3
by Robert Collins
 VF.get_sha1s needed changing to be stackable.  | 
1191  | 
        :param keys: The keys to build a map for
 | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1192  | 
        :param allow_missing: If some records are missing, rather than
 | 
| 
3350.8.3
by Robert Collins
 VF.get_sha1s needed changing to be stackable.  | 
1193  | 
            error, just return the data that could be generated.
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1194  | 
        """
 | 
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1195  | 
raw_map = self._get_record_map_unparsed(keys,  | 
1196  | 
allow_missing=allow_missing)  | 
|
1197  | 
return self._raw_map_to_record_map(raw_map)  | 
|
1198  | 
||
1199  | 
def _raw_map_to_record_map(self, raw_map):  | 
|
1200  | 
"""Parse the contents of _get_record_map_unparsed.  | 
|
| 
4032.1.1
by John Arbash Meinel
 Merge the removal of all trailing whitespace, and resolve conflicts.  | 
1201  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1202  | 
        :return: see _get_record_map.
 | 
1203  | 
        """
 | 
|
1204  | 
result = {}  | 
|
1205  | 
for key in raw_map:  | 
|
1206  | 
data, record_details, next = raw_map[key]  | 
|
1207  | 
content, digest = self._parse_record(key[-1], data)  | 
|
1208  | 
result[key] = content, record_details, digest, next  | 
|
1209  | 
return result  | 
|
1210  | 
||
1211  | 
def _get_record_map_unparsed(self, keys, allow_missing=False):  | 
|
1212  | 
"""Get the raw data for reconstructing keys without parsing it.  | 
|
| 
4032.1.1
by John Arbash Meinel
 Merge the removal of all trailing whitespace, and resolve conflicts.  | 
1213  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1214  | 
        :return: A dict suitable for parsing via _raw_map_to_record_map.
 | 
1215  | 
            key-> raw_bytes, (method, noeol), compression_parent
 | 
|
1216  | 
        """
 | 
|
| 
3789.2.11
by John Arbash Meinel
 KnitVersionedFile.get_record_stream now retries *and* fails correctly.  | 
1217  | 
        # This retries the whole request if anything fails. Potentially we
 | 
1218  | 
        # could be a bit more selective. We could track the keys whose records
 | 
|
1219  | 
        # we have successfully found, and then only request the new records
 | 
|
1220  | 
        # from there. However, _get_components_positions grabs the whole build
 | 
|
1221  | 
        # chain, which means we'll likely try to grab the same records again
 | 
|
| 
4005.3.7
by Robert Collins
 Review feedback.  | 
1222  | 
        # anyway. Also, can the build chains change as part of a pack
 | 
| 
3789.2.11
by John Arbash Meinel
 KnitVersionedFile.get_record_stream now retries *and* fails correctly.  | 
1223  | 
        # operation? We wouldn't want to end up with a broken chain.
 | 
| 
3789.2.10
by John Arbash Meinel
 The first function for KnitVersionedFiles can now retry on request.  | 
1224  | 
while True:  | 
1225  | 
try:  | 
|
1226  | 
position_map = self._get_components_positions(keys,  | 
|
1227  | 
allow_missing=allow_missing)  | 
|
| 
3789.2.11
by John Arbash Meinel
 KnitVersionedFile.get_record_stream now retries *and* fails correctly.  | 
1228  | 
                # key = component_id, r = record_details, i_m = index_memo,
 | 
1229  | 
                # n = next
 | 
|
| 
3789.2.10
by John Arbash Meinel
 The first function for KnitVersionedFiles can now retry on request.  | 
1230  | 
records = [(key, i_m) for key, (r, i_m, n)  | 
| 
3789.2.11
by John Arbash Meinel
 KnitVersionedFile.get_record_stream now retries *and* fails correctly.  | 
1231  | 
in position_map.iteritems()]  | 
| 
4039.3.1
by John Arbash Meinel
 Group records to read by pack file and sort by offset.  | 
1232  | 
                # Sort by the index memo, so that we request records from the
 | 
1233  | 
                # same pack file together, and in forward-sorted order
 | 
|
1234  | 
records.sort(key=operator.itemgetter(1))  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1235  | 
raw_record_map = {}  | 
1236  | 
for key, data in self._read_records_iter_unchecked(records):  | 
|
| 
3789.2.10
by John Arbash Meinel
 The first function for KnitVersionedFiles can now retry on request.  | 
1237  | 
(record_details, index_memo, next) = position_map[key]  | 
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1238  | 
raw_record_map[key] = data, record_details, next  | 
1239  | 
return raw_record_map  | 
|
| 
3789.2.10
by John Arbash Meinel
 The first function for KnitVersionedFiles can now retry on request.  | 
1240  | 
except errors.RetryWithNewPacks, e:  | 
1241  | 
self._access.reload_or_raise(e)  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1242  | 
|
| 
4039.3.6
by John Arbash Meinel
 Turn _split_by_prefix into a classmethod, and add direct tests.  | 
1243  | 
    @classmethod
 | 
1244  | 
def _split_by_prefix(cls, keys):  | 
|
| 
3763.4.1
by John Arbash Meinel
 Possible fix for bug #269456.  | 
1245  | 
"""For the given keys, split them up based on their prefix.  | 
1246  | 
||
1247  | 
        To keep memory pressure somewhat under control, split the
 | 
|
1248  | 
        requests back into per-file-id requests, otherwise "bzr co"
 | 
|
1249  | 
        extracts the full tree into memory before writing it to disk.
 | 
|
1250  | 
        This should be revisited if _get_content_maps() can ever cross
 | 
|
1251  | 
        file-id boundaries.
 | 
|
1252  | 
||
| 
4039.3.6
by John Arbash Meinel
 Turn _split_by_prefix into a classmethod, and add direct tests.  | 
1253  | 
        The keys for a given file_id are kept in the same relative order.
 | 
1254  | 
        Ordering between file_ids is not, though prefix_order will return the
 | 
|
1255  | 
        order that the key was first seen.
 | 
|
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1256  | 
|
| 
3763.4.1
by John Arbash Meinel
 Possible fix for bug #269456.  | 
1257  | 
        :param keys: An iterable of key tuples
 | 
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1258  | 
        :return: (split_map, prefix_order)
 | 
1259  | 
            split_map       A dictionary mapping prefix => keys
 | 
|
1260  | 
            prefix_order    The order that we saw the various prefixes
 | 
|
| 
3763.4.1
by John Arbash Meinel
 Possible fix for bug #269456.  | 
1261  | 
        """
 | 
1262  | 
split_by_prefix = {}  | 
|
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1263  | 
prefix_order = []  | 
| 
3763.4.1
by John Arbash Meinel
 Possible fix for bug #269456.  | 
1264  | 
for key in keys:  | 
1265  | 
if len(key) == 1:  | 
|
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1266  | 
prefix = ''  | 
1267  | 
else:  | 
|
1268  | 
prefix = key[0]  | 
|
1269  | 
||
1270  | 
if prefix in split_by_prefix:  | 
|
1271  | 
split_by_prefix[prefix].append(key)  | 
|
1272  | 
else:  | 
|
1273  | 
split_by_prefix[prefix] = [key]  | 
|
1274  | 
prefix_order.append(prefix)  | 
|
1275  | 
return split_by_prefix, prefix_order  | 
|
1276  | 
||
| 
4039.3.7
by John Arbash Meinel
 Some direct tests for _group_keys_for_io  | 
1277  | 
def _group_keys_for_io(self, keys, non_local_keys, positions,  | 
1278  | 
_min_buffer_size=_STREAM_MIN_BUFFER_SIZE):  | 
|
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1279  | 
"""For the given keys, group them into 'best-sized' requests.  | 
1280  | 
||
1281  | 
        The idea is to avoid making 1 request per file, but to never try to
 | 
|
1282  | 
        unpack an entire 1.5GB source tree in a single pass. Also when
 | 
|
1283  | 
        possible, we should try to group requests to the same pack file
 | 
|
1284  | 
        together.
 | 
|
1285  | 
||
| 
4039.3.7
by John Arbash Meinel
 Some direct tests for _group_keys_for_io  | 
1286  | 
        :return: list of (keys, non_local) tuples that indicate what keys
 | 
1287  | 
            should be fetched next.
 | 
|
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1288  | 
        """
 | 
1289  | 
        # TODO: Ideally we would group on 2 factors. We want to extract texts
 | 
|
1290  | 
        #       from the same pack file together, and we want to extract all
 | 
|
1291  | 
        #       the texts for a given build-chain together. Ultimately it
 | 
|
1292  | 
        #       probably needs a better global view.
 | 
|
| 
4039.3.3
by John Arbash Meinel
 Add some debugging code.  | 
1293  | 
total_keys = len(keys)  | 
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1294  | 
prefix_split_keys, prefix_order = self._split_by_prefix(keys)  | 
1295  | 
prefix_split_non_local_keys, _ = self._split_by_prefix(non_local_keys)  | 
|
1296  | 
cur_keys = []  | 
|
1297  | 
cur_non_local = set()  | 
|
1298  | 
cur_size = 0  | 
|
| 
4039.3.3
by John Arbash Meinel
 Add some debugging code.  | 
1299  | 
result = []  | 
1300  | 
sizes = []  | 
|
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1301  | 
for prefix in prefix_order:  | 
1302  | 
keys = prefix_split_keys[prefix]  | 
|
1303  | 
non_local = prefix_split_non_local_keys.get(prefix, [])  | 
|
| 
4039.3.4
by John Arbash Meinel
 Properly determine the total number of bytes needed for a given key.  | 
1304  | 
|
1305  | 
this_size = self._index._get_total_build_size(keys, positions)  | 
|
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1306  | 
cur_size += this_size  | 
1307  | 
cur_keys.extend(keys)  | 
|
1308  | 
cur_non_local.update(non_local)  | 
|
| 
4039.3.7
by John Arbash Meinel
 Some direct tests for _group_keys_for_io  | 
1309  | 
if cur_size > _min_buffer_size:  | 
| 
4039.3.3
by John Arbash Meinel
 Add some debugging code.  | 
1310  | 
result.append((cur_keys, cur_non_local))  | 
1311  | 
sizes.append(cur_size)  | 
|
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1312  | 
cur_keys = []  | 
| 
4039.3.4
by John Arbash Meinel
 Properly determine the total number of bytes needed for a given key.  | 
1313  | 
cur_non_local = set()  | 
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1314  | 
cur_size = 0  | 
1315  | 
if cur_keys:  | 
|
| 
4039.3.3
by John Arbash Meinel
 Add some debugging code.  | 
1316  | 
result.append((cur_keys, cur_non_local))  | 
1317  | 
sizes.append(cur_size)  | 
|
1318  | 
return result  | 
|
| 
3763.4.1
by John Arbash Meinel
 Possible fix for bug #269456.  | 
1319  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1320  | 
def get_record_stream(self, keys, ordering, include_delta_closure):  | 
1321  | 
"""Get a stream of records for keys.  | 
|
1322  | 
||
1323  | 
        :param keys: The keys to include.
 | 
|
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
1324  | 
        :param ordering: Either 'unordered' or 'topological'. A topologically
 | 
1325  | 
            sorted stream has compression parents strictly before their
 | 
|
1326  | 
            children.
 | 
|
1327  | 
        :param include_delta_closure: If True then the closure across any
 | 
|
1328  | 
            compression parents will be included (in the opaque data).
 | 
|
1329  | 
        :return: An iterator of ContentFactory objects, each of which is only
 | 
|
1330  | 
            valid until the iterator is advanced.
 | 
|
1331  | 
        """
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1332  | 
        # keys might be a generator
 | 
1333  | 
keys = set(keys)  | 
|
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1334  | 
if not keys:  | 
1335  | 
            return
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1336  | 
if not self._index.has_graph:  | 
| 
4111.1.1
by Robert Collins
 Add a groupcompress sort order.  | 
1337  | 
            # Cannot sort when no graph has been stored.
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1338  | 
ordering = 'unordered'  | 
| 
3789.2.1
by John Arbash Meinel
 _DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.  | 
1339  | 
|
1340  | 
remaining_keys = keys  | 
|
1341  | 
while True:  | 
|
1342  | 
try:  | 
|
1343  | 
keys = set(remaining_keys)  | 
|
1344  | 
for content_factory in self._get_remaining_record_stream(keys,  | 
|
1345  | 
ordering, include_delta_closure):  | 
|
1346  | 
remaining_keys.discard(content_factory.key)  | 
|
1347  | 
yield content_factory  | 
|
1348  | 
                return
 | 
|
1349  | 
except errors.RetryWithNewPacks, e:  | 
|
| 
3789.2.11
by John Arbash Meinel
 KnitVersionedFile.get_record_stream now retries *and* fails correctly.  | 
1350  | 
self._access.reload_or_raise(e)  | 
| 
3789.2.1
by John Arbash Meinel
 _DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.  | 
1351  | 
|
1352  | 
def _get_remaining_record_stream(self, keys, ordering,  | 
|
1353  | 
include_delta_closure):  | 
|
| 
3789.2.4
by John Arbash Meinel
 Add a multiple-record test, though it isn't quite what we want for the readv tests.  | 
1354  | 
"""This function is the 'retry' portion for get_record_stream."""  | 
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
1355  | 
if include_delta_closure:  | 
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
1356  | 
positions = self._get_components_positions(keys, allow_missing=True)  | 
| 
3350.3.3
by Robert Collins
 Functional get_record_stream interface tests covering full interface.  | 
1357  | 
else:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1358  | 
build_details = self._index.get_build_details(keys)  | 
| 
3350.6.11
by Martin Pool
 Review cleanups and documentation from Robert's mail on 2080618  | 
1359  | 
            # map from key to
 | 
1360  | 
            # (record_details, access_memo, compression_parent_key)
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1361  | 
positions = dict((key, self._build_details_to_components(details))  | 
1362  | 
for key, details in build_details.iteritems())  | 
|
1363  | 
absent_keys = keys.difference(set(positions))  | 
|
1364  | 
        # There may be more absent keys : if we're missing the basis component
 | 
|
1365  | 
        # and are trying to include the delta closure.
 | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1366  | 
        # XXX: We should not ever need to examine remote sources because we do
 | 
1367  | 
        # not permit deltas across versioned files boundaries.
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1368  | 
if include_delta_closure:  | 
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1369  | 
needed_from_fallback = set()  | 
| 
3350.6.11
by Martin Pool
 Review cleanups and documentation from Robert's mail on 2080618  | 
1370  | 
            # Build up reconstructable_keys dict.  key:True in this dict means
 | 
1371  | 
            # the key can be reconstructed.
 | 
|
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
1372  | 
reconstructable_keys = {}  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1373  | 
for key in keys:  | 
1374  | 
                # the delta chain
 | 
|
1375  | 
try:  | 
|
1376  | 
chain = [key, positions[key][2]]  | 
|
1377  | 
except KeyError:  | 
|
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1378  | 
needed_from_fallback.add(key)  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1379  | 
                    continue
 | 
1380  | 
result = True  | 
|
1381  | 
while chain[-1] is not None:  | 
|
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
1382  | 
if chain[-1] in reconstructable_keys:  | 
1383  | 
result = reconstructable_keys[chain[-1]]  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1384  | 
                        break
 | 
1385  | 
else:  | 
|
1386  | 
try:  | 
|
1387  | 
chain.append(positions[chain[-1]][2])  | 
|
1388  | 
except KeyError:  | 
|
1389  | 
                            # missing basis component
 | 
|
| 
3350.8.10
by Robert Collins
 Stacked insert_record_stream.  | 
1390  | 
needed_from_fallback.add(chain[-1])  | 
1391  | 
result = True  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1392  | 
                            break
 | 
1393  | 
for chain_key in chain[:-1]:  | 
|
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
1394  | 
reconstructable_keys[chain_key] = result  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1395  | 
if not result:  | 
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1396  | 
needed_from_fallback.add(key)  | 
1397  | 
        # Double index lookups here : need a unified api ?
 | 
|
| 
3350.8.14
by Robert Collins
 Review feedback.  | 
1398  | 
global_map, parent_maps = self._get_parent_map_with_sources(keys)  | 
| 
4111.1.1
by Robert Collins
 Add a groupcompress sort order.  | 
1399  | 
if ordering in ('topological', 'groupcompress'):  | 
1400  | 
if ordering == 'topological':  | 
|
1401  | 
                # Global topological sort
 | 
|
1402  | 
present_keys = tsort.topo_sort(global_map)  | 
|
1403  | 
else:  | 
|
1404  | 
present_keys = sort_groupcompress(global_map)  | 
|
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1405  | 
            # Now group by source:
 | 
1406  | 
source_keys = []  | 
|
1407  | 
current_source = None  | 
|
1408  | 
for key in present_keys:  | 
|
1409  | 
for parent_map in parent_maps:  | 
|
1410  | 
if key in parent_map:  | 
|
1411  | 
key_source = parent_map  | 
|
1412  | 
                        break
 | 
|
1413  | 
if current_source is not key_source:  | 
|
1414  | 
source_keys.append((key_source, []))  | 
|
1415  | 
current_source = key_source  | 
|
1416  | 
source_keys[-1][1].append(key)  | 
|
1417  | 
else:  | 
|
| 
3606.7.7
by John Arbash Meinel
 Add tests for the fetching behavior.  | 
1418  | 
if ordering != 'unordered':  | 
1419  | 
raise AssertionError('valid values for ordering are:'  | 
|
| 
4111.1.1
by Robert Collins
 Add a groupcompress sort order.  | 
1420  | 
' "unordered", "groupcompress" or "topological" not: %r'  | 
| 
3606.7.7
by John Arbash Meinel
 Add tests for the fetching behavior.  | 
1421  | 
% (ordering,))  | 
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1422  | 
            # Just group by source; remote sources first.
 | 
1423  | 
present_keys = []  | 
|
1424  | 
source_keys = []  | 
|
1425  | 
for parent_map in reversed(parent_maps):  | 
|
1426  | 
source_keys.append((parent_map, []))  | 
|
1427  | 
for key in parent_map:  | 
|
1428  | 
present_keys.append(key)  | 
|
1429  | 
source_keys[-1][1].append(key)  | 
|
| 
3878.1.1
by John Arbash Meinel
 KVF.get_record_stream('unordered') now returns the records based on I/O ordering.  | 
1430  | 
            # We have been requested to return these records in an order that
 | 
| 
3878.1.2
by John Arbash Meinel
 Move the sorting into each index, and customize it for Kndx access.  | 
1431  | 
            # suits us. So we ask the index to give us an optimally sorted
 | 
1432  | 
            # order.
 | 
|
| 
3878.1.1
by John Arbash Meinel
 KVF.get_record_stream('unordered') now returns the records based on I/O ordering.  | 
1433  | 
for source, sub_keys in source_keys:  | 
1434  | 
if source is parent_maps[0]:  | 
|
| 
3878.1.2
by John Arbash Meinel
 Move the sorting into each index, and customize it for Kndx access.  | 
1435  | 
                    # Only sort the keys for this VF
 | 
1436  | 
self._index._sort_keys_by_io(sub_keys, positions)  | 
|
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1437  | 
absent_keys = keys - set(global_map)  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1438  | 
for key in absent_keys:  | 
1439  | 
yield AbsentContentFactory(key)  | 
|
1440  | 
        # restrict our view to the keys we can answer.
 | 
|
1441  | 
        # XXX: Memory: TODO: batch data here to cap buffered data at (say) 1MB.
 | 
|
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1442  | 
        # XXX: At that point we need to consider the impact of double reads by
 | 
1443  | 
        # utilising components multiple times.
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1444  | 
if include_delta_closure:  | 
1445  | 
            # XXX: get_content_maps performs its own index queries; allow state
 | 
|
1446  | 
            # to be passed in.
 | 
|
| 
3763.4.1
by John Arbash Meinel
 Possible fix for bug #269456.  | 
1447  | 
non_local_keys = needed_from_fallback - absent_keys  | 
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
1448  | 
for keys, non_local_keys in self._group_keys_for_io(present_keys,  | 
1449  | 
non_local_keys,  | 
|
1450  | 
positions):  | 
|
1451  | 
generator = _VFContentMapGenerator(self, keys, non_local_keys,  | 
|
1452  | 
global_map)  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1453  | 
for record in generator.get_record_stream():  | 
1454  | 
yield record  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1455  | 
else:  | 
| 
3350.8.6
by Robert Collins
 get_record_stream stacking for delta access.  | 
1456  | 
for source, keys in source_keys:  | 
1457  | 
if source is parent_maps[0]:  | 
|
1458  | 
                    # this KnitVersionedFiles
 | 
|
1459  | 
records = [(key, positions[key][1]) for key in keys]  | 
|
1460  | 
for key, raw_data, sha1 in self._read_records_iter_raw(records):  | 
|
1461  | 
(record_details, index_memo, _) = positions[key]  | 
|
1462  | 
yield KnitContentFactory(key, global_map[key],  | 
|
1463  | 
record_details, sha1, raw_data, self._factory.annotated, None)  | 
|
1464  | 
else:  | 
|
1465  | 
vf = self._fallback_vfs[parent_maps.index(source) - 1]  | 
|
1466  | 
for record in vf.get_record_stream(keys, ordering,  | 
|
1467  | 
include_delta_closure):  | 
|
1468  | 
yield record  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1469  | 
|
1470  | 
def get_sha1s(self, keys):  | 
|
1471  | 
"""See VersionedFiles.get_sha1s()."""  | 
|
| 
3350.8.3
by Robert Collins
 VF.get_sha1s needed changing to be stackable.  | 
1472  | 
missing = set(keys)  | 
1473  | 
record_map = self._get_record_map(missing, allow_missing=True)  | 
|
1474  | 
result = {}  | 
|
1475  | 
for key, details in record_map.iteritems():  | 
|
1476  | 
if key not in missing:  | 
|
1477  | 
                continue
 | 
|
1478  | 
            # record entry 2 is the 'digest'.
 | 
|
1479  | 
result[key] = details[2]  | 
|
1480  | 
missing.difference_update(set(result))  | 
|
1481  | 
for source in self._fallback_vfs:  | 
|
1482  | 
if not missing:  | 
|
1483  | 
                break
 | 
|
1484  | 
new_result = source.get_sha1s(missing)  | 
|
1485  | 
result.update(new_result)  | 
|
1486  | 
missing.difference_update(set(new_result))  | 
|
1487  | 
return result  | 
|
| 
3052.2.2
by Robert Collins
 * Operations pulling data from a smart server where the underlying  | 
1488  | 
|
| 
3350.3.8
by Robert Collins
 Basic stream insertion, no fast path yet for knit to knit.  | 
1489  | 
def insert_record_stream(self, stream):  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1490  | 
"""Insert a record stream into this container.  | 
| 
3350.3.8
by Robert Collins
 Basic stream insertion, no fast path yet for knit to knit.  | 
1491  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1492  | 
        :param stream: A stream of records to insert.
 | 
| 
3350.3.8
by Robert Collins
 Basic stream insertion, no fast path yet for knit to knit.  | 
1493  | 
        :return: None
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1494  | 
        :seealso VersionedFiles.get_record_stream:
 | 
| 
3350.3.8
by Robert Collins
 Basic stream insertion, no fast path yet for knit to knit.  | 
1495  | 
        """
 | 
| 
3350.3.9
by Robert Collins
 Avoid full text reconstruction when transferring knit to knit via record streams.  | 
1496  | 
def get_adapter(adapter_key):  | 
1497  | 
try:  | 
|
1498  | 
return adapters[adapter_key]  | 
|
1499  | 
except KeyError:  | 
|
1500  | 
adapter_factory = adapter_registry.get(adapter_key)  | 
|
1501  | 
adapter = adapter_factory(self)  | 
|
1502  | 
adapters[adapter_key] = adapter  | 
|
1503  | 
return adapter  | 
|
| 
3871.4.3
by John Arbash Meinel
 We should only care if the compression parent is not available, not if all parents are available.  | 
1504  | 
delta_types = set()  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1505  | 
if self._factory.annotated:  | 
| 
3350.3.11
by Robert Collins
 Test inserting a stream that overlaps the current content of a knit does not error.  | 
1506  | 
            # self is annotated, we need annotated knits to use directly.
 | 
| 
3350.3.9
by Robert Collins
 Avoid full text reconstruction when transferring knit to knit via record streams.  | 
1507  | 
annotated = "annotated-"  | 
| 
3350.3.11
by Robert Collins
 Test inserting a stream that overlaps the current content of a knit does not error.  | 
1508  | 
convertibles = []  | 
| 
3350.3.9
by Robert Collins
 Avoid full text reconstruction when transferring knit to knit via record streams.  | 
1509  | 
else:  | 
| 
3350.3.11
by Robert Collins
 Test inserting a stream that overlaps the current content of a knit does not error.  | 
1510  | 
            # self is not annotated, but we can strip annotations cheaply.
 | 
| 
3350.3.9
by Robert Collins
 Avoid full text reconstruction when transferring knit to knit via record streams.  | 
1511  | 
annotated = ""  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1512  | 
convertibles = set(["knit-annotated-ft-gz"])  | 
1513  | 
if self._max_delta_chain:  | 
|
| 
3871.4.3
by John Arbash Meinel
 We should only care if the compression parent is not available, not if all parents are available.  | 
1514  | 
delta_types.add("knit-annotated-delta-gz")  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1515  | 
convertibles.add("knit-annotated-delta-gz")  | 
| 
3350.3.22
by Robert Collins
 Review feedback.  | 
1516  | 
        # The set of types we can cheaply adapt without needing basis texts.
 | 
| 
3350.3.9
by Robert Collins
 Avoid full text reconstruction when transferring knit to knit via record streams.  | 
1517  | 
native_types = set()  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1518  | 
if self._max_delta_chain:  | 
1519  | 
native_types.add("knit-%sdelta-gz" % annotated)  | 
|
| 
3871.4.3
by John Arbash Meinel
 We should only care if the compression parent is not available, not if all parents are available.  | 
1520  | 
delta_types.add("knit-%sdelta-gz" % annotated)  | 
| 
3350.3.9
by Robert Collins
 Avoid full text reconstruction when transferring knit to knit via record streams.  | 
1521  | 
native_types.add("knit-%sft-gz" % annotated)  | 
| 
3350.3.11
by Robert Collins
 Test inserting a stream that overlaps the current content of a knit does not error.  | 
1522  | 
knit_types = native_types.union(convertibles)  | 
| 
3350.3.8
by Robert Collins
 Basic stream insertion, no fast path yet for knit to knit.  | 
1523  | 
adapters = {}  | 
| 
3350.3.22
by Robert Collins
 Review feedback.  | 
1524  | 
        # Buffer all index entries that we can't add immediately because their
 | 
| 
3350.3.17
by Robert Collins
 Prevent corrupt knits being created when a stream is interrupted with basis parents not present.  | 
1525  | 
        # basis parent is missing. We don't buffer all because generating
 | 
1526  | 
        # annotations may require access to some of the new records. However we
 | 
|
1527  | 
        # can't generate annotations from new deltas until their basis parent
 | 
|
1528  | 
        # is present anyway, so we get away with not needing an index that
 | 
|
| 
3350.3.22
by Robert Collins
 Review feedback.  | 
1529  | 
        # includes the new keys.
 | 
| 
3830.3.15
by Martin Pool
 Check against all parents when deciding whether to store a fulltext in a stacked repository  | 
1530  | 
        #
 | 
1531  | 
        # See <http://launchpad.net/bugs/300177> about ordering of compression
 | 
|
1532  | 
        # parents in the records - to be conservative, we insist that all
 | 
|
1533  | 
        # parents must be present to avoid expanding to a fulltext.
 | 
|
1534  | 
        #
 | 
|
| 
3350.3.17
by Robert Collins
 Prevent corrupt knits being created when a stream is interrupted with basis parents not present.  | 
1535  | 
        # key = basis_parent, value = index entry to add
 | 
| 
4009.3.7
by Andrew Bennetts
 Most tests passing.  | 
1536  | 
buffered_index_entries = {}  | 
| 
3350.3.8
by Robert Collins
 Basic stream insertion, no fast path yet for knit to knit.  | 
1537  | 
for record in stream:  | 
| 
4052.1.2
by Robert Collins
 Review feedback - fix flushing buffered records in knit's insert_record_stream.  | 
1538  | 
buffered = False  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1539  | 
parents = record.parents  | 
| 
3871.4.3
by John Arbash Meinel
 We should only care if the compression parent is not available, not if all parents are available.  | 
1540  | 
if record.storage_kind in delta_types:  | 
1541  | 
                # TODO: eventually the record itself should track
 | 
|
1542  | 
                #       compression_parent
 | 
|
1543  | 
compression_parent = parents[0]  | 
|
1544  | 
else:  | 
|
1545  | 
compression_parent = None  | 
|
| 
3350.3.15
by Robert Collins
 Update the insert_record_stream contract to error if an absent record is provided.  | 
1546  | 
            # Raise an error when a record is missing.
 | 
1547  | 
if record.storage_kind == 'absent':  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1548  | 
raise RevisionNotPresent([record.key], self)  | 
| 
3830.3.15
by Martin Pool
 Check against all parents when deciding whether to store a fulltext in a stacked repository  | 
1549  | 
elif ((record.storage_kind in knit_types)  | 
| 
3871.4.3
by John Arbash Meinel
 We should only care if the compression parent is not available, not if all parents are available.  | 
1550  | 
and (compression_parent is None  | 
| 
3830.3.18
by Martin Pool
 Faster expression evaluation order  | 
1551  | 
or not self._fallback_vfs  | 
| 
3871.4.3
by John Arbash Meinel
 We should only care if the compression parent is not available, not if all parents are available.  | 
1552  | 
or self._index.has_key(compression_parent)  | 
1553  | 
or not self.has_key(compression_parent))):  | 
|
| 
3830.3.9
by Martin Pool
 Simplify kvf insert_record_stream; add has_key shorthand methods; update stacking effort tests  | 
1554  | 
                # we can insert the knit record literally if either it has no
 | 
1555  | 
                # compression parent OR we already have its basis in this kvf
 | 
|
1556  | 
                # OR the basis is not present even in the fallbacks.  In the
 | 
|
1557  | 
                # last case it will either turn up later in the stream and all
 | 
|
1558  | 
                # will be well, or it won't turn up at all and we'll raise an
 | 
|
1559  | 
                # error at the end.
 | 
|
| 
3830.3.13
by Martin Pool
 review cleanups to insert_record_stream  | 
1560  | 
                #
 | 
1561  | 
                # TODO: self.has_key is somewhat redundant with
 | 
|
1562  | 
                # self._index.has_key; we really want something that directly
 | 
|
1563  | 
                # asks if it's only present in the fallbacks. -- mbp 20081119
 | 
|
| 
3350.3.9
by Robert Collins
 Avoid full text reconstruction when transferring knit to knit via record streams.  | 
1564  | 
if record.storage_kind not in native_types:  | 
1565  | 
try:  | 
|
1566  | 
adapter_key = (record.storage_kind, "knit-delta-gz")  | 
|
1567  | 
adapter = get_adapter(adapter_key)  | 
|
1568  | 
except KeyError:  | 
|
1569  | 
adapter_key = (record.storage_kind, "knit-ft-gz")  | 
|
1570  | 
adapter = get_adapter(adapter_key)  | 
|
| 
4005.3.1
by Robert Collins
 Change the signature on VersionedFiles adapters to allow less typing and more flexability inside adapters.  | 
1571  | 
bytes = adapter.get_bytes(record)  | 
| 
3350.3.9
by Robert Collins
 Avoid full text reconstruction when transferring knit to knit via record streams.  | 
1572  | 
else:  | 
| 
4005.3.2
by Robert Collins
 First passing NetworkRecordStream test - a fulltext from any record type which isn't a chunked or fulltext can be serialised and deserialised successfully.  | 
1573  | 
                    # It's a knit record, it has a _raw_record field (even if
 | 
1574  | 
                    # it was reconstituted from a network stream).
 | 
|
1575  | 
bytes = record._raw_record  | 
|
| 
3350.3.9
by Robert Collins
 Avoid full text reconstruction when transferring knit to knit via record streams.  | 
1576  | 
options = [record._build_details[0]]  | 
1577  | 
if record._build_details[1]:  | 
|
1578  | 
options.append('no-eol')  | 
|
| 
3350.3.11
by Robert Collins
 Test inserting a stream that overlaps the current content of a knit does not error.  | 
1579  | 
                # Just blat it across.
 | 
1580  | 
                # Note: This does end up adding data on duplicate keys. As
 | 
|
1581  | 
                # modern repositories use atomic insertions this should not
 | 
|
1582  | 
                # lead to excessive growth in the event of interrupted fetches.
 | 
|
1583  | 
                # 'knit' repositories may suffer excessive growth, but as a
 | 
|
1584  | 
                # deprecated format this is tolerable. It can be fixed if
 | 
|
1585  | 
                # needed by in the kndx index support raising on a duplicate
 | 
|
1586  | 
                # add with identical parents and options.
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1587  | 
access_memo = self._access.add_raw_records(  | 
1588  | 
[(record.key, len(bytes))], bytes)[0]  | 
|
1589  | 
index_entry = (record.key, options, access_memo, parents)  | 
|
| 
3350.3.17
by Robert Collins
 Prevent corrupt knits being created when a stream is interrupted with basis parents not present.  | 
1590  | 
if 'fulltext' not in options:  | 
| 
3830.3.24
by John Arbash Meinel
 We don't require all parents to be present, just the compression parent.  | 
1591  | 
                    # Not a fulltext, so we need to make sure the compression
 | 
1592  | 
                    # parent will also be present.
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1593  | 
                    # Note that pack backed knits don't need to buffer here
 | 
1594  | 
                    # because they buffer all writes to the transaction level,
 | 
|
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
1595  | 
                    # but we don't expose that difference at the index level. If
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1596  | 
                    # the query here has sufficient cost to show up in
 | 
1597  | 
                    # profiling we should do that.
 | 
|
| 
3830.3.24
by John Arbash Meinel
 We don't require all parents to be present, just the compression parent.  | 
1598  | 
                    #
 | 
| 
3830.3.7
by Martin Pool
 KnitVersionedFiles.insert_record_stream checks that compression parents are in the same kvf, not in a fallback  | 
1599  | 
                    # They're required to be physically in this
 | 
1600  | 
                    # KnitVersionedFiles, not in a fallback.
 | 
|
| 
3871.4.3
by John Arbash Meinel
 We should only care if the compression parent is not available, not if all parents are available.  | 
1601  | 
if not self._index.has_key(compression_parent):  | 
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
1602  | 
pending = buffered_index_entries.setdefault(  | 
1603  | 
compression_parent, [])  | 
|
1604  | 
pending.append(index_entry)  | 
|
| 
4009.3.9
by Andrew Bennetts
 Remove some XXXs.  | 
1605  | 
buffered = True  | 
1606  | 
if not buffered:  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1607  | 
self._index.add_records([index_entry])  | 
| 
3890.2.9
by John Arbash Meinel
 Start using osutils.chunks_as_lines rather than osutils.split_lines.  | 
1608  | 
elif record.storage_kind == 'chunked':  | 
1609  | 
self.add_lines(record.key, parents,  | 
|
1610  | 
osutils.chunks_to_lines(record.get_bytes_as('chunked')))  | 
|
| 
3350.3.8
by Robert Collins
 Basic stream insertion, no fast path yet for knit to knit.  | 
1611  | 
else:  | 
| 
4005.3.8
by Robert Collins
 Handle record streams where a fulltext is obtainable from a record but not the storage_kind.  | 
1612  | 
                # Not suitable for direct insertion as a
 | 
| 
3849.3.2
by Andrew Bennetts
 Expand a comment inside insert_record_stream slightly.  | 
1613  | 
                # delta, either because it's not the right format, or this
 | 
1614  | 
                # KnitVersionedFiles doesn't permit deltas (_max_delta_chain ==
 | 
|
1615  | 
                # 0) or because it depends on a base only present in the
 | 
|
1616  | 
                # fallback kvfs.
 | 
|
| 
4187.3.6
by Andrew Bennetts
 Move the flush in KnitVersionedFiles.insert_record_stream so that it covers the add_lines call of the fallback case, not just the adapter.get_bytes.  | 
1617  | 
self._access.flush()  | 
| 
4005.3.8
by Robert Collins
 Handle record streams where a fulltext is obtainable from a record but not the storage_kind.  | 
1618  | 
try:  | 
1619  | 
                    # Try getting a fulltext directly from the record.
 | 
|
1620  | 
bytes = record.get_bytes_as('fulltext')  | 
|
1621  | 
except errors.UnavailableRepresentation:  | 
|
1622  | 
adapter_key = record.storage_kind, 'fulltext'  | 
|
1623  | 
adapter = get_adapter(adapter_key)  | 
|
1624  | 
bytes = adapter.get_bytes(record)  | 
|
1625  | 
lines = split_lines(bytes)  | 
|
| 
3350.3.11
by Robert Collins
 Test inserting a stream that overlaps the current content of a knit does not error.  | 
1626  | 
try:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1627  | 
self.add_lines(record.key, parents, lines)  | 
| 
3350.3.11
by Robert Collins
 Test inserting a stream that overlaps the current content of a knit does not error.  | 
1628  | 
except errors.RevisionAlreadyPresent:  | 
1629  | 
                    pass
 | 
|
| 
3350.3.17
by Robert Collins
 Prevent corrupt knits being created when a stream is interrupted with basis parents not present.  | 
1630  | 
            # Add any records whose basis parent is now available.
 | 
| 
4052.1.2
by Robert Collins
 Review feedback - fix flushing buffered records in knit's insert_record_stream.  | 
1631  | 
if not buffered:  | 
1632  | 
added_keys = [record.key]  | 
|
1633  | 
while added_keys:  | 
|
1634  | 
key = added_keys.pop(0)  | 
|
1635  | 
if key in buffered_index_entries:  | 
|
1636  | 
index_entries = buffered_index_entries[key]  | 
|
1637  | 
self._index.add_records(index_entries)  | 
|
1638  | 
added_keys.extend(  | 
|
1639  | 
[index_entry[0] for index_entry in index_entries])  | 
|
1640  | 
del buffered_index_entries[key]  | 
|
| 
4009.3.8
by Andrew Bennetts
 Fix test failure.  | 
1641  | 
if buffered_index_entries:  | 
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
1642  | 
            # There were index entries buffered at the end of the stream,
 | 
1643  | 
            # So these need to be added (if the index supports holding such
 | 
|
1644  | 
            # entries for later insertion)
 | 
|
1645  | 
for key in buffered_index_entries:  | 
|
1646  | 
index_entries = buffered_index_entries[key]  | 
|
1647  | 
self._index.add_records(index_entries,  | 
|
1648  | 
missing_compression_parents=True)  | 
|
| 
4009.3.2
by Andrew Bennetts
 Add test_insert_record_stream_delta_missing_basis_can_be_added_later.  | 
1649  | 
|
1650  | 
def get_missing_compression_parent_keys(self):  | 
|
| 
4009.3.3
by Andrew Bennetts
 Add docstrings.  | 
1651  | 
"""Return an iterable of keys of missing compression parents.  | 
1652  | 
||
1653  | 
        Check this after calling insert_record_stream to find out if there are
 | 
|
1654  | 
        any missing compression parents.  If there are, the records that
 | 
|
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
1655  | 
        depend on them are not able to be inserted safely. For atomic
 | 
1656  | 
        KnitVersionedFiles built on packs, the transaction should be aborted or
 | 
|
1657  | 
        suspended - commit will fail at this point. Nonatomic knits will error
 | 
|
1658  | 
        earlier because they have no staging area to put pending entries into.
 | 
|
| 
4009.3.3
by Andrew Bennetts
 Add docstrings.  | 
1659  | 
        """
 | 
| 
4009.3.7
by Andrew Bennetts
 Most tests passing.  | 
1660  | 
return self._index.get_missing_compression_parents()  | 
| 
3350.3.8
by Robert Collins
 Basic stream insertion, no fast path yet for knit to knit.  | 
1661  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1662  | 
def iter_lines_added_or_present_in_keys(self, keys, pb=None):  | 
1663  | 
"""Iterate over the lines in the versioned files from keys.  | 
|
1664  | 
||
1665  | 
        This may return lines from other keys. Each item the returned
 | 
|
1666  | 
        iterator yields is a tuple of a line and a text version that that line
 | 
|
1667  | 
        is present in (not introduced in).
 | 
|
1668  | 
||
1669  | 
        Ordering of results is in whatever order is most suitable for the
 | 
|
1670  | 
        underlying storage format.
 | 
|
1671  | 
||
1672  | 
        If a progress bar is supplied, it may be used to indicate progress.
 | 
|
1673  | 
        The caller is responsible for cleaning up progress bars (because this
 | 
|
1674  | 
        is an iterator).
 | 
|
1675  | 
||
1676  | 
        NOTES:
 | 
|
| 
3830.3.17
by Martin Pool
 Don't assume versions being unmentioned by iter_lines_added_or_changed implies the versions aren't present  | 
1677  | 
         * Lines are normalised by the underlying store: they will all have \\n
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1678  | 
           terminators.
 | 
1679  | 
         * Lines are returned in arbitrary order.
 | 
|
| 
3830.3.17
by Martin Pool
 Don't assume versions being unmentioned by iter_lines_added_or_changed implies the versions aren't present  | 
1680  | 
         * If a requested key did not change any lines (or didn't have any
 | 
1681  | 
           lines), it may not be mentioned at all in the result.
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1682  | 
|
| 
4110.2.10
by Martin Pool
 Tweak iter_lines progress messages  | 
1683  | 
        :param pb: Progress bar supplied by caller.
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1684  | 
        :return: An iterator over (line, key).
 | 
1685  | 
        """
 | 
|
1686  | 
if pb is None:  | 
|
1687  | 
pb = progress.DummyProgress()  | 
|
1688  | 
keys = set(keys)  | 
|
| 
3350.8.5
by Robert Collins
 Iter_lines_added_or_present_in_keys stacks.  | 
1689  | 
total = len(keys)  | 
| 
3789.2.12
by John Arbash Meinel
 iter_lines_added_or_present now retries.  | 
1690  | 
done = False  | 
1691  | 
while not done:  | 
|
1692  | 
try:  | 
|
1693  | 
                # we don't care about inclusions, the caller cares.
 | 
|
1694  | 
                # but we need to setup a list of records to visit.
 | 
|
1695  | 
                # we need key, position, length
 | 
|
1696  | 
key_records = []  | 
|
1697  | 
build_details = self._index.get_build_details(keys)  | 
|
1698  | 
for key, details in build_details.iteritems():  | 
|
1699  | 
if key in keys:  | 
|
1700  | 
key_records.append((key, details[0]))  | 
|
1701  | 
records_iter = enumerate(self._read_records_iter(key_records))  | 
|
1702  | 
for (key_idx, (key, data, sha_value)) in records_iter:  | 
|
| 
4103.3.2
by Martin Pool
 Remove trailing punctuation from progress messages  | 
1703  | 
pb.update('Walking content', key_idx, total)  | 
| 
3789.2.12
by John Arbash Meinel
 iter_lines_added_or_present now retries.  | 
1704  | 
compression_parent = build_details[key][1]  | 
1705  | 
if compression_parent is None:  | 
|
1706  | 
                        # fulltext
 | 
|
1707  | 
line_iterator = self._factory.get_fulltext_content(data)  | 
|
1708  | 
else:  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1709  | 
                        # Delta
 | 
| 
3789.2.12
by John Arbash Meinel
 iter_lines_added_or_present now retries.  | 
1710  | 
line_iterator = self._factory.get_linedelta_content(data)  | 
1711  | 
                    # Now that we are yielding the data for this key, remove it
 | 
|
1712  | 
                    # from the list
 | 
|
1713  | 
keys.remove(key)  | 
|
1714  | 
                    # XXX: It might be more efficient to yield (key,
 | 
|
1715  | 
                    # line_iterator) in the future. However for now, this is a
 | 
|
1716  | 
                    # simpler change to integrate into the rest of the
 | 
|
1717  | 
                    # codebase. RBC 20071110
 | 
|
1718  | 
for line in line_iterator:  | 
|
1719  | 
yield line, key  | 
|
1720  | 
done = True  | 
|
1721  | 
except errors.RetryWithNewPacks, e:  | 
|
1722  | 
self._access.reload_or_raise(e)  | 
|
| 
3830.3.17
by Martin Pool
 Don't assume versions being unmentioned by iter_lines_added_or_changed implies the versions aren't present  | 
1723  | 
        # If there are still keys we've not yet found, we look in the fallback
 | 
1724  | 
        # vfs, and hope to find them there.  Note that if the keys are found
 | 
|
1725  | 
        # but had no changes or no content, the fallback may not return
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1726  | 
        # anything.
 | 
| 
3830.3.17
by Martin Pool
 Don't assume versions being unmentioned by iter_lines_added_or_changed implies the versions aren't present  | 
1727  | 
if keys and not self._fallback_vfs:  | 
1728  | 
            # XXX: strictly the second parameter is meant to be the file id
 | 
|
1729  | 
            # but it's not easily accessible here.
 | 
|
1730  | 
raise RevisionNotPresent(keys, repr(self))  | 
|
| 
3350.8.5
by Robert Collins
 Iter_lines_added_or_present_in_keys stacks.  | 
1731  | 
for source in self._fallback_vfs:  | 
1732  | 
if not keys:  | 
|
1733  | 
                break
 | 
|
1734  | 
source_keys = set()  | 
|
1735  | 
for line, key in source.iter_lines_added_or_present_in_keys(keys):  | 
|
1736  | 
source_keys.add(key)  | 
|
1737  | 
yield line, key  | 
|
1738  | 
keys.difference_update(source_keys)  | 
|
| 
4103.3.2
by Martin Pool
 Remove trailing punctuation from progress messages  | 
1739  | 
pb.update('Walking content', total, total)  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1740  | 
|
1741  | 
def _make_line_delta(self, delta_seq, new_content):  | 
|
1742  | 
"""Generate a line delta from delta_seq and new_content."""  | 
|
1743  | 
diff_hunks = []  | 
|
1744  | 
for op in delta_seq.get_opcodes():  | 
|
1745  | 
if op[0] == 'equal':  | 
|
1746  | 
                continue
 | 
|
1747  | 
diff_hunks.append((op[1], op[2], op[4]-op[3], new_content._lines[op[3]:op[4]]))  | 
|
1748  | 
return diff_hunks  | 
|
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
1749  | 
|
| 
1596.2.34
by Robert Collins
 Optimise knit add to only diff once per parent, not once per parent + once for the delta generation.  | 
1750  | 
def _merge_annotations(self, content, parents, parent_texts={},  | 
| 
2520.4.140
by Aaron Bentley
 Use matching blocks from mpdiff for knit delta creation  | 
1751  | 
delta=None, annotated=None,  | 
1752  | 
left_matching_blocks=None):  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1753  | 
"""Merge annotations for content and generate deltas.  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1754  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1755  | 
        This is done by comparing the annotations based on changes to the text
 | 
1756  | 
        and generating a delta on the resulting full texts. If annotations are
 | 
|
1757  | 
        not being created then a simple delta is created.
 | 
|
| 
1596.2.27
by Robert Collins
 Note potential improvements in knit adds.  | 
1758  | 
        """
 | 
| 
2520.4.146
by Aaron Bentley
 Avoid get_matching_blocks for un-annotated text  | 
1759  | 
if left_matching_blocks is not None:  | 
1760  | 
delta_seq = diff._PrematchedMatcher(left_matching_blocks)  | 
|
1761  | 
else:  | 
|
1762  | 
delta_seq = None  | 
|
| 
1596.2.34
by Robert Collins
 Optimise knit add to only diff once per parent, not once per parent + once for the delta generation.  | 
1763  | 
if annotated:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1764  | 
for parent_key in parents:  | 
1765  | 
merge_content = self._get_content(parent_key, parent_texts)  | 
|
1766  | 
if (parent_key == parents[0] and delta_seq is not None):  | 
|
| 
2520.4.146
by Aaron Bentley
 Avoid get_matching_blocks for un-annotated text  | 
1767  | 
seq = delta_seq  | 
| 
2520.4.140
by Aaron Bentley
 Use matching blocks from mpdiff for knit delta creation  | 
1768  | 
else:  | 
1769  | 
seq = patiencediff.PatienceSequenceMatcher(  | 
|
1770  | 
None, merge_content.text(), content.text())  | 
|
| 
1596.2.34
by Robert Collins
 Optimise knit add to only diff once per parent, not once per parent + once for the delta generation.  | 
1771  | 
for i, j, n in seq.get_matching_blocks():  | 
1772  | 
if n == 0:  | 
|
1773  | 
                        continue
 | 
|
| 
3460.2.1
by Robert Collins
 * Inserting a bundle which changes the contents of a file with no trailing  | 
1774  | 
                    # this copies (origin, text) pairs across to the new
 | 
1775  | 
                    # content for any line that matches the last-checked
 | 
|
| 
2520.4.146
by Aaron Bentley
 Avoid get_matching_blocks for un-annotated text  | 
1776  | 
                    # parent.
 | 
| 
1596.2.34
by Robert Collins
 Optimise knit add to only diff once per parent, not once per parent + once for the delta generation.  | 
1777  | 
content._lines[j:j+n] = merge_content._lines[i:i+n]  | 
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
1778  | 
            # XXX: Robert says the following block is a workaround for a
 | 
1779  | 
            # now-fixed bug and it can probably be deleted. -- mbp 20080618
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1780  | 
if content._lines and content._lines[-1][1][-1] != '\n':  | 
1781  | 
                # The copied annotation was from a line without a trailing EOL,
 | 
|
1782  | 
                # reinstate one for the content object, to ensure correct
 | 
|
1783  | 
                # serialization.
 | 
|
1784  | 
line = content._lines[-1][1] + '\n'  | 
|
1785  | 
content._lines[-1] = (content._lines[-1][0], line)  | 
|
| 
1596.2.36
by Robert Collins
 add a get_delta api to versioned_file.  | 
1786  | 
if delta:  | 
| 
2520.4.146
by Aaron Bentley
 Avoid get_matching_blocks for un-annotated text  | 
1787  | 
if delta_seq is None:  | 
| 
1596.2.36
by Robert Collins
 add a get_delta api to versioned_file.  | 
1788  | 
reference_content = self._get_content(parents[0], parent_texts)  | 
1789  | 
new_texts = content.text()  | 
|
1790  | 
old_texts = reference_content.text()  | 
|
| 
2104.4.2
by John Arbash Meinel
 Small cleanup and NEWS entry about fixing bug #65714  | 
1791  | 
delta_seq = patiencediff.PatienceSequenceMatcher(  | 
| 
2100.2.1
by wang
 Replace python's difflib by patiencediff because the worst case  | 
1792  | 
None, old_texts, new_texts)  | 
| 
1596.2.36
by Robert Collins
 add a get_delta api to versioned_file.  | 
1793  | 
return self._make_line_delta(delta_seq, content)  | 
1794  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1795  | 
def _parse_record(self, version_id, data):  | 
1796  | 
"""Parse an original format knit record.  | 
|
1797  | 
||
1798  | 
        These have the last element of the key only present in the stored data.
 | 
|
1799  | 
        """
 | 
|
1800  | 
rec, record_contents = self._parse_record_unchecked(data)  | 
|
1801  | 
self._check_header_version(rec, version_id)  | 
|
1802  | 
return record_contents, rec[3]  | 
|
1803  | 
||
1804  | 
def _parse_record_header(self, key, raw_data):  | 
|
1805  | 
"""Parse a record header for consistency.  | 
|
1806  | 
||
1807  | 
        :return: the header and the decompressor stream.
 | 
|
1808  | 
                 as (stream, header_record)
 | 
|
1809  | 
        """
 | 
|
| 
3535.5.1
by John Arbash Meinel
 cleanup a few imports to be lazily loaded.  | 
1810  | 
df = tuned_gzip.GzipFile(mode='rb', fileobj=StringIO(raw_data))  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1811  | 
try:  | 
1812  | 
            # Current serialise
 | 
|
1813  | 
rec = self._check_header(key, df.readline())  | 
|
1814  | 
except Exception, e:  | 
|
1815  | 
raise KnitCorrupt(self,  | 
|
1816  | 
"While reading {%s} got %s(%s)"  | 
|
1817  | 
% (key, e.__class__.__name__, str(e)))  | 
|
1818  | 
return df, rec  | 
|
1819  | 
||
1820  | 
def _parse_record_unchecked(self, data):  | 
|
1821  | 
        # profiling notes:
 | 
|
1822  | 
        # 4168 calls in 2880 217 internal
 | 
|
1823  | 
        # 4168 calls to _parse_record_header in 2121
 | 
|
1824  | 
        # 4168 calls to readlines in 330
 | 
|
| 
3535.5.1
by John Arbash Meinel
 cleanup a few imports to be lazily loaded.  | 
1825  | 
df = tuned_gzip.GzipFile(mode='rb', fileobj=StringIO(data))  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1826  | 
try:  | 
1827  | 
record_contents = df.readlines()  | 
|
1828  | 
except Exception, e:  | 
|
1829  | 
raise KnitCorrupt(self, "Corrupt compressed record %r, got %s(%s)" %  | 
|
1830  | 
(data, e.__class__.__name__, str(e)))  | 
|
1831  | 
header = record_contents.pop(0)  | 
|
1832  | 
rec = self._split_header(header)  | 
|
1833  | 
last_line = record_contents.pop()  | 
|
1834  | 
if len(record_contents) != int(rec[2]):  | 
|
1835  | 
raise KnitCorrupt(self,  | 
|
1836  | 
'incorrect number of lines %s != %s'  | 
|
1837  | 
' for version {%s} %s'  | 
|
1838  | 
% (len(record_contents), int(rec[2]),  | 
|
1839  | 
rec[1], record_contents))  | 
|
1840  | 
if last_line != 'end %s\n' % rec[1]:  | 
|
1841  | 
raise KnitCorrupt(self,  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1842  | 
'unexpected version end line %r, wanted %r'  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1843  | 
% (last_line, rec[1]))  | 
1844  | 
df.close()  | 
|
1845  | 
return rec, record_contents  | 
|
1846  | 
||
1847  | 
def _read_records_iter(self, records):  | 
|
1848  | 
"""Read text records from data file and yield result.  | 
|
1849  | 
||
1850  | 
        The result will be returned in whatever is the fastest to read.
 | 
|
1851  | 
        Not by the order requested. Also, multiple requests for the same
 | 
|
1852  | 
        record will only yield 1 response.
 | 
|
1853  | 
        :param records: A list of (key, access_memo) entries
 | 
|
1854  | 
        :return: Yields (key, contents, digest) in the order
 | 
|
1855  | 
                 read, not the order requested
 | 
|
1856  | 
        """
 | 
|
1857  | 
if not records:  | 
|
1858  | 
            return
 | 
|
1859  | 
||
1860  | 
        # XXX: This smells wrong, IO may not be getting ordered right.
 | 
|
1861  | 
needed_records = sorted(set(records), key=operator.itemgetter(1))  | 
|
1862  | 
if not needed_records:  | 
|
1863  | 
            return
 | 
|
1864  | 
||
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1865  | 
        # The transport optimizes the fetching as well
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1866  | 
        # (ie, reads continuous ranges.)
 | 
1867  | 
raw_data = self._access.get_raw_records(  | 
|
1868  | 
[index_memo for key, index_memo in needed_records])  | 
|
1869  | 
||
1870  | 
for (key, index_memo), data in \  | 
|
1871  | 
izip(iter(needed_records), raw_data):  | 
|
1872  | 
content, digest = self._parse_record(key[-1], data)  | 
|
1873  | 
yield key, content, digest  | 
|
1874  | 
||
1875  | 
def _read_records_iter_raw(self, records):  | 
|
1876  | 
"""Read text records from data file and yield raw data.  | 
|
1877  | 
||
1878  | 
        This unpacks enough of the text record to validate the id is
 | 
|
1879  | 
        as expected but thats all.
 | 
|
1880  | 
||
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1881  | 
        Each item the iterator yields is (key, bytes,
 | 
1882  | 
            expected_sha1_of_full_text).
 | 
|
1883  | 
        """
 | 
|
1884  | 
for key, data in self._read_records_iter_unchecked(records):  | 
|
1885  | 
            # validate the header (note that we can only use the suffix in
 | 
|
1886  | 
            # current knit records).
 | 
|
1887  | 
df, rec = self._parse_record_header(key, data)  | 
|
1888  | 
df.close()  | 
|
1889  | 
yield key, data, rec[3]  | 
|
1890  | 
||
1891  | 
def _read_records_iter_unchecked(self, records):  | 
|
1892  | 
"""Read text records from data file and yield raw data.  | 
|
1893  | 
||
1894  | 
        No validation is done.
 | 
|
1895  | 
||
1896  | 
        Yields tuples of (key, data).
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1897  | 
        """
 | 
1898  | 
        # setup an iterator of the external records:
 | 
|
1899  | 
        # uses readv so nice and fast we hope.
 | 
|
1900  | 
if len(records):  | 
|
1901  | 
            # grab the disk data needed.
 | 
|
1902  | 
needed_offsets = [index_memo for key, index_memo  | 
|
1903  | 
in records]  | 
|
1904  | 
raw_records = self._access.get_raw_records(needed_offsets)  | 
|
1905  | 
||
1906  | 
for key, index_memo in records:  | 
|
1907  | 
data = raw_records.next()  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1908  | 
yield key, data  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1909  | 
|
1910  | 
def _record_to_data(self, key, digest, lines, dense_lines=None):  | 
|
1911  | 
"""Convert key, digest, lines into a raw data block.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
1912  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1913  | 
        :param key: The key of the record. Currently keys are always serialised
 | 
1914  | 
            using just the trailing component.
 | 
|
1915  | 
        :param dense_lines: The bytes of lines but in a denser form. For
 | 
|
1916  | 
            instance, if lines is a list of 1000 bytestrings each ending in \n,
 | 
|
1917  | 
            dense_lines may be a list with one line in it, containing all the
 | 
|
1918  | 
            1000's lines and their \n's. Using dense_lines if it is already
 | 
|
1919  | 
            known is a win because the string join to create bytes in this
 | 
|
1920  | 
            function spends less time resizing the final string.
 | 
|
1921  | 
        :return: (len, a StringIO instance with the raw data ready to read.)
 | 
|
1922  | 
        """
 | 
|
1923  | 
        # Note: using a string copy here increases memory pressure with e.g.
 | 
|
1924  | 
        # ISO's, but it is about 3 seconds faster on a 1.2Ghz intel machine
 | 
|
1925  | 
        # when doing the initial commit of a mozilla tree. RBC 20070921
 | 
|
1926  | 
bytes = ''.join(chain(  | 
|
1927  | 
["version %s %d %s\n" % (key[-1],  | 
|
1928  | 
len(lines),  | 
|
1929  | 
digest)],  | 
|
1930  | 
dense_lines or lines,  | 
|
1931  | 
["end %s\n" % key[-1]]))  | 
|
1932  | 
if type(bytes) != str:  | 
|
1933  | 
raise AssertionError(  | 
|
1934  | 
'data must be plain bytes was %s' % type(bytes))  | 
|
1935  | 
if lines and lines[-1][-1] != '\n':  | 
|
1936  | 
raise ValueError('corrupt lines value %r' % lines)  | 
|
| 
3535.5.1
by John Arbash Meinel
 cleanup a few imports to be lazily loaded.  | 
1937  | 
compressed_bytes = tuned_gzip.bytes_to_gzip(bytes)  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1938  | 
return len(compressed_bytes), compressed_bytes  | 
1939  | 
||
1940  | 
def _split_header(self, line):  | 
|
1941  | 
rec = line.split()  | 
|
1942  | 
if len(rec) != 4:  | 
|
1943  | 
raise KnitCorrupt(self,  | 
|
1944  | 
'unexpected number of elements in record header')  | 
|
1945  | 
return rec  | 
|
1946  | 
||
1947  | 
def keys(self):  | 
|
1948  | 
"""See VersionedFiles.keys."""  | 
|
1949  | 
if 'evil' in debug.debug_flags:  | 
|
1950  | 
trace.mutter_callsite(2, "keys scales with size of history")  | 
|
| 
3350.8.4
by Robert Collins
 Vf.keys() stacking support.  | 
1951  | 
sources = [self._index] + self._fallback_vfs  | 
1952  | 
result = set()  | 
|
1953  | 
for source in sources:  | 
|
1954  | 
result.update(source.keys())  | 
|
1955  | 
return result  | 
|
1956  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
1957  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1958  | 
class _ContentMapGenerator(object):  | 
1959  | 
"""Generate texts or expose raw deltas for a set of texts."""  | 
|
1960  | 
||
1961  | 
def _get_content(self, key):  | 
|
1962  | 
"""Get the content object for key."""  | 
|
| 
4005.3.7
by Robert Collins
 Review feedback.  | 
1963  | 
        # Note that _get_content is only called when the _ContentMapGenerator
 | 
1964  | 
        # has been constructed with just one key requested for reconstruction.
 | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1965  | 
if key in self.nonlocal_keys:  | 
1966  | 
record = self.get_record_stream().next()  | 
|
1967  | 
            # Create a content object on the fly
 | 
|
1968  | 
lines = osutils.chunks_to_lines(record.get_bytes_as('chunked'))  | 
|
1969  | 
return PlainKnitContent(lines, record.key)  | 
|
1970  | 
else:  | 
|
1971  | 
            # local keys we can ask for directly
 | 
|
1972  | 
return self._get_one_work(key)  | 
|
1973  | 
||
1974  | 
def get_record_stream(self):  | 
|
1975  | 
"""Get a record stream for the keys requested during __init__."""  | 
|
1976  | 
for record in self._work():  | 
|
1977  | 
yield record  | 
|
1978  | 
||
1979  | 
def _work(self):  | 
|
1980  | 
"""Produce maps of text and KnitContents as dicts.  | 
|
| 
4032.1.1
by John Arbash Meinel
 Merge the removal of all trailing whitespace, and resolve conflicts.  | 
1981  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
1982  | 
        :return: (text_map, content_map) where text_map contains the texts for
 | 
1983  | 
            the requested versions and content_map contains the KnitContents.
 | 
|
1984  | 
        """
 | 
|
1985  | 
        # NB: By definition we never need to read remote sources unless texts
 | 
|
1986  | 
        # are requested from them: we don't delta across stores - and we
 | 
|
1987  | 
        # explicitly do not want to to prevent data loss situations.
 | 
|
1988  | 
if self.global_map is None:  | 
|
1989  | 
self.global_map = self.vf.get_parent_map(self.keys)  | 
|
1990  | 
nonlocal_keys = self.nonlocal_keys  | 
|
1991  | 
||
1992  | 
missing_keys = set(nonlocal_keys)  | 
|
1993  | 
        # Read from remote versioned file instances and provide to our caller.
 | 
|
1994  | 
for source in self.vf._fallback_vfs:  | 
|
1995  | 
if not missing_keys:  | 
|
1996  | 
                break
 | 
|
1997  | 
            # Loop over fallback repositories asking them for texts - ignore
 | 
|
1998  | 
            # any missing from a particular fallback.
 | 
|
1999  | 
for record in source.get_record_stream(missing_keys,  | 
|
2000  | 
'unordered', True):  | 
|
2001  | 
if record.storage_kind == 'absent':  | 
|
2002  | 
                    # Not in thie particular stream, may be in one of the
 | 
|
2003  | 
                    # other fallback vfs objects.
 | 
|
2004  | 
                    continue
 | 
|
2005  | 
missing_keys.remove(record.key)  | 
|
2006  | 
yield record  | 
|
2007  | 
||
2008  | 
self._raw_record_map = self.vf._get_record_map_unparsed(self.keys,  | 
|
2009  | 
allow_missing=True)  | 
|
2010  | 
first = True  | 
|
2011  | 
for key in self.keys:  | 
|
2012  | 
if key in self.nonlocal_keys:  | 
|
2013  | 
                continue
 | 
|
2014  | 
yield LazyKnitContentFactory(key, self.global_map[key], self, first)  | 
|
2015  | 
first = False  | 
|
2016  | 
||
2017  | 
def _get_one_work(self, requested_key):  | 
|
2018  | 
        # Now, if we have calculated everything already, just return the
 | 
|
2019  | 
        # desired text.
 | 
|
2020  | 
if requested_key in self._contents_map:  | 
|
2021  | 
return self._contents_map[requested_key]  | 
|
| 
4005.3.7
by Robert Collins
 Review feedback.  | 
2022  | 
        # To simplify things, parse everything at once - code that wants one text
 | 
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
2023  | 
        # probably wants them all.
 | 
2024  | 
        # FUTURE: This function could be improved for the 'extract many' case
 | 
|
2025  | 
        # by tracking each component and only doing the copy when the number of
 | 
|
2026  | 
        # children than need to apply delta's to it is > 1 or it is part of the
 | 
|
2027  | 
        # final output.
 | 
|
2028  | 
multiple_versions = len(self.keys) != 1  | 
|
2029  | 
if self._record_map is None:  | 
|
2030  | 
self._record_map = self.vf._raw_map_to_record_map(  | 
|
2031  | 
self._raw_record_map)  | 
|
2032  | 
record_map = self._record_map  | 
|
2033  | 
        # raw_record_map is key:
 | 
|
| 
4032.1.1
by John Arbash Meinel
 Merge the removal of all trailing whitespace, and resolve conflicts.  | 
2034  | 
        # Have read and parsed records at this point.
 | 
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
2035  | 
for key in self.keys:  | 
2036  | 
if key in self.nonlocal_keys:  | 
|
2037  | 
                # already handled
 | 
|
2038  | 
                continue
 | 
|
2039  | 
components = []  | 
|
2040  | 
cursor = key  | 
|
2041  | 
while cursor is not None:  | 
|
2042  | 
try:  | 
|
2043  | 
record, record_details, digest, next = record_map[cursor]  | 
|
2044  | 
except KeyError:  | 
|
2045  | 
raise RevisionNotPresent(cursor, self)  | 
|
2046  | 
components.append((cursor, record, record_details, digest))  | 
|
2047  | 
cursor = next  | 
|
2048  | 
if cursor in self._contents_map:  | 
|
2049  | 
                    # no need to plan further back
 | 
|
2050  | 
components.append((cursor, None, None, None))  | 
|
2051  | 
                    break
 | 
|
2052  | 
||
2053  | 
content = None  | 
|
2054  | 
for (component_id, record, record_details,  | 
|
2055  | 
digest) in reversed(components):  | 
|
2056  | 
if component_id in self._contents_map:  | 
|
2057  | 
content = self._contents_map[component_id]  | 
|
2058  | 
else:  | 
|
2059  | 
content, delta = self._factory.parse_record(key[-1],  | 
|
2060  | 
record, record_details, content,  | 
|
2061  | 
copy_base_content=multiple_versions)  | 
|
2062  | 
if multiple_versions:  | 
|
2063  | 
self._contents_map[component_id] = content  | 
|
2064  | 
||
2065  | 
            # digest here is the digest from the last applied component.
 | 
|
2066  | 
text = content.text()  | 
|
2067  | 
actual_sha = sha_strings(text)  | 
|
2068  | 
if actual_sha != digest:  | 
|
2069  | 
raise SHA1KnitCorrupt(self, actual_sha, digest, key, text)  | 
|
2070  | 
if multiple_versions:  | 
|
2071  | 
return self._contents_map[requested_key]  | 
|
2072  | 
else:  | 
|
2073  | 
return content  | 
|
2074  | 
||
2075  | 
def _wire_bytes(self):  | 
|
2076  | 
"""Get the bytes to put on the wire for 'key'.  | 
|
2077  | 
||
2078  | 
        The first collection of bytes asked for returns the serialised
 | 
|
2079  | 
        raw_record_map and the additional details (key, parent) for key.
 | 
|
2080  | 
        Subsequent calls return just the additional details (key, parent).
 | 
|
2081  | 
        The wire storage_kind given for the first key is 'knit-delta-closure',
 | 
|
2082  | 
        For subsequent keys it is 'knit-delta-closure-ref'.
 | 
|
2083  | 
||
2084  | 
        :param key: A key from the content generator.
 | 
|
2085  | 
        :return: Bytes to put on the wire.
 | 
|
2086  | 
        """
 | 
|
2087  | 
lines = []  | 
|
2088  | 
        # kind marker for dispatch on the far side,
 | 
|
2089  | 
lines.append('knit-delta-closure')  | 
|
2090  | 
        # Annotated or not
 | 
|
2091  | 
if self.vf._factory.annotated:  | 
|
2092  | 
lines.append('annotated')  | 
|
2093  | 
else:  | 
|
2094  | 
lines.append('')  | 
|
2095  | 
        # then the list of keys
 | 
|
2096  | 
lines.append('\t'.join(['\x00'.join(key) for key in self.keys  | 
|
2097  | 
if key not in self.nonlocal_keys]))  | 
|
2098  | 
        # then the _raw_record_map in serialised form:
 | 
|
2099  | 
map_byte_list = []  | 
|
2100  | 
        # for each item in the map:
 | 
|
2101  | 
        # 1 line with key
 | 
|
2102  | 
        # 1 line with parents if the key is to be yielded (None: for None, '' for ())
 | 
|
2103  | 
        # one line with method
 | 
|
2104  | 
        # one line with noeol
 | 
|
2105  | 
        # one line with next ('' for None)
 | 
|
2106  | 
        # one line with byte count of the record bytes
 | 
|
2107  | 
        # the record bytes
 | 
|
2108  | 
for key, (record_bytes, (method, noeol), next) in \  | 
|
2109  | 
self._raw_record_map.iteritems():  | 
|
2110  | 
key_bytes = '\x00'.join(key)  | 
|
2111  | 
parents = self.global_map.get(key, None)  | 
|
2112  | 
if parents is None:  | 
|
2113  | 
parent_bytes = 'None:'  | 
|
2114  | 
else:  | 
|
2115  | 
parent_bytes = '\t'.join('\x00'.join(key) for key in parents)  | 
|
2116  | 
method_bytes = method  | 
|
2117  | 
if noeol:  | 
|
2118  | 
noeol_bytes = "T"  | 
|
2119  | 
else:  | 
|
2120  | 
noeol_bytes = "F"  | 
|
2121  | 
if next:  | 
|
2122  | 
next_bytes = '\x00'.join(next)  | 
|
2123  | 
else:  | 
|
2124  | 
next_bytes = ''  | 
|
2125  | 
map_byte_list.append('%s\n%s\n%s\n%s\n%s\n%d\n%s' % (  | 
|
2126  | 
key_bytes, parent_bytes, method_bytes, noeol_bytes, next_bytes,  | 
|
2127  | 
len(record_bytes), record_bytes))  | 
|
2128  | 
map_bytes = ''.join(map_byte_list)  | 
|
2129  | 
lines.append(map_bytes)  | 
|
2130  | 
bytes = '\n'.join(lines)  | 
|
2131  | 
return bytes  | 
|
2132  | 
||
2133  | 
||
2134  | 
class _VFContentMapGenerator(_ContentMapGenerator):  | 
|
2135  | 
"""Content map generator reading from a VersionedFiles object."""  | 
|
2136  | 
||
2137  | 
def __init__(self, versioned_files, keys, nonlocal_keys=None,  | 
|
2138  | 
global_map=None, raw_record_map=None):  | 
|
2139  | 
"""Create a _ContentMapGenerator.  | 
|
| 
4032.1.1
by John Arbash Meinel
 Merge the removal of all trailing whitespace, and resolve conflicts.  | 
2140  | 
|
| 
4005.3.6
by Robert Collins
 Support delta_closure=True with NetworkRecordStream to transmit deltas over the wire when full text extraction is required on the far end.  | 
2141  | 
        :param versioned_files: The versioned files that the texts are being
 | 
2142  | 
            extracted from.
 | 
|
2143  | 
        :param keys: The keys to produce content maps for.
 | 
|
2144  | 
        :param nonlocal_keys: An iterable of keys(possibly intersecting keys)
 | 
|
2145  | 
            which are known to not be in this knit, but rather in one of the
 | 
|
2146  | 
            fallback knits.
 | 
|
2147  | 
        :param global_map: The result of get_parent_map(keys) (or a supermap).
 | 
|
2148  | 
            This is required if get_record_stream() is to be used.
 | 
|
2149  | 
        :param raw_record_map: A unparsed raw record map to use for answering
 | 
|
2150  | 
            contents.
 | 
|
2151  | 
        """
 | 
|
2152  | 
        # The vf to source data from
 | 
|
2153  | 
self.vf = versioned_files  | 
|
2154  | 
        # The keys desired
 | 
|
2155  | 
self.keys = list(keys)  | 
|
2156  | 
        # Keys known to be in fallback vfs objects
 | 
|
2157  | 
if nonlocal_keys is None:  | 
|
2158  | 
self.nonlocal_keys = set()  | 
|
2159  | 
else:  | 
|
2160  | 
self.nonlocal_keys = frozenset(nonlocal_keys)  | 
|
2161  | 
        # Parents data for keys to be returned in get_record_stream
 | 
|
2162  | 
self.global_map = global_map  | 
|
2163  | 
        # The chunked lists for self.keys in text form
 | 
|
2164  | 
self._text_map = {}  | 
|
2165  | 
        # A cache of KnitContent objects used in extracting texts.
 | 
|
2166  | 
self._contents_map = {}  | 
|
2167  | 
        # All the knit records needed to assemble the requested keys as full
 | 
|
2168  | 
        # texts.
 | 
|
2169  | 
self._record_map = None  | 
|
2170  | 
if raw_record_map is None:  | 
|
2171  | 
self._raw_record_map = self.vf._get_record_map_unparsed(keys,  | 
|
2172  | 
allow_missing=True)  | 
|
2173  | 
else:  | 
|
2174  | 
self._raw_record_map = raw_record_map  | 
|
2175  | 
        # the factory for parsing records
 | 
|
2176  | 
self._factory = self.vf._factory  | 
|
2177  | 
||
2178  | 
||
2179  | 
class _NetworkContentMapGenerator(_ContentMapGenerator):  | 
|
2180  | 
"""Content map generator sourced from a network stream."""  | 
|
2181  | 
||
2182  | 
def __init__(self, bytes, line_end):  | 
|
2183  | 
"""Construct a _NetworkContentMapGenerator from a bytes block."""  | 
|
2184  | 
self._bytes = bytes  | 
|
2185  | 
self.global_map = {}  | 
|
2186  | 
self._raw_record_map = {}  | 
|
2187  | 
self._contents_map = {}  | 
|
2188  | 
self._record_map = None  | 
|
2189  | 
self.nonlocal_keys = []  | 
|
2190  | 
        # Get access to record parsing facilities
 | 
|
2191  | 
self.vf = KnitVersionedFiles(None, None)  | 
|
2192  | 
start = line_end  | 
|
2193  | 
        # Annotated or not
 | 
|
2194  | 
line_end = bytes.find('\n', start)  | 
|
2195  | 
line = bytes[start:line_end]  | 
|
2196  | 
start = line_end + 1  | 
|
2197  | 
if line == 'annotated':  | 
|
2198  | 
self._factory = KnitAnnotateFactory()  | 
|
2199  | 
else:  | 
|
2200  | 
self._factory = KnitPlainFactory()  | 
|
2201  | 
        # list of keys to emit in get_record_stream
 | 
|
2202  | 
line_end = bytes.find('\n', start)  | 
|
2203  | 
line = bytes[start:line_end]  | 
|
2204  | 
start = line_end + 1  | 
|
2205  | 
self.keys = [  | 
|
2206  | 
tuple(segment.split('\x00')) for segment in line.split('\t')  | 
|
2207  | 
if segment]  | 
|
2208  | 
        # now a loop until the end. XXX: It would be nice if this was just a
 | 
|
2209  | 
        # bunch of the same records as get_record_stream(..., False) gives, but
 | 
|
2210  | 
        # there is a decent sized gap stopping that at the moment.
 | 
|
2211  | 
end = len(bytes)  | 
|
2212  | 
while start < end:  | 
|
2213  | 
            # 1 line with key
 | 
|
2214  | 
line_end = bytes.find('\n', start)  | 
|
2215  | 
key = tuple(bytes[start:line_end].split('\x00'))  | 
|
2216  | 
start = line_end + 1  | 
|
2217  | 
            # 1 line with parents (None: for None, '' for ())
 | 
|
2218  | 
line_end = bytes.find('\n', start)  | 
|
2219  | 
line = bytes[start:line_end]  | 
|
2220  | 
if line == 'None:':  | 
|
2221  | 
parents = None  | 
|
2222  | 
else:  | 
|
2223  | 
parents = tuple(  | 
|
2224  | 
[tuple(segment.split('\x00')) for segment in line.split('\t')  | 
|
2225  | 
if segment])  | 
|
2226  | 
self.global_map[key] = parents  | 
|
2227  | 
start = line_end + 1  | 
|
2228  | 
            # one line with method
 | 
|
2229  | 
line_end = bytes.find('\n', start)  | 
|
2230  | 
line = bytes[start:line_end]  | 
|
2231  | 
method = line  | 
|
2232  | 
start = line_end + 1  | 
|
2233  | 
            # one line with noeol
 | 
|
2234  | 
line_end = bytes.find('\n', start)  | 
|
2235  | 
line = bytes[start:line_end]  | 
|
2236  | 
noeol = line == "T"  | 
|
2237  | 
start = line_end + 1  | 
|
2238  | 
            # one line with next ('' for None)
 | 
|
2239  | 
line_end = bytes.find('\n', start)  | 
|
2240  | 
line = bytes[start:line_end]  | 
|
2241  | 
if not line:  | 
|
2242  | 
next = None  | 
|
2243  | 
else:  | 
|
2244  | 
next = tuple(bytes[start:line_end].split('\x00'))  | 
|
2245  | 
start = line_end + 1  | 
|
2246  | 
            # one line with byte count of the record bytes
 | 
|
2247  | 
line_end = bytes.find('\n', start)  | 
|
2248  | 
line = bytes[start:line_end]  | 
|
2249  | 
count = int(line)  | 
|
2250  | 
start = line_end + 1  | 
|
2251  | 
            # the record bytes
 | 
|
2252  | 
record_bytes = bytes[start:start+count]  | 
|
2253  | 
start = start + count  | 
|
2254  | 
            # put it in the map
 | 
|
2255  | 
self._raw_record_map[key] = (record_bytes, (method, noeol), next)  | 
|
2256  | 
||
2257  | 
def get_record_stream(self):  | 
|
2258  | 
"""Get a record stream for for keys requested by the bytestream."""  | 
|
2259  | 
first = True  | 
|
2260  | 
for key in self.keys:  | 
|
2261  | 
yield LazyKnitContentFactory(key, self.global_map[key], self, first)  | 
|
2262  | 
first = False  | 
|
2263  | 
||
2264  | 
def _wire_bytes(self):  | 
|
2265  | 
return self._bytes  | 
|
2266  | 
||
2267  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2268  | 
class _KndxIndex(object):  | 
2269  | 
"""Manages knit index files  | 
|
2270  | 
||
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
2271  | 
    The index is kept in memory and read on startup, to enable
 | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
2272  | 
    fast lookups of revision information.  The cursor of the index
 | 
2273  | 
    file is always pointing to the end, making it easy to append
 | 
|
2274  | 
    entries.
 | 
|
2275  | 
||
2276  | 
    _cache is a cache for fast mapping from version id to a Index
 | 
|
2277  | 
    object.
 | 
|
2278  | 
||
2279  | 
    _history is a cache for fast mapping from indexes to version ids.
 | 
|
2280  | 
||
2281  | 
    The index data format is dictionary compressed when it comes to
 | 
|
2282  | 
    parent references; a index entry may only have parents that with a
 | 
|
2283  | 
    lover index number.  As a result, the index is topological sorted.
 | 
|
| 
1563.2.11
by Robert Collins
 Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.  | 
2284  | 
|
2285  | 
    Duplicate entries may be written to the index for a single version id
 | 
|
2286  | 
    if this is done then the latter one completely replaces the former:
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2287  | 
    this allows updates to correct version and parent information.
 | 
| 
1563.2.11
by Robert Collins
 Consolidate reweave and join as we have no separate usage, make reweave tests apply to all versionedfile implementations and deprecate the old reweave apis.  | 
2288  | 
    Note that the two entries may share the delta, and that successive
 | 
2289  | 
    annotations and references MUST point to the first entry.
 | 
|
| 
1641.1.2
by Robert Collins
 Change knit index files to be robust in the presence of partial writes.  | 
2290  | 
|
2291  | 
    The index file on disc contains a header, followed by one line per knit
 | 
|
2292  | 
    record. The same revision can be present in an index file more than once.
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2293  | 
    The first occurrence gets assigned a sequence number starting from 0.
 | 
2294  | 
||
| 
1641.1.2
by Robert Collins
 Change knit index files to be robust in the presence of partial writes.  | 
2295  | 
    The format of a single line is
 | 
2296  | 
    REVISION_ID FLAGS BYTE_OFFSET LENGTH( PARENT_ID|PARENT_SEQUENCE_ID)* :\n
 | 
|
2297  | 
    REVISION_ID is a utf8-encoded revision id
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2298  | 
    FLAGS is a comma separated list of flags about the record. Values include
 | 
| 
1641.1.2
by Robert Collins
 Change knit index files to be robust in the presence of partial writes.  | 
2299  | 
        no-eol, line-delta, fulltext.
 | 
2300  | 
    BYTE_OFFSET is the ascii representation of the byte offset in the data file
 | 
|
2301  | 
        that the the compressed data starts at.
 | 
|
2302  | 
    LENGTH is the ascii representation of the length of the data file.
 | 
|
2303  | 
    PARENT_ID a utf-8 revision id prefixed by a '.' that is a parent of
 | 
|
2304  | 
        REVISION_ID.
 | 
|
2305  | 
    PARENT_SEQUENCE_ID the ascii representation of the sequence number of a
 | 
|
2306  | 
        revision id already in the knit that is a parent of REVISION_ID.
 | 
|
2307  | 
    The ' :' marker is the end of record marker.
 | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2308  | 
|
| 
1641.1.2
by Robert Collins
 Change knit index files to be robust in the presence of partial writes.  | 
2309  | 
    partial writes:
 | 
| 
2158.3.1
by Dmitry Vasiliev
 KnitIndex tests/fixes/optimizations  | 
2310  | 
    when a write is interrupted to the index file, it will result in a line
 | 
2311  | 
    that does not end in ' :'. If the ' :' is not present at the end of a line,
 | 
|
2312  | 
    or at the end of the file, then the record that is missing it will be
 | 
|
2313  | 
    ignored by the parser.
 | 
|
| 
1641.1.2
by Robert Collins
 Change knit index files to be robust in the presence of partial writes.  | 
2314  | 
|
| 
1759.2.1
by Jelmer Vernooij
 Fix some types (found using aspell).  | 
2315  | 
    When writing new records to the index file, the data is preceded by '\n'
 | 
| 
1641.1.2
by Robert Collins
 Change knit index files to be robust in the presence of partial writes.  | 
2316  | 
    to ensure that records always start on new lines even if the last write was
 | 
2317  | 
    interrupted. As a result its normal for the last line in the index to be
 | 
|
2318  | 
    missing a trailing newline. One can be added with no harmful effects.
 | 
|
| 
3350.6.11
by Martin Pool
 Review cleanups and documentation from Robert's mail on 2080618  | 
2319  | 
|
2320  | 
    :ivar _kndx_cache: dict from prefix to the old state of KnitIndex objects,
 | 
|
2321  | 
        where prefix is e.g. the (fileid,) for .texts instances or () for
 | 
|
2322  | 
        constant-mapped things like .revisions, and the old state is
 | 
|
2323  | 
        tuple(history_vector, cache_dict).  This is used to prevent having an
 | 
|
2324  | 
        ABI change with the C extension that reads .kndx files.
 | 
|
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
2325  | 
    """
 | 
2326  | 
||
| 
1666.1.6
by Robert Collins
 Make knit the default format.  | 
2327  | 
HEADER = "# bzr knit index 8\n"  | 
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
2328  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2329  | 
def __init__(self, transport, mapper, get_scope, allow_writes, is_locked):  | 
2330  | 
"""Create a _KndxIndex on transport using mapper."""  | 
|
2331  | 
self._transport = transport  | 
|
2332  | 
self._mapper = mapper  | 
|
2333  | 
self._get_scope = get_scope  | 
|
2334  | 
self._allow_writes = allow_writes  | 
|
2335  | 
self._is_locked = is_locked  | 
|
2336  | 
self._reset_cache()  | 
|
2337  | 
self.has_graph = True  | 
|
2338  | 
||
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
2339  | 
def add_records(self, records, random_id=False, missing_compression_parents=False):  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2340  | 
"""Add multiple records to the index.  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2341  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2342  | 
        :param records: a list of tuples:
 | 
2343  | 
                         (key, options, access_memo, parents).
 | 
|
2344  | 
        :param random_id: If True the ids being added were randomly generated
 | 
|
2345  | 
            and no check for existence will be performed.
 | 
|
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
2346  | 
        :param missing_compression_parents: If True the records being added are
 | 
2347  | 
            only compressed against texts already in the index (or inside
 | 
|
2348  | 
            records). If False the records all refer to unavailable texts (or
 | 
|
2349  | 
            texts inside records) as compression parents.
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2350  | 
        """
 | 
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
2351  | 
if missing_compression_parents:  | 
2352  | 
            # It might be nice to get the edge of the records. But keys isn't
 | 
|
2353  | 
            # _wrong_.
 | 
|
2354  | 
keys = sorted(record[0] for record in records)  | 
|
2355  | 
raise errors.RevisionNotPresent(keys, self)  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2356  | 
paths = {}  | 
2357  | 
for record in records:  | 
|
2358  | 
key = record[0]  | 
|
2359  | 
prefix = key[:-1]  | 
|
2360  | 
path = self._mapper.map(key) + '.kndx'  | 
|
2361  | 
path_keys = paths.setdefault(path, (prefix, []))  | 
|
2362  | 
path_keys[1].append(record)  | 
|
2363  | 
for path in sorted(paths):  | 
|
2364  | 
prefix, path_keys = paths[path]  | 
|
2365  | 
self._load_prefixes([prefix])  | 
|
2366  | 
lines = []  | 
|
2367  | 
orig_history = self._kndx_cache[prefix][1][:]  | 
|
2368  | 
orig_cache = self._kndx_cache[prefix][0].copy()  | 
|
2369  | 
||
2370  | 
try:  | 
|
2371  | 
for key, options, (_, pos, size), parents in path_keys:  | 
|
2372  | 
if parents is None:  | 
|
2373  | 
                        # kndx indices cannot be parentless.
 | 
|
2374  | 
parents = ()  | 
|
2375  | 
line = "\n%s %s %s %s %s :" % (  | 
|
2376  | 
key[-1], ','.join(options), pos, size,  | 
|
2377  | 
self._dictionary_compress(parents))  | 
|
2378  | 
if type(line) != str:  | 
|
2379  | 
raise AssertionError(  | 
|
2380  | 
'data must be utf8 was %s' % type(line))  | 
|
2381  | 
lines.append(line)  | 
|
2382  | 
self._cache_key(key, options, pos, size, parents)  | 
|
2383  | 
if len(orig_history):  | 
|
2384  | 
self._transport.append_bytes(path, ''.join(lines))  | 
|
2385  | 
else:  | 
|
2386  | 
self._init_index(path, lines)  | 
|
2387  | 
except:  | 
|
2388  | 
                # If any problems happen, restore the original values and re-raise
 | 
|
2389  | 
self._kndx_cache[prefix] = (orig_cache, orig_history)  | 
|
2390  | 
                raise
 | 
|
2391  | 
||
| 
4011.5.7
by Andrew Bennetts
 Remove leading underscore from _scan_unvalidate_index, explicitly NotImplementedError it for _KndxIndex.  | 
2392  | 
def scan_unvalidated_index(self, graph_index):  | 
2393  | 
"""See _KnitGraphIndex.scan_unvalidated_index."""  | 
|
| 
4011.5.11
by Robert Collins
 Polish the KnitVersionedFiles.scan_unvalidated_index api.  | 
2394  | 
        # Because kndx files do not support atomic insertion via separate index
 | 
2395  | 
        # files, they do not support this method.
 | 
|
| 
4011.5.7
by Andrew Bennetts
 Remove leading underscore from _scan_unvalidate_index, explicitly NotImplementedError it for _KndxIndex.  | 
2396  | 
raise NotImplementedError(self.scan_unvalidated_index)  | 
2397  | 
||
2398  | 
def get_missing_compression_parents(self):  | 
|
2399  | 
"""See _KnitGraphIndex.get_missing_compression_parents."""  | 
|
| 
4011.5.11
by Robert Collins
 Polish the KnitVersionedFiles.scan_unvalidated_index api.  | 
2400  | 
        # Because kndx files do not support atomic insertion via separate index
 | 
2401  | 
        # files, they do not support this method.
 | 
|
2402  | 
raise NotImplementedError(self.get_missing_compression_parents)  | 
|
| 
4032.1.1
by John Arbash Meinel
 Merge the removal of all trailing whitespace, and resolve conflicts.  | 
2403  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2404  | 
def _cache_key(self, key, options, pos, size, parent_keys):  | 
| 
1596.2.18
by Robert Collins
 More microopimisations on index reading, now down to 16000 records/seconds.  | 
2405  | 
"""Cache a version record in the history array and index cache.  | 
| 
2158.3.1
by Dmitry Vasiliev
 KnitIndex tests/fixes/optimizations  | 
2406  | 
|
2407  | 
        This is inlined into _load_data for performance. KEEP IN SYNC.
 | 
|
| 
1596.2.18
by Robert Collins
 More microopimisations on index reading, now down to 16000 records/seconds.  | 
2408  | 
        (It saves 60ms, 25% of the __init__ overhead on local 4000 record
 | 
2409  | 
         indexes).
 | 
|
2410  | 
        """
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2411  | 
prefix = key[:-1]  | 
2412  | 
version_id = key[-1]  | 
|
2413  | 
        # last-element only for compatibilty with the C load_data.
 | 
|
2414  | 
parents = tuple(parent[-1] for parent in parent_keys)  | 
|
2415  | 
for parent in parent_keys:  | 
|
2416  | 
if parent[:-1] != prefix:  | 
|
2417  | 
raise ValueError("mismatched prefixes for %r, %r" % (  | 
|
2418  | 
key, parent_keys))  | 
|
2419  | 
cache, history = self._kndx_cache[prefix]  | 
|
| 
1596.2.14
by Robert Collins
 Make knit parsing non quadratic?  | 
2420  | 
        # only want the _history index to reference the 1st index entry
 | 
2421  | 
        # for version_id
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2422  | 
if version_id not in cache:  | 
2423  | 
index = len(history)  | 
|
2424  | 
history.append(version_id)  | 
|
| 
1628.1.1
by Robert Collins
 Cache the index number of versions in the knit index's self._cache so that  | 
2425  | 
else:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2426  | 
index = cache[version_id][5]  | 
2427  | 
cache[version_id] = (version_id,  | 
|
| 
1628.1.1
by Robert Collins
 Cache the index number of versions in the knit index's self._cache so that  | 
2428  | 
options,  | 
2429  | 
pos,  | 
|
2430  | 
size,  | 
|
2431  | 
parents,  | 
|
2432  | 
index)  | 
|
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
2433  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2434  | 
def check_header(self, fp):  | 
2435  | 
line = fp.readline()  | 
|
2436  | 
if line == '':  | 
|
2437  | 
            # An empty file can actually be treated as though the file doesn't
 | 
|
2438  | 
            # exist yet.
 | 
|
2439  | 
raise errors.NoSuchFile(self)  | 
|
2440  | 
if line != self.HEADER:  | 
|
2441  | 
raise KnitHeaderError(badline=line, filename=self)  | 
|
2442  | 
||
2443  | 
def _check_read(self):  | 
|
2444  | 
if not self._is_locked():  | 
|
2445  | 
raise errors.ObjectNotLocked(self)  | 
|
2446  | 
if self._get_scope() != self._scope:  | 
|
2447  | 
self._reset_cache()  | 
|
2448  | 
||
| 
3316.2.3
by Robert Collins
 Remove manual notification of transaction finishing on versioned files.  | 
2449  | 
def _check_write_ok(self):  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2450  | 
"""Assert if not writes are permitted."""  | 
2451  | 
if not self._is_locked():  | 
|
2452  | 
raise errors.ObjectNotLocked(self)  | 
|
| 
3316.2.5
by Robert Collins
 Review feedback.  | 
2453  | 
if self._get_scope() != self._scope:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2454  | 
self._reset_cache()  | 
| 
3316.2.3
by Robert Collins
 Remove manual notification of transaction finishing on versioned files.  | 
2455  | 
if self._mode != 'w':  | 
2456  | 
raise errors.ReadOnlyObjectDirtiedError(self)  | 
|
2457  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2458  | 
def get_build_details(self, keys):  | 
2459  | 
"""Get the method, index_memo and compression parent for keys.  | 
|
| 
3218.1.1
by Robert Collins
 Reduce index query pressure for text construction by batching the individual queries into single batch queries.  | 
2460  | 
|
| 
3224.1.29
by John Arbash Meinel
 Properly handle annotating when ghosts are present.  | 
2461  | 
        Ghosts are omitted from the result.
 | 
2462  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2463  | 
        :param keys: An iterable of keys.
 | 
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
2464  | 
        :return: A dict of key:(index_memo, compression_parent, parents,
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2465  | 
            record_details).
 | 
| 
3224.1.14
by John Arbash Meinel
 Switch to making content_details opaque, step 1  | 
2466  | 
            index_memo
 | 
2467  | 
                opaque structure to pass to read_records to extract the raw
 | 
|
2468  | 
                data
 | 
|
2469  | 
            compression_parent
 | 
|
2470  | 
                Content that this record is built upon, may be None
 | 
|
2471  | 
            parents
 | 
|
2472  | 
                Logical parents of this node
 | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
2473  | 
            record_details
 | 
| 
3224.1.14
by John Arbash Meinel
 Switch to making content_details opaque, step 1  | 
2474  | 
                extra information about the content which needs to be passed to
 | 
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
2475  | 
                Factory.parse_record
 | 
| 
3218.1.1
by Robert Collins
 Reduce index query pressure for text construction by batching the individual queries into single batch queries.  | 
2476  | 
        """
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2477  | 
parent_map = self.get_parent_map(keys)  | 
| 
3218.1.1
by Robert Collins
 Reduce index query pressure for text construction by batching the individual queries into single batch queries.  | 
2478  | 
result = {}  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2479  | 
for key in keys:  | 
2480  | 
if key not in parent_map:  | 
|
2481  | 
continue # Ghost  | 
|
2482  | 
method = self.get_method(key)  | 
|
2483  | 
parents = parent_map[key]  | 
|
| 
3218.1.1
by Robert Collins
 Reduce index query pressure for text construction by batching the individual queries into single batch queries.  | 
2484  | 
if method == 'fulltext':  | 
2485  | 
compression_parent = None  | 
|
2486  | 
else:  | 
|
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
2487  | 
compression_parent = parents[0]  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2488  | 
noeol = 'no-eol' in self.get_options(key)  | 
2489  | 
index_memo = self.get_position(key)  | 
|
2490  | 
result[key] = (index_memo, compression_parent,  | 
|
| 
3224.1.14
by John Arbash Meinel
 Switch to making content_details opaque, step 1  | 
2491  | 
parents, (method, noeol))  | 
| 
3218.1.1
by Robert Collins
 Reduce index query pressure for text construction by batching the individual queries into single batch queries.  | 
2492  | 
return result  | 
2493  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2494  | 
def get_method(self, key):  | 
2495  | 
"""Return compression method of specified key."""  | 
|
2496  | 
options = self.get_options(key)  | 
|
2497  | 
if 'fulltext' in options:  | 
|
2498  | 
return 'fulltext'  | 
|
2499  | 
elif 'line-delta' in options:  | 
|
2500  | 
return 'line-delta'  | 
|
2501  | 
else:  | 
|
2502  | 
raise errors.KnitIndexUnknownMethod(self, options)  | 
|
2503  | 
||
2504  | 
def get_options(self, key):  | 
|
2505  | 
"""Return a list representing options.  | 
|
2506  | 
||
2507  | 
        e.g. ['foo', 'bar']
 | 
|
2508  | 
        """
 | 
|
2509  | 
prefix, suffix = self._split_key(key)  | 
|
2510  | 
self._load_prefixes([prefix])  | 
|
| 
3350.8.9
by Robert Collins
 define behaviour for add_lines with stacked storage.  | 
2511  | 
try:  | 
2512  | 
return self._kndx_cache[prefix][0][suffix][1]  | 
|
2513  | 
except KeyError:  | 
|
2514  | 
raise RevisionNotPresent(key, self)  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2515  | 
|
2516  | 
def get_parent_map(self, keys):  | 
|
2517  | 
"""Get a map of the parents of keys.  | 
|
2518  | 
||
2519  | 
        :param keys: The keys to look up parents for.
 | 
|
2520  | 
        :return: A mapping from keys to parents. Absent keys are absent from
 | 
|
2521  | 
            the mapping.
 | 
|
2522  | 
        """
 | 
|
2523  | 
        # Parse what we need to up front, this potentially trades off I/O
 | 
|
2524  | 
        # locality (.kndx and .knit in the same block group for the same file
 | 
|
2525  | 
        # id) for less checking in inner loops.
 | 
|
| 
3350.6.10
by Martin Pool
 VersionedFiles review cleanups  | 
2526  | 
prefixes = set(key[:-1] for key in keys)  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2527  | 
self._load_prefixes(prefixes)  | 
2528  | 
result = {}  | 
|
2529  | 
for key in keys:  | 
|
2530  | 
prefix = key[:-1]  | 
|
2531  | 
try:  | 
|
2532  | 
suffix_parents = self._kndx_cache[prefix][0][key[-1]][4]  | 
|
2533  | 
except KeyError:  | 
|
2534  | 
                pass
 | 
|
2535  | 
else:  | 
|
2536  | 
result[key] = tuple(prefix + (suffix,) for  | 
|
2537  | 
suffix in suffix_parents)  | 
|
2538  | 
return result  | 
|
2539  | 
||
2540  | 
def get_position(self, key):  | 
|
2541  | 
"""Return details needed to access the version.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2542  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2543  | 
        :return: a tuple (key, data position, size) to hand to the access
 | 
2544  | 
            logic to get the record.
 | 
|
2545  | 
        """
 | 
|
2546  | 
prefix, suffix = self._split_key(key)  | 
|
2547  | 
self._load_prefixes([prefix])  | 
|
2548  | 
entry = self._kndx_cache[prefix][0][suffix]  | 
|
2549  | 
return key, entry[2], entry[3]  | 
|
2550  | 
||
| 
3830.3.12
by Martin Pool
 Review cleanups: unify has_key impls, add missing_keys(), clean up exception blocks  | 
2551  | 
has_key = _mod_index._has_key_from_parent_map  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2552  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2553  | 
def _init_index(self, path, extra_lines=[]):  | 
2554  | 
"""Initialize an index."""  | 
|
2555  | 
sio = StringIO()  | 
|
2556  | 
sio.write(self.HEADER)  | 
|
2557  | 
sio.writelines(extra_lines)  | 
|
2558  | 
sio.seek(0)  | 
|
2559  | 
self._transport.put_file_non_atomic(path, sio,  | 
|
2560  | 
create_parent_dir=True)  | 
|
2561  | 
                           # self._create_parent_dir)
 | 
|
2562  | 
                           # mode=self._file_mode,
 | 
|
2563  | 
                           # dir_mode=self._dir_mode)
 | 
|
2564  | 
||
2565  | 
def keys(self):  | 
|
2566  | 
"""Get all the keys in the collection.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2567  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2568  | 
        The keys are not ordered.
 | 
2569  | 
        """
 | 
|
2570  | 
result = set()  | 
|
2571  | 
        # Identify all key prefixes.
 | 
|
2572  | 
        # XXX: A bit hacky, needs polish.
 | 
|
2573  | 
if type(self._mapper) == ConstantMapper:  | 
|
2574  | 
prefixes = [()]  | 
|
2575  | 
else:  | 
|
2576  | 
relpaths = set()  | 
|
2577  | 
for quoted_relpath in self._transport.iter_files_recursive():  | 
|
2578  | 
path, ext = os.path.splitext(quoted_relpath)  | 
|
2579  | 
relpaths.add(path)  | 
|
2580  | 
prefixes = [self._mapper.unmap(path) for path in relpaths]  | 
|
2581  | 
self._load_prefixes(prefixes)  | 
|
2582  | 
for prefix in prefixes:  | 
|
2583  | 
for suffix in self._kndx_cache[prefix][1]:  | 
|
2584  | 
result.add(prefix + (suffix,))  | 
|
2585  | 
return result  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2586  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2587  | 
def _load_prefixes(self, prefixes):  | 
2588  | 
"""Load the indices for prefixes."""  | 
|
2589  | 
self._check_read()  | 
|
2590  | 
for prefix in prefixes:  | 
|
2591  | 
if prefix not in self._kndx_cache:  | 
|
2592  | 
                # the load_data interface writes to these variables.
 | 
|
2593  | 
self._cache = {}  | 
|
2594  | 
self._history = []  | 
|
2595  | 
self._filename = prefix  | 
|
2596  | 
try:  | 
|
2597  | 
path = self._mapper.map(prefix) + '.kndx'  | 
|
2598  | 
fp = self._transport.get(path)  | 
|
2599  | 
try:  | 
|
2600  | 
                        # _load_data may raise NoSuchFile if the target knit is
 | 
|
2601  | 
                        # completely empty.
 | 
|
2602  | 
_load_data(self, fp)  | 
|
2603  | 
finally:  | 
|
2604  | 
fp.close()  | 
|
2605  | 
self._kndx_cache[prefix] = (self._cache, self._history)  | 
|
2606  | 
del self._cache  | 
|
2607  | 
del self._filename  | 
|
2608  | 
del self._history  | 
|
2609  | 
except NoSuchFile:  | 
|
2610  | 
self._kndx_cache[prefix] = ({}, [])  | 
|
2611  | 
if type(self._mapper) == ConstantMapper:  | 
|
2612  | 
                        # preserve behaviour for revisions.kndx etc.
 | 
|
2613  | 
self._init_index(path)  | 
|
2614  | 
del self._cache  | 
|
2615  | 
del self._filename  | 
|
2616  | 
del self._history  | 
|
2617  | 
||
| 
3830.3.12
by Martin Pool
 Review cleanups: unify has_key impls, add missing_keys(), clean up exception blocks  | 
2618  | 
missing_keys = _mod_index._missing_keys_from_parent_map  | 
2619  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2620  | 
def _partition_keys(self, keys):  | 
2621  | 
"""Turn keys into a dict of prefix:suffix_list."""  | 
|
2622  | 
result = {}  | 
|
2623  | 
for key in keys:  | 
|
2624  | 
prefix_keys = result.setdefault(key[:-1], [])  | 
|
2625  | 
prefix_keys.append(key[-1])  | 
|
2626  | 
return result  | 
|
2627  | 
||
2628  | 
def _dictionary_compress(self, keys):  | 
|
2629  | 
"""Dictionary compress keys.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2630  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2631  | 
        :param keys: The keys to generate references to.
 | 
2632  | 
        :return: A string representation of keys. keys which are present are
 | 
|
2633  | 
            dictionary compressed, and others are emitted as fulltext with a
 | 
|
2634  | 
            '.' prefix.
 | 
|
2635  | 
        """
 | 
|
2636  | 
if not keys:  | 
|
2637  | 
return ''  | 
|
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
2638  | 
result_list = []  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2639  | 
prefix = keys[0][:-1]  | 
2640  | 
cache = self._kndx_cache[prefix][0]  | 
|
2641  | 
for key in keys:  | 
|
2642  | 
if key[:-1] != prefix:  | 
|
2643  | 
                # kndx indices cannot refer across partitioned storage.
 | 
|
2644  | 
raise ValueError("mismatched prefixes for %r" % keys)  | 
|
2645  | 
if key[-1] in cache:  | 
|
| 
1628.1.1
by Robert Collins
 Cache the index number of versions in the knit index's self._cache so that  | 
2646  | 
                # -- inlined lookup() --
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2647  | 
result_list.append(str(cache[key[-1]][5]))  | 
| 
1628.1.1
by Robert Collins
 Cache the index number of versions in the knit index's self._cache so that  | 
2648  | 
                # -- end lookup () --
 | 
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
2649  | 
else:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2650  | 
result_list.append('.' + key[-1])  | 
| 
1594.2.8
by Robert Collins
 add ghost aware apis to knits.  | 
2651  | 
return ' '.join(result_list)  | 
2652  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2653  | 
def _reset_cache(self):  | 
2654  | 
        # Possibly this should be a LRU cache. A dictionary from key_prefix to
 | 
|
2655  | 
        # (cache_dict, history_vector) for parsed kndx files.
 | 
|
2656  | 
self._kndx_cache = {}  | 
|
2657  | 
self._scope = self._get_scope()  | 
|
2658  | 
allow_writes = self._allow_writes()  | 
|
2659  | 
if allow_writes:  | 
|
2660  | 
self._mode = 'w'  | 
|
| 
1563.2.4
by Robert Collins
 First cut at including the knit implementation of versioned_file.  | 
2661  | 
else:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2662  | 
self._mode = 'r'  | 
2663  | 
||
| 
3878.1.2
by John Arbash Meinel
 Move the sorting into each index, and customize it for Kndx access.  | 
2664  | 
def _sort_keys_by_io(self, keys, positions):  | 
2665  | 
"""Figure out an optimal order to read the records for the given keys.  | 
|
2666  | 
||
2667  | 
        Sort keys, grouped by index and sorted by position.
 | 
|
2668  | 
||
2669  | 
        :param keys: A list of keys whose records we want to read. This will be
 | 
|
2670  | 
            sorted 'in-place'.
 | 
|
2671  | 
        :param positions: A dict, such as the one returned by
 | 
|
2672  | 
            _get_components_positions()
 | 
|
2673  | 
        :return: None
 | 
|
2674  | 
        """
 | 
|
| 
3878.1.3
by John Arbash Meinel
 Add a comment about what data we are sorting by.  | 
2675  | 
def get_sort_key(key):  | 
| 
3878.1.2
by John Arbash Meinel
 Move the sorting into each index, and customize it for Kndx access.  | 
2676  | 
index_memo = positions[key][1]  | 
2677  | 
            # Group by prefix and position. index_memo[0] is the key, so it is
 | 
|
2678  | 
            # (file_id, revision_id) and we don't want to sort on revision_id,
 | 
|
2679  | 
            # index_memo[1] is the position, and index_memo[2] is the size,
 | 
|
2680  | 
            # which doesn't matter for the sort
 | 
|
2681  | 
return index_memo[0][:-1], index_memo[1]  | 
|
| 
3878.1.3
by John Arbash Meinel
 Add a comment about what data we are sorting by.  | 
2682  | 
return keys.sort(key=get_sort_key)  | 
| 
3878.1.2
by John Arbash Meinel
 Move the sorting into each index, and customize it for Kndx access.  | 
2683  | 
|
| 
4039.3.5
by John Arbash Meinel
 Add direct tests for _get_total_build_size.  | 
2684  | 
_get_total_build_size = _get_total_build_size  | 
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
2685  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2686  | 
def _split_key(self, key):  | 
2687  | 
"""Split key into a prefix and suffix."""  | 
|
2688  | 
return key[:-1], key[-1]  | 
|
2689  | 
||
2690  | 
||
2691  | 
class _KnitGraphIndex(object):  | 
|
2692  | 
"""A KnitVersionedFiles index layered on GraphIndex."""  | 
|
2693  | 
||
2694  | 
def __init__(self, graph_index, is_locked, deltas=False, parents=True,  | 
|
| 
4257.4.11
by Andrew Bennetts
 Polish the patch.  | 
2695  | 
add_callback=None, track_external_parent_refs=False):  | 
| 
2592.3.2
by Robert Collins
 Implement a get_graph for a new KnitGraphIndex that will implement a KnitIndex on top of the GraphIndex API.  | 
2696  | 
"""Construct a KnitGraphIndex on a graph_index.  | 
2697  | 
||
2698  | 
        :param graph_index: An implementation of bzrlib.index.GraphIndex.
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2699  | 
        :param is_locked: A callback to check whether the object should answer
 | 
2700  | 
            queries.
 | 
|
| 
2592.3.13
by Robert Collins
 Implement KnitGraphIndex.get_method.  | 
2701  | 
        :param deltas: Allow delta-compressed records.
 | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2702  | 
        :param parents: If True, record knits parents, if not do not record
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2703  | 
            parents.
 | 
| 
2592.3.19
by Robert Collins
 Change KnitGraphIndex from returning data to performing a callback on insertions.  | 
2704  | 
        :param add_callback: If not None, allow additions to the index and call
 | 
2705  | 
            this callback with a list of added GraphIndex nodes:
 | 
|
| 
2592.3.33
by Robert Collins
 Change the order of index refs and values to make the no-graph knit index easier.  | 
2706  | 
            [(node, value, node_refs), ...]
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2707  | 
        :param is_locked: A callback, returns True if the index is locked and
 | 
2708  | 
            thus usable.
 | 
|
| 
4257.4.11
by Andrew Bennetts
 Polish the patch.  | 
2709  | 
        :param track_external_parent_refs: If True, record all external parent
 | 
2710  | 
            references parents from added records.  These can be retrieved
 | 
|
2711  | 
            later by calling get_missing_parents().
 | 
|
| 
2592.3.2
by Robert Collins
 Implement a get_graph for a new KnitGraphIndex that will implement a KnitIndex on top of the GraphIndex API.  | 
2712  | 
        """
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2713  | 
self._add_callback = add_callback  | 
| 
2592.3.2
by Robert Collins
 Implement a get_graph for a new KnitGraphIndex that will implement a KnitIndex on top of the GraphIndex API.  | 
2714  | 
self._graph_index = graph_index  | 
| 
2592.3.13
by Robert Collins
 Implement KnitGraphIndex.get_method.  | 
2715  | 
self._deltas = deltas  | 
| 
2592.3.34
by Robert Collins
 Rough unfactored support for parentless KnitGraphIndexs.  | 
2716  | 
self._parents = parents  | 
2717  | 
if deltas and not parents:  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2718  | 
            # XXX: TODO: Delta tree and parent graph should be conceptually
 | 
2719  | 
            # separate.
 | 
|
| 
2592.3.34
by Robert Collins
 Rough unfactored support for parentless KnitGraphIndexs.  | 
2720  | 
raise KnitCorrupt(self, "Cannot do delta compression without "  | 
2721  | 
"parent tracking.")  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2722  | 
self.has_graph = parents  | 
2723  | 
self._is_locked = is_locked  | 
|
| 
4011.5.1
by Andrew Bennetts
 Start to add _add_unvalidated_index/get_missing_compression_parents methods to _KnitGraphIndex.  | 
2724  | 
self._missing_compression_parents = set()  | 
| 
4257.4.11
by Andrew Bennetts
 Polish the patch.  | 
2725  | 
if track_external_parent_refs:  | 
2726  | 
self._external_parent_refs = set()  | 
|
| 
4257.4.10
by Andrew Bennetts
 Observe new revisions in _KnitGraphIndex.add_record rather than iterating all the uncommitted packs' indices.  | 
2727  | 
else:  | 
| 
4257.4.11
by Andrew Bennetts
 Polish the patch.  | 
2728  | 
self._external_parent_refs = None  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2729  | 
|
| 
3517.4.13
by Martin Pool
 Add repr methods  | 
2730  | 
def __repr__(self):  | 
2731  | 
return "%s(%r)" % (self.__class__.__name__, self._graph_index)  | 
|
2732  | 
||
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
2733  | 
def add_records(self, records, random_id=False,  | 
2734  | 
missing_compression_parents=False):  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2735  | 
"""Add multiple records to the index.  | 
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2736  | 
|
| 
2592.3.17
by Robert Collins
 Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.  | 
2737  | 
        This function does not insert data into the Immutable GraphIndex
 | 
2738  | 
        backing the KnitGraphIndex, instead it prepares data for insertion by
 | 
|
| 
2592.3.19
by Robert Collins
 Change KnitGraphIndex from returning data to performing a callback on insertions.  | 
2739  | 
        the caller and checks that it is safe to insert then calls
 | 
2740  | 
        self._add_callback with the prepared GraphIndex nodes.
 | 
|
| 
2592.3.17
by Robert Collins
 Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.  | 
2741  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2742  | 
        :param records: a list of tuples:
 | 
2743  | 
                         (key, options, access_memo, parents).
 | 
|
| 
2841.2.1
by Robert Collins
 * Commit no longer checks for new text keys during insertion when the  | 
2744  | 
        :param random_id: If True the ids being added were randomly generated
 | 
2745  | 
            and no check for existence will be performed.
 | 
|
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
2746  | 
        :param missing_compression_parents: If True the records being added are
 | 
2747  | 
            only compressed against texts already in the index (or inside
 | 
|
2748  | 
            records). If False the records all refer to unavailable texts (or
 | 
|
2749  | 
            texts inside records) as compression parents.
 | 
|
| 
2592.3.17
by Robert Collins
 Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.  | 
2750  | 
        """
 | 
| 
2592.3.19
by Robert Collins
 Change KnitGraphIndex from returning data to performing a callback on insertions.  | 
2751  | 
if not self._add_callback:  | 
2752  | 
raise errors.ReadOnlyError(self)  | 
|
| 
2592.3.17
by Robert Collins
 Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.  | 
2753  | 
        # we hope there are no repositories with inconsistent parentage
 | 
2754  | 
        # anymore.
 | 
|
2755  | 
||
2756  | 
keys = {}  | 
|
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
2757  | 
compression_parents = set()  | 
| 
4257.4.11
by Andrew Bennetts
 Polish the patch.  | 
2758  | 
parent_refs = self._external_parent_refs  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2759  | 
for (key, options, access_memo, parents) in records:  | 
2760  | 
if self._parents:  | 
|
2761  | 
parents = tuple(parents)  | 
|
| 
4257.4.10
by Andrew Bennetts
 Observe new revisions in _KnitGraphIndex.add_record rather than iterating all the uncommitted packs' indices.  | 
2762  | 
if parent_refs is not None:  | 
2763  | 
parent_refs.update(parents)  | 
|
2764  | 
parent_refs.discard(key)  | 
|
| 
2670.2.2
by Robert Collins
 * In ``bzrlib.knit`` the internal interface has been altered to use  | 
2765  | 
index, pos, size = access_memo  | 
| 
2592.3.17
by Robert Collins
 Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.  | 
2766  | 
if 'no-eol' in options:  | 
2767  | 
value = 'N'  | 
|
2768  | 
else:  | 
|
2769  | 
value = ' '  | 
|
2770  | 
value += "%d %d" % (pos, size)  | 
|
| 
2592.3.34
by Robert Collins
 Rough unfactored support for parentless KnitGraphIndexs.  | 
2771  | 
if not self._deltas:  | 
| 
2592.3.17
by Robert Collins
 Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.  | 
2772  | 
if 'line-delta' in options:  | 
2773  | 
raise KnitCorrupt(self, "attempt to add line-delta in non-delta knit")  | 
|
| 
2592.3.34
by Robert Collins
 Rough unfactored support for parentless KnitGraphIndexs.  | 
2774  | 
if self._parents:  | 
2775  | 
if self._deltas:  | 
|
2776  | 
if 'line-delta' in options:  | 
|
| 
2624.2.5
by Robert Collins
 Change bzrlib.index.Index keys to be 1-tuples, not strings.  | 
2777  | 
node_refs = (parents, (parents[0],))  | 
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
2778  | 
if missing_compression_parents:  | 
2779  | 
compression_parents.add(parents[0])  | 
|
| 
2592.3.34
by Robert Collins
 Rough unfactored support for parentless KnitGraphIndexs.  | 
2780  | 
else:  | 
| 
2624.2.5
by Robert Collins
 Change bzrlib.index.Index keys to be 1-tuples, not strings.  | 
2781  | 
node_refs = (parents, ())  | 
| 
2592.3.34
by Robert Collins
 Rough unfactored support for parentless KnitGraphIndexs.  | 
2782  | 
else:  | 
| 
2624.2.5
by Robert Collins
 Change bzrlib.index.Index keys to be 1-tuples, not strings.  | 
2783  | 
node_refs = (parents, )  | 
| 
2592.3.34
by Robert Collins
 Rough unfactored support for parentless KnitGraphIndexs.  | 
2784  | 
else:  | 
2785  | 
if parents:  | 
|
2786  | 
raise KnitCorrupt(self, "attempt to add node with parents "  | 
|
2787  | 
"in parentless index.")  | 
|
2788  | 
node_refs = ()  | 
|
| 
2624.2.5
by Robert Collins
 Change bzrlib.index.Index keys to be 1-tuples, not strings.  | 
2789  | 
keys[key] = (value, node_refs)  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2790  | 
        # check for dups
 | 
| 
2841.2.1
by Robert Collins
 * Commit no longer checks for new text keys during insertion when the  | 
2791  | 
if not random_id:  | 
2792  | 
present_nodes = self._get_entries(keys)  | 
|
2793  | 
for (index, key, value, node_refs) in present_nodes:  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2794  | 
if (value[0] != keys[key][0][0] or  | 
| 
3946.2.2
by Jelmer Vernooij
 Remove matching test, fix handling of parentless indexes.  | 
2795  | 
node_refs[:1] != keys[key][1][:1]):  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2796  | 
raise KnitCorrupt(self, "inconsistent details in add_records"  | 
| 
2841.2.1
by Robert Collins
 * Commit no longer checks for new text keys during insertion when the  | 
2797  | 
": %s %s" % ((value, node_refs), keys[key]))  | 
2798  | 
del keys[key]  | 
|
| 
2592.3.17
by Robert Collins
 Add add_version(s) to KnitGraphIndex, completing the required api for KnitVersionedFile.  | 
2799  | 
result = []  | 
| 
2592.3.34
by Robert Collins
 Rough unfactored support for parentless KnitGraphIndexs.  | 
2800  | 
if self._parents:  | 
2801  | 
for key, (value, node_refs) in keys.iteritems():  | 
|
2802  | 
result.append((key, value, node_refs))  | 
|
2803  | 
else:  | 
|
2804  | 
for key, (value, node_refs) in keys.iteritems():  | 
|
2805  | 
result.append((key, value))  | 
|
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
2806  | 
self._add_callback(result)  | 
2807  | 
if missing_compression_parents:  | 
|
2808  | 
            # This may appear to be incorrect (it does not check for
 | 
|
2809  | 
            # compression parents that are in the existing graph index),
 | 
|
2810  | 
            # but such records won't have been buffered, so this is
 | 
|
2811  | 
            # actually correct: every entry when
 | 
|
2812  | 
            # missing_compression_parents==True either has a missing parent, or
 | 
|
2813  | 
            # a parent that is one of the keys in records.
 | 
|
2814  | 
compression_parents.difference_update(keys)  | 
|
2815  | 
self._missing_compression_parents.update(compression_parents)  | 
|
2816  | 
        # Adding records may have satisfied missing compression parents.
 | 
|
| 
4009.3.7
by Andrew Bennetts
 Most tests passing.  | 
2817  | 
self._missing_compression_parents.difference_update(keys)  | 
| 
4032.1.1
by John Arbash Meinel
 Merge the removal of all trailing whitespace, and resolve conflicts.  | 
2818  | 
|
| 
4011.5.7
by Andrew Bennetts
 Remove leading underscore from _scan_unvalidate_index, explicitly NotImplementedError it for _KndxIndex.  | 
2819  | 
def scan_unvalidated_index(self, graph_index):  | 
| 
4011.5.1
by Andrew Bennetts
 Start to add _add_unvalidated_index/get_missing_compression_parents methods to _KnitGraphIndex.  | 
2820  | 
"""Inform this _KnitGraphIndex that there is an unvalidated index.  | 
2821  | 
||
2822  | 
        This allows this _KnitGraphIndex to keep track of any missing
 | 
|
2823  | 
        compression parents we may want to have filled in to make those
 | 
|
2824  | 
        indices valid.
 | 
|
2825  | 
||
2826  | 
        :param graph_index: A GraphIndex
 | 
|
2827  | 
        """
 | 
|
| 
4011.5.11
by Robert Collins
 Polish the KnitVersionedFiles.scan_unvalidated_index api.  | 
2828  | 
if self._deltas:  | 
2829  | 
new_missing = graph_index.external_references(ref_list_num=1)  | 
|
2830  | 
new_missing.difference_update(self.get_parent_map(new_missing))  | 
|
2831  | 
self._missing_compression_parents.update(new_missing)  | 
|
| 
4257.4.11
by Andrew Bennetts
 Polish the patch.  | 
2832  | 
if self._external_parent_refs is not None:  | 
| 
4257.4.16
by Andrew Bennetts
 Add comment, remove unnecessary vertical whitespace.  | 
2833  | 
            # Add parent refs from graph_index (and discard parent refs that
 | 
2834  | 
            # the graph_index has).
 | 
|
| 
4257.4.10
by Andrew Bennetts
 Observe new revisions in _KnitGraphIndex.add_record rather than iterating all the uncommitted packs' indices.  | 
2835  | 
for node in graph_index.iter_all_entries():  | 
| 
4257.4.11
by Andrew Bennetts
 Polish the patch.  | 
2836  | 
self._external_parent_refs.update(node[3][0])  | 
2837  | 
self._external_parent_refs.discard(node[1])  | 
|
| 
4009.3.7
by Andrew Bennetts
 Most tests passing.  | 
2838  | 
|
| 
4011.5.1
by Andrew Bennetts
 Start to add _add_unvalidated_index/get_missing_compression_parents methods to _KnitGraphIndex.  | 
2839  | 
def get_missing_compression_parents(self):  | 
| 
4009.3.12
by Robert Collins
 Polish on inserting record streams with missing compression parents.  | 
2840  | 
"""Return the keys of missing compression parents.  | 
2841  | 
||
2842  | 
        Missing compression parents occur when a record stream was missing
 | 
|
2843  | 
        basis texts, or a index was scanned that had missing basis texts.
 | 
|
| 
4011.5.1
by Andrew Bennetts
 Start to add _add_unvalidated_index/get_missing_compression_parents methods to _KnitGraphIndex.  | 
2844  | 
        """
 | 
2845  | 
return frozenset(self._missing_compression_parents)  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2846  | 
|
| 
4257.4.11
by Andrew Bennetts
 Polish the patch.  | 
2847  | 
def get_missing_parents(self):  | 
2848  | 
"""Return the keys of missing parents."""  | 
|
2849  | 
        # We may have false positives, so filter those out.
 | 
|
| 
4257.4.14
by Andrew Bennetts
 Add a unit test for _KnitGraphIndex.get_missing_parents, fix bug that it reveals.  | 
2850  | 
self._external_parent_refs.difference_update(  | 
2851  | 
self.get_parent_map(self._external_parent_refs))  | 
|
| 
4257.4.11
by Andrew Bennetts
 Polish the patch.  | 
2852  | 
return frozenset(self._external_parent_refs)  | 
2853  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2854  | 
def _check_read(self):  | 
2855  | 
"""raise if reads are not permitted."""  | 
|
2856  | 
if not self._is_locked():  | 
|
2857  | 
raise errors.ObjectNotLocked(self)  | 
|
2858  | 
||
2859  | 
def _check_write_ok(self):  | 
|
2860  | 
"""Assert if writes are not permitted."""  | 
|
2861  | 
if not self._is_locked():  | 
|
2862  | 
raise errors.ObjectNotLocked(self)  | 
|
2863  | 
||
2864  | 
def _compression_parent(self, an_entry):  | 
|
2865  | 
        # return the key that an_entry is compressed against, or None
 | 
|
2866  | 
        # Grab the second parent list (as deltas implies parents currently)
 | 
|
2867  | 
compression_parents = an_entry[3][1]  | 
|
2868  | 
if not compression_parents:  | 
|
2869  | 
return None  | 
|
2870  | 
if len(compression_parents) != 1:  | 
|
2871  | 
raise AssertionError(  | 
|
2872  | 
"Too many compression parents: %r" % compression_parents)  | 
|
2873  | 
return compression_parents[0]  | 
|
2874  | 
||
2875  | 
def get_build_details(self, keys):  | 
|
2876  | 
"""Get the method, index_memo and compression parent for version_ids.  | 
|
2877  | 
||
2878  | 
        Ghosts are omitted from the result.
 | 
|
2879  | 
||
2880  | 
        :param keys: An iterable of keys.
 | 
|
2881  | 
        :return: A dict of key:
 | 
|
2882  | 
            (index_memo, compression_parent, parents, record_details).
 | 
|
2883  | 
            index_memo
 | 
|
2884  | 
                opaque structure to pass to read_records to extract the raw
 | 
|
2885  | 
                data
 | 
|
2886  | 
            compression_parent
 | 
|
2887  | 
                Content that this record is built upon, may be None
 | 
|
2888  | 
            parents
 | 
|
2889  | 
                Logical parents of this node
 | 
|
2890  | 
            record_details
 | 
|
2891  | 
                extra information about the content which needs to be passed to
 | 
|
2892  | 
                Factory.parse_record
 | 
|
2893  | 
        """
 | 
|
2894  | 
self._check_read()  | 
|
2895  | 
result = {}  | 
|
2896  | 
entries = self._get_entries(keys, False)  | 
|
2897  | 
for entry in entries:  | 
|
2898  | 
key = entry[1]  | 
|
2899  | 
if not self._parents:  | 
|
2900  | 
parents = ()  | 
|
2901  | 
else:  | 
|
2902  | 
parents = entry[3][0]  | 
|
2903  | 
if not self._deltas:  | 
|
2904  | 
compression_parent_key = None  | 
|
2905  | 
else:  | 
|
2906  | 
compression_parent_key = self._compression_parent(entry)  | 
|
2907  | 
noeol = (entry[2][0] == 'N')  | 
|
2908  | 
if compression_parent_key:  | 
|
2909  | 
method = 'line-delta'  | 
|
2910  | 
else:  | 
|
2911  | 
method = 'fulltext'  | 
|
2912  | 
result[key] = (self._node_to_position(entry),  | 
|
2913  | 
compression_parent_key, parents,  | 
|
2914  | 
(method, noeol))  | 
|
2915  | 
return result  | 
|
2916  | 
||
2917  | 
def _get_entries(self, keys, check_present=False):  | 
|
2918  | 
"""Get the entries for keys.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2919  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2920  | 
        :param keys: An iterable of index key tuples.
 | 
2921  | 
        """
 | 
|
2922  | 
keys = set(keys)  | 
|
2923  | 
found_keys = set()  | 
|
2924  | 
if self._parents:  | 
|
2925  | 
for node in self._graph_index.iter_entries(keys):  | 
|
2926  | 
yield node  | 
|
2927  | 
found_keys.add(node[1])  | 
|
2928  | 
else:  | 
|
2929  | 
            # adapt parentless index to the rest of the code.
 | 
|
2930  | 
for node in self._graph_index.iter_entries(keys):  | 
|
2931  | 
yield node[0], node[1], node[2], ()  | 
|
2932  | 
found_keys.add(node[1])  | 
|
2933  | 
if check_present:  | 
|
2934  | 
missing_keys = keys.difference(found_keys)  | 
|
2935  | 
if missing_keys:  | 
|
2936  | 
raise RevisionNotPresent(missing_keys.pop(), self)  | 
|
2937  | 
||
2938  | 
def get_method(self, key):  | 
|
2939  | 
"""Return compression method of specified key."""  | 
|
2940  | 
return self._get_method(self._get_node(key))  | 
|
2941  | 
||
2942  | 
def _get_method(self, node):  | 
|
2943  | 
if not self._deltas:  | 
|
2944  | 
return 'fulltext'  | 
|
2945  | 
if self._compression_parent(node):  | 
|
2946  | 
return 'line-delta'  | 
|
2947  | 
else:  | 
|
2948  | 
return 'fulltext'  | 
|
2949  | 
||
2950  | 
def _get_node(self, key):  | 
|
2951  | 
try:  | 
|
2952  | 
return list(self._get_entries([key]))[0]  | 
|
2953  | 
except IndexError:  | 
|
2954  | 
raise RevisionNotPresent(key, self)  | 
|
2955  | 
||
2956  | 
def get_options(self, key):  | 
|
2957  | 
"""Return a list representing options.  | 
|
2958  | 
||
2959  | 
        e.g. ['foo', 'bar']
 | 
|
2960  | 
        """
 | 
|
2961  | 
node = self._get_node(key)  | 
|
2962  | 
options = [self._get_method(node)]  | 
|
2963  | 
if node[2][0] == 'N':  | 
|
2964  | 
options.append('no-eol')  | 
|
2965  | 
return options  | 
|
2966  | 
||
2967  | 
def get_parent_map(self, keys):  | 
|
2968  | 
"""Get a map of the parents of keys.  | 
|
2969  | 
||
2970  | 
        :param keys: The keys to look up parents for.
 | 
|
2971  | 
        :return: A mapping from keys to parents. Absent keys are absent from
 | 
|
2972  | 
            the mapping.
 | 
|
2973  | 
        """
 | 
|
2974  | 
self._check_read()  | 
|
2975  | 
nodes = self._get_entries(keys)  | 
|
2976  | 
result = {}  | 
|
2977  | 
if self._parents:  | 
|
2978  | 
for node in nodes:  | 
|
2979  | 
result[node[1]] = node[3][0]  | 
|
2980  | 
else:  | 
|
2981  | 
for node in nodes:  | 
|
2982  | 
result[node[1]] = None  | 
|
2983  | 
return result  | 
|
2984  | 
||
2985  | 
def get_position(self, key):  | 
|
2986  | 
"""Return details needed to access the version.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2987  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2988  | 
        :return: a tuple (index, data position, size) to hand to the access
 | 
2989  | 
            logic to get the record.
 | 
|
2990  | 
        """
 | 
|
2991  | 
node = self._get_node(key)  | 
|
2992  | 
return self._node_to_position(node)  | 
|
2993  | 
||
| 
3830.3.12
by Martin Pool
 Review cleanups: unify has_key impls, add missing_keys(), clean up exception blocks  | 
2994  | 
has_key = _mod_index._has_key_from_parent_map  | 
| 
3830.3.9
by Martin Pool
 Simplify kvf insert_record_stream; add has_key shorthand methods; update stacking effort tests  | 
2995  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2996  | 
def keys(self):  | 
2997  | 
"""Get all the keys in the collection.  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
2998  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
2999  | 
        The keys are not ordered.
 | 
3000  | 
        """
 | 
|
3001  | 
self._check_read()  | 
|
3002  | 
return [node[1] for node in self._graph_index.iter_all_entries()]  | 
|
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
3003  | 
|
| 
3830.3.12
by Martin Pool
 Review cleanups: unify has_key impls, add missing_keys(), clean up exception blocks  | 
3004  | 
missing_keys = _mod_index._missing_keys_from_parent_map  | 
3005  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3006  | 
def _node_to_position(self, node):  | 
3007  | 
"""Convert an index value to position details."""  | 
|
3008  | 
bits = node[2][1:].split(' ')  | 
|
3009  | 
return node[0], int(bits[0]), int(bits[1])  | 
|
3010  | 
||
| 
3878.1.2
by John Arbash Meinel
 Move the sorting into each index, and customize it for Kndx access.  | 
3011  | 
def _sort_keys_by_io(self, keys, positions):  | 
3012  | 
"""Figure out an optimal order to read the records for the given keys.  | 
|
3013  | 
||
3014  | 
        Sort keys, grouped by index and sorted by position.
 | 
|
3015  | 
||
3016  | 
        :param keys: A list of keys whose records we want to read. This will be
 | 
|
3017  | 
            sorted 'in-place'.
 | 
|
3018  | 
        :param positions: A dict, such as the one returned by
 | 
|
3019  | 
            _get_components_positions()
 | 
|
3020  | 
        :return: None
 | 
|
3021  | 
        """
 | 
|
3022  | 
def get_index_memo(key):  | 
|
| 
3878.1.3
by John Arbash Meinel
 Add a comment about what data we are sorting by.  | 
3023  | 
            # index_memo is at offset [1]. It is made up of (GraphIndex,
 | 
3024  | 
            # position, size). GI is an object, which will be unique for each
 | 
|
3025  | 
            # pack file. This causes us to group by pack file, then sort by
 | 
|
3026  | 
            # position. Size doesn't matter, but it isn't worth breaking up the
 | 
|
3027  | 
            # tuple.
 | 
|
| 
3878.1.2
by John Arbash Meinel
 Move the sorting into each index, and customize it for Kndx access.  | 
3028  | 
return positions[key][1]  | 
3029  | 
return keys.sort(key=get_index_memo)  | 
|
3030  | 
||
| 
4039.3.5
by John Arbash Meinel
 Add direct tests for _get_total_build_size.  | 
3031  | 
_get_total_build_size = _get_total_build_size  | 
| 
4039.3.2
by John Arbash Meinel
 Batch get_record_stream(fulltexts) into 5MB requests.  | 
3032  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3033  | 
|
3034  | 
class _KnitKeyAccess(object):  | 
|
3035  | 
"""Access to records in .knit files."""  | 
|
3036  | 
||
3037  | 
def __init__(self, transport, mapper):  | 
|
3038  | 
"""Create a _KnitKeyAccess with transport and mapper.  | 
|
3039  | 
||
3040  | 
        :param transport: The transport the access object is rooted at.
 | 
|
3041  | 
        :param mapper: The mapper used to map keys to .knit files.
 | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3042  | 
        """
 | 
3043  | 
self._transport = transport  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3044  | 
self._mapper = mapper  | 
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3045  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3046  | 
def add_raw_records(self, key_sizes, raw_data):  | 
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3047  | 
"""Add raw knit bytes to a storage area.  | 
3048  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3049  | 
        The data is spooled to the container writer in one bytes-record per
 | 
3050  | 
        raw data item.
 | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3051  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3052  | 
        :param sizes: An iterable of tuples containing the key and size of each
 | 
3053  | 
            raw data segment.
 | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3054  | 
        :param raw_data: A bytestring containing the data.
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3055  | 
        :return: A list of memos to retrieve the record later. Each memo is an
 | 
3056  | 
            opaque index memo. For _KnitKeyAccess the memo is (key, pos,
 | 
|
3057  | 
            length), where the key is the record key.
 | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3058  | 
        """
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3059  | 
if type(raw_data) != str:  | 
3060  | 
raise AssertionError(  | 
|
3061  | 
'data must be plain bytes was %s' % type(raw_data))  | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3062  | 
result = []  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3063  | 
offset = 0  | 
3064  | 
        # TODO: This can be tuned for writing to sftp and other servers where
 | 
|
3065  | 
        # append() is relatively expensive by grouping the writes to each key
 | 
|
3066  | 
        # prefix.
 | 
|
3067  | 
for key, size in key_sizes:  | 
|
3068  | 
path = self._mapper.map(key)  | 
|
3069  | 
try:  | 
|
3070  | 
base = self._transport.append_bytes(path + '.knit',  | 
|
3071  | 
raw_data[offset:offset+size])  | 
|
3072  | 
except errors.NoSuchFile:  | 
|
3073  | 
self._transport.mkdir(osutils.dirname(path))  | 
|
3074  | 
base = self._transport.append_bytes(path + '.knit',  | 
|
3075  | 
raw_data[offset:offset+size])  | 
|
3076  | 
            # if base == 0:
 | 
|
3077  | 
            # chmod.
 | 
|
3078  | 
offset += size  | 
|
3079  | 
result.append((key, base, size))  | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3080  | 
return result  | 
3081  | 
||
| 
4187.3.3
by Andrew Bennetts
 In KnitVersionedFiles.insert_record_stream, flush the access object before expanding a delta into a fulltext.  | 
3082  | 
def flush(self):  | 
| 
4187.3.4
by Andrew Bennetts
 Better docstrings and comments.  | 
3083  | 
"""Flush pending writes on this access object.  | 
3084  | 
        
 | 
|
3085  | 
        For .knit files this is a no-op.
 | 
|
3086  | 
        """
 | 
|
| 
4187.3.3
by Andrew Bennetts
 In KnitVersionedFiles.insert_record_stream, flush the access object before expanding a delta into a fulltext.  | 
3087  | 
        pass
 | 
3088  | 
||
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3089  | 
def get_raw_records(self, memos_for_retrieval):  | 
3090  | 
"""Get the raw bytes for a records.  | 
|
3091  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3092  | 
        :param memos_for_retrieval: An iterable containing the access memo for
 | 
3093  | 
            retrieving the bytes.
 | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3094  | 
        :return: An iterator over the bytes of the records.
 | 
3095  | 
        """
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3096  | 
        # first pass, group into same-index request to minimise readv's issued.
 | 
3097  | 
request_lists = []  | 
|
3098  | 
current_prefix = None  | 
|
3099  | 
for (key, offset, length) in memos_for_retrieval:  | 
|
3100  | 
if current_prefix == key[:-1]:  | 
|
3101  | 
current_list.append((offset, length))  | 
|
3102  | 
else:  | 
|
3103  | 
if current_prefix is not None:  | 
|
3104  | 
request_lists.append((current_prefix, current_list))  | 
|
3105  | 
current_prefix = key[:-1]  | 
|
3106  | 
current_list = [(offset, length)]  | 
|
3107  | 
        # handle the last entry
 | 
|
3108  | 
if current_prefix is not None:  | 
|
3109  | 
request_lists.append((current_prefix, current_list))  | 
|
3110  | 
for prefix, read_vector in request_lists:  | 
|
3111  | 
path = self._mapper.map(prefix) + '.knit'  | 
|
3112  | 
for pos, data in self._transport.readv(path, read_vector):  | 
|
3113  | 
yield data  | 
|
3114  | 
||
3115  | 
||
3116  | 
class _DirectPackAccess(object):  | 
|
3117  | 
"""Access to data in one or more packs with less translation."""  | 
|
3118  | 
||
| 
4187.3.3
by Andrew Bennetts
 In KnitVersionedFiles.insert_record_stream, flush the access object before expanding a delta into a fulltext.  | 
3119  | 
def __init__(self, index_to_packs, reload_func=None, flush_func=None):  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3120  | 
"""Create a _DirectPackAccess object.  | 
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3121  | 
|
3122  | 
        :param index_to_packs: A dict mapping index objects to the transport
 | 
|
3123  | 
            and file names for obtaining data.
 | 
|
| 
3789.2.5
by John Arbash Meinel
 Change _DirectPackAccess to only raise Retry when _reload_func is defined.  | 
3124  | 
        :param reload_func: A function to call if we determine that the pack
 | 
3125  | 
            files have moved and we need to reload our caches. See
 | 
|
3126  | 
            bzrlib.repo_fmt.pack_repo.AggregateIndex for more details.
 | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3127  | 
        """
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3128  | 
self._container_writer = None  | 
3129  | 
self._write_index = None  | 
|
3130  | 
self._indices = index_to_packs  | 
|
| 
3789.2.5
by John Arbash Meinel
 Change _DirectPackAccess to only raise Retry when _reload_func is defined.  | 
3131  | 
self._reload_func = reload_func  | 
| 
4187.3.3
by Andrew Bennetts
 In KnitVersionedFiles.insert_record_stream, flush the access object before expanding a delta into a fulltext.  | 
3132  | 
self._flush_func = flush_func  | 
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3133  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3134  | 
def add_raw_records(self, key_sizes, raw_data):  | 
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3135  | 
"""Add raw knit bytes to a storage area.  | 
3136  | 
||
| 
2670.2.3
by Robert Collins
 Review feedback.  | 
3137  | 
        The data is spooled to the container writer in one bytes-record per
 | 
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3138  | 
        raw data item.
 | 
3139  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3140  | 
        :param sizes: An iterable of tuples containing the key and size of each
 | 
3141  | 
            raw data segment.
 | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3142  | 
        :param raw_data: A bytestring containing the data.
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3143  | 
        :return: A list of memos to retrieve the record later. Each memo is an
 | 
3144  | 
            opaque index memo. For _DirectPackAccess the memo is (index, pos,
 | 
|
3145  | 
            length), where the index field is the write_index object supplied
 | 
|
3146  | 
            to the PackAccess object.
 | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3147  | 
        """
 | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3148  | 
if type(raw_data) != str:  | 
3149  | 
raise AssertionError(  | 
|
3150  | 
'data must be plain bytes was %s' % type(raw_data))  | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3151  | 
result = []  | 
3152  | 
offset = 0  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3153  | 
for key, size in key_sizes:  | 
3154  | 
p_offset, p_length = self._container_writer.add_bytes_record(  | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3155  | 
raw_data[offset:offset+size], [])  | 
3156  | 
offset += size  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3157  | 
result.append((self._write_index, p_offset, p_length))  | 
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3158  | 
return result  | 
3159  | 
||
| 
4187.3.3
by Andrew Bennetts
 In KnitVersionedFiles.insert_record_stream, flush the access object before expanding a delta into a fulltext.  | 
3160  | 
def flush(self):  | 
| 
4187.3.4
by Andrew Bennetts
 Better docstrings and comments.  | 
3161  | 
"""Flush pending writes on this access object.  | 
3162  | 
||
3163  | 
        This will flush any buffered writes to a NewPack.
 | 
|
3164  | 
        """
 | 
|
| 
4187.3.3
by Andrew Bennetts
 In KnitVersionedFiles.insert_record_stream, flush the access object before expanding a delta into a fulltext.  | 
3165  | 
if self._flush_func is not None:  | 
3166  | 
self._flush_func()  | 
|
3167  | 
||
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3168  | 
def get_raw_records(self, memos_for_retrieval):  | 
3169  | 
"""Get the raw bytes for a records.  | 
|
3170  | 
||
| 
3943.8.1
by Marius Kruger
 remove all trailing whitespace from bzr source  | 
3171  | 
        :param memos_for_retrieval: An iterable containing the (index, pos,
 | 
| 
2670.2.2
by Robert Collins
 * In ``bzrlib.knit`` the internal interface has been altered to use  | 
3172  | 
            length) memo for retrieving the bytes. The Pack access method
 | 
3173  | 
            looks up the pack to use for a given record in its index_to_pack
 | 
|
3174  | 
            map.
 | 
|
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3175  | 
        :return: An iterator over the bytes of the records.
 | 
3176  | 
        """
 | 
|
3177  | 
        # first pass, group into same-index requests
 | 
|
3178  | 
request_lists = []  | 
|
3179  | 
current_index = None  | 
|
3180  | 
for (index, offset, length) in memos_for_retrieval:  | 
|
3181  | 
if current_index == index:  | 
|
3182  | 
current_list.append((offset, length))  | 
|
3183  | 
else:  | 
|
3184  | 
if current_index is not None:  | 
|
3185  | 
request_lists.append((current_index, current_list))  | 
|
3186  | 
current_index = index  | 
|
3187  | 
current_list = [(offset, length)]  | 
|
3188  | 
        # handle the last entry
 | 
|
3189  | 
if current_index is not None:  | 
|
3190  | 
request_lists.append((current_index, current_list))  | 
|
3191  | 
for index, offsets in request_lists:  | 
|
| 
3789.2.1
by John Arbash Meinel
 _DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.  | 
3192  | 
try:  | 
3193  | 
transport, path = self._indices[index]  | 
|
3194  | 
except KeyError:  | 
|
3195  | 
                # A KeyError here indicates that someone has triggered an index
 | 
|
3196  | 
                # reload, and this index has gone missing, we need to start
 | 
|
3197  | 
                # over.
 | 
|
| 
3789.2.5
by John Arbash Meinel
 Change _DirectPackAccess to only raise Retry when _reload_func is defined.  | 
3198  | 
if self._reload_func is None:  | 
3199  | 
                    # If we don't have a _reload_func there is nothing that can
 | 
|
3200  | 
                    # be done
 | 
|
3201  | 
                    raise
 | 
|
| 
3789.2.28
by John Arbash Meinel
 We don't actually have a transport yet, so we can't use it as context.  | 
3202  | 
raise errors.RetryWithNewPacks(index,  | 
| 
3789.2.27
by John Arbash Meinel
 Add some context information to the Retry exceptions.  | 
3203  | 
reload_occurred=True,  | 
| 
3789.2.1
by John Arbash Meinel
 _DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.  | 
3204  | 
exc_info=sys.exc_info())  | 
3205  | 
try:  | 
|
3206  | 
reader = pack.make_readv_reader(transport, path, offsets)  | 
|
3207  | 
for names, read_func in reader.iter_records():  | 
|
3208  | 
yield read_func(None)  | 
|
3209  | 
except errors.NoSuchFile:  | 
|
3210  | 
                # A NoSuchFile error indicates that a pack file has gone
 | 
|
3211  | 
                # missing on disk, we need to trigger a reload, and start over.
 | 
|
| 
3789.2.5
by John Arbash Meinel
 Change _DirectPackAccess to only raise Retry when _reload_func is defined.  | 
3212  | 
if self._reload_func is None:  | 
3213  | 
                    raise
 | 
|
| 
3789.2.27
by John Arbash Meinel
 Add some context information to the Retry exceptions.  | 
3214  | 
raise errors.RetryWithNewPacks(transport.abspath(path),  | 
3215  | 
reload_occurred=False,  | 
|
| 
3789.2.1
by John Arbash Meinel
 _DirectPackAccess can now raise RetryWithNewPacks when we think something has happened.  | 
3216  | 
exc_info=sys.exc_info())  | 
| 
2592.3.66
by Robert Collins
 Allow adaption of KnitData to pack files.  | 
3217  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3218  | 
def set_writer(self, writer, index, transport_packname):  | 
| 
2592.3.70
by Robert Collins
 Allow setting a writer after creating a knit._PackAccess object.  | 
3219  | 
"""Set a writer to use for adding data."""  | 
| 
2592.3.208
by Robert Collins
 Start refactoring the knit-pack thunking to be clearer.  | 
3220  | 
if index is not None:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3221  | 
self._indices[index] = transport_packname  | 
3222  | 
self._container_writer = writer  | 
|
3223  | 
self._write_index = index  | 
|
| 
1684.3.3
by Robert Collins
 Add a special cased weaves to knit converter.  | 
3224  | 
|
| 
3789.2.5
by John Arbash Meinel
 Change _DirectPackAccess to only raise Retry when _reload_func is defined.  | 
3225  | 
def reload_or_raise(self, retry_exc):  | 
3226  | 
"""Try calling the reload function, or re-raise the original exception.  | 
|
3227  | 
||
3228  | 
        This should be called after _DirectPackAccess raises a
 | 
|
3229  | 
        RetryWithNewPacks exception. This function will handle the common logic
 | 
|
3230  | 
        of determining when the error is fatal versus being temporary.
 | 
|
3231  | 
        It will also make sure that the original exception is raised, rather
 | 
|
3232  | 
        than the RetryWithNewPacks exception.
 | 
|
3233  | 
||
3234  | 
        If this function returns, then the calling function should retry
 | 
|
3235  | 
        whatever operation was being performed. Otherwise an exception will
 | 
|
3236  | 
        be raised.
 | 
|
3237  | 
||
3238  | 
        :param retry_exc: A RetryWithNewPacks exception.
 | 
|
3239  | 
        """
 | 
|
| 
3789.2.6
by John Arbash Meinel
 Make _DirectPackAccess.reload_or_raise maintain the logic.  | 
3240  | 
is_error = False  | 
3241  | 
if self._reload_func is None:  | 
|
3242  | 
is_error = True  | 
|
3243  | 
elif not self._reload_func():  | 
|
3244  | 
            # The reload claimed that nothing changed
 | 
|
3245  | 
if not retry_exc.reload_occurred:  | 
|
3246  | 
                # If there wasn't an earlier reload, then we really were
 | 
|
3247  | 
                # expecting to find changes. We didn't find them, so this is a
 | 
|
3248  | 
                # hard error
 | 
|
3249  | 
is_error = True  | 
|
3250  | 
if is_error:  | 
|
3251  | 
exc_class, exc_value, exc_traceback = retry_exc.exc_info  | 
|
3252  | 
raise exc_class, exc_value, exc_traceback  | 
|
| 
3789.2.5
by John Arbash Meinel
 Change _DirectPackAccess to only raise Retry when _reload_func is defined.  | 
3253  | 
|
| 
1684.3.3
by Robert Collins
 Add a special cased weaves to knit converter.  | 
3254  | 
|
| 
2781.1.1
by Martin Pool
 merge cpatiencediff from Lukas  | 
3255  | 
# Deprecated, use PatienceSequenceMatcher instead
 | 
3256  | 
KnitSequenceMatcher = patiencediff.PatienceSequenceMatcher  | 
|
| 
2484.1.1
by John Arbash Meinel
 Add an initial function to read knit indexes in pyrex.  | 
3257  | 
|
3258  | 
||
| 
2770.1.2
by Aaron Bentley
 Convert to knit-only annotation  | 
3259  | 
def annotate_knit(knit, revision_id):  | 
3260  | 
"""Annotate a knit with no cached annotations.  | 
|
3261  | 
||
3262  | 
    This implementation is for knits with no cached annotations.
 | 
|
3263  | 
    It will work for knits with cached annotations, but this is not
 | 
|
3264  | 
    recommended.
 | 
|
3265  | 
    """
 | 
|
| 
3224.1.7
by John Arbash Meinel
 _StreamIndex also needs to return the proper values for get_build_details.  | 
3266  | 
annotator = _KnitAnnotator(knit)  | 
| 
3224.1.25
by John Arbash Meinel
 Quick change to the _KnitAnnotator api to use .annotate() instead of get_annotated_lines()  | 
3267  | 
return iter(annotator.annotate(revision_id))  | 
| 
3224.1.7
by John Arbash Meinel
 _StreamIndex also needs to return the proper values for get_build_details.  | 
3268  | 
|
3269  | 
||
3270  | 
class _KnitAnnotator(object):  | 
|
| 
3224.1.5
by John Arbash Meinel
 Start using a helper class for doing the knit-pack annotations.  | 
3271  | 
"""Build up the annotations for a text."""  | 
3272  | 
||
3273  | 
def __init__(self, knit):  | 
|
3274  | 
self._knit = knit  | 
|
3275  | 
||
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3276  | 
        # Content objects, differs from fulltexts because of how final newlines
 | 
3277  | 
        # are treated by knits. the content objects here will always have a
 | 
|
3278  | 
        # final newline
 | 
|
3279  | 
self._fulltext_contents = {}  | 
|
3280  | 
||
3281  | 
        # Annotated lines of specific revisions
 | 
|
3282  | 
self._annotated_lines = {}  | 
|
3283  | 
||
3284  | 
        # Track the raw data for nodes that we could not process yet.
 | 
|
3285  | 
        # This maps the revision_id of the base to a list of children that will
 | 
|
3286  | 
        # annotated from it.
 | 
|
3287  | 
self._pending_children = {}  | 
|
3288  | 
||
| 
3224.1.29
by John Arbash Meinel
 Properly handle annotating when ghosts are present.  | 
3289  | 
        # Nodes which cannot be extracted
 | 
3290  | 
self._ghosts = set()  | 
|
3291  | 
||
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3292  | 
        # Track how many children this node has, so we know if we need to keep
 | 
3293  | 
        # it
 | 
|
3294  | 
self._annotate_children = {}  | 
|
3295  | 
self._compression_children = {}  | 
|
3296  | 
||
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3297  | 
self._all_build_details = {}  | 
| 
3224.1.10
by John Arbash Meinel
 Introduce the heads_provider for reannotate.  | 
3298  | 
        # The children => parent revision_id graph
 | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3299  | 
self._revision_id_graph = {}  | 
3300  | 
||
| 
3224.1.10
by John Arbash Meinel
 Introduce the heads_provider for reannotate.  | 
3301  | 
self._heads_provider = None  | 
3302  | 
||
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3303  | 
self._nodes_to_keep_annotations = set()  | 
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3304  | 
self._generations_until_keep = 100  | 
3305  | 
||
3306  | 
def set_generations_until_keep(self, value):  | 
|
3307  | 
"""Set the number of generations before caching a node.  | 
|
3308  | 
||
3309  | 
        Setting this to -1 will cache every merge node, setting this higher
 | 
|
3310  | 
        will cache fewer nodes.
 | 
|
3311  | 
        """
 | 
|
3312  | 
self._generations_until_keep = value  | 
|
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3313  | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
3314  | 
def _add_fulltext_content(self, revision_id, content_obj):  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3315  | 
self._fulltext_contents[revision_id] = content_obj  | 
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3316  | 
        # TODO: jam 20080305 It might be good to check the sha1digest here
 | 
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3317  | 
return content_obj.text()  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3318  | 
|
3319  | 
def _check_parents(self, child, nodes_to_annotate):  | 
|
3320  | 
"""Check if all parents have been processed.  | 
|
3321  | 
||
3322  | 
        :param child: A tuple of (rev_id, parents, raw_content)
 | 
|
3323  | 
        :param nodes_to_annotate: If child is ready, add it to
 | 
|
3324  | 
            nodes_to_annotate, otherwise put it back in self._pending_children
 | 
|
3325  | 
        """
 | 
|
3326  | 
for parent_id in child[1]:  | 
|
| 
3224.1.29
by John Arbash Meinel
 Properly handle annotating when ghosts are present.  | 
3327  | 
if (parent_id not in self._annotated_lines):  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3328  | 
                # This parent is present, but another parent is missing
 | 
3329  | 
self._pending_children.setdefault(parent_id,  | 
|
3330  | 
[]).append(child)  | 
|
3331  | 
                break
 | 
|
3332  | 
else:  | 
|
3333  | 
            # This one is ready to be processed
 | 
|
3334  | 
nodes_to_annotate.append(child)  | 
|
3335  | 
||
3336  | 
def _add_annotation(self, revision_id, fulltext, parent_ids,  | 
|
3337  | 
left_matching_blocks=None):  | 
|
3338  | 
"""Add an annotation entry.  | 
|
3339  | 
||
3340  | 
        All parents should already have been annotated.
 | 
|
3341  | 
        :return: A list of children that now have their parents satisfied.
 | 
|
3342  | 
        """
 | 
|
3343  | 
a = self._annotated_lines  | 
|
3344  | 
annotated_parent_lines = [a[p] for p in parent_ids]  | 
|
3345  | 
annotated_lines = list(annotate.reannotate(annotated_parent_lines,  | 
|
| 
3224.1.10
by John Arbash Meinel
 Introduce the heads_provider for reannotate.  | 
3346  | 
fulltext, revision_id, left_matching_blocks,  | 
3347  | 
heads_provider=self._get_heads_provider()))  | 
|
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3348  | 
self._annotated_lines[revision_id] = annotated_lines  | 
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3349  | 
for p in parent_ids:  | 
3350  | 
ann_children = self._annotate_children[p]  | 
|
3351  | 
ann_children.remove(revision_id)  | 
|
3352  | 
if (not ann_children  | 
|
3353  | 
and p not in self._nodes_to_keep_annotations):  | 
|
3354  | 
del self._annotated_lines[p]  | 
|
3355  | 
del self._all_build_details[p]  | 
|
3356  | 
if p in self._fulltext_contents:  | 
|
3357  | 
del self._fulltext_contents[p]  | 
|
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3358  | 
        # Now that we've added this one, see if there are any pending
 | 
3359  | 
        # deltas to be done, certainly this parent is finished
 | 
|
3360  | 
nodes_to_annotate = []  | 
|
3361  | 
for child in self._pending_children.pop(revision_id, []):  | 
|
3362  | 
self._check_parents(child, nodes_to_annotate)  | 
|
3363  | 
return nodes_to_annotate  | 
|
3364  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3365  | 
def _get_build_graph(self, key):  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3366  | 
"""Get the graphs for building texts and annotations.  | 
3367  | 
||
3368  | 
        The data you need for creating a full text may be different than the
 | 
|
3369  | 
        data you need to annotate that text. (At a minimum, you need both
 | 
|
3370  | 
        parents to create an annotation, but only need 1 parent to generate the
 | 
|
3371  | 
        fulltext.)
 | 
|
3372  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3373  | 
        :return: A list of (key, index_memo) records, suitable for
 | 
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3374  | 
            passing to read_records_iter to start reading in the raw data fro/
 | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3375  | 
            the pack file.
 | 
3376  | 
        """
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3377  | 
if key in self._annotated_lines:  | 
| 
3224.1.10
by John Arbash Meinel
 Introduce the heads_provider for reannotate.  | 
3378  | 
            # Nothing to do
 | 
3379  | 
return []  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3380  | 
pending = set([key])  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3381  | 
records = []  | 
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3382  | 
generation = 0  | 
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3383  | 
kept_generation = 0  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3384  | 
while pending:  | 
3385  | 
            # get all pending nodes
 | 
|
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3386  | 
generation += 1  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3387  | 
this_iteration = pending  | 
3388  | 
build_details = self._knit._index.get_build_details(this_iteration)  | 
|
3389  | 
self._all_build_details.update(build_details)  | 
|
3390  | 
            # new_nodes = self._knit._index._get_entries(this_iteration)
 | 
|
3391  | 
pending = set()  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3392  | 
for key, details in build_details.iteritems():  | 
| 
3224.1.14
by John Arbash Meinel
 Switch to making content_details opaque, step 1  | 
3393  | 
(index_memo, compression_parent, parents,  | 
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
3394  | 
record_details) = details  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3395  | 
self._revision_id_graph[key] = parents  | 
3396  | 
records.append((key, index_memo))  | 
|
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3397  | 
                # Do we actually need to check _annotated_lines?
 | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3398  | 
pending.update(p for p in parents  | 
3399  | 
if p not in self._all_build_details)  | 
|
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3400  | 
if compression_parent:  | 
3401  | 
self._compression_children.setdefault(compression_parent,  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3402  | 
[]).append(key)  | 
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3403  | 
if parents:  | 
3404  | 
for parent in parents:  | 
|
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3405  | 
self._annotate_children.setdefault(parent,  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3406  | 
[]).append(key)  | 
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3407  | 
num_gens = generation - kept_generation  | 
3408  | 
if ((num_gens >= self._generations_until_keep)  | 
|
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3409  | 
and len(parents) > 1):  | 
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3410  | 
kept_generation = generation  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3411  | 
self._nodes_to_keep_annotations.add(key)  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3412  | 
|
3413  | 
missing_versions = this_iteration.difference(build_details.keys())  | 
|
| 
3224.1.29
by John Arbash Meinel
 Properly handle annotating when ghosts are present.  | 
3414  | 
self._ghosts.update(missing_versions)  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3415  | 
for missing_version in missing_versions:  | 
3416  | 
                # add a key, no parents
 | 
|
| 
3224.1.29
by John Arbash Meinel
 Properly handle annotating when ghosts are present.  | 
3417  | 
self._revision_id_graph[missing_version] = ()  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3418  | 
pending.discard(missing_version) # don't look for it  | 
| 
3376.2.4
by Martin Pool
 Remove every assert statement from bzrlib!  | 
3419  | 
if self._ghosts.intersection(self._compression_children):  | 
3420  | 
raise KnitCorrupt(  | 
|
3421  | 
"We cannot have nodes which have a ghost compression parent:\n"  | 
|
3422  | 
"ghosts: %r\n"  | 
|
3423  | 
"compression children: %r"  | 
|
3424  | 
% (self._ghosts, self._compression_children))  | 
|
| 
3224.1.29
by John Arbash Meinel
 Properly handle annotating when ghosts are present.  | 
3425  | 
        # Cleanout anything that depends on a ghost so that we don't wait for
 | 
3426  | 
        # the ghost to show up
 | 
|
3427  | 
for node in self._ghosts:  | 
|
3428  | 
if node in self._annotate_children:  | 
|
3429  | 
                # We won't be building this node
 | 
|
3430  | 
del self._annotate_children[node]  | 
|
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3431  | 
        # Generally we will want to read the records in reverse order, because
 | 
3432  | 
        # we find the parent nodes after the children
 | 
|
3433  | 
records.reverse()  | 
|
3434  | 
return records  | 
|
3435  | 
||
3436  | 
def _annotate_records(self, records):  | 
|
3437  | 
"""Build the annotations for the listed records."""  | 
|
3438  | 
        # We iterate in the order read, rather than a strict order requested
 | 
|
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3439  | 
        # However, process what we can, and put off to the side things that
 | 
3440  | 
        # still need parents, cleaning them up when those parents are
 | 
|
3441  | 
        # processed.
 | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
3442  | 
for (rev_id, record,  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3443  | 
digest) in self._knit._read_records_iter(records):  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3444  | 
if rev_id in self._annotated_lines:  | 
3445  | 
                continue
 | 
|
3446  | 
parent_ids = self._revision_id_graph[rev_id]  | 
|
| 
3224.1.29
by John Arbash Meinel
 Properly handle annotating when ghosts are present.  | 
3447  | 
parent_ids = [p for p in parent_ids if p not in self._ghosts]  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3448  | 
details = self._all_build_details[rev_id]  | 
| 
3224.1.14
by John Arbash Meinel
 Switch to making content_details opaque, step 1  | 
3449  | 
(index_memo, compression_parent, parents,  | 
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
3450  | 
record_details) = details  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3451  | 
nodes_to_annotate = []  | 
3452  | 
            # TODO: Remove the punning between compression parents, and
 | 
|
3453  | 
            #       parent_ids, we should be able to do this without assuming
 | 
|
3454  | 
            #       the build order
 | 
|
3455  | 
if len(parent_ids) == 0:  | 
|
3456  | 
                # There are no parents for this node, so just add it
 | 
|
3457  | 
                # TODO: This probably needs to be decoupled
 | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3458  | 
fulltext_content, delta = self._knit._factory.parse_record(  | 
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
3459  | 
rev_id, record, record_details, None)  | 
3460  | 
fulltext = self._add_fulltext_content(rev_id, fulltext_content)  | 
|
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3461  | 
nodes_to_annotate.extend(self._add_annotation(rev_id, fulltext,  | 
3462  | 
parent_ids, left_matching_blocks=None))  | 
|
3463  | 
else:  | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
3464  | 
child = (rev_id, parent_ids, record)  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3465  | 
                # Check if all the parents are present
 | 
3466  | 
self._check_parents(child, nodes_to_annotate)  | 
|
3467  | 
while nodes_to_annotate:  | 
|
3468  | 
                # Should we use a queue here instead of a stack?
 | 
|
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
3469  | 
(rev_id, parent_ids, record) = nodes_to_annotate.pop()  | 
| 
3224.1.14
by John Arbash Meinel
 Switch to making content_details opaque, step 1  | 
3470  | 
(index_memo, compression_parent, parents,  | 
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
3471  | 
record_details) = self._all_build_details[rev_id]  | 
| 
3777.4.1
by John Arbash Meinel
 Two fixes for annotate code.  | 
3472  | 
blocks = None  | 
| 
3224.1.14
by John Arbash Meinel
 Switch to making content_details opaque, step 1  | 
3473  | 
if compression_parent is not None:  | 
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3474  | 
comp_children = self._compression_children[compression_parent]  | 
| 
3376.2.4
by Martin Pool
 Remove every assert statement from bzrlib!  | 
3475  | 
if rev_id not in comp_children:  | 
3476  | 
raise AssertionError("%r not in compression children %r"  | 
|
3477  | 
% (rev_id, comp_children))  | 
|
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3478  | 
                    # If there is only 1 child, it is safe to reuse this
 | 
3479  | 
                    # content
 | 
|
3480  | 
reuse_content = (len(comp_children) == 1  | 
|
3481  | 
and compression_parent not in  | 
|
3482  | 
self._nodes_to_keep_annotations)  | 
|
3483  | 
if reuse_content:  | 
|
3484  | 
                        # Remove it from the cache since it will be changing
 | 
|
3485  | 
parent_fulltext_content = self._fulltext_contents.pop(compression_parent)  | 
|
3486  | 
                        # Make sure to copy the fulltext since it might be
 | 
|
3487  | 
                        # modified
 | 
|
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3488  | 
parent_fulltext = list(parent_fulltext_content.text())  | 
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3489  | 
else:  | 
3490  | 
parent_fulltext_content = self._fulltext_contents[compression_parent]  | 
|
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3491  | 
parent_fulltext = parent_fulltext_content.text()  | 
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3492  | 
comp_children.remove(rev_id)  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3493  | 
fulltext_content, delta = self._knit._factory.parse_record(  | 
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3494  | 
rev_id, record, record_details,  | 
3495  | 
parent_fulltext_content,  | 
|
| 
3224.1.19
by John Arbash Meinel
 Work on removing nodes from the working set once they aren't needed.  | 
3496  | 
copy_base_content=(not reuse_content))  | 
| 
3224.1.22
by John Arbash Meinel
 Cleanup the extra debugging info, and some >80 char lines.  | 
3497  | 
fulltext = self._add_fulltext_content(rev_id,  | 
3498  | 
fulltext_content)  | 
|
| 
3777.4.1
by John Arbash Meinel
 Two fixes for annotate code.  | 
3499  | 
if compression_parent == parent_ids[0]:  | 
3500  | 
                        # the compression_parent is the left parent, so we can
 | 
|
3501  | 
                        # re-use the delta
 | 
|
3502  | 
blocks = KnitContent.get_line_delta_blocks(delta,  | 
|
3503  | 
parent_fulltext, fulltext)  | 
|
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3504  | 
else:  | 
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3505  | 
fulltext_content = self._knit._factory.parse_fulltext(  | 
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
3506  | 
record, rev_id)  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3507  | 
fulltext = self._add_fulltext_content(rev_id,  | 
| 
3224.1.15
by John Arbash Meinel
 Finish removing method and noeol from general knowledge,  | 
3508  | 
fulltext_content)  | 
| 
3224.1.6
by John Arbash Meinel
 Refactor the annotation logic into a helper class.  | 
3509  | 
nodes_to_annotate.extend(  | 
3510  | 
self._add_annotation(rev_id, fulltext, parent_ids,  | 
|
3511  | 
left_matching_blocks=blocks))  | 
|
3512  | 
||
| 
3224.1.10
by John Arbash Meinel
 Introduce the heads_provider for reannotate.  | 
3513  | 
def _get_heads_provider(self):  | 
3514  | 
"""Create a heads provider for resolving ancestry issues."""  | 
|
3515  | 
if self._heads_provider is not None:  | 
|
3516  | 
return self._heads_provider  | 
|
3517  | 
parent_provider = _mod_graph.DictParentsProvider(  | 
|
3518  | 
self._revision_id_graph)  | 
|
3519  | 
graph_obj = _mod_graph.Graph(parent_provider)  | 
|
| 
3224.1.20
by John Arbash Meinel
 Reduce the number of cache misses by caching known heads answers  | 
3520  | 
head_cache = _mod_graph.FrozenHeadsCache(graph_obj)  | 
| 
3224.1.10
by John Arbash Meinel
 Introduce the heads_provider for reannotate.  | 
3521  | 
self._heads_provider = head_cache  | 
3522  | 
return head_cache  | 
|
3523  | 
||
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3524  | 
def annotate(self, key):  | 
3525  | 
"""Return the annotated fulltext at the given key.  | 
|
| 
3224.1.5
by John Arbash Meinel
 Start using a helper class for doing the knit-pack annotations.  | 
3526  | 
|
| 
3350.6.4
by Robert Collins
 First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.  | 
3527  | 
        :param key: The key to annotate.
 | 
| 
3224.1.5
by John Arbash Meinel
 Start using a helper class for doing the knit-pack annotations.  | 
3528  | 
        """
 | 
| 
3777.4.1
by John Arbash Meinel
 Two fixes for annotate code.  | 
3529  | 
if len(self._knit._fallback_vfs) > 0:  | 
| 
3517.4.1
by Martin Pool
 Merge unoptimized annotate code for stacking, and only use it when needed  | 
3530  | 
            # stacked knits can't use the fast path at present.
 | 
3531  | 
return self._simple_annotate(key)  | 
|
| 
3789.2.13
by John Arbash Meinel
 KnitVersionedFile.annotate() now retries when appropriate.  | 
3532  | 
while True:  | 
3533  | 
try:  | 
|
3534  | 
records = self._get_build_graph(key)  | 
|
3535  | 
if key in self._ghosts:  | 
|
3536  | 
raise errors.RevisionNotPresent(key, self._knit)  | 
|
3537  | 
self._annotate_records(records)  | 
|
3538  | 
return self._annotated_lines[key]  | 
|
3539  | 
except errors.RetryWithNewPacks, e:  | 
|
3540  | 
self._knit._access.reload_or_raise(e)  | 
|
3541  | 
                # The cached build_details are no longer valid
 | 
|
3542  | 
self._all_build_details.clear()  | 
|
| 
3224.1.5
by John Arbash Meinel
 Start using a helper class for doing the knit-pack annotations.  | 
3543  | 
|
| 
3517.4.1
by Martin Pool
 Merge unoptimized annotate code for stacking, and only use it when needed  | 
3544  | 
def _simple_annotate(self, key):  | 
3545  | 
"""Return annotated fulltext, rediffing from the full texts.  | 
|
3546  | 
||
3547  | 
        This is slow but makes no assumptions about the repository
 | 
|
3548  | 
        being able to produce line deltas.
 | 
|
3549  | 
        """
 | 
|
3550  | 
        # TODO: this code generates a parent maps of present ancestors; it
 | 
|
3551  | 
        # could be split out into a separate method, and probably should use
 | 
|
3552  | 
        # iter_ancestry instead. -- mbp and robertc 20080704
 | 
|
| 
3535.5.1
by John Arbash Meinel
 cleanup a few imports to be lazily loaded.  | 
3553  | 
graph = _mod_graph.Graph(self._knit)  | 
| 
3350.9.1
by Robert Collins
 Redo annotate more simply, using just the public interfaces for VersionedFiles.  | 
3554  | 
head_cache = _mod_graph.FrozenHeadsCache(graph)  | 
3555  | 
search = graph._make_breadth_first_searcher([key])  | 
|
3556  | 
keys = set()  | 
|
3557  | 
while True:  | 
|
3558  | 
try:  | 
|
3559  | 
present, ghosts = search.next_with_ghosts()  | 
|
3560  | 
except StopIteration:  | 
|
3561  | 
                break
 | 
|
3562  | 
keys.update(present)  | 
|
3563  | 
parent_map = self._knit.get_parent_map(keys)  | 
|
3564  | 
parent_cache = {}  | 
|
3565  | 
reannotate = annotate.reannotate  | 
|
3566  | 
for record in self._knit.get_record_stream(keys, 'topological', True):  | 
|
3567  | 
key = record.key  | 
|
| 
3890.2.9
by John Arbash Meinel
 Start using osutils.chunks_as_lines rather than osutils.split_lines.  | 
3568  | 
fulltext = osutils.chunks_to_lines(record.get_bytes_as('chunked'))  | 
| 
3517.4.2
by Martin Pool
 Make simple-annotation and graph code more tolerant of knits with no graph  | 
3569  | 
parents = parent_map[key]  | 
3570  | 
if parents is not None:  | 
|
3571  | 
parent_lines = [parent_cache[parent] for parent in parent_map[key]]  | 
|
3572  | 
else:  | 
|
3573  | 
parent_lines = []  | 
|
| 
3350.9.1
by Robert Collins
 Redo annotate more simply, using just the public interfaces for VersionedFiles.  | 
3574  | 
parent_cache[key] = list(  | 
3575  | 
reannotate(parent_lines, fulltext, key, None, head_cache))  | 
|
| 
3517.4.2
by Martin Pool
 Make simple-annotation and graph code more tolerant of knits with no graph  | 
3576  | 
try:  | 
3577  | 
return parent_cache[key]  | 
|
3578  | 
except KeyError, e:  | 
|
3579  | 
raise errors.RevisionNotPresent(key, self._knit)  | 
|
| 
3224.1.5
by John Arbash Meinel
 Start using a helper class for doing the knit-pack annotations.  | 
3580  | 
|
3581  | 
||
| 
2484.1.1
by John Arbash Meinel
 Add an initial function to read knit indexes in pyrex.  | 
3582  | 
try:  | 
| 
2484.1.12
by John Arbash Meinel
 Switch the layout to use a matching _knit_load_data_py.py and _knit_load_data_c.pyx  | 
3583  | 
from bzrlib._knit_load_data_c import _load_data_c as _load_data  | 
| 
2484.1.1
by John Arbash Meinel
 Add an initial function to read knit indexes in pyrex.  | 
3584  | 
except ImportError:  | 
| 
2484.1.12
by John Arbash Meinel
 Switch the layout to use a matching _knit_load_data_py.py and _knit_load_data_c.pyx  | 
3585  | 
from bzrlib._knit_load_data_py import _load_data_py as _load_data  |