ss: Move plugins to Trace Compass namespace
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / trace / indexer / AbstractFileCheckpointCollection.java
CommitLineData
032ecd45
MAL
1/*******************************************************************************
2 * Copyright (c) 2013 Ericsson
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 * Contributors:
10 * Marc-Andre Laperle - Initial API and implementation
11 *******************************************************************************/
12
13package org.eclipse.linuxtools.internal.tmf.core.trace.indexer;
14
15import java.io.File;
16import java.io.FileNotFoundException;
17import java.io.IOException;
18import java.io.RandomAccessFile;
19import java.nio.ByteBuffer;
20import java.nio.channels.FileChannel;
21import java.text.MessageFormat;
22
23import org.eclipse.linuxtools.internal.tmf.core.Activator;
24import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimeRange;
25import org.eclipse.linuxtools.tmf.core.timestamp.TmfTimestamp;
26import org.eclipse.linuxtools.tmf.core.trace.indexer.ITmfPersistentlyIndexable;
27
28/**
29 * Common implementation of file-based checkpoint collection
30 *
31 * @author Marc-Andre Laperle
32 */
33public abstract class AbstractFileCheckpointCollection implements ICheckpointCollection {
34
35 private static final int VERSION = 1;
36 private static final int SUB_VERSION_NONE = -1;
37
38 /**
39 * The base file header, can be extended
40 */
41 protected class CheckpointCollectionFileHeader {
42 private final static int SIZE = INT_SIZE +
43 INT_SIZE +
44 LONG_SIZE +
45 LONG_SIZE;
46
47 /**
48 * Get the size of the header in bytes. This should be overridden if the
49 * header is augmented with more data
50 *
51 * @return the size of the header in bytes
52 */
53 public int getSize() {
54 return SIZE;
55 }
56
57 /**
58 * Get the sub version of this header
59 *
60 * @return the sub version
61 */
62 public int getSubVersion() {
63 return SUB_VERSION_NONE;
64 }
65
66 /**
67 * Constructs a new file header for an existing file
68 *
69 * @param randomAccessFile
70 * the existing file
71 * @throws IOException
72 * if an I/O error occurs reading from the file
73 */
74 public CheckpointCollectionFileHeader(RandomAccessFile randomAccessFile) throws IOException {
75 fVersion = randomAccessFile.readInt();
76 fSize = randomAccessFile.readInt();
77 fNbEvents = randomAccessFile.readLong();
78 fTimeRangeOffset = randomAccessFile.readLong();
79 }
80
81 /**
82 * Constructs a new file header for the given version
83 *
84 * @param version
85 * the version
86 */
87 public CheckpointCollectionFileHeader(int version) {
88 fVersion = version;
89 }
90
91 /**
92 * Serialize the header to a file
93 *
94 * @param randomAccessFile
95 * the existing file
96 * @throws IOException
97 * if an I/O error occurs writing to the file
98 */
99 public void serialize(RandomAccessFile randomAccessFile) throws IOException {
100 randomAccessFile.seek(0);
101 randomAccessFile.writeInt(getVersion());
102 randomAccessFile.writeInt(fSize);
103 randomAccessFile.writeLong(fNbEvents);
104 randomAccessFile.writeLong(fTimeRangeOffset);
105 }
106
107 /**
108 * The version of the collection. Should be incremented if a binary
109 * incompatible change occurs.
110 */
111 protected final int fVersion;
112 /**
113 * The size of the collection expressed in a number of checkpoints.
114 */
115 protected int fSize = 0;
116 /**
117 * Offset in bytes where the time range is store
118 */
119 protected long fTimeRangeOffset;
120 /**
121 * The total number of events in the trace
122 */
123 protected long fNbEvents;
124 }
125
126 /**
127 * The size of an int in bytes
128 */
129 protected static final int INT_SIZE = 4;
130 /**
131 * The size of a long in bytes
132 */
133 protected static final int LONG_SIZE = 8;
134
135 /**
136 * The maximum size of the serialize buffer when writing the time range
137 */
138 protected static final int MAX_TIME_RANGE_SERIALIZE_SIZE = 1024;
139
140 /**
141 * The originating trace
142 */
143 private ITmfPersistentlyIndexable fTrace;
144
145 private long fCacheMisses = 0;
146 private boolean fCreatedFromScratch;
147
148 /**
149 * File handle for the file being read/written
150 */
151 private RandomAccessFile fRandomAccessFile;
152 /**
153 * File handle for the file being read/written
154 */
155 private File fFile;
156
157 /**
158 * The base file header
159 */
160 private final CheckpointCollectionFileHeader fHeader;
161
162 // Cached values
163 private FileChannel fFileChannel;
164 private TmfTimeRange fTimeRange;
165
166 /**
167 * Constructs a checkpoint collection for a given trace from scratch or from
168 * an existing file. When the checkpoint collection is created from scratch,
169 * it is populated by subsequent calls to {@link #insert}.
170 *
171 * @param file
172 * the file to use as the persistent storage
173 * @param trace
174 * the trace
175 */
176 public AbstractFileCheckpointCollection(File file, ITmfPersistentlyIndexable trace) {
177 fTrace = trace;
178 fFile = file;
179 setCreatedFromScratch(!fFile.exists());
180
181 CheckpointCollectionFileHeader header = null;
182
183 if (!isCreatedFromScratch()) {
184 header = tryRestore();
185 if (header == null) {
186 fFile.delete();
187 dispose();
188 }
189 }
190
191 if (isCreatedFromScratch()) {
192 header = initialize();
193 }
194
195 fHeader = header;
196 }
197
198 /**
199 * Creates a new basic file header with the version field initialized. This
200 * should be overridden if the file header is extended
201 *
202 * @return the created file header
203 */
204 protected CheckpointCollectionFileHeader createHeader() {
205 return new CheckpointCollectionFileHeader(VERSION);
206 }
207
208 /**
209 * Creates a new basic file header for an existing file. This should be
210 * overridden if the file header is extended
211 *
212 * @param randomAccessFile
213 * the existing file
214 * @return the created file header
215 * @throws IOException
216 * if an I/O error occurs reading from the file
217 */
218 protected CheckpointCollectionFileHeader createHeader(RandomAccessFile randomAccessFile) throws IOException {
219 return new CheckpointCollectionFileHeader(randomAccessFile);
220 }
221
222 /**
223 * Get the version of the collection.
224 *
225 * @return the version of the collection.
226 */
227 protected int getVersion() {
228 return VERSION;
229 }
230
231 /**
232 * Get the sub version of the collection.
233 *
234 * @return the sub version of the collection.
235 */
236 protected int getSubVersion() {
237 return SUB_VERSION_NONE;
238 }
239
240 private CheckpointCollectionFileHeader initialize() {
241 CheckpointCollectionFileHeader header = null;
242 try {
243 fRandomAccessFile = new RandomAccessFile(fFile, "rw"); //$NON-NLS-1$
244 fFileChannel = fRandomAccessFile.getChannel();
245 header = createHeader();
246
247 // Reserve space for header
248 fRandomAccessFile.setLength(header.getSize());
249
250 fTimeRange = new TmfTimeRange(new TmfTimestamp(0), new TmfTimestamp(0));
251 } catch (IOException e) {
252 Activator.logError(MessageFormat.format(Messages.ErrorOpeningIndex, fFile), e);
253 return null;
254 }
255
256 return header;
257 }
258
259 /**
260 * Try to restore the index from disk. Try to open the file and check the
261 * version. Returns the loaded header or null if it could not be loaded.
262 *
263 * @return the loaded header or null if it could not be loaded.
264 */
265 private CheckpointCollectionFileHeader tryRestore() {
266 CheckpointCollectionFileHeader header = null;
267
268 try {
269 fRandomAccessFile = new RandomAccessFile(fFile, "r"); //$NON-NLS-1$
270 fFileChannel = fRandomAccessFile.getChannel();
271 } catch (FileNotFoundException e) {
272 Activator.logError(MessageFormat.format(Messages.ErrorOpeningIndex, fFile), e);
273 return null;
274 }
275
276 try {
277 header = createHeader(fRandomAccessFile);
278 if (header.fVersion != VERSION || header.getSubVersion() != getSubVersion()) {
279 return null;
280 }
281 serializeInTimeRange(header);
282 } catch (IOException e) {
283 Activator.logError(MessageFormat.format(Messages.IOErrorReadingHeader, fFile), e);
284 return null;
285 }
286
287 return header;
288 }
289
290 private void serializeInTimeRange(CheckpointCollectionFileHeader header) throws IOException {
291 ByteBuffer b = ByteBuffer.allocate(MAX_TIME_RANGE_SERIALIZE_SIZE);
292 b.clear();
293 fFileChannel.read(b, header.fTimeRangeOffset);
294 b.flip();
295 fTimeRange = new TmfTimeRange(new TmfTimestamp(b), new TmfTimestamp(b));
296 }
297
298 private void serializeOutTimeRange() throws IOException {
299 fHeader.fTimeRangeOffset = fRandomAccessFile.length();
300 ByteBuffer b = ByteBuffer.allocate(MAX_TIME_RANGE_SERIALIZE_SIZE);
301 b.clear();
302 new TmfTimestamp(fTimeRange.getStartTime()).serialize(b);
303 new TmfTimestamp(fTimeRange.getEndTime()).serialize(b);
304 b.flip();
305 fFileChannel.write(b, fHeader.fTimeRangeOffset);
306 }
307
308 /**
309 * Set the index as complete. No more checkpoints will be inserted.
310 */
311 @Override
312 public void setIndexComplete() {
313 try {
314 serializeOutTimeRange();
315
316 fHeader.serialize(fRandomAccessFile);
317 } catch (IOException e) {
318 Activator.logError(MessageFormat.format(Messages.IOErrorWritingHeader, fFile), e);
319 }
320 }
321
322 /**
323 *
324 * @return true if the checkpoint collection was created from scratch, false
325 * otherwise
326 */
327 @Override
328 public boolean isCreatedFromScratch() {
329 return fCreatedFromScratch;
330 }
331
332 /**
333 * Set whether or not the collection is created from scratch
334 *
335 * @param isCreatedFromScratch
336 * whether or not the collection is created from scratch
337 */
338 protected void setCreatedFromScratch(boolean isCreatedFromScratch) {
339 fCreatedFromScratch = isCreatedFromScratch;
340 }
341
342 /**
343 * @return the number of cache misses.
344 */
345 public long getCacheMisses() {
346 return fCacheMisses;
347 }
348
349 /**
350 * Increment the number of cache misses.
351 */
352 protected void incCacheMisses() {
353 ++fCacheMisses;
354 }
355
356 /**
357 * Returns the size of the checkpoint collection expressed as a number of
358 * checkpoints.
359 *
360 * @return the size of the checkpoint collection
361 */
362 @Override
363 public int size() {
364 return fHeader.fSize;
365 }
366
367 /**
368 * Set the trace time range
369 *
370 * @param timeRange
371 * the trace time range
372 */
373 @Override
374 public void setTimeRange(TmfTimeRange timeRange) {
375 fTimeRange = timeRange;
376 }
377
378 /**
379 * Get the trace time range
380 *
381 * @return the trace time range
382 */
383 @Override
384 public TmfTimeRange getTimeRange() {
385 return fTimeRange;
386 }
387
388 /**
389 * Set the number of events in the trace
390 *
391 * @param nbEvents
392 * the number of events in the trace
393 */
394 @Override
395 public void setNbEvents(long nbEvents) {
396 fHeader.fNbEvents = nbEvents;
397 }
398
399 /**
400 * Get the number of events in the trace
401 *
402 * @return the number of events in the trace
403 */
404 @Override
405 public long getNbEvents() {
406 return fHeader.fNbEvents;
407 }
408
409 /**
410 * Get the trace
411 *
412 * @return the trace
413 */
414 protected ITmfPersistentlyIndexable getTrace() {
415 return fTrace;
416 }
417
418 /**
419 * Get the random access file currently opened
420 *
421 * @return the file
422 */
423 protected RandomAccessFile getRandomAccessFile() {
424 return fRandomAccessFile;
425 }
426
427 /**
428 * Get the file channel currently used for the index
429 *
430 * @return the file channel
431 */
432 protected FileChannel getFileChannel() {
433 return fRandomAccessFile.getChannel();
434 }
435
436 /**
437 * Get the file handle for the index
438 *
439 * @return the file
440 */
441 protected File getFile() {
442 return fFile;
443 }
444
445 /**
446 * Get the header for this collection
447 *
448 * @return the header
449 */
450 public CheckpointCollectionFileHeader getHeader() {
451 return fHeader;
452 }/**
453 * Dispose and delete the checkpoint collection
454 */
455 @Override
456 public void delete() {
457 dispose();
458 if (fFile.exists()) {
459 fFile.delete();
460 }
461 }
462
463 /**
464 * Dispose the collection and its resources
465 */
466 @Override
467 public void dispose() {
468 try {
469 if (fRandomAccessFile != null) {
470 fRandomAccessFile.close();
471 }
472 setCreatedFromScratch(true);
473 fRandomAccessFile = null;
474 } catch (IOException e) {
475 Activator.logError(MessageFormat.format(Messages.IOErrorClosingIndex, fFile), e);
476 }
477 }
478}
This page took 0.056149 seconds and 5 git commands to generate.