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