878
855
chkmap._dump_tree())
879
856
# Save everything to the map, and start over
880
857
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')
858
chkmap.map(('aac',), 'v')
859
chkmap.map(('aad',), 'v')
860
chkmap.map(('aae',), 'v')
861
chkmap.map(('aaf',), 'v')
885
862
# At this point, the previous nodes should not be paged in, but the
886
863
# 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)
864
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
865
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
866
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
867
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
868
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
869
self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
893
870
# Now unmapping one of the new nodes will use only the already-paged-in
894
871
# 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)
872
chkmap.unmap(('aaf',))
873
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
874
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
875
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
876
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
877
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
902
879
def test_unmap_pages_in_if_necessary(self):
903
880
store = self.get_chk_bytes()
904
881
chkmap = CHKMap(store, None)
905
882
# Should fit 2 keys per LeafNode
906
883
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')
884
chkmap.map(('aaa',), 'val')
885
chkmap.map(('aab',), 'val')
886
chkmap.map(('aac',), 'val')
910
887
self.assertEqualDiff("'' InternalNode\n"
911
888
" 'aaa' LeafNode\n"
912
889
" ('aaa',) 'val'\n"
918
895
root_key = chkmap._save()
919
896
# Save everything to the map, and start over
920
897
chkmap = CHKMap(store, root_key)
921
chkmap.map((b'aad',), b'v')
898
chkmap.map(('aad',), 'v')
922
899
# At this point, the previous nodes should not be paged in, but the
923
900
# 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)
901
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
902
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
903
self.assertIsInstance(chkmap._root_node._items['aac'], StaticTuple)
904
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
928
905
# Unmapping the new node will check the existing nodes to see if they
930
907
# Clear the page cache so we ensure we have to read all the children
931
908
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)
909
chkmap.unmap(('aad',))
910
self.assertIsInstance(chkmap._root_node._items['aaa'], LeafNode)
911
self.assertIsInstance(chkmap._root_node._items['aab'], LeafNode)
912
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
937
914
def test_unmap_pages_in_from_page_cache(self):
938
915
store = self.get_chk_bytes()
939
916
chkmap = CHKMap(store, None)
940
917
# Should fit 2 keys per LeafNode
941
918
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')
919
chkmap.map(('aaa',), 'val')
920
chkmap.map(('aab',), 'val')
921
chkmap.map(('aac',), 'val')
945
922
root_key = chkmap._save()
946
923
# Save everything to the map, and start over
947
924
chkmap = CHKMap(store, root_key)
948
chkmap.map((b'aad',), b'val')
925
chkmap.map(('aad',), 'val')
949
926
self.assertEqualDiff("'' InternalNode\n"
950
927
" 'aaa' LeafNode\n"
951
928
" ('aaa',) 'val'\n"
978
955
# Unmapping the new node will check the nodes from the page cache
979
956
# 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)
957
chkmap.unmap(('aad',))
958
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
959
self.assertIsInstance(chkmap._root_node._items['aab'], LeafNode)
960
self.assertIsInstance(chkmap._root_node._items['aac'], LeafNode)
985
962
def test_unmap_uses_existing_items(self):
986
963
store = self.get_chk_bytes()
987
964
chkmap = CHKMap(store, None)
988
965
# Should fit 2 keys per LeafNode
989
966
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')
967
chkmap.map(('aaa',), 'val')
968
chkmap.map(('aab',), 'val')
969
chkmap.map(('aac',), 'val')
993
970
root_key = chkmap._save()
994
971
# Save everything to the map, and start over
995
972
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')
973
chkmap.map(('aad',), 'val')
974
chkmap.map(('aae',), 'val')
975
chkmap.map(('aaf',), 'val')
999
976
# At this point, the previous nodes should not be paged in, but the
1000
977
# 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)
978
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
979
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
980
self.assertIsInstance(chkmap._root_node._items['aac'], StaticTuple)
981
self.assertIsInstance(chkmap._root_node._items['aad'], LeafNode)
982
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
983
self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
1008
985
# Unmapping a new node will see the other nodes that are already in
1009
986
# 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)
987
chkmap.unmap(('aad',))
988
self.assertIsInstance(chkmap._root_node._items['aaa'], StaticTuple)
989
self.assertIsInstance(chkmap._root_node._items['aab'], StaticTuple)
990
self.assertIsInstance(chkmap._root_node._items['aac'], StaticTuple)
991
self.assertIsInstance(chkmap._root_node._items['aae'], LeafNode)
992
self.assertIsInstance(chkmap._root_node._items['aaf'], LeafNode)
1017
994
def test_iter_changes_empty_ab(self):
1018
995
# Asking for changes between an empty dict to a dict with keys returns
1020
997
basis = self._get_map({}, maximum_size=10)
1021
998
target = self._get_map(
1022
{(b'a',): b'content here', (b'b',): b'more content'},
999
{('a',): 'content here', ('b',): 'more content'},
1023
1000
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))))
1001
self.assertEqual([(('a',), None, 'content here'),
1002
(('b',), None, 'more content')],
1003
sorted(list(target.iter_changes(basis))))
1028
1005
def test_iter_changes_ab_empty(self):
1029
1006
# Asking for changes between a dict with keys to an empty dict returns
1030
1007
# all the keys.
1031
basis = self._get_map({(b'a',): b'content here', (b'b',): b'more content'},
1008
basis = self._get_map({('a',): 'content here', ('b',): 'more content'},
1033
1010
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))))
1011
self.assertEqual([(('a',), 'content here', None),
1012
(('b',), 'more content', None)],
1013
sorted(list(target.iter_changes(basis))))
1038
1015
def test_iter_changes_empty_empty_is_empty(self):
1039
1016
basis = self._get_map({}, maximum_size=10)
1104
1081
# aaa to be not loaded
1105
1082
# 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'}
1083
basis_dict = {('aaa',): 'foo bar',
1084
('aab',): 'common altered a', ('b',): 'foo bar b'}
1108
1085
# 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'}
1086
target_dict = {('aaa',): 'foo bar',
1087
('aab',): 'common altered b', ('at',): 'foo bar t'}
1111
1088
basis = self._get_map(basis_dict, maximum_size=10)
1112
1089
target = self._get_map(target_dict, maximum_size=10,
1113
chk_bytes=basis._store)
1090
chk_bytes=basis._store)
1114
1091
basis_get = basis._store.get_record_stream
1116
1092
def get_record_stream(keys, order, fulltext):
1117
if (b'sha1:1adf7c0d1b9140ab5f33bb64c6275fa78b1580b7',) in keys:
1118
raise AssertionError("'aaa' pointer was followed %r" % keys)
1093
if ('sha1:1adf7c0d1b9140ab5f33bb64c6275fa78b1580b7',) in keys:
1094
self.fail("'aaa' pointer was followed %r" % keys)
1119
1095
return basis_get(keys, order, fulltext)
1120
1096
basis._store.get_record_stream = get_record_stream
1121
1097
result = sorted(list(target.iter_changes(basis)))
1122
1098
for change in result:
1123
if change[0] == (b'aaa',):
1099
if change[0] == ('aaa',):
1124
1100
self.fail("Found unexpected change: %s" % change)
1126
1102
def test_iter_changes_unchanged_keys_in_multi_key_leafs_ignored(self):
1127
1103
# Within a leaf there are no hash's to exclude keys, make sure multi
1128
1104
# 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'}
1105
basis_dict = {('aaa',): 'foo bar',
1106
('aab',): 'common altered a', ('b',): 'foo bar b'}
1107
target_dict = {('aaa',): 'foo bar',
1108
('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),
1110
(('aab',), 'common altered a', 'common altered b'),
1111
(('at',), None, 'foo bar t'),
1112
(('b',), 'foo bar b', None),
1138
1114
basis = self._get_map(basis_dict)
1139
1115
target = self._get_map(target_dict, chk_bytes=basis._store)
1148
1124
def test_iteritems_two_items(self):
1149
1125
chk_bytes = self.get_chk_bytes()
1150
1126
root_key = CHKMap.from_dict(chk_bytes,
1151
{(b"a", ): b"content here", (b"b", ): b"more content"})
1127
{"a":"content here", "b":"more content"})
1152
1128
chkmap = CHKMap(chk_bytes, root_key)
1153
self.assertEqual([((b"a",), b"content here"), ((b"b",), b"more content")],
1154
sorted(list(chkmap.iteritems())))
1129
self.assertEqual([(("a",), "content here"), (("b",), "more content")],
1130
sorted(list(chkmap.iteritems())))
1156
1132
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",)]))
1133
chkmap = self._get_map( {("a",):"content here", ("b",):"more content"})
1134
self.assertEqual({("a",): "content here"},
1135
self.to_dict(chkmap, [("a",)]))
1162
1137
def test_iteritems_keys_prefixed_by_2_width_nodes(self):
1163
1138
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'},
1139
{("a","a"):"content here", ("a", "b",):"more content",
1140
("b", ""): 'boring content'},
1166
1141
maximum_size=10, key_width=2)
1167
1142
self.assertEqual(
1168
{(b"a", b"a"): b"content here", (b"a", b"b"): b'more content'},
1169
self.to_dict(chkmap, [(b"a",)]))
1143
{("a", "a"): "content here", ("a", "b"): 'more content'},
1144
self.to_dict(chkmap, [("a",)]))
1171
1146
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'')))
1147
search_key_func = chk_map.search_key_registry.get('hash-16-way')
1148
self.assertEqual('E8B7BE43\x00E8B7BE43',
1149
search_key_func(StaticTuple('a', 'a')))
1150
self.assertEqual('E8B7BE43\x0071BEEFF9',
1151
search_key_func(StaticTuple('a', 'b')))
1152
self.assertEqual('71BEEFF9\x0000000000',
1153
search_key_func(StaticTuple('b', '')))
1179
1154
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'},
1155
{("a","a"):"content here", ("a", "b",):"more content",
1156
("b", ""): 'boring content'},
1182
1157
maximum_size=10, key_width=2, search_key_func=search_key_func)
1183
1158
self.assertEqual(
1184
{(b"a", b"a"): b"content here", (b"a", b"b"): b'more content'},
1185
self.to_dict(chkmap, [(b"a",)]))
1159
{("a", "a"): "content here", ("a", "b"): 'more content'},
1160
self.to_dict(chkmap, [("a",)]))
1187
1162
def test_iteritems_keys_prefixed_by_2_width_one_leaf(self):
1188
1163
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)
1164
{("a","a"):"content here", ("a", "b",):"more content",
1165
("b", ""): 'boring content'}, key_width=2)
1191
1166
self.assertEqual(
1192
{(b"a", b"a"): b"content here", (b"a", b"b"): b'more content'},
1193
self.to_dict(chkmap, [(b"a",)]))
1167
{("a", "a"): "content here", ("a", "b"): 'more content'},
1168
self.to_dict(chkmap, [("a",)]))
1195
1170
def test___len__empty(self):
1196
1171
chkmap = self._get_map({})
1197
1172
self.assertEqual(0, len(chkmap))
1199
1174
def test___len__2(self):
1200
chkmap = self._get_map({(b"foo",): b"bar", (b"gam",): b"quux"})
1175
chkmap = self._get_map({("foo",):"bar", ("gam",):"quux"})
1201
1176
self.assertEqual(2, len(chkmap))
1203
1178
def test_max_size_100_bytes_new(self):
1204
1179
# 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)
1180
chkmap = self._get_map({("k1"*50,):"v1", ("k2"*50,):"v2"}, maximum_size=100)
1207
1181
# We expect three nodes:
1208
1182
# A root, with two children, and with two key prefixes - k1 to one, and
1209
1183
# k2 to the other as our node splitting is only just being developed.
1402
1372
" 'test:2' LeafNode\n"
1403
1373
" ('2',) 'bar'\n"
1404
1374
" 'test:3' LeafNode\n"
1405
" ('3',) 'baz'\n", chkmap._dump_tree())
1376
, chkmap._dump_tree())
1407
1378
def test_search_key_16(self):
1408
1379
chk_bytes = self.get_chk_bytes()
1409
1380
chkmap = chk_map.CHKMap(chk_bytes, None,
1410
1381
search_key_func=chk_map._search_key_16)
1411
1382
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')
1383
chkmap.map(('1',), 'foo')
1384
chkmap.map(('2',), 'bar')
1385
chkmap.map(('3',), 'baz')
1415
1386
self.assertEqualDiff("'' InternalNode\n"
1416
1387
" '1' LeafNode\n"
1417
1388
" ('2',) 'bar'\n"
1418
1389
" '6' LeafNode\n"
1419
1390
" ('3',) 'baz'\n"
1420
1391
" '8' LeafNode\n"
1421
" ('1',) 'foo'\n", chkmap._dump_tree())
1393
, chkmap._dump_tree())
1422
1394
root_key = chkmap._save()
1423
1395
chkmap = chk_map.CHKMap(chk_bytes, root_key,
1424
1396
search_key_func=chk_map._search_key_16)
1425
1397
# We can get the values back correctly
1426
self.assertEqual([((b'1',), b'foo')],
1427
list(chkmap.iteritems([(b'1',)])))
1398
self.assertEqual([(('1',), 'foo')],
1399
list(chkmap.iteritems([('1',)])))
1428
1400
self.assertEqualDiff("'' InternalNode\n"
1429
1401
" '1' LeafNode\n"
1430
1402
" ('2',) 'bar'\n"
1431
1403
" '6' LeafNode\n"
1432
1404
" ('3',) 'baz'\n"
1433
1405
" '8' LeafNode\n"
1434
" ('1',) 'foo'\n", chkmap._dump_tree())
1407
, chkmap._dump_tree())
1436
1409
def test_search_key_255(self):
1437
1410
chk_bytes = self.get_chk_bytes()
1438
1411
chkmap = chk_map.CHKMap(chk_bytes, None,
1439
1412
search_key_func=chk_map._search_key_255)
1440
1413
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')
1414
chkmap.map(('1',), 'foo')
1415
chkmap.map(('2',), 'bar')
1416
chkmap.map(('3',), 'baz')
1444
1417
self.assertEqualDiff("'' InternalNode\n"
1445
1418
" '\\x1a' LeafNode\n"
1446
1419
" ('2',) 'bar'\n"
1447
1420
" 'm' LeafNode\n"
1448
1421
" ('3',) 'baz'\n"
1449
1422
" '\\x83' LeafNode\n"
1450
" ('1',) 'foo'\n", chkmap._dump_tree(encoding='latin1'))
1424
, chkmap._dump_tree())
1451
1425
root_key = chkmap._save()
1452
1426
chkmap = chk_map.CHKMap(chk_bytes, root_key,
1453
1427
search_key_func=chk_map._search_key_255)
1454
1428
# We can get the values back correctly
1455
self.assertEqual([((b'1',), b'foo')],
1456
list(chkmap.iteritems([(b'1',)])))
1429
self.assertEqual([(('1',), 'foo')],
1430
list(chkmap.iteritems([('1',)])))
1457
1431
self.assertEqualDiff("'' InternalNode\n"
1458
1432
" '\\x1a' LeafNode\n"
1459
1433
" ('2',) 'bar'\n"
1460
1434
" 'm' LeafNode\n"
1461
1435
" ('3',) 'baz'\n"
1462
1436
" '\\x83' LeafNode\n"
1463
" ('1',) 'foo'\n", chkmap._dump_tree(encoding='latin1'))
1438
, chkmap._dump_tree())
1465
1440
def test_search_key_collisions(self):
1466
1441
chkmap = chk_map.CHKMap(self.get_chk_bytes(), None,
1496
1472
def test_current_size_items(self):
1497
1473
node = LeafNode()
1498
1474
base_size = node._current_size()
1499
node.map(None, (b"foo bar",), b"baz")
1475
node.map(None, ("foo bar",), "baz")
1500
1476
self.assertEqual(base_size + 14, node._current_size())
1502
1478
def test_deserialise_empty(self):
1503
node = LeafNode.deserialise(b"chkleaf:\n10\n1\n0\n\n", (b"sha1:1234",))
1479
node = LeafNode.deserialise("chkleaf:\n10\n1\n0\n\n", ("sha1:1234",))
1504
1480
self.assertEqual(0, len(node))
1505
1481
self.assertEqual(10, node.maximum_size)
1506
self.assertEqual((b"sha1:1234",), node.key())
1482
self.assertEqual(("sha1:1234",), node.key())
1507
1483
self.assertIs(None, node._search_prefix)
1508
1484
self.assertIs(None, node._common_serialised_prefix)
1510
1486
def test_deserialise_items(self):
1511
1487
node = LeafNode.deserialise(
1512
b"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1488
"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1514
1490
self.assertEqual(2, len(node))
1515
self.assertEqual([((b"foo bar",), b"baz"), ((b"quux",), b"blarh")],
1516
sorted(node.iteritems(None)))
1491
self.assertEqual([(("foo bar",), "baz"), (("quux",), "blarh")],
1492
sorted(node.iteritems(None)))
1518
1494
def test_deserialise_item_with_null_width_1(self):
1519
1495
node = LeafNode.deserialise(
1520
b"chkleaf:\n0\n1\n2\n\nfoo\x001\nbar\x00baz\nquux\x001\nblarh\n",
1496
"chkleaf:\n0\n1\n2\n\nfoo\x001\nbar\x00baz\nquux\x001\nblarh\n",
1522
1498
self.assertEqual(2, len(node))
1523
self.assertEqual([((b"foo",), b"bar\x00baz"), ((b"quux",), b"blarh")],
1524
sorted(node.iteritems(None)))
1499
self.assertEqual([(("foo",), "bar\x00baz"), (("quux",), "blarh")],
1500
sorted(node.iteritems(None)))
1526
1502
def test_deserialise_item_with_null_width_2(self):
1527
1503
node = LeafNode.deserialise(
1528
b"chkleaf:\n0\n2\n2\n\nfoo\x001\x001\nbar\x00baz\n"
1529
b"quux\x00\x001\nblarh\n",
1504
"chkleaf:\n0\n2\n2\n\nfoo\x001\x001\nbar\x00baz\n"
1505
"quux\x00\x001\nblarh\n",
1531
1507
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)))
1508
self.assertEqual([(("foo", "1"), "bar\x00baz"), (("quux", ""), "blarh")],
1509
sorted(node.iteritems(None)))
1535
1511
def test_iteritems_selected_one_of_two_items(self):
1536
1512
node = LeafNode.deserialise(
1537
b"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1513
"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1539
1515
self.assertEqual(2, len(node))
1540
self.assertEqual([((b"quux",), b"blarh")],
1541
sorted(node.iteritems(None, [(b"quux",), (b"qaz",)])))
1516
self.assertEqual([(("quux",), "blarh")],
1517
sorted(node.iteritems(None, [("quux",), ("qaz",)])))
1543
1519
def test_deserialise_item_with_common_prefix(self):
1544
1520
node = LeafNode.deserialise(
1545
b"chkleaf:\n0\n2\n2\nfoo\x00\n1\x001\nbar\x00baz\n2\x001\nblarh\n",
1521
"chkleaf:\n0\n2\n2\nfoo\x00\n1\x001\nbar\x00baz\n2\x001\nblarh\n",
1547
1523
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)))
1524
self.assertEqual([(("foo", "1"), "bar\x00baz"), (("foo", "2"), "blarh")],
1525
sorted(node.iteritems(None)))
1550
1526
self.assertIs(chk_map._unknown, node._search_prefix)
1551
self.assertEqual(b'foo\x00', node._common_serialised_prefix)
1527
self.assertEqual('foo\x00', node._common_serialised_prefix)
1553
1529
def test_deserialise_multi_line(self):
1554
1530
node = LeafNode.deserialise(
1555
b"chkleaf:\n0\n2\n2\nfoo\x00\n1\x002\nbar\nbaz\n2\x002\nblarh\n\n",
1531
"chkleaf:\n0\n2\n2\nfoo\x00\n1\x002\nbar\nbaz\n2\x002\nblarh\n\n",
1557
1533
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)))
1534
self.assertEqual([(("foo", "1"), "bar\nbaz"),
1535
(("foo", "2"), "blarh\n"),
1536
], sorted(node.iteritems(None)))
1561
1537
self.assertIs(chk_map._unknown, node._search_prefix)
1562
self.assertEqual(b'foo\x00', node._common_serialised_prefix)
1538
self.assertEqual('foo\x00', node._common_serialised_prefix)
1564
1540
def test_key_new(self):
1565
1541
node = LeafNode()
1566
1542
self.assertEqual(None, node.key())
1568
1544
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")
1545
node = LeafNode.deserialise("chkleaf:\n10\n1\n0\n\n", ("sha1:1234",))
1546
node.map(None, ("foo bar",), "baz quux")
1571
1547
self.assertEqual(None, node.key())
1573
1549
def test_key_after_unmap(self):
1574
1550
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",))
1551
"chkleaf:\n0\n1\n2\n\nfoo bar\x001\nbaz\nquux\x001\nblarh\n",
1553
node.unmap(None, ("foo bar",))
1578
1554
self.assertEqual(None, node.key())
1580
1556
def test_map_exceeding_max_size_only_entry_new(self):
1581
1557
node = LeafNode()
1582
1558
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)
1559
result = node.map(None, ("foo bar",), "baz quux")
1560
self.assertEqual(("foo bar", [("", node)]), result)
1585
1561
self.assertTrue(10 < node._current_size())
1587
1563
def test_map_exceeding_max_size_second_entry_early_difference_new(self):
1588
1564
node = LeafNode()
1589
1565
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)
1566
node.map(None, ("foo bar",), "baz quux")
1567
prefix, result = list(node.map(None, ("blue",), "red"))
1568
self.assertEqual("", prefix)
1593
1569
self.assertEqual(2, len(result))
1594
split_chars = {result[0][0], result[1][0]}
1595
self.assertEqual({b"f", b"b"}, split_chars)
1570
split_chars = set([result[0][0], result[1][0]])
1571
self.assertEqual(set(["f", "b"]), split_chars)
1596
1572
nodes = dict(result)
1598
self.assertEqual({(b"foo bar",): b"baz quux"},
1599
self.to_dict(node, None))
1574
self.assertEqual({("foo bar",): "baz quux"}, self.to_dict(node, None))
1600
1575
self.assertEqual(10, node.maximum_size)
1601
1576
self.assertEqual(1, node._key_width)
1603
self.assertEqual({(b"blue",): b"red"}, self.to_dict(node, None))
1578
self.assertEqual({("blue",): "red"}, self.to_dict(node, None))
1604
1579
self.assertEqual(10, node.maximum_size)
1605
1580
self.assertEqual(1, node._key_width)
1607
1582
def test_map_first(self):
1608
1583
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))
1584
result = node.map(None, ("foo bar",), "baz quux")
1585
self.assertEqual(("foo bar", [("", node)]), result)
1586
self.assertEqual({("foo bar",):"baz quux"}, self.to_dict(node, None))
1613
1587
self.assertEqual(1, len(node))
1615
1589
def test_map_second(self):
1616
1590
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))
1591
node.map(None, ("foo bar",), "baz quux")
1592
result = node.map(None, ("bingo",), "bango")
1593
self.assertEqual(("", [("", node)]), result)
1594
self.assertEqual({("foo bar",):"baz quux", ("bingo",):"bango"},
1595
self.to_dict(node, None))
1622
1596
self.assertEqual(2, len(node))
1624
1598
def test_map_replacement(self):
1625
1599
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))
1600
node.map(None, ("foo bar",), "baz quux")
1601
result = node.map(None, ("foo bar",), "bango")
1602
self.assertEqual(("foo bar", [("", node)]), result)
1603
self.assertEqual({("foo bar",): "bango"},
1604
self.to_dict(node, None))
1631
1605
self.assertEqual(1, len(node))
1633
1607
def test_serialise_empty(self):
1634
1608
store = self.get_chk_bytes()
1635
1609
node = LeafNode()
1636
1610
node.set_maximum_size(10)
1637
expected_key = (b"sha1:f34c3f0634ea3f85953dffa887620c0a5b1f4a51",)
1611
expected_key = ("sha1:f34c3f0634ea3f85953dffa887620c0a5b1f4a51",)
1638
1612
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))
1613
list(node.serialise(store)))
1614
self.assertEqual("chkleaf:\n10\n1\n0\n\n", self.read_bytes(store, expected_key))
1642
1615
self.assertEqual(expected_key, node.key())
1644
1617
def test_serialise_items(self):
1645
1618
store = self.get_chk_bytes()
1646
1619
node = LeafNode()
1647
1620
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)
1621
node.map(None, ("foo bar",), "baz quux")
1622
expected_key = ("sha1:f89fac7edfc6bdb1b1b54a556012ff0c646ef5e0",)
1623
self.assertEqual('foo bar', node._common_serialised_prefix)
1651
1624
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))
1625
list(node.serialise(store)))
1626
self.assertEqual("chkleaf:\n10\n1\n1\nfoo bar\n\x001\nbaz quux\n",
1627
self.read_bytes(store, expected_key))
1655
1628
self.assertEqual(expected_key, node.key())
1657
1630
def test_unique_serialised_prefix_empty_new(self):
1678
1651
def test_map_maintains_common_prefixes(self):
1679
1652
node = LeafNode()
1680
1653
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)
1654
node.map(None, ("foo bar", "baz"), "baz quux")
1655
self.assertEqual('foo bar\x00baz', node._search_prefix)
1656
self.assertEqual('foo bar\x00baz', node._common_serialised_prefix)
1657
node.map(None, ("foo bar", "bing"), "baz quux")
1658
self.assertEqual('foo bar\x00b', node._search_prefix)
1659
self.assertEqual('foo bar\x00b', node._common_serialised_prefix)
1660
node.map(None, ("fool", "baby"), "baz quux")
1661
self.assertEqual('foo', node._search_prefix)
1662
self.assertEqual('foo', node._common_serialised_prefix)
1663
node.map(None, ("foo bar", "baz"), "replaced")
1664
self.assertEqual('foo', node._search_prefix)
1665
self.assertEqual('foo', node._common_serialised_prefix)
1666
node.map(None, ("very", "different"), "value")
1667
self.assertEqual('', node._search_prefix)
1668
self.assertEqual('', node._common_serialised_prefix)
1697
1670
def test_unmap_maintains_common_prefixes(self):
1698
1671
node = LeafNode()
1699
1672
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"))
1673
node.map(None, ("foo bar", "baz"), "baz quux")
1674
node.map(None, ("foo bar", "bing"), "baz quux")
1675
node.map(None, ("fool", "baby"), "baz quux")
1676
node.map(None, ("very", "different"), "value")
1677
self.assertEqual('', node._search_prefix)
1678
self.assertEqual('', node._common_serialised_prefix)
1679
node.unmap(None, ("very", "different"))
1680
self.assertEqual("foo", node._search_prefix)
1681
self.assertEqual("foo", node._common_serialised_prefix)
1682
node.unmap(None, ("fool", "baby"))
1683
self.assertEqual('foo bar\x00b', node._search_prefix)
1684
self.assertEqual('foo bar\x00b', node._common_serialised_prefix)
1685
node.unmap(None, ("foo bar", "baz"))
1686
self.assertEqual('foo bar\x00bing', node._search_prefix)
1687
self.assertEqual('foo bar\x00bing', node._common_serialised_prefix)
1688
node.unmap(None, ("foo bar", "bing"))
1716
1689
self.assertEqual(None, node._search_prefix)
1717
1690
self.assertEqual(None, node._common_serialised_prefix)
1821
1794
self.assertEqual(2, len(node_key_filter))
1823
1796
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)
1797
node = InternalNode('f')
1799
child.set_maximum_size(100)
1800
child.map(None, ("foo",), "val")
1801
child.map(None, ("fob",), "val")
1802
node.add_node('fo', child)
1804
child.set_maximum_size(100)
1805
child.map(None, ("far",), "val")
1806
child.map(None, ("faz",), "val")
1807
node.add_node("fa", child)
1837
1810
def test__iter_nodes_single_entry(self):
1838
1811
node = self.make_fo_fa_node()
1839
key_filter = [(b'foo',)]
1812
key_filter = [('foo',)]
1840
1813
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1841
1814
self.assertEqual(1, len(nodes))
1842
1815
self.assertEqual(key_filter, nodes[0][1])
1844
1817
def test__iter_nodes_single_entry_misses(self):
1845
1818
node = self.make_fo_fa_node()
1846
key_filter = [(b'bar',)]
1819
key_filter = [('bar',)]
1847
1820
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1848
1821
self.assertEqual(0, len(nodes))
1850
1823
def test__iter_nodes_mixed_key_width(self):
1851
1824
node = self.make_fo_fa_node()
1852
key_filter = [(b'foo', b'bar'), (b'foo',), (b'fo',), (b'b',)]
1825
key_filter = [('foo', 'bar'), ('foo',), ('fo',), ('b',)]
1853
1826
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1854
1827
self.assertEqual(1, len(nodes))
1855
1828
matches = key_filter[:]
1856
matches.remove((b'b',))
1829
matches.remove(('b',))
1857
1830
self.assertEqual(sorted(matches), sorted(nodes[0][1]))
1859
1832
def test__iter_nodes_match_all(self):
1860
1833
node = self.make_fo_fa_node()
1861
key_filter = [(b'foo', b'bar'), (b'foo',), (b'fo',), (b'f',)]
1834
key_filter = [('foo', 'bar'), ('foo',), ('fo',), ('f',)]
1862
1835
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1863
1836
self.assertEqual(2, len(nodes))
1865
1838
def test__iter_nodes_fixed_widths_and_misses(self):
1866
1839
node = self.make_fo_fa_node()
1867
1840
# foo and faa should both match one child, baz should miss
1868
key_filter = [(b'foo',), (b'faa',), (b'baz',)]
1841
key_filter = [('foo',), ('faa',), ('baz',)]
1869
1842
nodes = list(node._iter_nodes(None, key_filter=key_filter))
1870
1843
self.assertEqual(2, len(nodes))
1871
1844
for node, matches in nodes:
1878
1851
def test_iteritems_two_children(self):
1879
1852
node = InternalNode()
1880
1853
leaf1 = LeafNode()
1881
leaf1.map(None, (b'foo bar',), b'quux')
1854
leaf1.map(None, ('foo bar',), 'quux')
1882
1855
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)))
1856
leaf2.map(None, ('strange',), 'beast')
1857
node.add_node("f", leaf1)
1858
node.add_node("s", leaf2)
1859
self.assertEqual([(('foo bar',), 'quux'), (('strange',), 'beast')],
1860
sorted(node.iteritems(None)))
1889
1862
def test_iteritems_two_children_partial(self):
1890
1863
node = InternalNode()
1891
1864
leaf1 = LeafNode()
1892
leaf1.map(None, (b'foo bar',), b'quux')
1865
leaf1.map(None, ('foo bar',), 'quux')
1893
1866
leaf2 = LeafNode()
1894
leaf2.map(None, (b'strange',), b'beast')
1895
node.add_node(b"f", leaf1)
1867
leaf2.map(None, ('strange',), 'beast')
1868
node.add_node("f", leaf1)
1896
1869
# This sets up a path that should not be followed - it will error if
1897
1870
# 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',)])))
1871
node._items['f'] = None
1872
node.add_node("s", leaf2)
1873
self.assertEqual([(('strange',), 'beast')],
1874
sorted(node.iteritems(None, [('strange',), ('weird',)])))
1903
1876
def test_iteritems_two_children_with_hash(self):
1904
search_key_func = chk_map.search_key_registry.get(b'hash-255-way')
1877
search_key_func = chk_map.search_key_registry.get('hash-255-way')
1905
1878
node = InternalNode(search_key_func=search_key_func)
1906
1879
leaf1 = LeafNode(search_key_func=search_key_func)
1907
leaf1.map(None, StaticTuple(b'foo bar',), b'quux')
1880
leaf1.map(None, StaticTuple('foo bar',), 'quux')
1908
1881
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)
1882
leaf2.map(None, StaticTuple('strange',), 'beast')
1883
self.assertEqual('\xbeF\x014', search_key_func(StaticTuple('foo bar',)))
1884
self.assertEqual('\x85\xfa\xf7K', search_key_func(StaticTuple('strange',)))
1885
node.add_node("\xbe", leaf1)
1915
1886
# This sets up a path that should not be followed - it will error if
1916
1887
# 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',)])))
1888
node._items['\xbe'] = None
1889
node.add_node("\x85", leaf2)
1890
self.assertEqual([(('strange',), 'beast')],
1891
sorted(node.iteritems(None, [StaticTuple('strange',),
1892
StaticTuple('weird',)])))
1923
1894
def test_iteritems_partial_empty(self):
1924
1895
node = InternalNode()
1925
self.assertEqual([], sorted(node.iteritems([(b'missing',)])))
1896
self.assertEqual([], sorted(node.iteritems([('missing',)])))
1927
1898
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)
1899
chkmap = self._get_map({('k1',):'foo', ('k2',):'bar'}, maximum_size=10)
1930
1900
chkmap._ensure_root()
1931
1901
node = chkmap._root_node
1932
1902
# Ensure test validity: nothing paged in below the root.
1933
1903
self.assertEqual(2,
1934
len([value for value in node._items.values()
1935
if isinstance(value, StaticTuple)]))
1904
len([value for value in node._items.values()
1905
if type(value) is StaticTuple]))
1936
1906
# 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)
1907
prefix, nodes = node.map(None, ('k3',), 'quux')
1908
self.assertEqual("k", prefix)
1909
self.assertEqual([("", node)], nodes)
1940
1910
# check new child details
1941
child = node._items[b'k3']
1911
child = node._items['k3']
1942
1912
self.assertIsInstance(child, LeafNode)
1943
1913
self.assertEqual(1, len(child))
1944
self.assertEqual({(b'k3',): b'quux'}, self.to_dict(child, None))
1914
self.assertEqual({('k3',): 'quux'}, self.to_dict(child, None))
1945
1915
self.assertEqual(None, child._key)
1946
1916
self.assertEqual(10, child.maximum_size)
1947
1917
self.assertEqual(1, child._key_width)
1948
1918
# Check overall structure:
1949
1919
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))
1920
self.assertEqual({('k1',): 'foo', ('k2',): 'bar', ('k3',): 'quux'},
1921
self.to_dict(chkmap))
1952
1922
# serialising should only serialise the new data - k3 and the internal
1954
1924
keys = list(node.serialise(chkmap._store))
1956
1926
self.assertEqual([child_key, keys[1]], keys)
1958
1928
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)
1929
chkmap = self._get_map({('k1',):'foo', ('k22',):'bar'}, maximum_size=10)
1961
1930
# Check for the canonical root value for this tree:
1962
1931
self.assertEqualDiff("'' InternalNode\n"
1963
1932
" 'k1' LeafNode\n"
1964
1933
" ('k1',) 'foo'\n"
1965
1934
" 'k2' LeafNode\n"
1966
" ('k22',) 'bar'\n", chkmap._dump_tree())
1936
, chkmap._dump_tree())
1967
1937
# _dump_tree pages everything in, so reload using just the root
1968
1938
chkmap = CHKMap(chkmap._store, chkmap._root_node)
1969
1939
chkmap._ensure_root()
1970
1940
node = chkmap._root_node
1971
1941
# Ensure test validity: nothing paged in below the root.
1972
1942
self.assertEqual(2,
1973
len([value for value in node._items.values()
1974
if isinstance(value, StaticTuple)]))
1943
len([value for value in node._items.values()
1944
if type(value) is StaticTuple]))
1975
1945
# now, mapping to k23 causes k22 ('k2' in node) to split into k22 and
1976
1946
# k23, which for simplicity in the current implementation generates
1977
1947
# 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)
1948
prefix, nodes = node.map(chkmap._store, ('k23',), 'quux')
1949
self.assertEqual("k", prefix)
1950
self.assertEqual([("", node)], nodes)
1981
1951
# check new child details
1982
child = node._items[b'k2']
1952
child = node._items['k2']
1983
1953
self.assertIsInstance(child, InternalNode)
1984
1954
self.assertEqual(2, len(child))
1985
self.assertEqual({(b'k22',): b'bar', (b'k23',): b'quux'},
1986
self.to_dict(child, None))
1955
self.assertEqual({('k22',): 'bar', ('k23',): 'quux'},
1956
self.to_dict(child, None))
1987
1957
self.assertEqual(None, child._key)
1988
1958
self.assertEqual(10, child.maximum_size)
1989
1959
self.assertEqual(1, child._key_width)
1990
1960
self.assertEqual(3, child._node_width)
1991
1961
# Check overall structure:
1992
1962
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))
1963
self.assertEqual({('k1',): 'foo', ('k22',): 'bar', ('k23',): 'quux'},
1964
self.to_dict(chkmap))
1995
1965
# serialising should only serialise the new data - although k22 hasn't
1996
1966
# changed because its a special corner case (splitting on with only one
1997
1967
# key leaves one node unaltered), in general k22 is serialised, so we
1998
1968
# expect k22, k23, the new internal node, and node, to be serialised.
1999
1969
keys = list(node.serialise(chkmap._store))
2000
1970
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))
1971
k22_key = child._items['k22']._key
1972
k23_key = child._items['k23']._key
1973
self.assertEqual([k22_key, k23_key, child_key, node.key()], keys)
2004
1974
self.assertEqualDiff("'' InternalNode\n"
2005
1975
" 'k1' LeafNode\n"
2006
1976
" ('k1',) 'foo'\n"
2207
2182
def test__read_all_roots_multi_new_prepares_queues(self):
2208
2183
c_map = self.make_one_deep_map(chk_map._search_key_plain)
2209
2184
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')
2185
c_map._dump_tree() # load everything
2186
key1_a = c_map._root_node._items['a'].key()
2187
key1_c = c_map._root_node._items['c'].key()
2188
c_map.map(('abb',), 'new abb content')
2214
2189
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()
2190
key2_a = c_map._root_node._items['a'].key()
2191
key2_c = c_map._root_node._items['c'].key()
2217
2192
c_map = chk_map.CHKMap(self.get_chk_bytes(), key1,
2218
2193
chk_map._search_key_plain)
2219
c_map.map((b'ccc',), b'new ccc content')
2194
c_map.map(('ccc',), 'new ccc content')
2220
2195
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()
2196
key3_a = c_map._root_node._items['a'].key()
2197
key3_c = c_map._root_node._items['c'].key()
2223
2198
diff = self.get_difference([key2, key3], [key1],
2224
2199
chk_map._search_key_plain)
2225
2200
root_results = [record.key for record in diff._read_all_roots()]
2226
2201
self.assertEqual(sorted([key2, key3]), sorted(root_results))
2227
2202
# 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))
2203
self.assertEqual([key2_a, key3_c], diff._new_queue)
2229
2204
self.assertEqual([], diff._new_item_queue)
2230
2205
# 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))
2206
self.assertEqual([key1_a, key1_c], diff._old_queue)
2233
2208
def test__read_all_roots_different_depths(self):
2234
2209
c_map = self.make_two_deep_map(chk_map._search_key_plain)
2235
c_map._dump_tree() # load everything
2210
c_map._dump_tree() # load everything
2236
2211
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()
2212
key1_a = c_map._root_node._items['a'].key()
2213
key1_c = c_map._root_node._items['c'].key()
2214
key1_d = c_map._root_node._items['d'].key()
2241
2216
c_map2 = self.make_one_deep_two_prefix_map(chk_map._search_key_plain)
2242
2217
c_map2._dump_tree()
2243
2218
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()
2219
key2_aa = c_map2._root_node._items['aa'].key()
2220
key2_ad = c_map2._root_node._items['ad'].key()
2247
2222
diff = self.get_difference([key2], [key1], chk_map._search_key_plain)
2248
2223
root_results = [record.key for record in diff._read_all_roots()]