Test that the buffer pool handles a write error correctly. Delete the scratch directory before an operation that would cause a write and test that subsequent API calls return errors as expected.
| 1612 | // directory before an operation that would cause a write and test that subsequent API |
| 1613 | // calls return errors as expected. |
| 1614 | void BufferPoolTest::TestWriteError( |
| 1615 | int write_delay_ms, const string& compression, bool punch_holes) { |
| 1616 | InitTmpFileMgr(1, compression, punch_holes); |
| 1617 | int MAX_NUM_BUFFERS = 2; |
| 1618 | int64_t TOTAL_MEM = MAX_NUM_BUFFERS * TEST_BUFFER_LEN; |
| 1619 | BufferPool pool(test_env_->metrics(), TEST_BUFFER_LEN, TOTAL_MEM, TOTAL_MEM); |
| 1620 | global_reservations_.InitRootTracker(NewProfile(), TOTAL_MEM); |
| 1621 | ClientHandle client; |
| 1622 | ASSERT_OK(pool.RegisterClient("test client", NewFileGroup(), &global_reservations_, |
| 1623 | nullptr, TOTAL_MEM, NewProfile(), &client)); |
| 1624 | ASSERT_TRUE(client.IncreaseReservation(TOTAL_MEM)); |
| 1625 | client.impl_->set_debug_write_delay_ms(write_delay_ms); |
| 1626 | |
| 1627 | vector<PageHandle> pages; |
| 1628 | CreatePages(&pool, &client, TEST_BUFFER_LEN, MAX_NUM_BUFFERS, &pages); |
| 1629 | // Unpin two pages here, to ensure that backing storage is allocated in tmp file. |
| 1630 | UnpinAll(&pool, &client, &pages); |
| 1631 | WaitForAllWrites(&client); |
| 1632 | // Repin the pages |
| 1633 | ASSERT_OK(PinAll(&pool, &client, &pages)); |
| 1634 | // Remove permissions to the backing storage so that future writes will fail |
| 1635 | ASSERT_GT(RemoveScratchPerms(test_env_->tmp_file_mgr()->GetTmpDirPath(0)), 0); |
| 1636 | // Give the first write a chance to fail before the second write starts. |
| 1637 | const int INTERVAL_MS = 10; |
| 1638 | UnpinAll(&pool, &client, &pages, INTERVAL_MS); |
| 1639 | WaitForAllWrites(&client); |
| 1640 | |
| 1641 | // Subsequent calls to APIs that require allocating memory should fail: the write error |
| 1642 | // is picked up asynchronously. |
| 1643 | BufferHandle tmp_buffer; |
| 1644 | PageHandle tmp_page; |
| 1645 | Status error = pool.AllocateBuffer(&client, TEST_BUFFER_LEN, &tmp_buffer); |
| 1646 | EXPECT_EQ(TErrorCode::SCRATCH_ALLOCATION_FAILED, error.code()); |
| 1647 | ASSERT_NE(string::npos, error.msg().msg().find(GetBackendString())); |
| 1648 | EXPECT_FALSE(tmp_buffer.is_open()); |
| 1649 | error = pool.CreatePage(&client, TEST_BUFFER_LEN, &tmp_page); |
| 1650 | EXPECT_EQ(TErrorCode::SCRATCH_ALLOCATION_FAILED, error.code()); |
| 1651 | EXPECT_FALSE(tmp_page.is_open()); |
| 1652 | error = pool.Pin(&client, pages.data()); |
| 1653 | EXPECT_EQ(TErrorCode::SCRATCH_ALLOCATION_FAILED, error.code()); |
| 1654 | EXPECT_FALSE(pages[0].is_pinned()); |
| 1655 | |
| 1656 | // Transferring reservation does not result in an error. |
| 1657 | bool transferred; |
| 1658 | EXPECT_OK( |
| 1659 | client.TransferReservationTo(&global_reservations_, TEST_BUFFER_LEN, &transferred)); |
| 1660 | EXPECT_TRUE(transferred); |
| 1661 | |
| 1662 | DestroyAll(&pool, &client, &pages); |
| 1663 | pool.DeregisterClient(&client); |
| 1664 | global_reservations_.Close(); |
| 1665 | } |
| 1666 | |
| 1667 | TEST_F(BufferPoolTest, WriteError) { |
| 1668 | TestWriteError(0, "", false); |
nothing calls this directly
no test coverage detected