1 /*******************************************************************************
2 * Copyright (c) 2012, 2013 Ericsson
3 * Copyright (c) 2010, 2011 École Polytechnique de Montréal
4 * Copyright (c) 2010, 2011 Alexandre Montplaisir <alexandre.montplaisir@gmail.com>
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
11 *******************************************************************************/
13 package org
.eclipse
.linuxtools
.internal
.tmf
.core
.statesystem
.backends
.historytree
;
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
;
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.
33 /* reference to the tree to which this IO-object belongs */
34 private final HistoryTree tree
;
36 /* Fields related to the file I/O */
37 private final File historyTreeFile
;
38 private final FileInputStream fis
;
39 private final FileOutputStream fos
;
40 private final FileChannel fcIn
;
41 private final FileChannel fcOut
;
43 // TODO test/benchmark optimal cache size
44 private final int CACHE_SIZE
= 256;
45 private final HTNode fNodeCache
[] = new HTNode
[CACHE_SIZE
];
48 * Standard constructor
52 * Are we creating a new file from scratch?
55 HT_IO(HistoryTree tree
, boolean newFile
) throws IOException
{
57 historyTreeFile
= tree
.getConfig().getStateFile();
58 boolean success1
= true;
61 /* Create a new empty History Tree file */
62 if (historyTreeFile
.exists()) {
63 success1
= historyTreeFile
.delete();
65 boolean success2
= historyTreeFile
.createNewFile();
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());
71 fis
= new FileInputStream(historyTreeFile
);
72 fos
= new FileOutputStream(historyTreeFile
, false);
75 * We want to open an existing file, make sure we don't squash the
76 * existing content when opening the fos!
78 this.fis
= new FileInputStream(historyTreeFile
);
79 this.fos
= new FileOutputStream(historyTreeFile
, true);
81 this.fcIn
= fis
.getChannel();
82 this.fcOut
= fos
.getChannel();
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.
90 * Sequence number of the node we want
91 * @return The wanted node in object form
92 * @throws ClosedChannelException
93 * If the channel was closed before we could read
95 HTNode
readNode(int seqNumber
) throws ClosedChannelException
{
96 HTNode node
= readNodeFromMemory(seqNumber
);
98 return readNodeFromDisk(seqNumber
);
103 private HTNode
readNodeFromMemory(int seqNumber
) {
104 for (HTNode node
: tree
.getLatestBranch()) {
105 if (node
.getSequenceNumber() == seqNumber
) {
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
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.
122 synchronized HTNode
readNodeFromDisk(int seqNumber
) throws ClosedChannelException
{
123 /* Do a cache lookup */
124 int offset
= seqNumber
& (CACHE_SIZE
- 1);
125 HTNode readNode
= fNodeCache
[offset
];
126 if (readNode
!= null && readNode
.getSequenceNumber() == seqNumber
) {
132 seekFCToNodePos(fcIn
, seqNumber
);
133 readNode
= HTNode
.readNode(tree
, fcIn
);
135 /* Put the node in the cache. */
136 fNodeCache
[offset
] = readNode
;
138 } catch (ClosedChannelException e
) {
140 } catch (IOException e
) {
141 /* Other types of IOExceptions shouldn't happen at this point though */
147 void writeNode(HTNode node
) {
149 /* Insert the node into the cache. */
150 int seqNumber
= node
.getSequenceNumber();
151 int offset
= seqNumber
& (CACHE_SIZE
- 1);
152 fNodeCache
[offset
] = node
;
154 /* Position ourselves at the start of the node and write it */
155 seekFCToNodePos(fcOut
, seqNumber
);
156 node
.writeSelf(fcOut
);
157 } catch (IOException e
) {
158 /* If we were able to open the file, we should be fine now... */
163 FileChannel
getFcOut() {
167 FileInputStream
supplyATReader() {
170 * Position ourselves at the start of the Mapping section in the
171 * file (which is right after the Blocks)
173 seekFCToNodePos(fcIn
, tree
.getNodeCount());
174 } catch (IOException e
) {
180 File
supplyATWriterFile() {
181 return tree
.getConfig().getStateFile();
184 long supplyATWriterFilePos() {
185 return HistoryTree
.TREE_HEADER_SIZE
186 + ((long) tree
.getNodeCount() * tree
.getConfig().getBlockSize());
189 synchronized void closeFile() {
193 } catch (IOException e
) {
198 synchronized void deleteFile() {
201 if (!historyTreeFile
.delete()) {
202 /* We didn't succeed in deleting the file */
208 * Seek the given FileChannel to the position corresponding to the node that
212 * @throws IOException
214 private void seekFCToNodePos(FileChannel fc
, int seqNumber
)
216 fc
.position(HistoryTree
.TREE_HEADER_SIZE
+ (long) seqNumber
217 * tree
.getConfig().getBlockSize());
219 * cast to (long) is needed to make sure the result is a long too and
220 * doesn't get truncated
This page took 0.043401 seconds and 6 git commands to generate.