43
43
condition_isinstance(TestBTreeNodes))
44
44
import bzrlib._btree_serializer_py as py_module
45
45
scenarios = [('python', {'parse_btree': py_module})]
46
if CompiledBtreeParserFeature.available():
47
# Is there a way to do this that gets missing feature failures rather
48
# than no indication to the user?
49
import bzrlib._btree_serializer_pyx as c_module
50
scenarios.append(('C', {'parse_btree': c_module}))
46
if compiled_btreeparser_feature.available():
47
scenarios.append(('C', {'parse_btree':
48
compiled_btreeparser_feature.module}))
51
49
return multiply_tests(node_tests, scenarios, others)
54
class _CompiledBtreeParserFeature(tests.Feature):
57
import bzrlib._btree_serializer_pyx
62
def feature_name(self):
63
return 'bzrlib._btree_serializer_pyx'
65
CompiledBtreeParserFeature = _CompiledBtreeParserFeature()
52
compiled_btreeparser_feature = tests.ModuleAvailableFeature(
53
'bzrlib._btree_serializer_pyx')
68
56
class BTreeTestCase(TestCaseWithTransport):
125
113
class TestBTreeBuilder(BTreeTestCase):
115
def test_clear_cache(self):
116
builder = btree_index.BTreeBuilder(reference_lists=0, key_elements=1)
117
# This is a no-op, but we need the api to be consistent with other
118
# BTreeGraphIndex apis.
119
builder.clear_cache()
127
121
def test_empty_1_0(self):
128
122
builder = btree_index.BTreeBuilder(key_elements=1, reference_lists=0)
129
123
# NamedTemporaryFile dies on builder.finish().read(). weird.
155
149
temp_file = builder.finish()
156
150
content = temp_file.read()
158
self.assertEqual(158, len(content))
152
self.assertEqual(131, len(content))
159
153
self.assertEqual(
160
154
"B+Tree Graph Index 2\nnode_ref_lists=0\nkey_elements=1\nlen=5\n"
161
155
"row_lengths=1\n",
179
173
temp_file = builder.finish()
180
174
content = temp_file.read()
182
self.assertEqual(264, len(content))
176
self.assertEqual(238, len(content))
183
177
self.assertEqual(
184
178
"B+Tree Graph Index 2\nnode_ref_lists=2\nkey_elements=2\nlen=10\n"
185
179
"row_lengths=1\n",
245
239
temp_file = builder.finish()
246
240
content = temp_file.read()
248
self.assertEqual(181, len(content))
242
self.assertEqual(155, len(content))
249
243
self.assertEqual(
250
244
"B+Tree Graph Index 2\nnode_ref_lists=0\nkey_elements=1\nlen=10\n"
251
245
"row_lengths=1\n",
353
347
# Test the parts of the index that take up memory are doing so
355
349
self.assertEqual(1, len(builder._nodes))
356
self.assertEqual(1, len(builder._keys))
357
350
self.assertIs(None, builder._nodes_by_key)
358
351
builder.add_node(*nodes[1])
359
352
self.assertEqual(0, len(builder._nodes))
360
self.assertEqual(0, len(builder._keys))
361
353
self.assertIs(None, builder._nodes_by_key)
362
354
self.assertEqual(1, len(builder._backing_indices))
363
355
self.assertEqual(2, builder._backing_indices[0].key_count())
364
356
# now back to memory
365
357
builder.add_node(*nodes[2])
366
358
self.assertEqual(1, len(builder._nodes))
367
self.assertEqual(1, len(builder._keys))
368
359
self.assertIs(None, builder._nodes_by_key)
369
360
# And spills to a second backing index combing all
370
361
builder.add_node(*nodes[3])
371
362
self.assertEqual(0, len(builder._nodes))
372
self.assertEqual(0, len(builder._keys))
373
363
self.assertIs(None, builder._nodes_by_key)
374
364
self.assertEqual(2, len(builder._backing_indices))
375
365
self.assertEqual(None, builder._backing_indices[0])
378
368
builder.add_node(*nodes[4])
379
369
builder.add_node(*nodes[5])
380
370
self.assertEqual(0, len(builder._nodes))
381
self.assertEqual(0, len(builder._keys))
382
371
self.assertIs(None, builder._nodes_by_key)
383
372
self.assertEqual(2, len(builder._backing_indices))
384
373
self.assertEqual(2, builder._backing_indices[0].key_count())
442
431
# Test the parts of the index that take up memory are doing so
444
433
self.assertEqual(1, len(builder._nodes))
445
self.assertEqual(1, len(builder._keys))
446
434
self.assertIs(None, builder._nodes_by_key)
447
435
builder.add_node(*nodes[1])
448
436
self.assertEqual(0, len(builder._nodes))
449
self.assertEqual(0, len(builder._keys))
450
437
self.assertIs(None, builder._nodes_by_key)
451
438
self.assertEqual(1, len(builder._backing_indices))
452
439
self.assertEqual(2, builder._backing_indices[0].key_count())
453
440
# now back to memory
454
441
builder.add_node(*nodes[2])
455
442
self.assertEqual(1, len(builder._nodes))
456
self.assertEqual(1, len(builder._keys))
457
443
self.assertIs(None, builder._nodes_by_key)
458
444
# And spills to a second backing index but doesn't combine
459
445
builder.add_node(*nodes[3])
460
446
self.assertEqual(0, len(builder._nodes))
461
self.assertEqual(0, len(builder._keys))
462
447
self.assertIs(None, builder._nodes_by_key)
463
448
self.assertEqual(2, len(builder._backing_indices))
464
449
for backing_index in builder._backing_indices:
467
452
builder.add_node(*nodes[4])
468
453
builder.add_node(*nodes[5])
469
454
self.assertEqual(0, len(builder._nodes))
470
self.assertEqual(0, len(builder._keys))
471
455
self.assertIs(None, builder._nodes_by_key)
472
456
self.assertEqual(3, len(builder._backing_indices))
473
457
for backing_index in builder._backing_indices:
532
516
builder.add_node(*nodes[0])
533
517
# Test the parts of the index that take up memory are doing so
535
self.assertEqual(1, len(builder._keys))
536
519
self.assertEqual(1, len(builder._nodes))
537
520
self.assertIs(None, builder._nodes_by_key)
538
521
builder.add_node(*nodes[1])
539
self.assertEqual(0, len(builder._keys))
540
522
self.assertEqual(0, len(builder._nodes))
541
523
self.assertIs(None, builder._nodes_by_key)
542
524
self.assertEqual(1, len(builder._backing_indices))
545
527
old = dict(builder._get_nodes_by_key()) #Build up the nodes by key dict
546
528
builder.add_node(*nodes[2])
547
529
self.assertEqual(1, len(builder._nodes))
548
self.assertEqual(1, len(builder._keys))
549
530
self.assertIsNot(None, builder._nodes_by_key)
550
531
self.assertNotEqual({}, builder._nodes_by_key)
551
532
# We should have a new entry
553
534
# And spills to a second backing index combing all
554
535
builder.add_node(*nodes[3])
555
536
self.assertEqual(0, len(builder._nodes))
556
self.assertEqual(0, len(builder._keys))
557
537
self.assertIs(None, builder._nodes_by_key)
558
538
self.assertEqual(2, len(builder._backing_indices))
559
539
self.assertEqual(None, builder._backing_indices[0])
562
542
builder.add_node(*nodes[4])
563
543
builder.add_node(*nodes[5])
564
544
self.assertEqual(0, len(builder._nodes))
565
self.assertEqual(0, len(builder._keys))
566
545
self.assertIs(None, builder._nodes_by_key)
567
546
self.assertEqual(2, len(builder._backing_indices))
568
547
self.assertEqual(2, builder._backing_indices[0].key_count())
639
618
size = trans.put_file('index', stream)
640
619
return btree_index.BTreeGraphIndex(trans, 'index', size)
621
def test_clear_cache(self):
622
nodes = self.make_nodes(160, 2, 2)
623
index = self.make_index(ref_lists=2, key_elements=2, nodes=nodes)
624
self.assertEqual(1, len(list(index.iter_entries([nodes[30][0]]))))
625
self.assertEqual([1, 4], index._row_lengths)
626
self.assertIsNot(None, index._root_node)
627
internal_node_pre_clear = index._internal_node_cache.keys()
628
self.assertTrue(len(index._leaf_node_cache) > 0)
630
# We don't touch _root_node or _internal_node_cache, both should be
631
# small, and can save a round trip or two
632
self.assertIsNot(None, index._root_node)
633
# NOTE: We don't want to affect the _internal_node_cache, as we expect
634
# it will be small, and if we ever do touch this index again, it
635
# will save round-trips. This assertion isn't very strong,
636
# becuase without a 3-level index, we don't have any internal
638
self.assertEqual(internal_node_pre_clear,
639
index._internal_node_cache.keys())
640
self.assertEqual(0, len(index._leaf_node_cache))
642
642
def test_trivial_constructor(self):
643
643
transport = get_transport('trace+' + self.get_url(''))
644
644
index = btree_index.BTreeGraphIndex(transport, 'index', None)
691
691
# The entire index should have been read, as it is one page long.
692
692
self.assertEqual([('readv', 'index', [(0, size)], False, None)],
693
693
transport._activity)
694
self.assertEqual(1199, size)
694
self.assertEqual(1173, size)
696
696
def test__read_nodes_no_size_one_page_reads_once(self):
697
697
self.make_index(nodes=[(('key',), 'value', ())])
745
745
# The entire index should have been read linearly.
746
746
self.assertEqual([('readv', 'index', [(0, size)], False, None)],
747
747
transport._activity)
748
self.assertEqual(1514, size)
748
self.assertEqual(1488, size)
750
750
def test_validate_two_pages(self):
751
751
builder = btree_index.BTreeBuilder(key_elements=2, reference_lists=2)
1281
1281
def test_exists(self):
1282
1282
# This is just to let the user know if they don't have the feature
1284
self.requireFeature(CompiledBtreeParserFeature)
1284
self.requireFeature(compiled_btreeparser_feature)
1287
1287
class TestMultiBisectRight(tests.TestCase):