doc: Document the enabling specific event by name feature
[deliverable/tracecompass.git] / statesystem / org.eclipse.tracecompass.statesystem.core / src / org / eclipse / tracecompass / internal / statesystem / core / backend / historytree / HT_IO.java
CommitLineData
a52fde77 1/*******************************************************************************
60ae41e1 2 * Copyright (c) 2012, 2014 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
e894a508 13package org.eclipse.tracecompass.internal.statesystem.core.backend.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 20import java.nio.channels.FileChannel;
b2648641 21import java.util.logging.Logger;
a52fde77 22
aa353506 23import org.eclipse.jdt.annotation.NonNull;
4018d70a 24import org.eclipse.jdt.annotation.NonNullByDefault;
b2648641 25import org.eclipse.tracecompass.common.core.log.TraceCompassLog;
49a817d5
MK
26import org.eclipse.tracecompass.internal.statesystem.core.Activator;
27
a52fde77 28/**
360f899e
EB
29 * This class abstracts inputs/outputs of the HistoryTree nodes.
30 *
31 * It contains all the methods and descriptors to handle reading/writing nodes
32 * to the tree-file on disk and all the caching mechanisms.
33 *
49a817d5
MK
34 * This abstraction is mainly for code isolation/clarification purposes. Every
35 * HistoryTree must contain 1 and only 1 HT_IO element.
3de60236 36 *
ffd0aa67 37 * @author Alexandre Montplaisir
a52fde77
AM
38 */
39class HT_IO {
4018d70a
MK
40
41 @NonNullByDefault
42 private static final class CacheElement {
43 private final HTNode value;
44 private final HT_IO key;
45
46 public CacheElement(HT_IO ss, HTNode node) {
47 key = ss;
48 value = node;
49 }
50
51 public HT_IO getKey() {
52 return key;
53 }
54
55 public HTNode getValue() {
56 return value;
57 }
58 }
59
360f899e
EB
60 /* Configuration of the History Tree */
61 private final HTConfig fConfig;
a52fde77
AM
62
63 /* Fields related to the file I/O */
c772ff74
MK
64 private final FileInputStream fFileInputStream;
65 private final FileOutputStream fFileOutputStream;
66 private final FileChannel fFileChannelIn;
67 private final FileChannel fFileChannelOut;
a52fde77 68
0c1d4577 69 // TODO test/benchmark optimal cache size
c772ff74
MK
70 /**
71 * Cache size, must be a power of 2
72 */
49a817d5 73 private static final int CACHE_SIZE = 256;
c772ff74 74 private static final int CACHE_MASK = CACHE_SIZE - 1;
4018d70a 75 private static final CacheElement NODE_CACHE[] = new CacheElement[CACHE_SIZE];
6993c1ca 76
b2648641
GB
77 private static final Logger LOGGER = TraceCompassLog.getLogger(HT_IO.class);
78
a52fde77
AM
79 /**
80 * Standard constructor
3de60236 81 *
360f899e 82 * @param config
49a817d5 83 * The configuration object for the StateHistoryTree
ab604305 84 * @param newFile
360f899e 85 * Flag indicating that the file must be created from scratch
49a817d5 86 *
a52fde77 87 * @throws IOException
360f899e 88 * An exception can be thrown when file cannot be accessed
a52fde77 89 */
8d47cc34 90 public HT_IO(HTConfig config, boolean newFile) throws IOException {
360f899e 91 fConfig = config;
a52fde77 92
360f899e 93 File historyTreeFile = config.getStateFile();
a52fde77 94 if (newFile) {
360f899e 95 boolean success1 = true;
a52fde77
AM
96 /* Create a new empty History Tree file */
97 if (historyTreeFile.exists()) {
ab604305
AM
98 success1 = historyTreeFile.delete();
99 }
cb42195c 100 boolean success2 = historyTreeFile.createNewFile();
ab604305
AM
101 if (!(success1 && success2)) {
102 /* It seems we do not have permission to create the new file */
103 throw new IOException("Cannot create new file at " + //$NON-NLS-1$
104 historyTreeFile.getName());
a52fde77 105 }
c772ff74
MK
106 fFileInputStream = new FileInputStream(historyTreeFile);
107 fFileOutputStream = new FileOutputStream(historyTreeFile, false);
a52fde77
AM
108 } else {
109 /*
110 * We want to open an existing file, make sure we don't squash the
111 * existing content when opening the fos!
112 */
c772ff74
MK
113 fFileInputStream = new FileInputStream(historyTreeFile);
114 fFileOutputStream = new FileOutputStream(historyTreeFile, true);
a52fde77 115 }
c772ff74
MK
116 fFileChannelIn = fFileInputStream.getChannel();
117 fFileChannelOut = fFileOutputStream.getChannel();
a52fde77
AM
118 }
119
a52fde77 120 /**
8d47cc34 121 * Read a node from the file on disk.
3b7f5abe 122 *
8d47cc34
AM
123 * @param seqNumber
124 * The sequence number of the node to read.
125 * @return The object representing the node
3b7f5abe
AM
126 * @throws ClosedChannelException
127 * Usually happens because the file was closed while we were
128 * reading. Instead of using a big reader-writer lock, we'll
129 * just catch this exception.
a52fde77 130 */
aa353506 131 public synchronized @NonNull HTNode readNode(int seqNumber) throws ClosedChannelException {
6993c1ca 132 /* Do a cache lookup */
4018d70a
MK
133 int offset = (seqNumber + hashCode()) & CACHE_MASK;
134 CacheElement cachedNode = NODE_CACHE[offset];
135
136 if (cachedNode != null && cachedNode.getKey() == this && cachedNode.getValue().getSequenceNumber() == seqNumber) {
b2648641 137 LOGGER.finest(() -> "[HtIo:CacheHit] seqNum=" + seqNumber); //$NON-NLS-1$
4018d70a 138 return cachedNode.getValue();
6993c1ca
EB
139 }
140
141 /* Lookup on disk */
a52fde77 142 try {
c772ff74 143 seekFCToNodePos(fFileChannelIn, seqNumber);
4018d70a 144 HTNode readNode = HTNode.readNode(fConfig, fFileChannelIn);
b2648641 145 LOGGER.finest(() -> "[HtIo:CacheMiss] seqNum=" + seqNumber); //$NON-NLS-1$
6993c1ca
EB
146
147 /* Put the node in the cache. */
4018d70a 148 NODE_CACHE[offset] = new CacheElement(this, readNode);
a52fde77 149 return readNode;
aa353506 150
3b7f5abe
AM
151 } catch (ClosedChannelException e) {
152 throw e;
a52fde77 153 } catch (IOException e) {
4018d70a
MK
154 /*
155 * Other types of IOExceptions shouldn't happen at this point though
156 */
49a817d5 157 Activator.getDefault().logError(e.getMessage(), e);
aa353506 158 throw new IllegalStateException();
a52fde77
AM
159 }
160 }
161
e8b7cc14 162 public synchronized void writeNode(HTNode node) {
a52fde77 163 try {
6993c1ca
EB
164 /* Insert the node into the cache. */
165 int seqNumber = node.getSequenceNumber();
4018d70a
MK
166 int offset = (seqNumber + hashCode()) & CACHE_MASK;
167 NODE_CACHE[offset] = new CacheElement(this, node);
6993c1ca 168
a52fde77 169 /* Position ourselves at the start of the node and write it */
c772ff74
MK
170 seekFCToNodePos(fFileChannelOut, seqNumber);
171 node.writeSelf(fFileChannelOut);
a52fde77
AM
172 } catch (IOException e) {
173 /* If we were able to open the file, we should be fine now... */
49a817d5 174 Activator.getDefault().logError(e.getMessage(), e);
a52fde77
AM
175 }
176 }
177
e8b7cc14 178 public FileChannel getFcOut() {
c772ff74 179 return fFileChannelOut;
a52fde77
AM
180 }
181
8d47cc34 182 public FileInputStream supplyATReader(int nodeOffset) {
a52fde77
AM
183 try {
184 /*
185 * Position ourselves at the start of the Mapping section in the
186 * file (which is right after the Blocks)
187 */
c772ff74 188 seekFCToNodePos(fFileChannelIn, nodeOffset);
a52fde77 189 } catch (IOException e) {
49a817d5 190 Activator.getDefault().logError(e.getMessage(), e);
a52fde77 191 }
c772ff74 192 return fFileInputStream;
a52fde77
AM
193 }
194
8d47cc34 195 public synchronized void closeFile() {
3de60236 196 try {
c772ff74
MK
197 fFileInputStream.close();
198 fFileOutputStream.close();
3de60236 199 } catch (IOException e) {
49a817d5 200 Activator.getDefault().logError(e.getMessage(), e);
3de60236 201 }
1a4205d9
AM
202 }
203
8d47cc34 204 public synchronized void deleteFile() {
1a4205d9 205 closeFile();
3de60236 206
360f899e 207 File historyTreeFile = fConfig.getStateFile();
6993c1ca 208 if (!historyTreeFile.delete()) {
36bf82a2 209 /* We didn't succeed in deleting the file */
49a817d5 210 Activator.getDefault().logError("Failed to delete" + historyTreeFile.getName()); //$NON-NLS-1$
36bf82a2
AM
211 }
212 }
213
a52fde77
AM
214 /**
215 * Seek the given FileChannel to the position corresponding to the node that
216 * has seqNumber
3de60236 217 *
49a817d5
MK
218 * @param fc
219 * the channel to seek
220 * @param seqNumber
221 * the node sequence number to seek the channel to
a52fde77 222 * @throws IOException
49a817d5 223 * If some other I/O error occurs
a52fde77
AM
224 */
225 private void seekFCToNodePos(FileChannel fc, int seqNumber)
226 throws IOException {
a52fde77 227 /*
360f899e 228 * Cast to (long) is needed to make sure the result is a long too and
a52fde77
AM
229 * doesn't get truncated
230 */
360f899e 231 fc.position(HistoryTree.TREE_HEADER_SIZE
49a817d5 232 + ((long) seqNumber) * fConfig.getBlockSize());
a52fde77
AM
233 }
234
235}
This page took 0.098799 seconds and 5 git commands to generate.