StateSystem: Aesthetic changes to HT_IO.java
[deliverable/tracecompass.git] / statesystem / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / internal / statesystem / core / backend / historytree / HT_IO.java
1 /*******************************************************************************
2 * Copyright (c) 2012, 2014 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.tracecompass.internal.statesystem.core.backend.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 import org.eclipse.jdt.annotation.NonNull;
23 import org.eclipse.tracecompass.internal.statesystem.core.Activator;
24
25 /**
26 * This class abstracts inputs/outputs of the HistoryTree nodes.
27 *
28 * It contains all the methods and descriptors to handle reading/writing nodes
29 * to the tree-file on disk and all the caching mechanisms.
30 *
31 * This abstraction is mainly for code isolation/clarification purposes. Every
32 * HistoryTree must contain 1 and only 1 HT_IO element.
33 *
34 * @author Alexandre Montplaisir
35 *
36 */
37 class HT_IO {
38 /* Configuration of the History Tree */
39 private final HTConfig fConfig;
40
41 /* Fields related to the file I/O */
42 private final FileInputStream fFileInputStream;
43 private final FileOutputStream fFileOutputStream;
44 private final FileChannel fFileChannelIn;
45 private final FileChannel fFileChannelOut;
46
47 // TODO test/benchmark optimal cache size
48 /**
49 * Cache size, must be a power of 2
50 */
51 private static final int CACHE_SIZE = 256;
52 private static final int CACHE_MASK = CACHE_SIZE - 1;
53 private final HTNode fNodeCache[] = new HTNode[CACHE_SIZE];
54
55 /**
56 * Standard constructor
57 *
58 * @param config
59 * The configuration object for the StateHistoryTree
60 * @param newFile
61 * Flag indicating that the file must be created from scratch
62 *
63 * @throws IOException
64 * An exception can be thrown when file cannot be accessed
65 */
66 public HT_IO(HTConfig config, boolean newFile) throws IOException {
67 fConfig = config;
68
69 File historyTreeFile = config.getStateFile();
70 if (newFile) {
71 boolean success1 = true;
72 /* Create a new empty History Tree file */
73 if (historyTreeFile.exists()) {
74 success1 = historyTreeFile.delete();
75 }
76 boolean success2 = historyTreeFile.createNewFile();
77 if (!(success1 && success2)) {
78 /* It seems we do not have permission to create the new file */
79 throw new IOException("Cannot create new file at " + //$NON-NLS-1$
80 historyTreeFile.getName());
81 }
82 fFileInputStream = new FileInputStream(historyTreeFile);
83 fFileOutputStream = new FileOutputStream(historyTreeFile, false);
84 } else {
85 /*
86 * We want to open an existing file, make sure we don't squash the
87 * existing content when opening the fos!
88 */
89 fFileInputStream = new FileInputStream(historyTreeFile);
90 fFileOutputStream = new FileOutputStream(historyTreeFile, true);
91 }
92 fFileChannelIn = fFileInputStream.getChannel();
93 fFileChannelOut = fFileOutputStream.getChannel();
94 }
95
96 /**
97 * Read a node from the file on disk.
98 *
99 * @param seqNumber
100 * The sequence number of the node to read.
101 * @return The object representing the node
102 * @throws ClosedChannelException
103 * Usually happens because the file was closed while we were
104 * reading. Instead of using a big reader-writer lock, we'll
105 * just catch this exception.
106 */
107 public synchronized @NonNull HTNode readNode(int seqNumber) throws ClosedChannelException {
108 /* Do a cache lookup */
109 int offset = seqNumber & CACHE_MASK;
110 HTNode readNode = fNodeCache[offset];
111 if (readNode != null && readNode.getSequenceNumber() == seqNumber) {
112 return readNode;
113 }
114
115 /* Lookup on disk */
116 try {
117 seekFCToNodePos(fFileChannelIn, seqNumber);
118 readNode = HTNode.readNode(fConfig, fFileChannelIn);
119
120 /* Put the node in the cache. */
121 fNodeCache[offset] = readNode;
122 return readNode;
123
124 } catch (ClosedChannelException e) {
125 throw e;
126 } catch (IOException e) {
127 /* Other types of IOExceptions shouldn't happen at this point though */
128 Activator.getDefault().logError(e.getMessage(), e);
129 throw new IllegalStateException();
130 }
131 }
132
133 public synchronized void writeNode(HTNode node) {
134 try {
135 /* Insert the node into the cache. */
136 int seqNumber = node.getSequenceNumber();
137 int offset = seqNumber & CACHE_MASK;
138 fNodeCache[offset] = node;
139
140 /* Position ourselves at the start of the node and write it */
141 seekFCToNodePos(fFileChannelOut, seqNumber);
142 node.writeSelf(fFileChannelOut);
143 } catch (IOException e) {
144 /* If we were able to open the file, we should be fine now... */
145 Activator.getDefault().logError(e.getMessage(), e);
146 }
147 }
148
149 public FileChannel getFcOut() {
150 return fFileChannelOut;
151 }
152
153 public FileInputStream supplyATReader(int nodeOffset) {
154 try {
155 /*
156 * Position ourselves at the start of the Mapping section in the
157 * file (which is right after the Blocks)
158 */
159 seekFCToNodePos(fFileChannelIn, nodeOffset);
160 } catch (IOException e) {
161 Activator.getDefault().logError(e.getMessage(), e);
162 }
163 return fFileInputStream;
164 }
165
166 public synchronized void closeFile() {
167 try {
168 fFileInputStream.close();
169 fFileOutputStream.close();
170 } catch (IOException e) {
171 Activator.getDefault().logError(e.getMessage(), e);
172 }
173 }
174
175 public synchronized void deleteFile() {
176 closeFile();
177
178 File historyTreeFile = fConfig.getStateFile();
179 if (!historyTreeFile.delete()) {
180 /* We didn't succeed in deleting the file */
181 Activator.getDefault().logError("Failed to delete" + historyTreeFile.getName()); //$NON-NLS-1$
182 }
183 }
184
185 /**
186 * Seek the given FileChannel to the position corresponding to the node that
187 * has seqNumber
188 *
189 * @param fc
190 * the channel to seek
191 * @param seqNumber
192 * the node sequence number to seek the channel to
193 * @throws IOException
194 * If some other I/O error occurs
195 */
196 private void seekFCToNodePos(FileChannel fc, int seqNumber)
197 throws IOException {
198 /*
199 * Cast to (long) is needed to make sure the result is a long too and
200 * doesn't get truncated
201 */
202 fc.position(HistoryTree.TREE_HEADER_SIZE
203 + ((long) seqNumber) * fConfig.getBlockSize());
204 }
205
206 }
This page took 0.03555 seconds and 5 git commands to generate.