tmf: Remove back-reference from HT-Node to HT-Tree
[deliverable/tracecompass.git] / org.eclipse.linuxtools.tmf.core / src / org / eclipse / linuxtools / internal / tmf / core / statesystem / backends / historytree / HT_IO.java
CommitLineData
a52fde77 1/*******************************************************************************
61759503 2 * Copyright (c) 2012, 2013 Ericsson
a52fde77
AM
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
f9a76cac 13package org.eclipse.linuxtools.internal.tmf.core.statesystem.backends.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 *
ffd0aa67 28 * @author Alexandre Montplaisir
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 42
0c1d4577 43 // TODO test/benchmark optimal cache size
6993c1ca
EB
44 private final int CACHE_SIZE = 256;
45 private final HTNode fNodeCache[] = new HTNode[CACHE_SIZE];
46
a52fde77
AM
47 /**
48 * Standard constructor
3de60236 49 *
a52fde77 50 * @param tree
ab604305
AM
51 * @param newFile
52 * Are we creating a new file from scratch?
a52fde77
AM
53 * @throws IOException
54 */
55 HT_IO(HistoryTree tree, boolean newFile) throws IOException {
56 this.tree = tree;
cb42195c
AM
57 historyTreeFile = tree.getConfig().getStateFile();
58 boolean success1 = true;
a52fde77
AM
59
60 if (newFile) {
61 /* Create a new empty History Tree file */
62 if (historyTreeFile.exists()) {
ab604305
AM
63 success1 = historyTreeFile.delete();
64 }
cb42195c 65 boolean success2 = historyTreeFile.createNewFile();
ab604305
AM
66 if (!(success1 && success2)) {
67 /* It seems we do not have permission to create the new file */
68 throw new IOException("Cannot create new file at " + //$NON-NLS-1$
69 historyTreeFile.getName());
a52fde77 70 }
a52fde77
AM
71 fis = new FileInputStream(historyTreeFile);
72 fos = new FileOutputStream(historyTreeFile, false);
73 } else {
74 /*
75 * We want to open an existing file, make sure we don't squash the
76 * existing content when opening the fos!
77 */
78 this.fis = new FileInputStream(historyTreeFile);
79 this.fos = new FileOutputStream(historyTreeFile, true);
80 }
81 this.fcIn = fis.getChannel();
82 this.fcOut = fos.getChannel();
83 }
84
85 /**
86 * Generic "read node" method, which checks if the node is in memory first,
87 * and if it's not it goes to disk to retrieve it.
3de60236 88 *
a52fde77
AM
89 * @param seqNumber
90 * Sequence number of the node we want
91 * @return The wanted node in object form
3b7f5abe
AM
92 * @throws ClosedChannelException
93 * If the channel was closed before we could read
a52fde77 94 */
3b7f5abe 95 HTNode readNode(int seqNumber) throws ClosedChannelException {
a52fde77
AM
96 HTNode node = readNodeFromMemory(seqNumber);
97 if (node == null) {
98 return readNodeFromDisk(seqNumber);
99 }
100 return node;
101 }
102
103 private HTNode readNodeFromMemory(int seqNumber) {
cb42195c 104 for (HTNode node : tree.getLatestBranch()) {
a52fde77
AM
105 if (node.getSequenceNumber() == seqNumber) {
106 return node;
107 }
108 }
109 return null;
110 }
111
112 /**
113 * This method here isn't private, if we know for sure the node cannot be in
114 * memory it's a bit faster to use this directly (when opening a file from
115 * disk for example)
3b7f5abe
AM
116 *
117 * @throws ClosedChannelException
118 * Usually happens because the file was closed while we were
119 * reading. Instead of using a big reader-writer lock, we'll
120 * just catch this exception.
a52fde77 121 */
3b7f5abe 122 synchronized HTNode readNodeFromDisk(int seqNumber) throws ClosedChannelException {
6993c1ca
EB
123 /* Do a cache lookup */
124 int offset = seqNumber & (CACHE_SIZE - 1);
125 HTNode readNode = fNodeCache[offset];
126 if (readNode != null && readNode.getSequenceNumber() == seqNumber) {
127 return readNode;
128 }
129
130 /* Lookup on disk */
a52fde77
AM
131 try {
132 seekFCToNodePos(fcIn, seqNumber);
ffd0aa67 133 readNode = HTNode.readNode(tree.getConfig(), fcIn);
6993c1ca
EB
134
135 /* Put the node in the cache. */
136 fNodeCache[offset] = readNode;
a52fde77 137 return readNode;
3b7f5abe
AM
138 } catch (ClosedChannelException e) {
139 throw e;
a52fde77 140 } catch (IOException e) {
3b7f5abe 141 /* Other types of IOExceptions shouldn't happen at this point though */
a52fde77
AM
142 e.printStackTrace();
143 return null;
144 }
145 }
146
147 void writeNode(HTNode node) {
148 try {
6993c1ca
EB
149 /* Insert the node into the cache. */
150 int seqNumber = node.getSequenceNumber();
151 int offset = seqNumber & (CACHE_SIZE - 1);
152 fNodeCache[offset] = node;
153
a52fde77 154 /* Position ourselves at the start of the node and write it */
6993c1ca 155 seekFCToNodePos(fcOut, seqNumber);
a52fde77
AM
156 node.writeSelf(fcOut);
157 } catch (IOException e) {
158 /* If we were able to open the file, we should be fine now... */
159 e.printStackTrace();
160 }
161 }
162
163 FileChannel getFcOut() {
164 return this.fcOut;
165 }
166
167 FileInputStream supplyATReader() {
168 try {
169 /*
170 * Position ourselves at the start of the Mapping section in the
171 * file (which is right after the Blocks)
172 */
173 seekFCToNodePos(fcIn, tree.getNodeCount());
174 } catch (IOException e) {
175 e.printStackTrace();
176 }
177 return fis;
178 }
179
180 File supplyATWriterFile() {
cb42195c 181 return tree.getConfig().getStateFile();
a52fde77
AM
182 }
183
184 long supplyATWriterFilePos() {
cb42195c
AM
185 return HistoryTree.TREE_HEADER_SIZE
186 + ((long) tree.getNodeCount() * tree.getConfig().getBlockSize());
a52fde77
AM
187 }
188
1a4205d9 189 synchronized void closeFile() {
3de60236
AM
190 try {
191 fis.close();
192 fos.close();
193 } catch (IOException e) {
194 e.printStackTrace();
195 }
1a4205d9
AM
196 }
197
198 synchronized void deleteFile() {
199 closeFile();
3de60236 200
6993c1ca 201 if (!historyTreeFile.delete()) {
36bf82a2
AM
202 /* We didn't succeed in deleting the file */
203 //TODO log it?
204 }
205 }
206
a52fde77
AM
207 /**
208 * Seek the given FileChannel to the position corresponding to the node that
209 * has seqNumber
3de60236 210 *
a52fde77
AM
211 * @param seqNumber
212 * @throws IOException
213 */
214 private void seekFCToNodePos(FileChannel fc, int seqNumber)
215 throws IOException {
cb42195c
AM
216 fc.position(HistoryTree.TREE_HEADER_SIZE + (long) seqNumber
217 * tree.getConfig().getBlockSize());
a52fde77
AM
218 /*
219 * cast to (long) is needed to make sure the result is a long too and
220 * doesn't get truncated
221 */
222 }
223
224}
This page took 0.04745 seconds and 5 git commands to generate.