@@ -294,6 +294,7 @@ TEST(BPlusTreeTests, DISABLED_TombstoneCoalesceTest) {
294294 GenericKey<8 > index_key;
295295 RID rid;
296296
297+ // insert 0, 1, 2, 3, 4, 5, 6 into the b+ tree
297298 size_t num_keys = 7 ;
298299 for (size_t i = 0 ; i < num_keys; i++) {
299300 int64_t value = i & 0xFFFFFFFF ;
@@ -302,8 +303,9 @@ TEST(BPlusTreeTests, DISABLED_TombstoneCoalesceTest) {
302303 tree.Insert (index_key, rid);
303304 }
304305
305- page_id_t larger_pid;
306- page_id_t smaller_pid;
306+ // there should be a larger leaf page and a smaller leaf page
307+ page_id_t larger_pid = INVALID_PAGE_ID;
308+ page_id_t smaller_pid = INVALID_PAGE_ID;
307309 auto leaf = IndexLeaves<GenericKey<8 >, RID, GenericComparator<8 >, 2 >(tree.GetRootPageId (), bpm);
308310 while (leaf.Valid ()) {
309311 if ((*leaf)->GetSize () == 4 ) {
@@ -313,49 +315,75 @@ TEST(BPlusTreeTests, DISABLED_TombstoneCoalesceTest) {
313315 }
314316 ++leaf;
315317 }
318+ ASSERT_NE (larger_pid, INVALID_PAGE_ID);
319+ ASSERT_NE (smaller_pid, INVALID_PAGE_ID);
316320
317- std::vector<GenericKey<8 >> to_delete;
321+ // figure out keys to delete from the larger and smaller pages
322+ std::vector<GenericKey<8 >> to_del_from_larger_page;
323+ std::vector<GenericKey<8 >> to_del_from_smaller_page;
318324 {
319325 auto larger_page = bpm->ReadPage (larger_pid).As <LeafPage>();
320326 auto smaller_page = bpm->ReadPage (smaller_pid).As <LeafPage>();
321- for (size_t i = 0 ; i < 2 ; i++) {
322- to_delete.push_back (larger_page->KeyAt (2 + i));
323- to_delete.push_back (smaller_page->KeyAt (i));
324- }
325- to_delete.push_back (larger_page->KeyAt (0 ));
326- to_delete.push_back (smaller_page->KeyAt (2 ));
327+
328+ to_del_from_larger_page = {
329+ larger_page->KeyAt (0 ),
330+ larger_page->KeyAt (1 ),
331+ larger_page->KeyAt (2 ),
332+ };
333+ to_del_from_smaller_page = {
334+ smaller_page->KeyAt (0 ),
335+ smaller_page->KeyAt (1 ),
336+ smaller_page->KeyAt (2 ),
337+ };
327338 }
328- for (auto k : to_delete) {
339+
340+ // delete keys alternating between the larger and smaller pages.
341+ // The final delete from the smaller page should force a coalesce.
342+ std::vector<GenericKey<8 >> to_del = {
343+ // clang-format off
344+ // Otherwise these are folded into two hard-to-read lines
345+ to_del_from_larger_page[0 ],
346+ to_del_from_smaller_page[0 ],
347+ to_del_from_larger_page[1 ],
348+ to_del_from_smaller_page[1 ],
349+ to_del_from_larger_page[2 ],
350+ to_del_from_smaller_page[2 ],
351+ // clang-format on
352+ };
353+ for (auto k : to_del) {
329354 tree.Remove (k);
330355 }
331356
332- size_t num_leaves = 0 ;
333- page_id_t remaining_pid ;
357+ // ensure index is still correct
358+ std::vector< page_id_t > leaves ;
334359 leaf = IndexLeaves<GenericKey<8 >, RID, GenericComparator<8 >, 2 >(tree.GetRootPageId (), bpm);
335360 while (leaf.Valid ()) {
336- remaining_pid = leaf.guard_ ->GetPageId ();
337- num_leaves++;
361+ leaves.push_back (leaf.guard_ ->GetPageId ());
338362 ++leaf;
339363 }
364+ ASSERT_EQ (leaves, std::vector<page_id_t >{tree.GetRootPageId ()});
365+
366+ // get the only leaf page in the b+ tree
367+ page_id_t root_page_id = tree.GetRootPageId ();
368+ auto root_page = bpm->ReadPage (root_page_id).As <LeafPage>();
369+ ASSERT_EQ (root_page->IsLeafPage (), true );
340370
341- EXPECT_EQ (num_leaves, 1 );
342- auto page = bpm->ReadPage (remaining_pid).As <LeafPage>();
343- auto tombstones = page->GetTombstones ();
371+ auto tombstones = root_page->GetTombstones ();
344372 EXPECT_EQ (tombstones.size (), 2 );
345- if (remaining_pid == smaller_pid) {
346- EXPECT_EQ (tombstones[0 ].GetAsInteger (), to_delete[2 ].GetAsInteger ());
347- EXPECT_EQ (tombstones[1 ].GetAsInteger (), to_delete[4 ].GetAsInteger ());
348- index_key.SetFromInteger (7 );
349- int64_t value = 7 & 0xFFFFFFFF ;
350- rid.Set (static_cast <int32_t >(7L >> 32 ), value);
351- tree.Insert (index_key, rid);
352- EXPECT_EQ (tombstones[0 ].GetAsInteger (), to_delete[2 ].GetAsInteger ());
353- EXPECT_EQ (tombstones[1 ].GetAsInteger (), to_delete[4 ].GetAsInteger ());
354- } else {
355- EXPECT_EQ (tombstones[0 ].GetAsInteger (), to_delete[3 ].GetAsInteger ());
356- EXPECT_EQ (tombstones[1 ].GetAsInteger (), to_delete[5 ].GetAsInteger ());
373+
374+ // final set of tombstones should either be the last two keys logically
375+ // deleted from the smaller page or the last two keys logically deleted
376+ // from the larger page.
377+ bool eq_to_smaller_page = true ;
378+ bool eq_to_larger_page = true ;
379+ for (int i = 0 ; i < 2 ; i++) {
380+ eq_to_smaller_page &= tombstones[i].GetAsInteger () == to_del_from_smaller_page[1 + i].GetAsInteger ();
381+ eq_to_larger_page &= tombstones[i].GetAsInteger () == to_del_from_larger_page[1 + i].GetAsInteger ();
357382 }
358383
384+ ASSERT_EQ (!eq_to_smaller_page || !eq_to_larger_page, true );
385+ EXPECT_EQ (eq_to_smaller_page || eq_to_larger_page, true );
386+
359387 delete bpm;
360388 delete disk_manager;
361389}
0 commit comments