17
17
"""Python implementation of _search_key functions, etc."""
19
from __future__ import absolute_import
24
from ..sixish import bytesintern
25
from ..static_tuple import StaticTuple
22
from bzrlib.static_tuple import StaticTuple
28
25
_InternalNode = None
33
29
# Depending on python version and platform, zlib.crc32 will return either a
34
30
# signed (<= 2.5 >= 3.0) or an unsigned (2.5, 2.6).
42
38
# Though we really don't need that 32nd bit of accuracy. (even 2**24
43
39
# is probably enough node fan out for realistic trees.)
44
return zlib.crc32(bit) & 0xFFFFFFFF
40
return zlib.crc32(bit)&0xFFFFFFFF
47
43
def _search_key_16(key):
48
44
"""Map the key tuple into a search key string which has 16-way fan out."""
49
return b'\x00'.join([b'%08X' % _crc32(bit) for bit in key])
45
return '\x00'.join(['%08X' % _crc32(bit) for bit in key])
52
48
def _search_key_255(key):
55
51
We use 255-way because '\n' is used as a delimiter, and causes problems
58
data = b'\x00'.join([struct.pack('>L', _crc32(bit)) for bit in key])
59
return data.replace(b'\n', b'_')
62
def _deserialise_leaf_node(data, key, search_key_func=None):
54
bytes = '\x00'.join([struct.pack('>L', _crc32(bit)) for bit in key])
55
return bytes.replace('\n', '_')
58
def _deserialise_leaf_node(bytes, key, search_key_func=None):
63
59
"""Deserialise bytes, with key key, into a LeafNode.
65
61
:param bytes: The bytes of the node.
68
64
global _unknown, _LeafNode, _InternalNode
69
65
if _LeafNode is None:
66
from bzrlib import chk_map
71
67
_unknown = chk_map._unknown
72
68
_LeafNode = chk_map.LeafNode
73
69
_InternalNode = chk_map.InternalNode
74
70
result = _LeafNode(search_key_func=search_key_func)
75
71
# Splitlines can split on '\r' so don't use it, split('\n') adds an
76
72
# extra '' if the bytes ends in a final newline.
77
lines = data.split(b'\n')
73
lines = bytes.split('\n')
78
74
trailing = lines.pop()
80
76
raise AssertionError('We did not have a final newline for %s'
83
if lines[0] != b'chkleaf:':
79
if lines[0] != 'chkleaf:':
84
80
raise ValueError("not a serialised leaf node: %r" % bytes)
85
81
maximum_size = int(lines[1])
86
82
width = int(lines[2])
90
86
while pos < len(lines):
91
87
line = prefix + lines[pos]
92
elements = line.split(b'\x00')
88
elements = line.split('\x00')
94
90
if len(elements) != width + 1:
95
91
raise AssertionError(
96
92
'Incorrect number of elements (%d vs %d) for: %r'
97
93
% (len(elements), width + 1, line))
98
94
num_value_lines = int(elements[-1])
99
value_lines = lines[pos:pos + num_value_lines]
95
value_lines = lines[pos:pos+num_value_lines]
100
96
pos += num_value_lines
101
value = b'\n'.join(value_lines)
97
value = '\n'.join(value_lines)
102
98
items[StaticTuple.from_sequence(elements[:-1])] = value
103
99
if len(items) != length:
104
100
raise AssertionError("item count (%d) mismatch for key %s,"
105
" bytes %r" % (length, key, bytes))
101
" bytes %r" % (length, key, bytes))
106
102
result._items = items
107
103
result._len = length
108
104
result._maximum_size = maximum_size
109
105
result._key = key
110
106
result._key_width = width
111
result._raw_size = (sum(map(len, lines[5:])) # the length of the suffix
112
+ (length) * (len(prefix))
107
result._raw_size = (sum(map(len, lines[5:])) # the length of the suffix
108
+ (length)*(len(prefix))
115
111
result._search_prefix = None
116
112
result._common_serialised_prefix = None
118
114
result._search_prefix = _unknown
119
115
result._common_serialised_prefix = prefix
120
if len(data) != result._current_size():
116
if len(bytes) != result._current_size():
121
117
raise AssertionError('_current_size computed incorrectly')
125
def _deserialise_internal_node(data, key, search_key_func=None):
121
def _deserialise_internal_node(bytes, key, search_key_func=None):
126
122
global _unknown, _LeafNode, _InternalNode
127
123
if _InternalNode is None:
128
from . import chk_map
124
from bzrlib import chk_map
129
125
_unknown = chk_map._unknown
130
126
_LeafNode = chk_map.LeafNode
131
127
_InternalNode = chk_map.InternalNode
133
129
# Splitlines can split on '\r' so don't use it, remove the extra ''
134
130
# from the result of split('\n') because we should have a trailing
136
lines = data.split(b'\n')
132
lines = bytes.split('\n')
138
134
raise ValueError("last line must be ''")
141
if lines[0] != b'chknode:':
137
if lines[0] != 'chknode:':
142
138
raise ValueError("not a serialised internal node: %r" % bytes)
143
139
maximum_size = int(lines[1])
144
140
width = int(lines[2])
146
142
common_prefix = lines[4]
147
143
for line in lines[5:]:
148
144
line = common_prefix + line
149
prefix, flat_key = line.rsplit(b'\x00', 1)
145
prefix, flat_key = line.rsplit('\x00', 1)
150
146
items[prefix] = StaticTuple(flat_key,)
151
147
if len(items) == 0:
152
148
raise AssertionError("We didn't find any item for %s" % key)
157
153
result._key_width = width
158
154
# XXX: InternalNodes don't really care about their size, and this will
159
155
# change if we add prefix compression
160
result._raw_size = None # len(bytes)
156
result._raw_size = None # len(bytes)
161
157
result._node_width = len(prefix)
162
158
result._search_prefix = common_prefix
166
def _bytes_to_text_key(data):
167
"""Take a CHKInventory value string and return a (file_id, rev_id) tuple"""
168
sections = data.split(b'\n')
169
kind, file_id = sections[0].split(b': ')
170
return (bytesintern(file_id), bytesintern(sections[3]))