use of org.apache.ignite.internal.processors.cache.persistence.file.RandomAccessFileIO in project ignite by apache.
the class CorruptedTreeFailureHandlingTest method testCorruptedPage.
/**
* Check that if a corrupted page exists, an {@link CorruptedTreeException}
* will be thrown and a diagnostic file will be generated.
*
* @throws Exception If failed.
*/
@Test
public void testCorruptedPage() throws Exception {
IgniteEx srv = startGrid(0);
File diagnosticDir = new File(srv.context().config().getWorkDirectory(), "diagnostic");
FileUtils.deleteDirectory(diagnosticDir);
srv.cluster().state(ClusterState.ACTIVE);
IgniteCache<Integer, Integer> cache = srv.getOrCreateCache(DEFAULT_CACHE_NAME);
for (int i = 0; i < 10; i++) cache.put(i, i);
int pageSize = srv.configuration().getDataStorageConfiguration().getPageSize();
int grpId = srv.context().cache().cacheGroups().stream().filter(context -> context.cacheOrGroupName().equals(DEFAULT_CACHE_NAME)).findAny().orElseThrow(() -> new RuntimeException("Cache group not found")).groupId();
stopGrid(0, false);
// Node is stopped, we're ready to corrupt partition data.
long link = linkRef.get();
long pageId = PageIdUtils.pageId(link);
int itemId = PageIdUtils.itemId(link);
ByteBuffer pageBuf = ByteBuffer.allocateDirect(pageSize);
OpenOption[] options = { StandardOpenOption.READ, StandardOpenOption.WRITE };
try (RandomAccessFileIO fileIO = new RandomAccessFileIO(fileRef.get(), options)) {
DataPageIO dataPageIO = DataPageIO.VERSIONS.latest();
long pageOff = pageSize + PageIdUtils.pageIndex(pageId) * pageSize;
// Read index page.
fileIO.position(pageOff);
fileIO.readFully(pageBuf);
long pageAddr = GridUnsafe.bufferAddress(pageBuf);
// Remove existing item from index page.
dataPageIO.removeRow(pageAddr, itemId, pageSize);
// Recalculate CRC.
PageIO.setCrc(pageAddr, 0);
pageBuf.rewind();
PageIO.setCrc(pageAddr, FastCrc.calcCrc(pageBuf, pageSize));
// Write it back.
pageBuf.rewind();
fileIO.position(pageOff);
fileIO.writeFully(pageBuf);
}
LogListener logLsnr = LogListener.matches("CorruptedTreeException has occurred. " + "To diagnose it, make a backup of the following directories: ").build();
srv = startGrid(0, cfg -> {
cfg.setGridLogger(new ListeningTestLogger(cfg.getGridLogger(), logLsnr));
});
// Add modified page to WAL so it won't be restored to previous (valid) state.
pageBuf.rewind();
ByteBuffer cpBuf = ByteBuffer.allocate(pageBuf.capacity());
cpBuf.put(pageBuf);
PageSnapshot pageSnapshot = new PageSnapshot(new FullPageId(pageId, grpId), cpBuf.array(), pageSize);
srv.context().cache().context().wal().log(pageSnapshot);
// Access cache.
cache = srv.cache(DEFAULT_CACHE_NAME);
try {
for (int i = 0; i < CACHE_ENTRIES; i++) cache.get(i);
fail("Cache operations are expected to fail");
} catch (Throwable e) {
assertTrue(X.hasCause(e, CorruptedTreeException.class));
}
assertTrue(GridTestUtils.waitForCondition(() -> G.allGrids().isEmpty(), 10_000L));
assertTrue(diagnosticDir.exists());
assertTrue(diagnosticDir.isDirectory());
Pattern corruptedPagesFileNamePtrn = corruptedPagesFileNamePattern();
File[] txtFiles = diagnosticDir.listFiles((dir, name) -> corruptedPagesFileNamePtrn.matcher(name).matches());
assertFalse(F.isEmpty(txtFiles));
assertEquals(1, txtFiles.length);
assertTrue(logLsnr.check());
}
Aggregations