blob: 1939cb75f3e61359ef3d6196902e24134417c268 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.tracecompass.internal.datastore.core.historytree;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.datastore.core.interval.HTInterval;
import org.eclipse.tracecompass.internal.datastore.core.historytree.HtIo;
import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.HTNode;
import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.HistoryTreeStub;
import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.HtTestUtils;
import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.IHTNode.NodeType;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* Test the {@link HtIo} class
*
* @author Geneviève Bastien
*/
public class HtIoTest {
private static final int BLOCKSIZE = HtTestUtils.BLOCKSIZE;
private static final int NB_CHILDREN = 3;
private @Nullable HtIo<HTInterval, HTNode<HTInterval>> fHtIo;
private @Nullable File fStateFile;
/**
* Construct the tree IO Object
*
* @throws IOException
* Exception with the file
*/
@Before
public void setUp() throws IOException {
File file = File.createTempFile("tmp", null);
assertNotNull(file);
fStateFile = file;
fHtIo = new HtIo<>(file,
HtTestUtils.BLOCKSIZE,
NB_CHILDREN,
true,
HtTestUtils.READ_FACTORY,
HistoryTreeStub.NODE_FACTORY);
}
/**
* Delete the file after test
*/
@After
public void cleanUp() {
HtIo<HTInterval, HTNode<HTInterval>> htIo = fHtIo;
if (htIo != null) {
htIo.deleteFile();
}
}
private static HTNode<HTInterval> createCoreNode(int seqNum, int parentNum) {
HTNode<HTInterval> node = HistoryTreeStub.NODE_FACTORY.createNode(NodeType.CORE,
BLOCKSIZE, NB_CHILDREN, seqNum, parentNum, 0L);
return node;
}
private static HTNode<HTInterval> createLeafNode(int seqNum, int parentNum) {
HTNode<HTInterval> node = HistoryTreeStub.NODE_FACTORY.createNode(NodeType.LEAF,
BLOCKSIZE, NB_CHILDREN, seqNum, parentNum, 0L);
return node;
}
/**
* Test reading and writing nodes
*
* @throws IOException
* Exception thrown by the file
*/
@Test
public void testReadWriteNode() throws IOException {
HtIo<HTInterval, HTNode<HTInterval>> htio = fHtIo;
assertNotNull(htio);
int coreNodeSeqNum = 0;
int leafNodeSeqNum = 1;
// Add a core node and a leaf node
HTNode<HTInterval> coreNode = createCoreNode(coreNodeSeqNum, -1);
assertFalse(HtIo.isInCache(htio, coreNodeSeqNum));
htio.writeNode(coreNode);
assertTrue(HtIo.isInCache(htio, coreNodeSeqNum));
HTNode<HTInterval> leafNode = createLeafNode(leafNodeSeqNum, coreNodeSeqNum);
assertFalse(HtIo.isInCache(htio, leafNodeSeqNum));
htio.writeNode(leafNode);
assertTrue(HtIo.isInCache(htio, leafNodeSeqNum));
// Now read the nodes from the same htio object, they should be in cache
HTNode<HTInterval> coreRead = htio.readNode(coreNodeSeqNum);
assertEquals(coreNode, coreRead);
HTNode<HTInterval> leafRead = htio.readNode(leafNodeSeqNum);
assertEquals(leafNode, leafRead);
// Invalidate the cache
HtIo.clearCache();
// Re-read the nodes, they should now be read from disk and be in the
// cache after
assertFalse(HtIo.isInCache(htio, coreNodeSeqNum));
coreRead = htio.readNode(coreNodeSeqNum);
assertEquals(coreNode, coreRead);
assertTrue(HtIo.isInCache(htio, coreNodeSeqNum));
// Read the leaf node from disk
assertFalse(HtIo.isInCache(htio, leafNodeSeqNum));
leafRead = htio.readNode(leafNodeSeqNum);
assertEquals(leafNode, leafRead);
assertTrue(HtIo.isInCache(htio, leafNodeSeqNum));
// Close the file and reopen a new htio object
htio.closeFile();
assertNotNull(fStateFile);
htio = new HtIo<>(fStateFile,
BLOCKSIZE,
NB_CHILDREN,
false,
HtTestUtils.READ_FACTORY,
HistoryTreeStub.NODE_FACTORY);
fHtIo = htio;
// Read the core node from the disk
assertFalse(HtIo.isInCache(htio, coreNodeSeqNum));
coreRead = htio.readNode(coreNodeSeqNum);
assertEquals(coreNode, coreRead);
// Read the leaf node from the disk
assertFalse(HtIo.isInCache(htio, leafNodeSeqNum));
leafRead = htio.readNode(leafNodeSeqNum);
assertEquals(leafNode, leafRead);
// Re-read the nodes, they should have been read from the cache
assertTrue(HtIo.isInCache(htio, coreNodeSeqNum));
coreRead = htio.readNode(coreNodeSeqNum);
assertEquals(coreNode, coreRead);
// Read the leaf node from cache
assertTrue(HtIo.isInCache(htio, leafNodeSeqNum));
leafRead = htio.readNode(leafNodeSeqNum);
assertEquals(leafNode, leafRead);
}
/**
* Test that the section at the end of the file where extra data can be
* written works well
*
* @throws IOException
* Exception thrown by the file
*/
@Test
public void testExtraDataSave() throws IOException {
writeBufferAtNodePos(2);
}
/**
* Test that writing at the beginning of the file works well
*
* @throws IOException
* Exception thrown by the file
*/
@Test
public void testHeaderDataSave() throws IOException {
writeBufferAtNodePos(-1);
}
/**
* Test that writing data far beyond the node section end works.
*
* @throws IOException
* Exception thrown by the file
*/
@Test
public void testTooFarData() throws IOException {
writeBufferAtNodePos(6);
}
private void writeBufferAtNodePos(int nodeOffset) throws IOException {
HtIo<HTInterval, HTNode<HTInterval>> htio = fHtIo;
assertNotNull(htio);
int coreNodeSeqNum = 0;
int leafNodeSeqNum = 1;
// Add a core node and a leaf node
HTNode<HTInterval> coreNode = createCoreNode(coreNodeSeqNum, -1);
assertFalse(HtIo.isInCache(htio, coreNodeSeqNum));
htio.writeNode(coreNode);
assertTrue(HtIo.isInCache(htio, coreNodeSeqNum));
HTNode<HTInterval> leafNode = createLeafNode(leafNodeSeqNum, coreNodeSeqNum);
assertFalse(HtIo.isInCache(htio, leafNodeSeqNum));
htio.writeNode(leafNode);
assertTrue(HtIo.isInCache(htio, leafNodeSeqNum));
// Write 3 integers at some position of the file
ByteBuffer buffer = ByteBuffer.allocate(12);
buffer.putInt(32);
buffer.putInt(33);
buffer.putInt(232);
buffer.flip();
try (FileOutputStream fcOut = htio.getFileWriter(nodeOffset)) {
fcOut.write(buffer.array());
}
// Close the file and reopen a new htio object
htio.closeFile();
assertNotNull(fStateFile);
htio = new HtIo<>(fStateFile,
BLOCKSIZE,
NB_CHILDREN,
false,
HtTestUtils.READ_FACTORY,
HistoryTreeStub.NODE_FACTORY);
fHtIo = htio;
// Read the same 3 integers at the same position in the file
byte[] bytes = new byte[12];
htio.supplyATReader(nodeOffset).read(bytes);
buffer = ByteBuffer.wrap(bytes);
assertEquals(32, buffer.getInt());
assertEquals(33, buffer.getInt());
assertEquals(232, buffer.getInt());
}
}