tmf: Handle race between state system queries and diposal
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / historytree / HT_IO.java
CommitLineData
a52fde77
AM
1/*******************************************************************************
2 * Copyright (c) 2012 Ericsson
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
3de60236 5 *
a52fde77
AM
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
3de60236 10 *
a52fde77
AM
11 *******************************************************************************/
12
2ab9afbc 13package org.eclipse.linuxtools.internal.tmf.core.statesystem.historytree;
a52fde77
AM
14
15import java.io.File;
16import java.io.FileInputStream;
17import java.io.FileOutputStream;
18import java.io.IOException;
3b7f5abe 19import java.nio.channels.ClosedChannelException;
a52fde77
AM
20import java.nio.channels.FileChannel;
21
22/**
23 * This class exists mainly for code isolation/clarification purposes. It
24 * contains all the methods and descriptors to handle reading/writing to the
25 * tree-file on disk and all the caching mechanisms. Every HistoryTree should
26 * contain 1 and only 1 HT_IO element.
3de60236 27 *
a52fde77 28 * @author alexmont
3de60236 29 *
a52fde77
AM
30 */
31class HT_IO {
32
33 /* reference to the tree to which this IO-object belongs */
34 private final HistoryTree tree;
35
36 /* Fields related to the file I/O */
36bf82a2 37 private final File historyTreeFile;
3de60236
AM
38 private final FileInputStream fis;
39 private final FileOutputStream fos;
40 private final FileChannel fcIn;
41 private final FileChannel fcOut;
a52fde77
AM
42
43 /**
44 * Standard constructor
3de60236 45 *
a52fde77 46 * @param tree
ab604305
AM
47 * @param newFile
48 * Are we creating a new file from scratch?
a52fde77
AM
49 * @throws IOException
50 */
51 HT_IO(HistoryTree tree, boolean newFile) throws IOException {
52 this.tree = tree;
36bf82a2 53 historyTreeFile = tree.config.stateFile;
ab604305 54 boolean success1 = true, success2;
a52fde77
AM
55
56 if (newFile) {
57 /* Create a new empty History Tree file */
58 if (historyTreeFile.exists()) {
ab604305
AM
59 success1 = historyTreeFile.delete();
60 }
61 success2 = historyTreeFile.createNewFile();
62 if (!(success1 && success2)) {
63 /* It seems we do not have permission to create the new file */
64 throw new IOException("Cannot create new file at " + //$NON-NLS-1$
65 historyTreeFile.getName());
a52fde77 66 }
a52fde77
AM
67 fis = new FileInputStream(historyTreeFile);
68 fos = new FileOutputStream(historyTreeFile, false);
69 } else {
70 /*
71 * We want to open an existing file, make sure we don't squash the
72 * existing content when opening the fos!
73 */
74 this.fis = new FileInputStream(historyTreeFile);
75 this.fos = new FileOutputStream(historyTreeFile, true);
76 }
77 this.fcIn = fis.getChannel();
78 this.fcOut = fos.getChannel();
79 }
80
81 /**
82 * Generic "read node" method, which checks if the node is in memory first,
83 * and if it's not it goes to disk to retrieve it.
3de60236 84 *
a52fde77
AM
85 * @param seqNumber
86 * Sequence number of the node we want
87 * @return The wanted node in object form
3b7f5abe
AM
88 * @throws ClosedChannelException
89 * If the channel was closed before we could read
a52fde77 90 */
3b7f5abe 91 HTNode readNode(int seqNumber) throws ClosedChannelException {
a52fde77
AM
92 HTNode node = readNodeFromMemory(seqNumber);
93 if (node == null) {
94 return readNodeFromDisk(seqNumber);
95 }
96 return node;
97 }
98
99 private HTNode readNodeFromMemory(int seqNumber) {
100 for (HTNode node : tree.latestBranch) {
101 if (node.getSequenceNumber() == seqNumber) {
102 return node;
103 }
104 }
105 return null;
106 }
107
108 /**
109 * This method here isn't private, if we know for sure the node cannot be in
110 * memory it's a bit faster to use this directly (when opening a file from
111 * disk for example)
3b7f5abe
AM
112 *
113 * @throws ClosedChannelException
114 * Usually happens because the file was closed while we were
115 * reading. Instead of using a big reader-writer lock, we'll
116 * just catch this exception.
a52fde77 117 */
3b7f5abe 118 synchronized HTNode readNodeFromDisk(int seqNumber) throws ClosedChannelException {
a52fde77
AM
119 HTNode readNode;
120 try {
121 seekFCToNodePos(fcIn, seqNumber);
122 readNode = HTNode.readNode(tree, fcIn);
123 return readNode;
3b7f5abe
AM
124 } catch (ClosedChannelException e) {
125 throw e;
a52fde77 126 } catch (IOException e) {
3b7f5abe 127 /* Other types of IOExceptions shouldn't happen at this point though */
a52fde77
AM
128 e.printStackTrace();
129 return null;
130 }
131 }
132
133 void writeNode(HTNode node) {
134 try {
135 /* Position ourselves at the start of the node and write it */
136 seekFCToNodePos(fcOut, node.getSequenceNumber());
137 node.writeSelf(fcOut);
138 } catch (IOException e) {
139 /* If we were able to open the file, we should be fine now... */
140 e.printStackTrace();
141 }
142 }
143
144 FileChannel getFcOut() {
145 return this.fcOut;
146 }
147
148 FileInputStream supplyATReader() {
149 try {
150 /*
151 * Position ourselves at the start of the Mapping section in the
152 * file (which is right after the Blocks)
153 */
154 seekFCToNodePos(fcIn, tree.getNodeCount());
155 } catch (IOException e) {
156 e.printStackTrace();
157 }
158 return fis;
159 }
160
161 File supplyATWriterFile() {
162 return tree.config.stateFile;
163 }
164
165 long supplyATWriterFilePos() {
166 return HistoryTree.getTreeHeaderSize()
167 + ((long) tree.getNodeCount() * tree.config.blockSize);
168 }
169
1a4205d9 170 synchronized void closeFile() {
3de60236
AM
171 try {
172 fis.close();
173 fos.close();
174 } catch (IOException e) {
175 e.printStackTrace();
176 }
1a4205d9
AM
177 }
178
179 synchronized void deleteFile() {
180 closeFile();
3de60236 181
36bf82a2
AM
182 if(!historyTreeFile.delete()) {
183 /* We didn't succeed in deleting the file */
184 //TODO log it?
185 }
186 }
187
a52fde77
AM
188 /**
189 * Seek the given FileChannel to the position corresponding to the node that
190 * has seqNumber
3de60236 191 *
a52fde77
AM
192 * @param seqNumber
193 * @throws IOException
194 */
195 private void seekFCToNodePos(FileChannel fc, int seqNumber)
196 throws IOException {
197 fc.position(HistoryTree.getTreeHeaderSize() + (long) seqNumber
198 * tree.config.blockSize);
199 /*
200 * cast to (long) is needed to make sure the result is a long too and
201 * doesn't get truncated
202 */
203 }
204
205}
This page took 0.041329 seconds and 5 git commands to generate.