113
113
keys.append((key, value, refs))
116
def shrink_page_size(self):
117
"""Shrink the default page size so that less fits in a page."""
118
old_page_size = btree_index._PAGE_SIZE
120
btree_index._PAGE_SIZE = old_page_size
121
self.addCleanup(cleanup)
122
btree_index._PAGE_SIZE = 2048
117
125
class TestBTreeBuilder(BTreeTestCase):
277
285
# pointer to the second node that the internal node is for, _not_
278
286
# the first, otherwise the first node overlaps with the last node of
279
287
# the prior internal node on that row.
280
# We will be adding 140,000 nodes, so spill at 200,001 to prevent
281
# having to flush anything out to disk.
282
builder = btree_index.BTreeBuilder(key_elements=2, reference_lists=2,
284
# 140K nodes is *just* enough to create a two internal nodes on the
286
nodes = self.make_nodes(70000, 2, 2)
288
self.shrink_page_size()
289
builder = btree_index.BTreeBuilder(key_elements=2, reference_lists=2)
290
# 40K nodes is enough to create a two internal nodes on the second
291
# level, with a 2K page size
292
nodes = self.make_nodes(20000, 2, 2)
288
294
for node in nodes:
289
295
builder.add_node(*node)
683
689
def test_iter_all_entries_reads(self):
684
690
# iterating all entries reads the header, then does a linear
692
self.shrink_page_size()
686
693
builder = btree_index.BTreeBuilder(key_elements=2, reference_lists=2,
688
# 140k nodes is enough to create a three-level index, which shows that
689
# we skip the internal nodes and just read the leaf nodes.
690
nodes = self.make_nodes(70000, 2, 2)
695
# 40k nodes is enough to create a two internal nodes on the second
696
# level, with a 2K page size
697
nodes = self.make_nodes(20000, 2, 2)
691
698
for node in nodes:
692
699
builder.add_node(*node)
693
700
transport = get_transport('trace+' + self.get_url(''))
694
701
size = transport.put_file('index', builder.finish())
695
self.assertEqual(2624681, size, 'number of expected bytes in the'
702
self.assertEqual(780162, size, 'number of expected bytes in the'
704
page_size = btree_index._PAGE_SIZE
698
706
index = btree_index.BTreeGraphIndex(transport, 'index', size)
699
707
del transport._activity[:]
706
714
self.assertEqual(3, len(index._row_lengths),
707
715
"Not enough rows: %r" % index._row_lengths)
708
716
# Should be as long as the nodes we supplied
709
self.assertEqual(140000, len(found_nodes))
717
self.assertEqual(40000, len(found_nodes))
710
718
# Should have the same content
711
719
self.assertEqual(set(nodes), set(bare_nodes))
712
720
# Should have done linear scan IO up the index, ignoring
714
722
# The entire index should have been read
715
723
total_pages = sum(index._row_lengths)
716
724
self.assertEqual(total_pages, index._row_offsets[-1])
717
self.assertEqual(2624681, size)
725
self.assertEqual(780162, size)
718
726
# The start of the leaves
719
first_byte = index._row_offsets[-2] * btree_index._PAGE_SIZE
727
first_byte = index._row_offsets[-2] * page_size
720
728
readv_request = []
721
for offset in range(first_byte, size, 4096):
722
readv_request.append((offset, 4096))
729
for offset in range(first_byte, size, page_size):
730
readv_request.append((offset, page_size))
723
731
# The last page is truncated
724
readv_request[-1] = (readv_request[-1][0], 2624681 % 4096)
725
expected = [('readv', 'index', [(0, 4096)], False, None),
732
readv_request[-1] = (readv_request[-1][0], 780162 % page_size)
733
expected = [('readv', 'index', [(0, page_size)], False, None),
726
734
('readv', 'index', readv_request, False, None)]
727
735
if expected != transport._activity:
728
736
self.assertEqualDiff(pprint.pformat(expected),