ss: Rename packages to org.eclipse.tracecompass.*
[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 /**
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 public 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 * Read a node from the file on disk.
91 *
92 * @param seqNumber
93 * The sequence number of the node to read.
94 * @return The object representing the node
95 * @throws ClosedChannelException
96 * Usually happens because the file was closed while we were
97 * reading. Instead of using a big reader-writer lock, we'll
98 * just catch this exception.
99 */
100 public synchronized HTNode readNode(int seqNumber) throws ClosedChannelException {
101 /* Do a cache lookup */
102 int offset = seqNumber & (CACHE_SIZE - 1);
103 HTNode readNode = fNodeCache[offset];
104 if (readNode != null && readNode.getSequenceNumber() == seqNumber) {
105 return readNode;
106 }
107
108 /* Lookup on disk */
109 try {
110 seekFCToNodePos(fcIn, seqNumber);
111 readNode = HTNode.readNode(fConfig, fcIn);
112
113 /* Put the node in the cache. */
114 fNodeCache[offset] = readNode;
115 return readNode;
116 } catch (ClosedChannelException e) {
117 throw e;
118 } catch (IOException e) {
119 /* Other types of IOExceptions shouldn't happen at this point though */
120 e.printStackTrace();
121 return null;
122 }
123 }
124
125 public synchronized void writeNode(HTNode node) {
126 try {
127 /* Insert the node into the cache. */
128 int seqNumber = node.getSequenceNumber();
129 int offset = seqNumber & (CACHE_SIZE - 1);
130 fNodeCache[offset] = node;
131
132 /* Position ourselves at the start of the node and write it */
133 seekFCToNodePos(fcOut, seqNumber);
134 node.writeSelf(fcOut);
135 } catch (IOException e) {
136 /* If we were able to open the file, we should be fine now... */
137 e.printStackTrace();
138 }
139 }
140
141 public FileChannel getFcOut() {
142 return this.fcOut;
143 }
144
145 public FileInputStream supplyATReader(int nodeOffset) {
146 try {
147 /*
148 * Position ourselves at the start of the Mapping section in the
149 * file (which is right after the Blocks)
150 */
151 seekFCToNodePos(fcIn, nodeOffset);
152 } catch (IOException e) {
153 e.printStackTrace();
154 }
155 return fis;
156 }
157
158 public synchronized void closeFile() {
159 try {
160 fis.close();
161 fos.close();
162 } catch (IOException e) {
163 e.printStackTrace();
164 }
165 }
166
167 public synchronized void deleteFile() {
168 closeFile();
169
170 File historyTreeFile = fConfig.getStateFile();
171 if (!historyTreeFile.delete()) {
172 /* We didn't succeed in deleting the file */
173 //TODO log it?
174 }
175 }
176
177 /**
178 * Seek the given FileChannel to the position corresponding to the node that
179 * has seqNumber
180 *
181 * @param fc the channel to seek
182 * @param seqNumber the node sequence number to seek the channel to
183 * @throws IOException
184 */
185 private void seekFCToNodePos(FileChannel fc, int seqNumber)
186 throws IOException {
187 /*
188 * Cast to (long) is needed to make sure the result is a long too and
189 * doesn't get truncated
190 */
191 fc.position(HistoryTree.TREE_HEADER_SIZE
192 + ((long) seqNumber) * fConfig.getBlockSize());
193 }
194
195 }
This page took 0.037224 seconds and 5 git commands to generate.