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