878
874
chkmap._dump_tree())
879
875
# Save everything to the map, and start over
880
876
chkmap = CHKMap(store, chkmap._save())
881
chkmap.map((b'aac',), b'v')
882
chkmap.map((b'aad',), b'v')
883
chkmap.map((b'aae',), b'v')
884
chkmap.map((b'aaf',), b'v')
877
chkmap.map(('aac',), 'v')
878
chkmap.map(('aad',), 'v')
879
chkmap.map(('aae',), 'v')
880
chkmap.map(('aaf',), 'v')
885
881
# At this point, the previous nodes should not be paged in, but the
886
882
# newly added nodes would be
887
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
888
self.assertIsInstance(chkmap._root_node._items[b'aab'], StaticTuple)
889
self.assertIsInstance(chkmap._root_node._items[b'aac'], LeafNode)
890
self.assertIsInstance(chkmap._root_node._items[b'aad'], LeafNode)
891
self.assertIsInstance(chkmap._root_node._items[b'aae'], LeafNode)
892
self.assertIsInstance(chkmap._root_node._items[b'aaf'], LeafNode)
883
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
884
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
885
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
886
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
887
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
888
self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
893
889
# Now unmapping one of the new nodes will use only the already-paged-in
894
890
# nodes to determine that we don't need to do more.
895
chkmap.unmap((b'aaf',))
896
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
897
self.assertIsInstance(chkmap._root_node._items[b'aab'], StaticTuple)
898
self.assertIsInstance(chkmap._root_node._items[b'aac'], LeafNode)
899
self.assertIsInstance(chkmap._root_node._items[b'aad'], LeafNode)
900
self.assertIsInstance(chkmap._root_node._items[b'aae'], LeafNode)
891
chkmap.unmap(('aaf',))
892
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
893
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
894
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
895
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
896
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
902
898
def test_unmap_pages_in_if_necessary(self):
903
899
store = self.get_chk_bytes()
904
900
chkmap = CHKMap(store, None)
905
901
# Should fit 2 keys per LeafNode
906
902
chkmap._root_node.set_maximum_size(30)
907
chkmap.map((b'aaa',), b'val')
908
chkmap.map((b'aab',), b'val')
909
chkmap.map((b'aac',), b'val')
903
chkmap.map(('aaa',), 'val')
904
chkmap.map(('aab',), 'val')
905
chkmap.map(('aac',), 'val')
910
906
self.assertEqualDiff("'' InternalNode\n"
911
907
" 'aaa' LeafNode\n"
912
908
" ('aaa',) 'val'\n"
918
914
root_key = chkmap._save()
919
915
# Save everything to the map, and start over
920
916
chkmap = CHKMap(store, root_key)
921
chkmap.map((b'aad',), b'v')
917
chkmap.map(('aad',), 'v')
922
918
# At this point, the previous nodes should not be paged in, but the
923
919
# newly added node would be
924
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
925
self.assertIsInstance(chkmap._root_node._items[b'aab'], StaticTuple)
926
self.assertIsInstance(chkmap._root_node._items[b'aac'], StaticTuple)
927
self.assertIsInstance(chkmap._root_node._items[b'aad'], LeafNode)
920
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
921
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
922
self.assertIsInstance(chkmap._root_node._items['aac'], StaticTuple)
923
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
928
924
# Unmapping the new node will check the existing nodes to see if they
930
926
# Clear the page cache so we ensure we have to read all the children
931
927
chk_map.clear_cache()
932
chkmap.unmap((b'aad',))
933
self.assertIsInstance(chkmap._root_node._items[b'aaa'], LeafNode)
934
self.assertIsInstance(chkmap._root_node._items[b'aab'], LeafNode)
935
self.assertIsInstance(chkmap._root_node._items[b'aac'], LeafNode)
928
chkmap.unmap(('aad',))
929
self.assertIsInstance(chkmap._root_node._items['aaa'], LeafNode)
930
self.assertIsInstance(chkmap._root_node._items['aab'], LeafNode)
931
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
937
933
def test_unmap_pages_in_from_page_cache(self):
938
934
store = self.get_chk_bytes()
939
935
chkmap = CHKMap(store, None)
940
936
# Should fit 2 keys per LeafNode
941
937
chkmap._root_node.set_maximum_size(30)
942
chkmap.map((b'aaa',), b'val')
943
chkmap.map((b'aab',), b'val')
944
chkmap.map((b'aac',), b'val')
938
chkmap.map(('aaa',), 'val')
939
chkmap.map(('aab',), 'val')
940
chkmap.map(('aac',), 'val')
945
941
root_key = chkmap._save()
946
942
# Save everything to the map, and start over
947
943
chkmap = CHKMap(store, root_key)
948
chkmap.map((b'aad',), b'val')
944
chkmap.map(('aad',), 'val')
949
945
self.assertEqualDiff("'' InternalNode\n"
950
946
" 'aaa' LeafNode\n"
951
947
" ('aaa',) 'val'\n"
978
974
# Unmapping the new node will check the nodes from the page cache
979
975
# first, and not have to read in 'aaa'
980
chkmap.unmap((b'aad',))
981
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
982
self.assertIsInstance(chkmap._root_node._items[b'aab'], LeafNode)
983
self.assertIsInstance(chkmap._root_node._items[b'aac'], LeafNode)
976
chkmap.unmap(('aad',))
977
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
978
self.assertIsInstance(chkmap._root_node._items['aab'], LeafNode)
979
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
985
981
def test_unmap_uses_existing_items(self):
986
982
store = self.get_chk_bytes()
987
983
chkmap = CHKMap(store, None)
988
984
# Should fit 2 keys per LeafNode
989
985
chkmap._root_node.set_maximum_size(30)
990
chkmap.map((b'aaa',), b'val')
991
chkmap.map((b'aab',), b'val')
992
chkmap.map((b'aac',), b'val')
986
chkmap.map(('aaa',), 'val')
987
chkmap.map(('aab',), 'val')
988
chkmap.map(('aac',), 'val')
993
989
root_key = chkmap._save()
994
990
# Save everything to the map, and start over
995
991
chkmap = CHKMap(store, root_key)
996
chkmap.map((b'aad',), b'val')
997
chkmap.map((b'aae',), b'val')
998
chkmap.map((b'aaf',), b'val')
992
chkmap.map(('aad',), 'val')
993
chkmap.map(('aae',), 'val')
994
chkmap.map(('aaf',), 'val')
999
995
# At this point, the previous nodes should not be paged in, but the
1000
996
# newly added node would be
1001
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
1002
self.assertIsInstance(chkmap._root_node._items[b'aab'], StaticTuple)
1003
self.assertIsInstance(chkmap._root_node._items[b'aac'], StaticTuple)
1004
self.assertIsInstance(chkmap._root_node._items[b'aad'], LeafNode)
1005
self.assertIsInstance(chkmap._root_node._items[b'aae'], LeafNode)
1006
self.assertIsInstance(chkmap._root_node._items[b'aaf'], LeafNode)
997
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
998
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
999
self.assertIsInstance(chkmap._root_node._items['aac'], StaticTuple)
1000
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
1001
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
1002
self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
1008
1004
# Unmapping a new node will see the other nodes that are already in
1009
1005
# memory, and not need to page in anything else
1010
chkmap.unmap((b'aad',))
1011
self.assertIsInstance(chkmap._root_node._items[b'aaa'], StaticTuple)
1012
self.assertIsInstance(chkmap._root_node._items[b'aab'], StaticTuple)
1013
self.assertIsInstance(chkmap._root_node._items[b'aac'], StaticTuple)
1014
self.assertIsInstance(chkmap._root_node._items[b'aae'], LeafNode)
1015
self.assertIsInstance(chkmap._root_node._items[b'aaf'], LeafNode)
1006
chkmap.unmap(('aad',))
1007
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
1008
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
1009
self.assertIsInstance(chkmap._root_node._items['aac'], StaticTuple)
1010
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
1011
self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
1017
1013
def test_iter_changes_empty_ab(self):
1018
1014
# Asking for changes between an empty dict to a dict with keys returns
1019
1015
# all the keys.
1020
1016
basis = self._get_map({}, maximum_size=10)
1021
1017
target = self._get_map(
1022
{(b'a',): b'content here', (b'b',): b'more content'},
1018
{('a',): 'content here', ('b',): 'more content'},
1023
1019
chk_bytes=basis._store, maximum_size=10)
1024
self.assertEqual([((b'a',), None, b'content here'),
1025
((b'b',), None, b'more content')],
1026
sorted(list(target.iter_changes(basis))))
1020
self.assertEqual([(('a',), None, 'content here'),
1021
(('b',), None, 'more content')],
1022
sorted(list(target.iter_changes(basis))))
1028
1024
def test_iter_changes_ab_empty(self):
1029
1025
# Asking for changes between a dict with keys to an empty dict returns
1030
1026
# all the keys.
1031
basis = self._get_map({(b'a',): b'content here', (b'b',): b'more content'},
1027
basis = self._get_map({('a',): 'content here', ('b',): 'more content'},
1033
1029
target = self._get_map({}, chk_bytes=basis._store, maximum_size=10)
1034
self.assertEqual([((b'a',), b'content here', None),
1035
((b'b',), b'more content', None)],
1036
sorted(list(target.iter_changes(basis))))
1030
self.assertEqual([(('a',), 'content here', None),
1031
(('b',), 'more content', None)],
1032
sorted(list(target.iter_changes(basis))))
1038
1034
def test_iter_changes_empty_empty_is_empty(self):
1039
1035
basis = self._get_map({}, maximum_size=10)
1104
1100
# aaa to be not loaded
1105
1101
# aaa not to be in result.
1106
basis_dict = {(b'aaa',): b'foo bar',
1107
(b'aab',): b'common altered a', (b'b',): b'foo bar b'}
1102
basis_dict = {('aaa',): 'foo bar',
1103
('aab',): 'common altered a', ('b',): 'foo bar b'}
1108
1104
# target splits at byte 1, at is target only
1109
target_dict = {(b'aaa',): b'foo bar',
1110
(b'aab',): b'common altered b', (b'at',): b'foo bar t'}
1105
target_dict = {('aaa',): 'foo bar',
1106
('aab',): 'common altered b', ('at',): 'foo bar t'}
1111
1107
basis = self._get_map(basis_dict, maximum_size=10)
1112
1108
target = self._get_map(target_dict, maximum_size=10,
1113
chk_bytes=basis._store)
1109
chk_bytes=basis._store)
1114
1110
basis_get = basis._store.get_record_stream
1116
1111
def get_record_stream(keys, order, fulltext):
1117
if (b'sha1:1adf7c0d1b9140ab5f33bb64c6275fa78b1580b7',) in keys:
1112
if ('sha1:1adf7c0d1b9140ab5f33bb64c6275fa78b1580b7',) in keys:
1118
1113
raise AssertionError("'aaa' pointer was followed %r" % keys)
1119
1114
return basis_get(keys, order, fulltext)
1120
1115
basis._store.get_record_stream = get_record_stream
1121
1116
result = sorted(list(target.iter_changes(basis)))
1122
1117
for change in result:
1123
if change[0] == (b'aaa',):
1118
if change[0] == ('aaa',):
1124
1119
self.fail("Found unexpected change: %s" % change)
1126
1121
def test_iter_changes_unchanged_keys_in_multi_key_leafs_ignored(self):
1127
1122
# Within a leaf there are no hash's to exclude keys, make sure multi
1128
1123
# value leaf nodes are handled well.
1129
basis_dict = {(b'aaa',): b'foo bar',
1130
(b'aab',): b'common altered a', (b'b',): b'foo bar b'}
1131
target_dict = {(b'aaa',): b'foo bar',
1132
(b'aab',): b'common altered b', (b'at',): b'foo bar t'}
1124
basis_dict = {('aaa',): 'foo bar',
1125
('aab',): 'common altered a', ('b',): 'foo bar b'}
1126
target_dict = {('aaa',): 'foo bar',
1127
('aab',): 'common altered b', ('at',): 'foo bar t'}
1134
((b'aab',), b'common altered a', b'common altered b'),
1135
((b'at',), None, b'foo bar t'),
1136
((b'b',), b'foo bar b', None),
1129
(('aab',), 'common altered a', 'common altered b'),
1130
(('at',), None, 'foo bar t'),
1131
(('b',), 'foo bar b', None),
1138
1133
basis = self._get_map(basis_dict)
1139
1134
target = self._get_map(target_dict, chk_bytes=basis._store)
1148
1143
def test_iteritems_two_items(self):
1149
1144
chk_bytes = self.get_chk_bytes()
1150
1145
root_key = CHKMap.from_dict(chk_bytes,
1151
{(b"a", ): b"content here", (b"b", ): b"more content"})
1146
{"a":"content here", "b":"more content"})
1152
1147
chkmap = CHKMap(chk_bytes, root_key)
1153
self.assertEqual([((b"a",), b"content here"), ((b"b",), b"more content")],
1154
sorted(list(chkmap.iteritems())))
1148
self.assertEqual([(("a",), "content here"), (("b",), "more content")],
1149
sorted(list(chkmap.iteritems())))
1156
1151
def test_iteritems_selected_one_of_two_items(self):
1157
chkmap = self._get_map(
1158
{(b"a",): b"content here", (b"b",): b"more content"})
1159
self.assertEqual({(b"a",): b"content here"},
1160
self.to_dict(chkmap, [(b"a",)]))
1152
chkmap = self._get_map( {("a",):"content here", ("b",):"more content"})
1153
self.assertEqual({("a",): "content here"},
1154
self.to_dict(chkmap, [("a",)]))
1162
1156
def test_iteritems_keys_prefixed_by_2_width_nodes(self):
1163
1157
chkmap = self._get_map(
1164
{(b"a", b"a"): b"content here", (b"a", b"b",): b"more content",
1165
(b"b", b""): b'boring content'},
1158
{("a","a"):"content here", ("a", "b",):"more content",
1159
("b", ""): 'boring content'},
1166
1160
maximum_size=10, key_width=2)
1167
1161
self.assertEqual(
1168
{(b"a", b"a"): b"content here", (b"a", b"b"): b'more content'},
1169
self.to_dict(chkmap, [(b"a",)]))
1162
{("a", "a"): "content here", ("a", "b"): 'more content'},
1163
self.to_dict(chkmap, [("a",)]))
1171
1165
def test_iteritems_keys_prefixed_by_2_width_nodes_hashed(self):
1172
search_key_func = chk_map.search_key_registry.get(b'hash-16-way')
1173
self.assertEqual(b'E8B7BE43\x00E8B7BE43',
1174
search_key_func(StaticTuple(b'a', b'a')))
1175
self.assertEqual(b'E8B7BE43\x0071BEEFF9',
1176
search_key_func(StaticTuple(b'a', b'b')))
1177
self.assertEqual(b'71BEEFF9\x0000000000',
1178
search_key_func(StaticTuple(b'b', b'')))
1166
search_key_func = chk_map.search_key_registry.get('hash-16-way')
1167
self.assertEqual('E8B7BE43\x00E8B7BE43',
1168
search_key_func(StaticTuple('a', 'a')))
1169
self.assertEqual('E8B7BE43\x0071BEEFF9',
1170
search_key_func(StaticTuple('a', 'b')))
1171
self.assertEqual('71BEEFF9\x0000000000',
1172
search_key_func(StaticTuple('b', '')))
1179
1173
chkmap = self._get_map(
1180
{(b"a", b"a"): b"content here", (b"a", b"b",): b"more content",
1181
(b"b", b""): b'boring content'},
1174
{("a","a"):"content here", ("a", "b",):"more content",
1175
("b", ""): 'boring content'},
1182
1176
maximum_size=10, key_width=2, search_key_func=search_key_func)
1183
1177
self.assertEqual(
1184
{(b"a", b"a"): b"content here", (b"a", b"b"): b'more content'},
1185
self.to_dict(chkmap, [(b"a",)]))
1178
{("a", "a"): "content here", ("a", "b"): 'more content'},
1179
self.to_dict(chkmap, [("a",)]))
1187
1181
def test_iteritems_keys_prefixed_by_2_width_one_leaf(self):
1188
1182
chkmap = self._get_map(
1189
{(b"a", b"a"): b"content here", (b"a", b"b",): b"more content",
1190
(b"b", b""): b'boring content'}, key_width=2)
1183
{("a","a"):"content here", ("a", "b",):"more content",
1184
("b", ""): 'boring content'}, key_width=2)
1191
1185
self.assertEqual(
1192
{(b"a", b"a"): b"content here", (b"a", b"b"): b'more content'},
1193
self.to_dict(chkmap, [(b"a",)]))
1186
{("a", "a"): "content here", ("a", "b"): 'more content'},
1187
self.to_dict(chkmap, [("a",)]))
1195
1189
def test___len__empty(self):
1196
1190
chkmap = self._get_map({})
1197
1191
self.assertEqual(0, len(chkmap))
1199
1193
def test___len__2(self):
1200
chkmap = self._get_map({(b"foo",): b"bar", (b"gam",): b"quux"})
1194
chkmap = self._get_map({("foo",):"bar", ("gam",):"quux"})
1201
1195
self.assertEqual(2, len(chkmap))
1203
1197
def test_max_size_100_bytes_new(self):
1204
1198
# When there is a 100 byte upper node limit, a tree is formed.
1205
chkmap = self._get_map(
1206
{(b"k1" * 50,): b"v1", (b"k2" * 50,): b"v2"}, maximum_size=100)
1199
chkmap = self._get_map({("k1"*50,):"v1", ("k2"*50,):"v2"}, maximum_size=100)
1207
1200
# We expect three nodes:
1208
1201
# A root, with two children, and with two key prefixes - k1 to one, and
1209
1202
# k2 to the other as our node splitting is only just being developed.
1402
1391
" 'test:2' LeafNode\n"
1403
1392
" ('2',) 'bar'\n"
1404
1393
" 'test:3' LeafNode\n"
1405
" ('3',) 'baz'\n", chkmap._dump_tree())
1395
, chkmap._dump_tree())
1407
1397
def test_search_key_16(self):
1408
1398
chk_bytes = self.get_chk_bytes()
1409
1399
chkmap = chk_map.CHKMap(chk_bytes, None,
1410
1400
search_key_func=chk_map._search_key_16)
1411
1401
chkmap._root_node.set_maximum_size(10)
1412
chkmap.map((b'1',), b'foo')
1413
chkmap.map((b'2',), b'bar')
1414
chkmap.map((b'3',), b'baz')
1402
chkmap.map(('1',), 'foo')
1403
chkmap.map(('2',), 'bar')
1404
chkmap.map(('3',), 'baz')
1415
1405
self.assertEqualDiff("'' InternalNode\n"
1416
1406
" '1' LeafNode\n"
1417
1407
" ('2',) 'bar'\n"
1418
1408
" '6' LeafNode\n"
1419
1409
" ('3',) 'baz'\n"
1420
1410
" '8' LeafNode\n"
1421
" ('1',) 'foo'\n", chkmap._dump_tree())
1412
, chkmap._dump_tree())
1422
1413
root_key = chkmap._save()
1423
1414
chkmap = chk_map.CHKMap(chk_bytes, root_key,
1424
1415
search_key_func=chk_map._search_key_16)
1425
1416
# We can get the values back correctly
1426
self.assertEqual([((b'1',), b'foo')],
1427
list(chkmap.iteritems([(b'1',)])))
1417
self.assertEqual([(('1',), 'foo')],
1418
list(chkmap.iteritems([('1',)])))
1428
1419
self.assertEqualDiff("'' InternalNode\n"
1429
1420
" '1' LeafNode\n"
1430
1421
" ('2',) 'bar'\n"
1431
1422
" '6' LeafNode\n"
1432
1423
" ('3',) 'baz'\n"
1433
1424
" '8' LeafNode\n"
1434
" ('1',) 'foo'\n", chkmap._dump_tree())
1426
, chkmap._dump_tree())
1436
1428
def test_search_key_255(self):
1437
1429
chk_bytes = self.get_chk_bytes()
1438
1430
chkmap = chk_map.CHKMap(chk_bytes, None,
1439
1431
search_key_func=chk_map._search_key_255)
1440
1432
chkmap._root_node.set_maximum_size(10)
1441
chkmap.map((b'1',), b'foo')
1442
chkmap.map((b'2',), b'bar')
1443
chkmap.map((b'3',), b'baz')
1433
chkmap.map(('1',), 'foo')
1434
chkmap.map(('2',), 'bar')
1435
chkmap.map(('3',), 'baz')
1444
1436
self.assertEqualDiff("'' InternalNode\n"
1445
1437
" '\\x1a' LeafNode\n"
1446
1438
" ('2',) 'bar'\n"
1447
1439
" 'm' LeafNode\n"
1448
1440
" ('3',) 'baz'\n"
1449
1441
" '\\x83' LeafNode\n"
1450
" ('1',) 'foo'\n", chkmap._dump_tree(encoding='latin1'))
1443
, chkmap._dump_tree())
1451
1444
root_key = chkmap._save()
1452
1445
chkmap = chk_map.CHKMap(chk_bytes, root_key,
1453
1446
search_key_func=chk_map._search_key_255)
1454
1447
# We can get the values back correctly
1455
self.assertEqual([((b'1',), b'foo')],
1456
list(chkmap.iteritems([(b'1',)])))
1448
self.assertEqual([(('1',), 'foo')],
1449
list(chkmap.iteritems([('1',)])))
1457
1450
self.assertEqualDiff("'' InternalNode\n"
1458
1451
" '\\x1a' LeafNode\n"
1459
1452
" ('2',) 'bar'\n"
1460
1453
" 'm' LeafNode\n"
1461
1454
" ('3',) 'baz'\n"
1462
1455
" '\\x83' LeafNode\n"
1463
" ('1',) 'foo'\n", chkmap._dump_tree(encoding='latin1'))
1457
, chkmap._dump_tree())
1465
1459
def test_search_key_collisions(self):
1466
1460
chkmap = chk_map.CHKMap(self.get_chk_bytes(), None,
1496
1491
def test_current_size_items(self):
1497
1492
node = LeafNode()
1498
1493
base_size = node._current_size()
1499
node.map(None, (b"foo bar",), b"baz")
1494
node.map(None, ("foo bar",), "baz")
1500
1495
self.assertEqual(base_size + 14, node._current_size())
1502
1497
def test_deserialise_empty(self):
1503
node = LeafNode.deserialise(b"chkleaf:\n10\n1\n0\n\n", (b"sha1:1234",))
1498
node = LeafNode.deserialise("chkleaf:\n10\n1\n0\n\n", ("sha1:1234",))
1504
1499
self.assertEqual(0, len(node))
1505
1500
self.assertEqual(10, node.maximum_size)
1506
self.assertEqual((b"sha1:1234",), node.key())
1501
self.assertEqual(("sha1:1234",), node.key())
1507
1502
self.assertIs(None, node._search_prefix)
1508
1503
self.assertIs(None, node._common_serialised_prefix)
1510
1505
def test_deserialise_items(self):
1511
1506
node = LeafNode.deserialise(
1512
b"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1507
"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1514
1509
self.assertEqual(2, len(node))
1515
self.assertEqual([((b"foo bar",), b"baz"), ((b"quux",), b"blarh")],
1516
sorted(node.iteritems(None)))
1510
self.assertEqual([(("foo bar",), "baz"), (("quux",), "blarh")],
1511
sorted(node.iteritems(None)))
1518
1513
def test_deserialise_item_with_null_width_1(self):
1519
1514
node = LeafNode.deserialise(
1520
b"chkleaf:\n0\n1\n2\n\nfoo\x001\nbar\x00baz\nquux\x001\nblarh\n",
1515
"chkleaf:\n0\n1\n2\n\nfoo\x001\nbar\x00baz\nquux\x001\nblarh\n",
1522
1517
self.assertEqual(2, len(node))
1523
self.assertEqual([((b"foo",), b"bar\x00baz"), ((b"quux",), b"blarh")],
1524
sorted(node.iteritems(None)))
1518
self.assertEqual([(("foo",), "bar\x00baz"), (("quux",), "blarh")],
1519
sorted(node.iteritems(None)))
1526
1521
def test_deserialise_item_with_null_width_2(self):
1527
1522
node = LeafNode.deserialise(
1528
b"chkleaf:\n0\n2\n2\n\nfoo\x001\x001\nbar\x00baz\n"
1529
b"quux\x00\x001\nblarh\n",
1523
"chkleaf:\n0\n2\n2\n\nfoo\x001\x001\nbar\x00baz\n"
1524
"quux\x00\x001\nblarh\n",
1531
1526
self.assertEqual(2, len(node))
1532
self.assertEqual([((b"foo", b"1"), b"bar\x00baz"), ((b"quux", b""), b"blarh")],
1533
sorted(node.iteritems(None)))
1527
self.assertEqual([(("foo", "1"), "bar\x00baz"), (("quux", ""), "blarh")],
1528
sorted(node.iteritems(None)))
1535
1530
def test_iteritems_selected_one_of_two_items(self):
1536
1531
node = LeafNode.deserialise(
1537
b"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1532
"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1539
1534
self.assertEqual(2, len(node))
1540
self.assertEqual([((b"quux",), b"blarh")],
1541
sorted(node.iteritems(None, [(b"quux",), (b"qaz",)])))
1535
self.assertEqual([(("quux",), "blarh")],
1536
sorted(node.iteritems(None, [("quux",), ("qaz",)])))
1543
1538
def test_deserialise_item_with_common_prefix(self):
1544
1539
node = LeafNode.deserialise(
1545
b"chkleaf:\n0\n2\n2\nfoo\x00\n1\x001\nbar\x00baz\n2\x001\nblarh\n",
1540
"chkleaf:\n0\n2\n2\nfoo\x00\n1\x001\nbar\x00baz\n2\x001\nblarh\n",
1547
1542
self.assertEqual(2, len(node))
1548
self.assertEqual([((b"foo", b"1"), b"bar\x00baz"), ((b"foo", b"2"), b"blarh")],
1549
sorted(node.iteritems(None)))
1543
self.assertEqual([(("foo", "1"), "bar\x00baz"), (("foo", "2"), "blarh")],
1544
sorted(node.iteritems(None)))
1550
1545
self.assertIs(chk_map._unknown, node._search_prefix)
1551
self.assertEqual(b'foo\x00', node._common_serialised_prefix)
1546
self.assertEqual('foo\x00', node._common_serialised_prefix)
1553
1548
def test_deserialise_multi_line(self):
1554
1549
node = LeafNode.deserialise(
1555
b"chkleaf:\n0\n2\n2\nfoo\x00\n1\x002\nbar\nbaz\n2\x002\nblarh\n\n",
1550
"chkleaf:\n0\n2\n2\nfoo\x00\n1\x002\nbar\nbaz\n2\x002\nblarh\n\n",
1557
1552
self.assertEqual(2, len(node))
1558
self.assertEqual([((b"foo", b"1"), b"bar\nbaz"),
1559
((b"foo", b"2"), b"blarh\n"),
1560
], sorted(node.iteritems(None)))
1553
self.assertEqual([(("foo", "1"), "bar\nbaz"),
1554
(("foo", "2"), "blarh\n"),
1555
], sorted(node.iteritems(None)))
1561
1556
self.assertIs(chk_map._unknown, node._search_prefix)
1562
self.assertEqual(b'foo\x00', node._common_serialised_prefix)
1557
self.assertEqual('foo\x00', node._common_serialised_prefix)
1564
1559
def test_key_new(self):
1565
1560
node = LeafNode()
1566
1561
self.assertEqual(None, node.key())
1568
1563
def test_key_after_map(self):
1569
node = LeafNode.deserialise(b"chkleaf:\n10\n1\n0\n\n", (b"sha1:1234",))
1570
node.map(None, (b"foo bar",), b"baz quux")
1564
node = LeafNode.deserialise("chkleaf:\n10\n1\n0\n\n", ("sha1:1234",))
1565
node.map(None, ("foo bar",), "baz quux")
1571
1566
self.assertEqual(None, node.key())
1573
1568
def test_key_after_unmap(self):
1574
1569
node = LeafNode.deserialise(
1575
b"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1577
node.unmap(None, (b"foo bar",))
1570
"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1572
node.unmap(None, ("foo bar",))
1578
1573
self.assertEqual(None, node.key())
1580
1575
def test_map_exceeding_max_size_only_entry_new(self):
1581
1576
node = LeafNode()
1582
1577
node.set_maximum_size(10)
1583
result = node.map(None, (b"foo bar",), b"baz quux")
1584
self.assertEqual((b"foo bar", [(b"", node)]), result)
1578
result = node.map(None, ("foo bar",), "baz quux")
1579
self.assertEqual(("foo bar", [("", node)]), result)
1585
1580
self.assertTrue(10 < node._current_size())
1587
1582
def test_map_exceeding_max_size_second_entry_early_difference_new(self):
1588
1583
node = LeafNode()
1589
1584
node.set_maximum_size(10)
1590
node.map(None, (b"foo bar",), b"baz quux")
1591
prefix, result = list(node.map(None, (b"blue",), b"red"))
1592
self.assertEqual(b"", prefix)
1585
node.map(None, ("foo bar",), "baz quux")
1586
prefix, result = list(node.map(None, ("blue",), "red"))
1587
self.assertEqual("", prefix)
1593
1588
self.assertEqual(2, len(result))
1594
1589
split_chars = {result[0][0], result[1][0]}
1595
self.assertEqual({b"f", b"b"}, split_chars)
1590
self.assertEqual({"f", "b"}, split_chars)
1596
1591
nodes = dict(result)
1598
self.assertEqual({(b"foo bar",): b"baz quux"},
1599
self.to_dict(node, None))
1593
self.assertEqual({("foo bar",): "baz quux"}, self.to_dict(node, None))
1600
1594
self.assertEqual(10, node.maximum_size)
1601
1595
self.assertEqual(1, node._key_width)
1603
self.assertEqual({(b"blue",): b"red"}, self.to_dict(node, None))
1597
self.assertEqual({("blue",): "red"}, self.to_dict(node, None))
1604
1598
self.assertEqual(10, node.maximum_size)
1605
1599
self.assertEqual(1, node._key_width)
1607
1601
def test_map_first(self):
1608
1602
node = LeafNode()
1609
result = node.map(None, (b"foo bar",), b"baz quux")
1610
self.assertEqual((b"foo bar", [(b"", node)]), result)
1611
self.assertEqual({(b"foo bar",): b"baz quux"},
1612
self.to_dict(node, None))
1603
result = node.map(None, ("foo bar",), "baz quux")
1604
self.assertEqual(("foo bar", [("", node)]), result)
1605
self.assertEqual({("foo bar",):"baz quux"}, self.to_dict(node, None))
1613
1606
self.assertEqual(1, len(node))
1615
1608
def test_map_second(self):
1616
1609
node = LeafNode()
1617
node.map(None, (b"foo bar",), b"baz quux")
1618
result = node.map(None, (b"bingo",), b"bango")
1619
self.assertEqual((b"", [(b"", node)]), result)
1620
self.assertEqual({(b"foo bar",): b"baz quux", (b"bingo",): b"bango"},
1621
self.to_dict(node, None))
1610
node.map(None, ("foo bar",), "baz quux")
1611
result = node.map(None, ("bingo",), "bango")
1612
self.assertEqual(("", [("", node)]), result)
1613
self.assertEqual({("foo bar",):"baz quux", ("bingo",):"bango"},
1614
self.to_dict(node, None))
1622
1615
self.assertEqual(2, len(node))
1624
1617
def test_map_replacement(self):
1625
1618
node = LeafNode()
1626
node.map(None, (b"foo bar",), b"baz quux")
1627
result = node.map(None, (b"foo bar",), b"bango")
1628
self.assertEqual((b"foo bar", [(b"", node)]), result)
1629
self.assertEqual({(b"foo bar",): b"bango"},
1630
self.to_dict(node, None))
1619
node.map(None, ("foo bar",), "baz quux")
1620
result = node.map(None, ("foo bar",), "bango")
1621
self.assertEqual(("foo bar", [("", node)]), result)
1622
self.assertEqual({("foo bar",): "bango"},
1623
self.to_dict(node, None))
1631
1624
self.assertEqual(1, len(node))
1633
1626
def test_serialise_empty(self):
1634
1627
store = self.get_chk_bytes()
1635
1628
node = LeafNode()
1636
1629
node.set_maximum_size(10)
1637
expected_key = (b"sha1:f34c3f0634ea3f85953dffa887620c0a5b1f4a51",)
1630
expected_key = ("sha1:f34c3f0634ea3f85953dffa887620c0a5b1f4a51",)
1638
1631
self.assertEqual([expected_key],
1639
list(node.serialise(store)))
1640
self.assertEqual(b"chkleaf:\n10\n1\n0\n\n",
1641
self.read_bytes(store, expected_key))
1632
list(node.serialise(store)))
1633
self.assertEqual("chkleaf:\n10\n1\n0\n\n", self.read_bytes(store, expected_key))
1642
1634
self.assertEqual(expected_key, node.key())
1644
1636
def test_serialise_items(self):
1645
1637
store = self.get_chk_bytes()
1646
1638
node = LeafNode()
1647
1639
node.set_maximum_size(10)
1648
node.map(None, (b"foo bar",), b"baz quux")
1649
expected_key = (b"sha1:f89fac7edfc6bdb1b1b54a556012ff0c646ef5e0",)
1650
self.assertEqual(b'foo bar', node._common_serialised_prefix)
1640
node.map(None, ("foo bar",), "baz quux")
1641
expected_key = ("sha1:f89fac7edfc6bdb1b1b54a556012ff0c646ef5e0",)
1642
self.assertEqual('foo bar', node._common_serialised_prefix)
1651
1643
self.assertEqual([expected_key],
1652
list(node.serialise(store)))
1653
self.assertEqual(b"chkleaf:\n10\n1\n1\nfoo bar\n\x001\nbaz quux\n",
1654
self.read_bytes(store, expected_key))
1644
list(node.serialise(store)))
1645
self.assertEqual("chkleaf:\n10\n1\n1\nfoo bar\n\x001\nbaz quux\n",
1646
self.read_bytes(store, expected_key))
1655
1647
self.assertEqual(expected_key, node.key())
1657
1649
def test_unique_serialised_prefix_empty_new(self):
1678
1670
def test_map_maintains_common_prefixes(self):
1679
1671
node = LeafNode()
1680
1672
node._key_width = 2
1681
node.map(None, (b"foo bar", b"baz"), b"baz quux")
1682
self.assertEqual(b'foo bar\x00baz', node._search_prefix)
1683
self.assertEqual(b'foo bar\x00baz', node._common_serialised_prefix)
1684
node.map(None, (b"foo bar", b"bing"), b"baz quux")
1685
self.assertEqual(b'foo bar\x00b', node._search_prefix)
1686
self.assertEqual(b'foo bar\x00b', node._common_serialised_prefix)
1687
node.map(None, (b"fool", b"baby"), b"baz quux")
1688
self.assertEqual(b'foo', node._search_prefix)
1689
self.assertEqual(b'foo', node._common_serialised_prefix)
1690
node.map(None, (b"foo bar", b"baz"), b"replaced")
1691
self.assertEqual(b'foo', node._search_prefix)
1692
self.assertEqual(b'foo', node._common_serialised_prefix)
1693
node.map(None, (b"very", b"different"), b"value")
1694
self.assertEqual(b'', node._search_prefix)
1695
self.assertEqual(b'', node._common_serialised_prefix)
1673
node.map(None, ("foo bar", "baz"), "baz quux")
1674
self.assertEqual('foo bar\x00baz', node._search_prefix)
1675
self.assertEqual('foo bar\x00baz', node._common_serialised_prefix)
1676
node.map(None, ("foo bar", "bing"), "baz quux")
1677
self.assertEqual('foo bar\x00b', node._search_prefix)
1678
self.assertEqual('foo bar\x00b', node._common_serialised_prefix)
1679
node.map(None, ("fool", "baby"), "baz quux")
1680
self.assertEqual('foo', node._search_prefix)
1681
self.assertEqual('foo', node._common_serialised_prefix)
1682
node.map(None, ("foo bar", "baz"), "replaced")
1683
self.assertEqual('foo', node._search_prefix)
1684
self.assertEqual('foo', node._common_serialised_prefix)
1685
node.map(None, ("very", "different"), "value")
1686
self.assertEqual('', node._search_prefix)
1687
self.assertEqual('', node._common_serialised_prefix)
1697
1689
def test_unmap_maintains_common_prefixes(self):
1698
1690
node = LeafNode()
1699
1691
node._key_width = 2
1700
node.map(None, (b"foo bar", b"baz"), b"baz quux")
1701
node.map(None, (b"foo bar", b"bing"), b"baz quux")
1702
node.map(None, (b"fool", b"baby"), b"baz quux")
1703
node.map(None, (b"very", b"different"), b"value")
1704
self.assertEqual(b'', node._search_prefix)
1705
self.assertEqual(b'', node._common_serialised_prefix)
1706
node.unmap(None, (b"very", b"different"))
1707
self.assertEqual(b"foo", node._search_prefix)
1708
self.assertEqual(b"foo", node._common_serialised_prefix)
1709
node.unmap(None, (b"fool", b"baby"))
1710
self.assertEqual(b'foo bar\x00b', node._search_prefix)
1711
self.assertEqual(b'foo bar\x00b', node._common_serialised_prefix)
1712
node.unmap(None, (b"foo bar", b"baz"))
1713
self.assertEqual(b'foo bar\x00bing', node._search_prefix)
1714
self.assertEqual(b'foo bar\x00bing', node._common_serialised_prefix)
1715
node.unmap(None, (b"foo bar", b"bing"))
1692
node.map(None, ("foo bar", "baz"), "baz quux")
1693
node.map(None, ("foo bar", "bing"), "baz quux")
1694
node.map(None, ("fool", "baby"), "baz quux")
1695
node.map(None, ("very", "different"), "value")
1696
self.assertEqual('', node._search_prefix)
1697
self.assertEqual('', node._common_serialised_prefix)
1698
node.unmap(None, ("very", "different"))
1699
self.assertEqual("foo", node._search_prefix)
1700
self.assertEqual("foo", node._common_serialised_prefix)
1701
node.unmap(None, ("fool", "baby"))
1702
self.assertEqual('foo bar\x00b', node._search_prefix)
1703
self.assertEqual('foo bar\x00b', node._common_serialised_prefix)
1704
node.unmap(None, ("foo bar", "baz"))
1705
self.assertEqual('foo bar\x00bing', node._search_prefix)
1706
self.assertEqual('foo bar\x00bing', node._common_serialised_prefix)
1707
node.unmap(None, ("foo bar", "bing"))
1716
1708
self.assertEqual(None, node._search_prefix)
1717
1709
self.assertEqual(None, node._common_serialised_prefix)
1821
1813
self.assertEqual(2, len(node_key_filter))
1823
1815
def make_fo_fa_node(self):
1824
node = InternalNode(b'f')
1826
child.set_maximum_size(100)
1827
child.map(None, (b"foo",), b"val")
1828
child.map(None, (b"fob",), b"val")
1829
node.add_node(b'fo', child)
1831
child.set_maximum_size(100)
1832
child.map(None, (b"far",), b"val")
1833
child.map(None, (b"faz",), b"val")
1834
node.add_node(b"fa", child)
1816
node = InternalNode('f')
1818
child.set_maximum_size(100)
1819
child.map(None, ("foo",), "val")
1820
child.map(None, ("fob",), "val")
1821
node.add_node('fo', child)
1823
child.set_maximum_size(100)
1824
child.map(None, ("far",), "val")
1825
child.map(None, ("faz",), "val")
1826
node.add_node("fa", child)
1837
1829
def test__iter_nodes_single_entry(self):
1838
1830
node = self.make_fo_fa_node()
1839
key_filter = [(b'foo',)]
1831
key_filter = [('foo',)]
1840
1832
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1841
1833
self.assertEqual(1, len(nodes))
1842
1834
self.assertEqual(key_filter, nodes[0][1])
1844
1836
def test__iter_nodes_single_entry_misses(self):
1845
1837
node = self.make_fo_fa_node()
1846
key_filter = [(b'bar',)]
1838
key_filter = [('bar',)]
1847
1839
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1848
1840
self.assertEqual(0, len(nodes))
1850
1842
def test__iter_nodes_mixed_key_width(self):
1851
1843
node = self.make_fo_fa_node()
1852
key_filter = [(b'foo', b'bar'), (b'foo',), (b'fo',), (b'b',)]
1844
key_filter = [('foo', 'bar'), ('foo',), ('fo',), ('b',)]
1853
1845
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1854
1846
self.assertEqual(1, len(nodes))
1855
1847
matches = key_filter[:]
1856
matches.remove((b'b',))
1848
matches.remove(('b',))
1857
1849
self.assertEqual(sorted(matches), sorted(nodes[0][1]))
1859
1851
def test__iter_nodes_match_all(self):
1860
1852
node = self.make_fo_fa_node()
1861
key_filter = [(b'foo', b'bar'), (b'foo',), (b'fo',), (b'f',)]
1853
key_filter = [('foo', 'bar'), ('foo',), ('fo',), ('f',)]
1862
1854
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1863
1855
self.assertEqual(2, len(nodes))
1865
1857
def test__iter_nodes_fixed_widths_and_misses(self):
1866
1858
node = self.make_fo_fa_node()
1867
1859
# foo and faa should both match one child, baz should miss
1868
key_filter = [(b'foo',), (b'faa',), (b'baz',)]
1860
key_filter = [('foo',), ('faa',), ('baz',)]
1869
1861
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1870
1862
self.assertEqual(2, len(nodes))
1871
1863
for node, matches in nodes:
1878
1870
def test_iteritems_two_children(self):
1879
1871
node = InternalNode()
1880
1872
leaf1 = LeafNode()
1881
leaf1.map(None, (b'foo bar',), b'quux')
1873
leaf1.map(None, ('foo bar',), 'quux')
1882
1874
leaf2 = LeafNode()
1883
leaf2.map(None, (b'strange',), b'beast')
1884
node.add_node(b"f", leaf1)
1885
node.add_node(b"s", leaf2)
1886
self.assertEqual([((b'foo bar',), b'quux'), ((b'strange',), b'beast')],
1887
sorted(node.iteritems(None)))
1875
leaf2.map(None, ('strange',), 'beast')
1876
node.add_node("f", leaf1)
1877
node.add_node("s", leaf2)
1878
self.assertEqual([(('foo bar',), 'quux'), (('strange',), 'beast')],
1879
sorted(node.iteritems(None)))
1889
1881
def test_iteritems_two_children_partial(self):
1890
1882
node = InternalNode()
1891
1883
leaf1 = LeafNode()
1892
leaf1.map(None, (b'foo bar',), b'quux')
1884
leaf1.map(None, ('foo bar',), 'quux')
1893
1885
leaf2 = LeafNode()
1894
leaf2.map(None, (b'strange',), b'beast')
1895
node.add_node(b"f", leaf1)
1886
leaf2.map(None, ('strange',), 'beast')
1887
node.add_node("f", leaf1)
1896
1888
# This sets up a path that should not be followed - it will error if
1897
1889
# the code tries to.
1898
node._items[b'f'] = None
1899
node.add_node(b"s", leaf2)
1900
self.assertEqual([((b'strange',), b'beast')],
1901
sorted(node.iteritems(None, [(b'strange',), (b'weird',)])))
1890
node._items['f'] = None
1891
node.add_node("s", leaf2)
1892
self.assertEqual([(('strange',), 'beast')],
1893
sorted(node.iteritems(None, [('strange',), ('weird',)])))
1903
1895
def test_iteritems_two_children_with_hash(self):
1904
search_key_func = chk_map.search_key_registry.get(b'hash-255-way')
1896
search_key_func = chk_map.search_key_registry.get('hash-255-way')
1905
1897
node = InternalNode(search_key_func=search_key_func)
1906
1898
leaf1 = LeafNode(search_key_func=search_key_func)
1907
leaf1.map(None, StaticTuple(b'foo bar',), b'quux')
1899
leaf1.map(None, StaticTuple('foo bar',), 'quux')
1908
1900
leaf2 = LeafNode(search_key_func=search_key_func)
1909
leaf2.map(None, StaticTuple(b'strange',), b'beast')
1910
self.assertEqual(b'\xbeF\x014', search_key_func(
1911
StaticTuple(b'foo bar',)))
1912
self.assertEqual(b'\x85\xfa\xf7K', search_key_func(
1913
StaticTuple(b'strange',)))
1914
node.add_node(b"\xbe", leaf1)
1901
leaf2.map(None, StaticTuple('strange',), 'beast')
1902
self.assertEqual('\xbeF\x014', search_key_func(StaticTuple('foo bar',)))
1903
self.assertEqual('\x85\xfa\xf7K', search_key_func(StaticTuple('strange',)))
1904
node.add_node("\xbe", leaf1)
1915
1905
# This sets up a path that should not be followed - it will error if
1916
1906
# the code tries to.
1917
node._items[b'\xbe'] = None
1918
node.add_node(b"\x85", leaf2)
1919
self.assertEqual([((b'strange',), b'beast')],
1920
sorted(node.iteritems(None, [StaticTuple(b'strange',),
1921
StaticTuple(b'weird',)])))
1907
node._items['\xbe'] = None
1908
node.add_node("\x85", leaf2)
1909
self.assertEqual([(('strange',), 'beast')],
1910
sorted(node.iteritems(None, [StaticTuple('strange',),
1911
StaticTuple('weird',)])))
1923
1913
def test_iteritems_partial_empty(self):
1924
1914
node = InternalNode()
1925
self.assertEqual([], sorted(node.iteritems([(b'missing',)])))
1915
self.assertEqual([], sorted(node.iteritems([('missing',)])))
1927
1917
def test_map_to_new_child_new(self):
1928
chkmap = self._get_map(
1929
{(b'k1',): b'foo', (b'k2',): b'bar'}, maximum_size=10)
1918
chkmap = self._get_map({('k1',):'foo', ('k2',):'bar'}, maximum_size=10)
1930
1919
chkmap._ensure_root()
1931
1920
node = chkmap._root_node
1932
1921
# Ensure test validity: nothing paged in below the root.
1933
1922
self.assertEqual(2,
1934
len([value for value in node._items.values()
1935
if isinstance(value, StaticTuple)]))
1923
len([value for value in node._items.values()
1924
if isinstance(value, StaticTuple)]))
1936
1925
# now, mapping to k3 should add a k3 leaf
1937
prefix, nodes = node.map(None, (b'k3',), b'quux')
1938
self.assertEqual(b"k", prefix)
1939
self.assertEqual([(b"", node)], nodes)
1926
prefix, nodes = node.map(None, ('k3',), 'quux')
1927
self.assertEqual("k", prefix)
1928
self.assertEqual([("", node)], nodes)
1940
1929
# check new child details
1941
child = node._items[b'k3']
1930
child = node._items['k3']
1942
1931
self.assertIsInstance(child, LeafNode)
1943
1932
self.assertEqual(1, len(child))
1944
self.assertEqual({(b'k3',): b'quux'}, self.to_dict(child, None))
1933
self.assertEqual({('k3',): 'quux'}, self.to_dict(child, None))
1945
1934
self.assertEqual(None, child._key)
1946
1935
self.assertEqual(10, child.maximum_size)
1947
1936
self.assertEqual(1, child._key_width)
1948
1937
# Check overall structure:
1949
1938
self.assertEqual(3, len(chkmap))
1950
self.assertEqual({(b'k1',): b'foo', (b'k2',): b'bar', (b'k3',): b'quux'},
1951
self.to_dict(chkmap))
1939
self.assertEqual({('k1',): 'foo', ('k2',): 'bar', ('k3',): 'quux'},
1940
self.to_dict(chkmap))
1952
1941
# serialising should only serialise the new data - k3 and the internal
1954
1943
keys = list(node.serialise(chkmap._store))
1956
1945
self.assertEqual([child_key, keys[1]], keys)
1958
1947
def test_map_to_child_child_splits_new(self):
1959
chkmap = self._get_map(
1960
{(b'k1',): b'foo', (b'k22',): b'bar'}, maximum_size=10)
1948
chkmap = self._get_map({('k1',):'foo', ('k22',):'bar'}, maximum_size=10)
1961
1949
# Check for the canonical root value for this tree:
1962
1950
self.assertEqualDiff("'' InternalNode\n"
1963
1951
" 'k1' LeafNode\n"
1964
1952
" ('k1',) 'foo'\n"
1965
1953
" 'k2' LeafNode\n"
1966
" ('k22',) 'bar'\n", chkmap._dump_tree())
1955
, chkmap._dump_tree())
1967
1956
# _dump_tree pages everything in, so reload using just the root
1968
1957
chkmap = CHKMap(chkmap._store, chkmap._root_node)
1969
1958
chkmap._ensure_root()
1970
1959
node = chkmap._root_node
1971
1960
# Ensure test validity: nothing paged in below the root.
1972
1961
self.assertEqual(2,
1973
len([value for value in node._items.values()
1974
if isinstance(value, StaticTuple)]))
1962
len([value for value in node._items.values()
1963
if isinstance(value, StaticTuple)]))
1975
1964
# now, mapping to k23 causes k22 ('k2' in node) to split into k22 and
1976
1965
# k23, which for simplicity in the current implementation generates
1977
1966
# a new internal node between node, and k22/k23.
1978
prefix, nodes = node.map(chkmap._store, (b'k23',), b'quux')
1979
self.assertEqual(b"k", prefix)
1980
self.assertEqual([(b"", node)], nodes)
1967
prefix, nodes = node.map(chkmap._store, ('k23',), 'quux')
1968
self.assertEqual("k", prefix)
1969
self.assertEqual([("", node)], nodes)
1981
1970
# check new child details
1982
child = node._items[b'k2']
1971
child = node._items['k2']
1983
1972
self.assertIsInstance(child, InternalNode)
1984
1973
self.assertEqual(2, len(child))
1985
self.assertEqual({(b'k22',): b'bar', (b'k23',): b'quux'},
1986
self.to_dict(child, None))
1974
self.assertEqual({('k22',): 'bar', ('k23',): 'quux'},
1975
self.to_dict(child, None))
1987
1976
self.assertEqual(None, child._key)
1988
1977
self.assertEqual(10, child.maximum_size)
1989
1978
self.assertEqual(1, child._key_width)
1990
1979
self.assertEqual(3, child._node_width)
1991
1980
# Check overall structure:
1992
1981
self.assertEqual(3, len(chkmap))
1993
self.assertEqual({(b'k1',): b'foo', (b'k22',): b'bar', (b'k23',): b'quux'},
1994
self.to_dict(chkmap))
1982
self.assertEqual({('k1',): 'foo', ('k22',): 'bar', ('k23',): 'quux'},
1983
self.to_dict(chkmap))
1995
1984
# serialising should only serialise the new data - although k22 hasn't
1996
1985
# changed because its a special corner case (splitting on with only one
1997
1986
# key leaves one node unaltered), in general k22 is serialised, so we
1998
1987
# expect k22, k23, the new internal node, and node, to be serialised.
1999
1988
keys = list(node.serialise(chkmap._store))
2000
1989
child_key = child._key
2001
k22_key = child._items[b'k22']._key
2002
k23_key = child._items[b'k23']._key
2003
self.assertEqual({k22_key, k23_key, child_key, node.key()}, set(keys))
1990
k22_key = child._items['k22']._key
1991
k23_key = child._items['k23']._key
1992
self.assertEqual([k22_key, k23_key, child_key, node.key()], keys)
2004
1993
self.assertEqualDiff("'' InternalNode\n"
2005
1994
" 'k1' LeafNode\n"
2006
1995
" ('k1',) 'foo'\n"
2207
2201
def test__read_all_roots_multi_new_prepares_queues(self):
2208
2202
c_map = self.make_one_deep_map(chk_map._search_key_plain)
2209
2203
key1 = c_map.key()
2210
c_map._dump_tree() # load everything
2211
key1_a = c_map._root_node._items[b'a'].key()
2212
key1_c = c_map._root_node._items[b'c'].key()
2213
c_map.map((b'abb',), b'new abb content')
2204
c_map._dump_tree() # load everything
2205
key1_a = c_map._root_node._items['a'].key()
2206
key1_c = c_map._root_node._items['c'].key()
2207
c_map.map(('abb',), 'new abb content')
2214
2208
key2 = c_map._save()
2215
key2_a = c_map._root_node._items[b'a'].key()
2216
key2_c = c_map._root_node._items[b'c'].key()
2209
key2_a = c_map._root_node._items['a'].key()
2210
key2_c = c_map._root_node._items['c'].key()
2217
2211
c_map = chk_map.CHKMap(self.get_chk_bytes(), key1,
2218
2212
chk_map._search_key_plain)
2219
c_map.map((b'ccc',), b'new ccc content')
2213
c_map.map(('ccc',), 'new ccc content')
2220
2214
key3 = c_map._save()
2221
key3_a = c_map._root_node._items[b'a'].key()
2222
key3_c = c_map._root_node._items[b'c'].key()
2215
key3_a = c_map._root_node._items['a'].key()
2216
key3_c = c_map._root_node._items['c'].key()
2223
2217
diff = self.get_difference([key2, key3], [key1],
2224
2218
chk_map._search_key_plain)
2225
2219
root_results = [record.key for record in diff._read_all_roots()]
2226
2220
self.assertEqual(sorted([key2, key3]), sorted(root_results))
2227
2221
# We should have queued up key2_a, and key3_c, but not key2_c or key3_c
2228
self.assertEqual({key2_a, key3_c}, set(diff._new_queue))
2222
self.assertEqual([key2_a, key3_c], diff._new_queue)
2229
2223
self.assertEqual([], diff._new_item_queue)
2230
2224
# And we should have queued up both a and c for the old set
2231
self.assertEqual({key1_a, key1_c}, set(diff._old_queue))
2225
self.assertEqual([key1_a, key1_c], diff._old_queue)
2233
2227
def test__read_all_roots_different_depths(self):
2234
2228
c_map = self.make_two_deep_map(chk_map._search_key_plain)
2235
c_map._dump_tree() # load everything
2229
c_map._dump_tree() # load everything
2236
2230
key1 = c_map.key()
2237
key1_a = c_map._root_node._items[b'a'].key()
2238
key1_c = c_map._root_node._items[b'c'].key()
2239
key1_d = c_map._root_node._items[b'd'].key()
2231
key1_a = c_map._root_node._items['a'].key()
2232
key1_c = c_map._root_node._items['c'].key()
2233
key1_d = c_map._root_node._items['d'].key()
2241
2235
c_map2 = self.make_one_deep_two_prefix_map(chk_map._search_key_plain)
2242
2236
c_map2._dump_tree()
2243
2237
key2 = c_map2.key()
2244
key2_aa = c_map2._root_node._items[b'aa'].key()
2245
key2_ad = c_map2._root_node._items[b'ad'].key()
2238
key2_aa = c_map2._root_node._items['aa'].key()
2239
key2_ad = c_map2._root_node._items['ad'].key()
2247
2241
diff = self.get_difference([key2], [key1], chk_map._search_key_plain)
2248
2242
root_results = [record.key for record in diff._read_all_roots()]