Commit | Line | Data |
---|---|---|
8b03451b GB |
1 | /******************************************************************************* |
2 | * Copyright (c) 2017 École Polytechnique de Montréal | |
3 | * | |
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 | *******************************************************************************/ | |
9 | ||
10 | package org.eclipse.tracecompass.internal.datastore.core.historytree; | |
11 | ||
12 | import static org.junit.Assert.assertEquals; | |
13 | import static org.junit.Assert.assertFalse; | |
14 | import static org.junit.Assert.assertNotNull; | |
15 | import static org.junit.Assert.assertTrue; | |
16 | ||
17 | import java.io.File; | |
18 | import java.io.FileOutputStream; | |
19 | import java.io.IOException; | |
20 | import java.nio.ByteBuffer; | |
21 | ||
22 | import org.eclipse.jdt.annotation.Nullable; | |
dad84716 | 23 | import org.eclipse.tracecompass.datastore.core.interval.HTInterval; |
8b03451b GB |
24 | import org.eclipse.tracecompass.internal.datastore.core.historytree.HtIo; |
25 | import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.HTNode; | |
26 | import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.HistoryTreeStub; | |
27 | import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.HtTestUtils; | |
28 | import org.eclipse.tracecompass.internal.provisional.datastore.core.historytree.IHTNode.NodeType; | |
8b03451b GB |
29 | import org.junit.After; |
30 | import org.junit.Before; | |
31 | import org.junit.Test; | |
32 | ||
33 | /** | |
34 | * Test the {@link HtIo} class | |
35 | * | |
36 | * @author Geneviève Bastien | |
37 | */ | |
38 | public class HtIoTest { | |
39 | ||
40 | private static final int BLOCKSIZE = HtTestUtils.BLOCKSIZE; | |
41 | private static final int NB_CHILDREN = 3; | |
42 | ||
43 | private @Nullable HtIo<HTInterval, HTNode<HTInterval>> fHtIo; | |
44 | private @Nullable File fStateFile; | |
45 | ||
46 | /** | |
47 | * Construct the tree IO Object | |
48 | * | |
49 | * @throws IOException | |
50 | * Exception with the file | |
51 | */ | |
52 | @Before | |
53 | public void setUp() throws IOException { | |
54 | File file = File.createTempFile("tmp", null); | |
55 | assertNotNull(file); | |
56 | fStateFile = file; | |
57 | ||
58 | fHtIo = new HtIo<>(file, | |
59 | HtTestUtils.BLOCKSIZE, | |
60 | NB_CHILDREN, | |
61 | true, | |
62 | HtTestUtils.READ_FACTORY, | |
63 | HistoryTreeStub.NODE_FACTORY); | |
64 | } | |
65 | ||
66 | /** | |
67 | * Delete the file after test | |
68 | */ | |
69 | @After | |
70 | public void cleanUp() { | |
71 | HtIo<HTInterval, HTNode<HTInterval>> htIo = fHtIo; | |
72 | if (htIo != null) { | |
73 | htIo.deleteFile(); | |
74 | } | |
75 | } | |
76 | ||
77 | private static HTNode<HTInterval> createCoreNode(int seqNum, int parentNum) { | |
78 | HTNode<HTInterval> node = HistoryTreeStub.NODE_FACTORY.createNode(NodeType.CORE, | |
79 | BLOCKSIZE, NB_CHILDREN, seqNum, parentNum, 0L); | |
80 | return node; | |
81 | } | |
82 | ||
83 | private static HTNode<HTInterval> createLeafNode(int seqNum, int parentNum) { | |
84 | HTNode<HTInterval> node = HistoryTreeStub.NODE_FACTORY.createNode(NodeType.LEAF, | |
85 | BLOCKSIZE, NB_CHILDREN, seqNum, parentNum, 0L); | |
86 | return node; | |
87 | } | |
88 | ||
89 | /** | |
90 | * Test reading and writing nodes | |
91 | * | |
92 | * @throws IOException | |
93 | * Exception thrown by the file | |
94 | */ | |
95 | @Test | |
96 | public void testReadWriteNode() throws IOException { | |
97 | HtIo<HTInterval, HTNode<HTInterval>> htio = fHtIo; | |
98 | assertNotNull(htio); | |
99 | ||
100 | int coreNodeSeqNum = 0; | |
101 | int leafNodeSeqNum = 1; | |
102 | ||
103 | // Add a core node and a leaf node | |
104 | HTNode<HTInterval> coreNode = createCoreNode(coreNodeSeqNum, -1); | |
105 | assertFalse(HtIo.isInCache(htio, coreNodeSeqNum)); | |
106 | htio.writeNode(coreNode); | |
107 | assertTrue(HtIo.isInCache(htio, coreNodeSeqNum)); | |
108 | ||
109 | HTNode<HTInterval> leafNode = createLeafNode(leafNodeSeqNum, coreNodeSeqNum); | |
110 | assertFalse(HtIo.isInCache(htio, leafNodeSeqNum)); | |
111 | htio.writeNode(leafNode); | |
112 | assertTrue(HtIo.isInCache(htio, leafNodeSeqNum)); | |
113 | ||
114 | // Now read the nodes from the same htio object, they should be in cache | |
115 | HTNode<HTInterval> coreRead = htio.readNode(coreNodeSeqNum); | |
116 | assertEquals(coreNode, coreRead); | |
117 | HTNode<HTInterval> leafRead = htio.readNode(leafNodeSeqNum); | |
118 | assertEquals(leafNode, leafRead); | |
119 | ||
120 | // Invalidate the cache | |
121 | HtIo.clearCache(); | |
122 | ||
123 | // Re-read the nodes, they should now be read from disk and be in the | |
124 | // cache after | |
125 | assertFalse(HtIo.isInCache(htio, coreNodeSeqNum)); | |
126 | coreRead = htio.readNode(coreNodeSeqNum); | |
127 | assertEquals(coreNode, coreRead); | |
128 | assertTrue(HtIo.isInCache(htio, coreNodeSeqNum)); | |
129 | ||
130 | // Read the leaf node from disk | |
131 | assertFalse(HtIo.isInCache(htio, leafNodeSeqNum)); | |
132 | leafRead = htio.readNode(leafNodeSeqNum); | |
133 | assertEquals(leafNode, leafRead); | |
134 | assertTrue(HtIo.isInCache(htio, leafNodeSeqNum)); | |
135 | ||
136 | // Close the file and reopen a new htio object | |
137 | htio.closeFile(); | |
138 | ||
139 | assertNotNull(fStateFile); | |
140 | htio = new HtIo<>(fStateFile, | |
141 | BLOCKSIZE, | |
142 | NB_CHILDREN, | |
143 | false, | |
144 | HtTestUtils.READ_FACTORY, | |
145 | HistoryTreeStub.NODE_FACTORY); | |
146 | ||
147 | fHtIo = htio; | |
148 | ||
149 | // Read the core node from the disk | |
150 | assertFalse(HtIo.isInCache(htio, coreNodeSeqNum)); | |
151 | coreRead = htio.readNode(coreNodeSeqNum); | |
152 | assertEquals(coreNode, coreRead); | |
153 | ||
154 | // Read the leaf node from the disk | |
155 | assertFalse(HtIo.isInCache(htio, leafNodeSeqNum)); | |
156 | leafRead = htio.readNode(leafNodeSeqNum); | |
157 | assertEquals(leafNode, leafRead); | |
158 | ||
159 | // Re-read the nodes, they should have been read from the cache | |
160 | assertTrue(HtIo.isInCache(htio, coreNodeSeqNum)); | |
161 | coreRead = htio.readNode(coreNodeSeqNum); | |
162 | assertEquals(coreNode, coreRead); | |
163 | ||
164 | // Read the leaf node from cache | |
165 | assertTrue(HtIo.isInCache(htio, leafNodeSeqNum)); | |
166 | leafRead = htio.readNode(leafNodeSeqNum); | |
167 | assertEquals(leafNode, leafRead); | |
168 | } | |
169 | ||
170 | /** | |
171 | * Test that the section at the end of the file where extra data can be | |
172 | * written works well | |
173 | * | |
174 | * @throws IOException | |
175 | * Exception thrown by the file | |
176 | */ | |
177 | @Test | |
178 | public void testExtraDataSave() throws IOException { | |
179 | writeBufferAtNodePos(2); | |
180 | } | |
181 | ||
182 | /** | |
183 | * Test that writing at the beginning of the file works well | |
184 | * | |
185 | * @throws IOException | |
186 | * Exception thrown by the file | |
187 | */ | |
188 | @Test | |
189 | public void testHeaderDataSave() throws IOException { | |
190 | writeBufferAtNodePos(-1); | |
191 | } | |
192 | ||
193 | /** | |
194 | * Test that writing data far beyond the node section end works. | |
195 | * | |
196 | * @throws IOException | |
197 | * Exception thrown by the file | |
198 | */ | |
199 | @Test | |
200 | public void testTooFarData() throws IOException { | |
201 | writeBufferAtNodePos(6); | |
202 | } | |
203 | ||
204 | private void writeBufferAtNodePos(int nodeOffset) throws IOException { | |
205 | HtIo<HTInterval, HTNode<HTInterval>> htio = fHtIo; | |
206 | assertNotNull(htio); | |
207 | ||
208 | int coreNodeSeqNum = 0; | |
209 | int leafNodeSeqNum = 1; | |
210 | ||
211 | // Add a core node and a leaf node | |
212 | HTNode<HTInterval> coreNode = createCoreNode(coreNodeSeqNum, -1); | |
213 | assertFalse(HtIo.isInCache(htio, coreNodeSeqNum)); | |
214 | htio.writeNode(coreNode); | |
215 | assertTrue(HtIo.isInCache(htio, coreNodeSeqNum)); | |
216 | ||
217 | HTNode<HTInterval> leafNode = createLeafNode(leafNodeSeqNum, coreNodeSeqNum); | |
218 | assertFalse(HtIo.isInCache(htio, leafNodeSeqNum)); | |
219 | htio.writeNode(leafNode); | |
220 | assertTrue(HtIo.isInCache(htio, leafNodeSeqNum)); | |
221 | ||
222 | // Write 3 integers at some position of the file | |
223 | ByteBuffer buffer = ByteBuffer.allocate(12); | |
224 | buffer.putInt(32); | |
225 | buffer.putInt(33); | |
226 | buffer.putInt(232); | |
227 | buffer.flip(); | |
228 | ||
229 | try (FileOutputStream fcOut = htio.getFileWriter(nodeOffset)) { | |
230 | fcOut.write(buffer.array()); | |
231 | } | |
232 | ||
233 | // Close the file and reopen a new htio object | |
234 | htio.closeFile(); | |
235 | assertNotNull(fStateFile); | |
236 | htio = new HtIo<>(fStateFile, | |
237 | BLOCKSIZE, | |
238 | NB_CHILDREN, | |
239 | false, | |
240 | HtTestUtils.READ_FACTORY, | |
241 | HistoryTreeStub.NODE_FACTORY); | |
242 | ||
243 | fHtIo = htio; | |
244 | ||
245 | // Read the same 3 integers at the same position in the file | |
246 | byte[] bytes = new byte[12]; | |
247 | htio.supplyATReader(nodeOffset).read(bytes); | |
248 | buffer = ByteBuffer.wrap(bytes); | |
249 | assertEquals(32, buffer.getInt()); | |
250 | assertEquals(33, buffer.getInt()); | |
251 | assertEquals(232, buffer.getInt()); | |
252 | } | |
253 | } |