1 /*******************************************************************************
2 * Copyright (c) 2015 École Polytechnique de Montréal
4 * All rights reserved. This program and the accompanying materials are
5 * made available under the terms of the Eclipse Public License v1.0 which
6 * accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
8 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.statesystem
.core
.tests
.backend
.historytree
;
12 import static org
.junit
.Assert
.assertEquals
;
13 import static org
.junit
.Assert
.assertNotNull
;
14 import static org
.junit
.Assert
.fail
;
17 import java
.io
.IOException
;
18 import java
.nio
.channels
.ClosedChannelException
;
19 import java
.util
.List
;
21 import org
.eclipse
.jdt
.annotation
.Nullable
;
22 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTConfig
;
23 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTInterval
;
24 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HTNode
;
25 import org
.eclipse
.tracecompass
.internal
.statesystem
.core
.backend
.historytree
.HistoryTree
;
26 import org
.eclipse
.tracecompass
.statesystem
.core
.statevalue
.TmfStateValue
;
27 import org
.eclipse
.tracecompass
.statesystem
.core
.tests
.stubs
.backend
.HistoryTreeStub
;
28 import org
.junit
.After
;
29 import org
.junit
.Before
;
30 import org
.junit
.Test
;
33 * Tests the history tree
35 * @author Geneviève Bastien
37 public class HistoryTreeTest
{
40 /* Minimal allowed blocksize */
41 private static final int BLOCK_SIZE
= HistoryTree
.TREE_HEADER_SIZE
;
43 private static final HTInterval NULL_INTERVAL
= new HTInterval(10, 20, 1, TmfStateValue
.nullValue());
45 /* String with 23 characters, interval in file will be 25 bytes long */
46 private static final String TEST_STRING
= "abcdefghifklmnopqrstuvw";
47 private static final TmfStateValue STRING_VALUE
= TmfStateValue
.newValueString(TEST_STRING
);
48 private static final HTInterval STRING_INTERVAL
= new HTInterval(10, 20, 1, STRING_VALUE
);
50 private static final TmfStateValue LONG_VALUE
= TmfStateValue
.newValueLong(10L);
51 private static final HTInterval LONG_INTERVAL
= new HTInterval(10, 20, 1, LONG_VALUE
);
53 private static final TmfStateValue INT_VALUE
= TmfStateValue
.newValueInt(1);
54 private static final HTInterval INT_INTERVAL
= new HTInterval(10, 20, 1, INT_VALUE
);
56 private @Nullable File fTempFile
;
59 * Create the temporary file for this history tree
62 public void setupTest() {
64 fTempFile
= File
.createTempFile("tmpStateSystem", null);
65 } catch (IOException e
) {
71 * Delete the temporary history tree file after the test
74 public void cleanup() {
75 if (fTempFile
!= null) {
81 * Setup a history tree.
84 * The max number of children per node in the tree (tree config
87 private HistoryTreeStub
setupSmallTree(int maxChildren
) {
88 HistoryTreeStub ht
= null;
90 File newFile
= fTempFile
;
91 assertNotNull(newFile
);
92 HTConfig config
= new HTConfig(newFile
,
94 maxChildren
, /* Number of children */
95 1, /* Provider version */
97 ht
= new HistoryTreeStub(config
);
99 } catch (IOException e
) {
100 fail(e
.getMessage());
108 * Setup a history tree with config MAX_CHILDREN = 3.
110 private HistoryTreeStub
setupSmallTree() {
111 return setupSmallTree(3);
114 private static long fillValues(HistoryTree ht
, TmfStateValue value
, int nbValues
, long start
) {
115 for (int i
= 0; i
< nbValues
; i
++) {
116 ht
.insertInterval(new HTInterval(start
+ i
, start
+ i
+ 1, 1, value
));
118 return start
+ nbValues
;
122 * Insert intervals in the tree to fill the current leaf node to capacity,
123 * without exceeding it.
125 * This guarantees that the following insertion will create new nodes.
128 * The history tree in which to insert
129 * @return Start time of the current leaf node. Future insertions should be
130 * greater than or equal to this to make sure the intervals go in
133 private static long fillNextLeafNode(HistoryTreeStub ht
, long leafNodeStart
) {
134 int prevCount
= ht
.getNodeCount();
135 int prevDepth
= ht
.getDepth();
137 /* Fill the following leaf node */
138 HTNode node
= ht
.getLatestLeaf();
139 int intervalSize
= STRING_INTERVAL
.getSizeOnDisk();
140 int nodeFreeSpace
= node
.getNodeFreeSpace();
141 int nbIntervals
= nodeFreeSpace
/ intervalSize
;
142 long ret
= fillValues(ht
, STRING_VALUE
, nbIntervals
, leafNodeStart
);
144 /* Make sure we haven't changed the depth or node count */
145 assertEquals(prevCount
, ht
.getNodeCount());
146 assertEquals(prevDepth
, ht
.getDepth());
152 * Test that nodes are filled
154 * It fills nodes with sequential intervals from one attribute only, so that
155 * leafs should be filled.
158 public void testSequentialFill() {
159 HistoryTreeStub ht
= setupSmallTree();
161 HTNode node
= ht
.getLatestLeaf();
162 assertEquals(0, node
.getNodeUsagePercent());
164 /* Add null intervals up to ~10% */
165 int nodeFreeSpace
= node
.getNodeFreeSpace();
166 int intervalSize
= NULL_INTERVAL
.getSizeOnDisk();
167 int nbIntervals
= nodeFreeSpace
/ 10 / intervalSize
;
168 long start
= fillValues(ht
, TmfStateValue
.nullValue(), nbIntervals
, 1);
169 assertEquals(nodeFreeSpace
- nbIntervals
* intervalSize
, node
.getNodeFreeSpace());
171 /* Add integer intervals up to ~20% */
172 nodeFreeSpace
= node
.getNodeFreeSpace();
173 intervalSize
= INT_INTERVAL
.getSizeOnDisk();
174 nbIntervals
= nodeFreeSpace
/ 10 / intervalSize
;
175 start
= fillValues(ht
, INT_VALUE
, nbIntervals
, start
);
176 assertEquals(nodeFreeSpace
- nbIntervals
* intervalSize
, node
.getNodeFreeSpace());
178 /* Add long intervals up to ~30% */
179 nodeFreeSpace
= node
.getNodeFreeSpace();
180 intervalSize
= LONG_INTERVAL
.getSizeOnDisk();
181 nbIntervals
= nodeFreeSpace
/ 10 / intervalSize
;
182 start
= fillValues(ht
, LONG_VALUE
, nbIntervals
, start
);
183 assertEquals(nodeFreeSpace
- nbIntervals
* intervalSize
, node
.getNodeFreeSpace());
185 /* Add string intervals up to ~40% */
186 nodeFreeSpace
= node
.getNodeFreeSpace();
187 intervalSize
= STRING_INTERVAL
.getSizeOnDisk();
188 nbIntervals
= nodeFreeSpace
/ 10 / intervalSize
;
189 start
= fillValues(ht
, STRING_VALUE
, nbIntervals
, start
);
190 assertEquals(nodeFreeSpace
- nbIntervals
* intervalSize
, node
.getNodeFreeSpace());
195 * Test the addition of new nodes to the tree and make sure the tree is
196 * built with the right structure
199 public void testDepth() {
200 HistoryTreeStub ht
= setupSmallTree();
202 /* Fill a first node */
203 HTNode node
= ht
.getLatestLeaf();
204 int nodeFreeSpace
= node
.getNodeFreeSpace();
205 int nbIntervals
= nodeFreeSpace
/ (STRING_INTERVAL
.getSizeOnDisk());
206 long start
= fillValues(ht
, STRING_VALUE
, nbIntervals
, 1);
208 /* Add intervals that should add a sibling to the node */
209 assertEquals(1, ht
.getNodeCount());
210 assertEquals(1, ht
.getDepth());
211 start
= fillValues(ht
, STRING_VALUE
, 1, start
);
212 assertEquals(3, ht
.getNodeCount());
213 assertEquals(2, ht
.getDepth());
215 /* Fill the latest leaf node (2nd child) */
216 node
= ht
.getLatestLeaf();
217 nodeFreeSpace
= node
.getNodeFreeSpace();
218 nbIntervals
= nodeFreeSpace
/ (STRING_INTERVAL
.getSizeOnDisk());
219 start
= fillValues(ht
, STRING_VALUE
, nbIntervals
, start
);
222 * Add an interval that should add another sibling to the previous nodes
224 start
= fillValues(ht
, STRING_VALUE
, 1, start
);
225 assertEquals(4, ht
.getNodeCount());
226 assertEquals(2, ht
.getDepth());
228 /* Fill the latest leaf node (3rd and last child) */
229 node
= ht
.getLatestLeaf();
230 nodeFreeSpace
= node
.getNodeFreeSpace();
231 nbIntervals
= nodeFreeSpace
/ (STRING_INTERVAL
.getSizeOnDisk());
232 start
= fillValues(ht
, STRING_VALUE
, nbIntervals
, start
);
234 /* The new node created here should generate a new branch */
235 start
= fillValues(ht
, STRING_VALUE
, 1, start
);
236 assertEquals(7, ht
.getNodeCount());
237 assertEquals(3, ht
.getDepth());
241 * Make sure the node sequence numbers and parent pointers are set correctly
242 * when new nodes are created.
245 * We are building a tree whose node sequence numbers will look like this at
258 * However while building, the parent pointers may be different.
261 * @throws ClosedChannelException
265 public void testNodeSequenceNumbers() throws ClosedChannelException
{
266 /* Represents the start time of the current leaf node */
269 HistoryTreeStub ht
= setupSmallTree(2);
270 start
= fillNextLeafNode(ht
, start
);
272 List
<HTNode
> branch
= ht
.getLatestBranch();
273 assertEquals(1, branch
.size());
274 assertEquals( 0, branch
.get(0).getSequenceNumber());
275 assertEquals(-1, branch
.get(0).getParentSequenceNumber());
277 /* Create a new branch */
278 start
= fillValues(ht
, STRING_VALUE
, 1, start
);
279 start
= fillNextLeafNode(ht
, start
);
280 assertEquals(3, ht
.getNodeCount());
281 assertEquals(2, ht
.getDepth());
283 /* Make sure the first node's parent was updated */
284 HTNode node
= ht
.readNode(0);
285 assertEquals(0, node
.getSequenceNumber());
286 assertEquals(1, node
.getParentSequenceNumber());
288 /* Make sure the new branch is alright */
289 branch
= ht
.getLatestBranch();
290 assertEquals(2, branch
.size());
291 assertEquals( 1, branch
.get(0).getSequenceNumber());
292 assertEquals(-1, branch
.get(0).getParentSequenceNumber());
293 assertEquals( 2, branch
.get(1).getSequenceNumber());
294 assertEquals( 1, branch
.get(1).getParentSequenceNumber());
296 /* Create a third branch */
297 start
= fillValues(ht
, STRING_VALUE
, 1, start
);
298 start
= fillNextLeafNode(ht
, start
);
299 assertEquals(6, ht
.getNodeCount());
300 assertEquals(3, ht
.getDepth());
302 /* Make sure all previous nodes are still correct */
303 node
= ht
.readNode(0);
304 assertEquals(0, node
.getSequenceNumber());
305 assertEquals(1, node
.getParentSequenceNumber());
306 node
= ht
.readNode(1);
307 assertEquals(1, node
.getSequenceNumber());
308 assertEquals(3, node
.getParentSequenceNumber());
309 node
= ht
.readNode(2);
310 assertEquals(2, node
.getSequenceNumber());
311 assertEquals(1, node
.getParentSequenceNumber());
313 /* Verify the contents of the new latest branch */
314 branch
= ht
.getLatestBranch();
315 assertEquals(3, branch
.size());
316 assertEquals( 3, branch
.get(0).getSequenceNumber());
317 assertEquals(-1, branch
.get(0).getParentSequenceNumber());
318 assertEquals( 4, branch
.get(1).getSequenceNumber());
319 assertEquals( 3, branch
.get(1).getParentSequenceNumber());
320 assertEquals( 5, branch
.get(2).getSequenceNumber());
321 assertEquals( 4, branch
.get(2).getParentSequenceNumber());