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