tmf: Avoid HistoryTree to expose its internal HT_IO node.
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / backends / historytree / HT_IO.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
5 *
6 * All rights reserved. This program and the accompanying materials are
7 * made available under the terms of the Eclipse Public License v1.0 which
8 * accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 *******************************************************************************/
12
13 package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.historytree;
14
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.nio.channels.ClosedChannelException;
20 import java.nio.channels.FileChannel;
21
22 /**
23 * This class abstracts inputs/outputs of the HistoryTree nodes.
24 *
25 * It contains all the methods and descriptors to handle reading/writing nodes
26 * to the tree-file on disk and all the caching mechanisms.
27 *
28 * This abstraction is mainly for code isolation/clarification purposes.
29 * Every HistoryTree must contain 1 and only 1 HT_IO element.
30 *
31 * @author Alexandre Montplaisir
32 *
33 */
34 class HT_IO {
35 /* Configuration of the History Tree */
36 private final HTConfig fConfig;
37
38 /* Fields related to the file I/O */
39 private final FileInputStream fis;
40 private final FileOutputStream fos;
41 private final FileChannel fcIn;
42 private final FileChannel fcOut;
43
44 // TODO test/benchmark optimal cache size
45 private final int CACHE_SIZE = 256;
46 private final HTNode fNodeCache[] = new HTNode[CACHE_SIZE];
47
48 /**
49 * Standard constructor
50 *
51 * @param config
52 * The configuration object for the StateHistoryTree
53 * @param newFile
54 * Flag indicating that the file must be created from scratch
55
56 * @throws IOException
57 * An exception can be thrown when file cannot be accessed
58 */
59 HT_IO(HTConfig config, boolean newFile) throws IOException {
60 fConfig = config;
61
62 File historyTreeFile = config.getStateFile();
63 if (newFile) {
64 boolean success1 = true;
65 /* Create a new empty History Tree file */
66 if (historyTreeFile.exists()) {
67 success1 = historyTreeFile.delete();
68 }
69 boolean success2 = historyTreeFile.createNewFile();
70 if (!(success1 && success2)) {
71 /* It seems we do not have permission to create the new file */
72 throw new IOException("Cannot create new file at " + //$NON-NLS-1$
73 historyTreeFile.getName());
74 }
75 fis = new FileInputStream(historyTreeFile);
76 fos = new FileOutputStream(historyTreeFile, false);
77 } else {
78 /*
79 * We want to open an existing file, make sure we don't squash the
80 * existing content when opening the fos!
81 */
82 this.fis = new FileInputStream(historyTreeFile);
83 this.fos = new FileOutputStream(historyTreeFile, true);
84 }
85 this.fcIn = fis.getChannel();
86 this.fcOut = fos.getChannel();
87 }
88
89 /**
90 * This method here isn't private, if we know for sure the node cannot be in
91 * memory it's a bit faster to use this directly (when opening a file from
92 * disk for example)
93 *
94 * @throws ClosedChannelException
95 * Usually happens because the file was closed while we were
96 * reading. Instead of using a big reader-writer lock, we'll
97 * just catch this exception.
98 */
99 synchronized HTNode readNode(int seqNumber) throws ClosedChannelException {
100 /* Do a cache lookup */
101 int offset = seqNumber & (CACHE_SIZE - 1);
102 HTNode readNode = fNodeCache[offset];
103 if (readNode != null && readNode.getSequenceNumber() == seqNumber) {
104 return readNode;
105 }
106
107 /* Lookup on disk */
108 try {
109 seekFCToNodePos(fcIn, seqNumber);
110 readNode = HTNode.readNode(fConfig, fcIn);
111
112 /* Put the node in the cache. */
113 fNodeCache[offset] = readNode;
114 return readNode;
115 } catch (ClosedChannelException e) {
116 throw e;
117 } catch (IOException e) {
118 /* Other types of IOExceptions shouldn't happen at this point though */
119 e.printStackTrace();
120 return null;
121 }
122 }
123
124 void writeNode(HTNode node) {
125 try {
126 /* Insert the node into the cache. */
127 int seqNumber = node.getSequenceNumber();
128 int offset = seqNumber & (CACHE_SIZE - 1);
129 fNodeCache[offset] = node;
130
131 /* Position ourselves at the start of the node and write it */
132 seekFCToNodePos(fcOut, seqNumber);
133 node.writeSelf(fcOut);
134 } catch (IOException e) {
135 /* If we were able to open the file, we should be fine now... */
136 e.printStackTrace();
137 }
138 }
139
140 FileChannel getFcOut() {
141 return this.fcOut;
142 }
143
144 FileInputStream supplyATReader(int nodeOffset) {
145 try {
146 /*
147 * Position ourselves at the start of the Mapping section in the
148 * file (which is right after the Blocks)
149 */
150 seekFCToNodePos(fcIn, nodeOffset);
151 } catch (IOException e) {
152 e.printStackTrace();
153 }
154 return fis;
155 }
156
157 synchronized void closeFile() {
158 try {
159 fis.close();
160 fos.close();
161 } catch (IOException e) {
162 e.printStackTrace();
163 }
164 }
165
166 synchronized void deleteFile() {
167 closeFile();
168
169 File historyTreeFile = fConfig.getStateFile();
170 if (!historyTreeFile.delete()) {
171 /* We didn't succeed in deleting the file */
172 //TODO log it?
173 }
174 }
175
176 /**
177 * Seek the given FileChannel to the position corresponding to the node that
178 * has seqNumber
179 *
180 * @param fc the channel to seek
181 * @param seqNumber the node sequence number to seek the channel to
182 * @throws IOException
183 */
184 private void seekFCToNodePos(FileChannel fc, int seqNumber)
185 throws IOException {
186 /*
187 * Cast to (long) is needed to make sure the result is a long too and
188 * doesn't get truncated
189 */
190 fc.position(HistoryTree.TREE_HEADER_SIZE
191 + ((long) seqNumber) * fConfig.getBlockSize());
192 }
193
194 }
This page took 0.054912 seconds and 5 git commands to generate.