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