1
# Copyright (C) 2005, 2006 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
4
4
# Johan Rydberg <jrydberg@gnu.org>
58
59
'bzrlib.knit', 'FTAnnotatedToUnannotated')
59
60
adapter_registry.register_lazy(('knit-annotated-ft-gz', 'fulltext'),
60
61
'bzrlib.knit', 'FTAnnotatedToFullText')
62
# adapter_registry.register_lazy(('knit-annotated-ft-gz', 'chunked'),
63
# 'bzrlib.knit', 'FTAnnotatedToChunked')
63
66
class ContentFactory(object):
83
86
self.parents = None
89
class ChunkedContentFactory(ContentFactory):
90
"""Static data content factory.
92
This takes a 'chunked' list of strings. The only requirement on 'chunked' is
93
that ''.join(lines) becomes a valid fulltext. A tuple of a single string
94
satisfies this, as does a list of lines.
96
:ivar sha1: None, or the sha1 of the content fulltext.
97
:ivar storage_kind: The native storage kind of this factory. Always
99
:ivar key: The key of this content. Each key is a tuple with a single
101
:ivar parents: A tuple of parent keys for self.key. If the object has
102
no parent information, None (as opposed to () for an empty list of
106
def __init__(self, key, parents, sha1, chunks):
107
"""Create a ContentFactory."""
109
self.storage_kind = 'chunked'
111
self.parents = parents
112
self._chunks = chunks
114
def get_bytes_as(self, storage_kind):
115
if storage_kind == 'chunked':
117
elif storage_kind == 'fulltext':
118
return ''.join(self._chunks)
119
raise errors.UnavailableRepresentation(self.key, storage_kind,
86
123
class FulltextContentFactory(ContentFactory):
87
124
"""Static data content factory.
89
126
This takes a fulltext when created and just returns that during
90
127
get_bytes_as('fulltext').
92
129
:ivar sha1: None, or the sha1 of the content fulltext.
93
130
:ivar storage_kind: The native storage kind of this factory. Always
110
147
def get_bytes_as(self, storage_kind):
111
148
if storage_kind == self.storage_kind:
112
149
return self._text
150
elif storage_kind == 'chunked':
113
152
raise errors.UnavailableRepresentation(self.key, storage_kind,
114
153
self.storage_kind)
522
561
def __init__(self, backing_vf):
523
"""Create a RecordingVersionedFileDsecorator decorating backing_vf.
562
"""Create a RecordingVersionedFilesDecorator decorating backing_vf.
525
564
:param backing_vf: The versioned file to answer all methods.
561
600
return self._backing_vf.keys()
603
class OrderingVersionedFilesDecorator(RecordingVersionedFilesDecorator):
604
"""A VF that records calls, and returns keys in specific order.
606
:ivar calls: A list of the calls made; can be reset at any time by
610
def __init__(self, backing_vf, key_priority):
611
"""Create a RecordingVersionedFilesDecorator decorating backing_vf.
613
:param backing_vf: The versioned file to answer all methods.
614
:param key_priority: A dictionary defining what order keys should be
615
returned from an 'unordered' get_record_stream request.
616
Keys with lower priority are returned first, keys not present in
617
the map get an implicit priority of 0, and are returned in
618
lexicographical order.
620
RecordingVersionedFilesDecorator.__init__(self, backing_vf)
621
self._key_priority = key_priority
623
def get_record_stream(self, keys, sort_order, include_delta_closure):
624
self.calls.append(("get_record_stream", list(keys), sort_order,
625
include_delta_closure))
626
if sort_order == 'unordered':
628
return (self._key_priority.get(key, 0), key)
629
# Use a defined order by asking for the keys one-by-one from the
631
for key in sorted(keys, key=sort_key):
632
for record in self._backing_vf.get_record_stream([key],
633
'unordered', include_delta_closure):
636
for record in self._backing_vf.get_record_stream(keys, sort_order,
637
include_delta_closure):
564
641
class KeyMapper(object):
565
642
"""KeyMappers map between keys and underlying partitioned storage."""
765
842
if not mpvf.has_version(p))
766
843
# It seems likely that adding all the present parents as fulltexts can
767
844
# easily exhaust memory.
768
split_lines = osutils.split_lines
845
chunks_to_lines = osutils.chunks_to_lines
769
846
for record in self.get_record_stream(needed_parents, 'unordered',
771
848
if record.storage_kind == 'absent':
773
mpvf.add_version(split_lines(record.get_bytes_as('fulltext')),
850
mpvf.add_version(chunks_to_lines(record.get_bytes_as('chunked')),
775
852
for (key, parent_keys, expected_sha1, mpdiff), lines in\
776
853
zip(records, mpvf.get_line_list(versions)):
847
924
raise NotImplementedError(self.get_sha1s)
926
has_key = index._has_key_from_parent_map
849
928
def insert_record_stream(self, stream):
850
929
"""Insert a record stream into this container.
899
978
ghosts = maybe_ghosts - set(self.get_parent_map(maybe_ghosts))
900
979
knit_keys.difference_update(ghosts)
902
split_lines = osutils.split_lines
981
chunks_to_lines = osutils.chunks_to_lines
903
982
for record in self.get_record_stream(knit_keys, 'topological', True):
904
lines[record.key] = split_lines(record.get_bytes_as('fulltext'))
983
lines[record.key] = chunks_to_lines(record.get_bytes_as('chunked'))
905
984
# line_block_dict = {}
906
985
# for parent, blocks in record.extract_line_blocks():
907
986
# line_blocks[parent] = blocks
922
1001
parent_lines, left_parent_blocks))
1004
missing_keys = index._missing_keys_from_parent_map
925
1006
def _extract_blocks(self, version_id, source, target):
1208
1289
lines = self._lines[key]
1209
1290
parents = self._parents[key]
1210
1291
pending.remove(key)
1211
yield FulltextContentFactory(key, parents, None,
1292
yield ChunkedContentFactory(key, parents, None, lines)
1213
1293
for versionedfile in self.fallback_versionedfiles:
1214
1294
for record in versionedfile.get_record_stream(
1215
1295
pending, 'unordered', True):
1379
1459
if lines is not None:
1380
1460
if not isinstance(lines, list):
1381
1461
raise AssertionError
1382
yield FulltextContentFactory((k,), None,
1462
yield ChunkedContentFactory((k,), None,
1383
1463
sha1=osutils.sha_strings(lines),
1384
text=''.join(lines))
1386
1466
yield AbsentContentFactory((k,))