blob: 4287f808796fd43ea9ad74ccda5fae29cc70f0c4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2013, 2015 École Polytechnique de Montréal
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License 2.0 which
* accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Geneviève Bastien - Initial API and implementation
* Bernd Hufmann - Integrated history builder functionality
*******************************************************************************/
package org.eclipse.tracecompass.tmf.core.statesystem;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.FileUtils;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.common.core.NonNullUtils;
import org.eclipse.tracecompass.common.core.log.TraceCompassLog;
import org.eclipse.tracecompass.common.core.log.TraceCompassLogUtils.ScopeLog;
import org.eclipse.tracecompass.internal.tmf.core.Activator;
import org.eclipse.tracecompass.internal.tmf.core.statesystem.backends.partial.PartialHistoryBackend;
import org.eclipse.tracecompass.internal.tmf.core.statesystem.backends.partial.PartialStateSystem;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystem;
import org.eclipse.tracecompass.statesystem.core.ITmfStateSystemBuilder;
import org.eclipse.tracecompass.statesystem.core.StateSystemFactory;
import org.eclipse.tracecompass.statesystem.core.backend.IStateHistoryBackend;
import org.eclipse.tracecompass.statesystem.core.backend.StateHistoryBackendFactory;
import org.eclipse.tracecompass.statesystem.core.interval.ITmfStateInterval;
import org.eclipse.tracecompass.statesystem.core.snapshot.StateSnapshot;
import org.eclipse.tracecompass.tmf.core.analysis.TmfAbstractAnalysisModule;
import org.eclipse.tracecompass.tmf.core.event.ITmfEvent;
import org.eclipse.tracecompass.tmf.core.exceptions.TmfTraceException;
import org.eclipse.tracecompass.tmf.core.request.ITmfEventRequest;
import org.eclipse.tracecompass.tmf.core.request.TmfEventRequest;
import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
import org.eclipse.tracecompass.tmf.core.signal.TmfTraceRangeUpdatedSignal;
import org.eclipse.tracecompass.tmf.core.statesystem.ITmfStateProvider.FutureEventType;
import org.eclipse.tracecompass.tmf.core.timestamp.TmfTimeRange;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTraceCompleteness;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
import org.eclipse.tracecompass.tmf.core.trace.TmfTraceUtils;
import org.eclipse.tracecompass.tmf.core.trace.experiment.TmfExperiment;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
/**
* Abstract analysis module to generate a state system. It is a base class that
* can be used as a shortcut by analysis who just need to build a single state
* system with a state provider.
*
* Analysis implementing this class should only need to provide a state system
* and optionally a backend (default to NULL) and, if required, a filename
* (defaults to the analysis'ID)
*
* @author Geneviève Bastien
*/
public abstract class TmfStateSystemAnalysisModule extends TmfAbstractAnalysisModule
implements ITmfAnalysisModuleWithStateSystems {
private static final Logger LOGGER = TraceCompassLog.getLogger(TmfStateSystemAnalysisModule.class);
private static final String EXTENSION = ".ht"; //$NON-NLS-1$
private final CountDownLatch fInitialized = new CountDownLatch(1);
private final Object fRequestSyncObj = new Object();
private @Nullable ITmfStateSystemBuilder fStateSystem;
private @Nullable ITmfEventRequest fRequest;
private @Nullable TmfTimeRange fTimeRange = null;
private int fNbRead = 0;
private boolean fInitializationSucceeded;
private volatile @Nullable ITmfStateProvider fStateProvider;
private @Nullable Integer fProviderVersion = null;
/**
* State system backend types
*
* @author Geneviève Bastien
*/
protected enum StateSystemBackendType {
/** Full history in file */
FULL,
/** In memory state system */
INMEM,
/** Null history */
NULL,
/** State system backed with partial history */
PARTIAL
}
/**
* Retrieve a state system belonging to trace, by passing the ID of the relevant
* analysis module.
*
* This will start the execution of the analysis module, and start the
* construction of the state system, if needed.
*
* @param trace
* The trace for which you want the state system
* @param moduleId
* The ID of the state system analysis module
* @return The state system, or null if there was no match or the module was not
* initialized correctly
*/
public static @Nullable ITmfStateSystem getStateSystem(ITmfTrace trace, String moduleId) {
TmfStateSystemAnalysisModule module = TmfTraceUtils.getAnalysisModuleOfClass(trace, TmfStateSystemAnalysisModule.class, moduleId);
if (module != null) {
ITmfStateSystem ss = module.getStateSystem();
if (ss != null) {
return ss;
}
IStatus status = module.schedule();
if (status.isOK()) {
return module.waitForInitialization() ? module.getStateSystem() : null;
}
}
return null;
}
/**
* Get the state provider for this analysis module
*
* @return the state provider
*/
protected abstract ITmfStateProvider createStateProvider();
/**
* Get the state system backend type used by this module
*
* @return The {@link StateSystemBackendType}
*/
protected StateSystemBackendType getBackendType() {
/* Using full history by default, sub-classes can override */
return StateSystemBackendType.FULL;
}
/**
* Get the supplementary file name where to save this state system. The default
* is the ID of the analysis followed by the extension.
*
* @return The supplementary file name
*/
protected String getSsFileName() {
return getId() + EXTENSION;
}
/**
* Get the state system generated by this analysis, or null if it is not yet
* created.
*
* @return The state system
*/
@Nullable
public ITmfStateSystem getStateSystem() {
return fStateSystem;
}
@Override
public Map<String, Integer> getProviderVersions() {
Integer providerVersion = fProviderVersion;
if (providerVersion == null) {
return Collections.emptyMap();
}
ImmutableMap.Builder<String, Integer> builder = new Builder<>();
for (ITmfStateSystem ss : getStateSystems()) {
builder.put(ss.getSSID(), providerVersion);
}
return builder.build();
}
/**
* @since 2.0
*/
@Override
public boolean waitForInitialization() {
try {
fInitialized.await();
} catch (InterruptedException e) {
return false;
}
return fInitializationSucceeded;
}
@Override
protected void onFail() {
super.onFail();
// Make sure any analysis waiting for initialization can continue
if (fInitialized.getCount() > 0) {
analysisReady(false);
}
}
/**
* @since 2.0
*/
@Override
public boolean isQueryable(long ts) {
/*
* Return true if there is no state provider available (the analysis is not
* being built)
*/
ITmfStateProvider provider = fStateProvider;
if (provider == null) {
return true;
}
return ts <= provider.getLatestSafeTime();
}
// ------------------------------------------------------------------------
// TmfAbstractAnalysisModule
// ------------------------------------------------------------------------
/**
* Get the file where to save the results of the analysis
*
* @return The file to save the results in
* @since 2.3
*/
@VisibleForTesting
protected @Nullable File getSsFile() {
ITmfTrace trace = getTrace();
if (trace == null) {
return null;
}
String directory = TmfTraceManager.getSupplementaryFileDir(trace);
File htFile = new File(directory + getSsFileName());
return htFile;
}
@Override
protected boolean executeAnalysis(@Nullable final IProgressMonitor monitor) {
IProgressMonitor mon = (monitor == null ? new NullProgressMonitor() : monitor);
final ITmfStateProvider provider = createStateProvider();
fProviderVersion = provider.getVersion();
String id = getId();
/*
* FIXME: State systems should make use of the monitor, to be cancelled
*/
try (ScopeLog log = new ScopeLog(LOGGER, Level.FINE, "StateSystemAnalysis:executing", "id", id)) { //$NON-NLS-1$ //$NON-NLS-2$
/* Get the state system according to backend */
StateSystemBackendType backend = getBackendType();
ITmfTrace trace = getTrace();
if (trace == null) {
// Analysis was cancelled in the meantime
analysisReady(false);
return false;
}
File htFile;
switch (backend) {
case FULL:
htFile = getSsFile();
if (htFile == null) {
return false;
}
createFullHistory(id, provider, htFile);
break;
case PARTIAL:
htFile = getSsFile();
if (htFile == null) {
return false;
}
createPartialHistory(id, provider, htFile);
break;
case INMEM:
createInMemoryHistory(id, provider);
break;
case NULL:
createNullHistory(id, provider);
break;
default:
break;
}
} catch (TmfTraceException e) {
analysisReady(false);
return false;
}
return !mon.isCanceled();
}
/**
* Make the module available and set whether the initialization succeeded or
* not. If not, no state system is available and
* {@link #waitForInitialization()} should return false.
*
* @param success
* True if the initialization succeeded, false otherwise
*/
private void analysisReady(boolean succeeded) {
fInitializationSucceeded = succeeded;
fInitialized.countDown();
}
@Override
protected void canceling() {
ITmfEventRequest req = fRequest;
if ((req != null) && (!req.isCompleted())) {
req.cancel();
}
}
@Override
public void dispose() {
super.dispose();
if (fStateSystem != null) {
fStateSystem.dispose();
}
}
// ------------------------------------------------------------------------
// History creation methods
// ------------------------------------------------------------------------
/*
* Load the history file matching the target trace. If the file already exists,
* it will be opened directly. If not, it will be created from scratch.
*/
private void createFullHistory(String id, ITmfStateProvider provider, File htFile) throws TmfTraceException {
/* If the target file already exists, do not rebuild it uselessly */
// TODO for now we assume it's complete. Might be a good idea to check
// at least if its range matches the trace's range.
if (htFile.exists()) {
/* Load an existing history */
final int version = provider.getVersion();
try {
IStateHistoryBackend backend = StateHistoryBackendFactory.createHistoryTreeBackendExistingFile(
id, htFile, version);
fStateSystem = StateSystemFactory.newStateSystem(backend, false);
analysisReady(true);
return;
} catch (IOException e) {
/*
* There was an error opening the existing file. Perhaps it was corrupted,
* perhaps it's an old version? We'll just fall-through and try to build a new
* one from scratch instead.
*/
}
}
/* Size of the blocking queue to use when building a state history */
final int QUEUE_SIZE = 10000;
try {
IStateHistoryBackend backend = StateHistoryBackendFactory.createHistoryTreeBackendNewFile(
id, htFile, provider.getVersion(), provider.getStartTime(), QUEUE_SIZE);
fStateSystem = StateSystemFactory.newStateSystem(backend);
provider.assignTargetStateSystem(fStateSystem);
build(provider);
} catch (IOException e) {
/*
* If it fails here however, it means there was a problem writing to the disk,
* so throw a real exception this time.
*/
throw new TmfTraceException(e.toString(), e);
}
}
/*
* Create a new state system backed with a partial history. A partial history is
* similar to a "full" one (which you get with {@link #newFullHistory}), except
* that the file on disk is much smaller, but queries are a bit slower.
*
* Also note that single-queries are implemented using a full-query underneath,
* (which are much slower), so this might not be a good fit for a use case where
* you have to do lots of single queries.
*/
private void createPartialHistory(String id, ITmfStateProvider provider, File htPartialFile)
throws TmfTraceException {
/*
* The order of initializations is very tricky (but very important!) here. We
* need to follow this pattern: (1 is done before the call to this method)
* <ol>
* <li>Instantiate realStateProvider</li>
* <li>Instantiate realBackend</li>
* <li>Instantiate partialBackend, with prereqs:
* <ol>
* <li>Instantiate partialProvider, via realProvider.getNew()</li>
* <li>Instantiate nullBackend (partialSS's backend)</li>
* <li>Instantiate partialSS</li>
* <li>partialProvider.assignSS(partialSS)</li>
* </ol>
* <li>Instantiate realSS</li>
* <li>partialSS.assignUpstream(realSS)</li>
* <li>realProvider.assignSS (realSS)</li>
* <li>Call HistoryBuilder(realProvider, realSS, partialBackend) to build the
* thing.</li></li>
*/
/* Size of the blocking queue to use when building a state history */
final int QUEUE_SIZE = 10000;
final long granularity = 50000;
/* 2 */
IStateHistoryBackend realBackend = null;
try {
realBackend = StateHistoryBackendFactory.createHistoryTreeBackendNewFile(
id, htPartialFile, provider.getVersion(), provider.getStartTime(), QUEUE_SIZE);
} catch (IOException e) {
throw new TmfTraceException(e.toString(), e);
}
/* 3a */
ITmfStateProvider partialProvider = provider.getNewInstance();
/* 3b-3c, constructor automatically uses a NullBackend */
PartialStateSystem pss = new PartialStateSystem();
/* 3d */
partialProvider.assignTargetStateSystem(pss);
/* 3 */
IStateHistoryBackend partialBackend = new PartialHistoryBackend(id + ".partial", partialProvider, pss, realBackend, granularity); //$NON-NLS-1$
/* 4 */
ITmfStateSystemBuilder realSS = StateSystemFactory.newStateSystem(partialBackend);
/* 5 */
pss.assignUpstream(realSS);
/* 6 */
provider.assignTargetStateSystem(realSS);
/* 7 */
fStateSystem = realSS;
build(provider);
}
/*
* Create a new state system using a null history back-end. This means that no
* history intervals will be saved anywhere, and as such only {@link
* ITmfStateSystem#queryOngoingState} will be available.
*/
private void createNullHistory(String id, ITmfStateProvider provider) {
IStateHistoryBackend backend = StateHistoryBackendFactory.createNullBackend(id);
fStateSystem = StateSystemFactory.newStateSystem(backend);
provider.assignTargetStateSystem(fStateSystem);
build(provider);
}
/*
* Create a new state system using in-memory interval storage. This should only
* be done for very small state system, and will be naturally limited to 2^31
* intervals.
*/
private void createInMemoryHistory(String id, ITmfStateProvider provider) {
IStateHistoryBackend backend = StateHistoryBackendFactory.createInMemoryBackend(id, provider.getStartTime());
fStateSystem = StateSystemFactory.newStateSystem(backend);
provider.assignTargetStateSystem(fStateSystem);
build(provider);
}
private void disposeProvider(boolean deleteFiles) {
ITmfStateProvider provider = fStateProvider;
boolean shouldDeleteFiles = deleteFiles;
if (provider != null) {
provider.dispose();
Throwable failureCause = provider.getFailureCause();
/*
* Fail the analysis if the provider failed and force the file deletion
*/
if (failureCause != null) {
fail(failureCause);
shouldDeleteFiles = true;
}
}
fStateProvider = null;
if (shouldDeleteFiles && (fStateSystem != null)) {
fStateSystem.removeFiles();
}
completingBuild(shouldDeleteFiles);
}
/**
* The state system and analysis construction has completed. The state provider
* has been disposed, either at the end of the analysis, when it is cancelled or
* has failed. Children classes should override this if they need to close or
* dispose of anything at the end of the analysis execution.
*
* @param deleteFiles
* If <code>true</code>, files that were built during the execution
* should be deleted, otherwise they should be saved.
* @since 3.3
*/
protected void completingBuild(boolean deleteFiles) {
// Nothing to do, classes may override this
}
private void build(ITmfStateProvider provider) {
if (fStateSystem == null) {
throw new IllegalArgumentException();
}
/*
* Note we have to do this before fStateProvider is assigned. After that, the
* signal listener below will start sending real trace events through the state
* provider.
*/
loadInitialState(provider);
/* Continue on initializing the event request to read trace events. */
ITmfEventRequest request = fRequest;
if ((request != null) && (!request.isCompleted())) {
request.cancel();
}
fTimeRange = TmfTimeRange.ETERNITY;
final ITmfTrace trace = provider.getTrace();
if (!isCompleteTrace(trace)) {
fTimeRange = trace.getTimeRange();
}
fStateProvider = provider;
synchronized (fRequestSyncObj) {
startRequest();
request = fRequest;
}
/*
* The state system object is now created, we can consider this module
* "initialized" (components can retrieve it and start doing queries).
*/
analysisReady(true);
/*
* Block the executeAnalysis() construction is complete (so that the progress
* monitor displays that it is running).
*/
try {
if (request != null) {
request.waitForCompletion();
if (request.isFailed()) {
Throwable failureCause = request.getFailureCause();
if (failureCause != null) {
fail(failureCause);
} else {
fail(new RuntimeException("Event request failed without a cause")); //$NON-NLS-1$
}
}
}
} catch (InterruptedException e) {
fail(e);
}
}
/**
* Batch-load the initial state, if there is any.
*/
private void loadInitialState(ITmfStateProvider provider) {
final ITmfTrace trace = provider.getTrace();
File path = new File(trace.getPath());
path = path.isDirectory() ? path : path.getParentFile();
if (path == null) {
return;
}
for (ITmfStateSystem ss : getStateSystems()) {
if (ss instanceof ITmfStateSystemBuilder) {
StateSnapshot snapshot = StateSnapshot.read(path.toPath(), ss.getSSID());
if (snapshot == null || provider.getVersion() != snapshot.getVersion()) {
/*
* No statedump found, nothing to pre-load or Do not load the statedump if its
* version does not match the current provider.
*/
continue;
}
List<List<String>> paths = new ArrayList<>();
/* create quark list */
for (Entry<List<String>, ITmfStateInterval> attributeSnapshot : snapshot.getStates().entrySet()) {
List<String> attributePath = Objects.requireNonNull(attributeSnapshot.getKey());
ITmfStateInterval state = Objects.requireNonNull(attributeSnapshot.getValue());
while (paths.size() <= state.getAttribute()) {
paths.add(Collections.singletonList("Dummy" + paths.size())); //$NON-NLS-1$
}
paths.set(state.getAttribute(), attributePath);
}
/*
* Populate quarks in order
*/
int i = 0;
for (List<String> attributePath : paths) {
int quark = ((ITmfStateSystemBuilder) ss).getQuarkAbsoluteAndAdd(attributePath.toArray(new String[attributePath.size()]));
if (i != quark) {
Activator.logWarning("Quark for analysis " + getClass().getCanonicalName() + " not the same ( " + quark + " != " + i + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
}
i++;
}
/* Load the statedump into the statesystem */
for (ITmfStateInterval interval : snapshot.getStates().values()) {
Object initialState = interval.getValue();
int attribute = interval.getAttribute();
provider.addFutureEvent(interval.getStartTime(), initialState, attribute, FutureEventType.MODIFICATION);
if (interval.getEndTime() != Long.MIN_VALUE) {
provider.addFutureEvent(interval.getEndTime() + 1, (Object) null, attribute, FutureEventType.MODIFICATION);
}
}
}
}
}
/**
* A request to build a state system from a state provider
*
* @since 2.3
*/
@VisibleForTesting
protected class StateSystemEventRequest extends TmfEventRequest {
private final ITmfStateProvider sci;
private final ITmfTrace trace;
/**
* Constructor
*
* @param sp
* The state provider used to build the state system
* @param timeRange
* The requested time range for the request
* @param index
* The event number at which to start the request
*/
public StateSystemEventRequest(ITmfStateProvider sp, TmfTimeRange timeRange, int index) {
super(ITmfEvent.class,
timeRange,
index,
ITmfEventRequest.ALL_DATA,
ITmfEventRequest.ExecutionType.BACKGROUND,
TmfStateSystemAnalysisModule.this.getDependencyLevel());
this.sci = sp;
trace = sci.getTrace();
}
/**
* Constructor
*
* @param sp
* The state provider used to build the state system
* @param timeRange
* The requested time range for the request
* @param index
* The event number at which to start the request
* @param nbRequested
* The number of events requested
* @since 4.1
*/
public StateSystemEventRequest(ITmfStateProvider sp, TmfTimeRange timeRange, int index, int nbRequested) {
super(ITmfEvent.class,
timeRange,
index,
nbRequested,
ITmfEventRequest.ExecutionType.BACKGROUND,
TmfStateSystemAnalysisModule.this.getDependencyLevel());
sci = sp;
trace = sci.getTrace();
}
@Override
public void handleData(final ITmfEvent event) {
super.handleData(event);
processEvent(event, trace);
}
private void processEvent(final ITmfEvent event, ITmfTrace tmfTrace) {
if (event.getTrace() == tmfTrace) {
sci.processEvent(event);
} else if (tmfTrace instanceof TmfExperiment) {
/*
* If the request is for an experiment, check if the event is from one of the
* child trace
*/
for (ITmfTrace childTrace : ((TmfExperiment) tmfTrace).getTraces()) {
processEvent(event, childTrace);
}
}
}
@Override
public void handleSuccess() {
super.handleSuccess();
if (isCompleteTrace(trace)) {
disposeProvider(false);
} else {
fNbRead += getNbRead();
synchronized (fRequestSyncObj) {
final TmfTimeRange timeRange = fTimeRange;
if (timeRange != null && getRange().getEndTime().toNanos() < timeRange.getEndTime().toNanos()) {
startRequest();
}
}
}
}
@Override
public void handleCancel() {
super.handleCancel();
disposeProvider(true);
}
@Override
public void handleFailure() {
super.handleFailure();
disposeProvider(true);
}
}
// ------------------------------------------------------------------------
// ITmfAnalysisModuleWithStateSystems
// ------------------------------------------------------------------------
@Override
@Nullable
public ITmfStateSystem getStateSystem(String id) {
if (id.equals(getId())) {
return fStateSystem;
}
return null;
}
@Override
public @NonNull Iterable<@NonNull ITmfStateSystem> getStateSystems() {
ITmfStateSystemBuilder stateSystem = fStateSystem;
if (stateSystem == null) {
return Collections.emptySet();
}
return Collections.singleton(stateSystem);
}
/**
* Signal handler for the TmfTraceRangeUpdatedSignal signal
*
* @param signal
* The incoming signal
*/
@TmfSignalHandler
public void traceRangeUpdated(final TmfTraceRangeUpdatedSignal signal) {
fTimeRange = signal.getRange();
ITmfStateProvider stateProvider = fStateProvider;
synchronized (fRequestSyncObj) {
if (signal.getTrace() == getTrace() && stateProvider != null && stateProvider.getAssignedStateSystem() != null) {
ITmfEventRequest request = fRequest;
if ((request == null) || request.isCompleted()) {
startRequest();
}
}
}
}
private void startRequest() {
ITmfStateProvider stateProvider = fStateProvider;
TmfTimeRange timeRange = fTimeRange;
if (stateProvider == null || timeRange == null) {
return;
}
ITmfEventRequest request = createEventRequest(stateProvider, timeRange, fNbRead);
stateProvider.getTrace().sendRequest(request);
fRequest = request;
}
/**
* Create a new event request
*
* @param stateProvider
* The state provider used to build the state system
* @param timeRange
* The requested time range for the request
* @param nbRead
* The event number at which to start the request
* @return A new event request
* @since 2.3
*/
@VisibleForTesting
protected ITmfEventRequest createEventRequest(ITmfStateProvider stateProvider, TmfTimeRange timeRange, int nbRead) {
return new StateSystemEventRequest(stateProvider, timeRange, nbRead);
}
private static boolean isCompleteTrace(ITmfTrace trace) {
return !(trace instanceof ITmfTraceCompleteness) || ((ITmfTraceCompleteness) trace).isComplete();
}
// ------------------------------------------------------------------------
// ITmfPropertiesProvider
// ------------------------------------------------------------------------
/**
* @since 2.0
*/
@Override
public @NonNull Map<@NonNull String, @NonNull String> getProperties() {
Map<@NonNull String, @NonNull String> properties = super.getProperties();
StateSystemBackendType backend = getBackendType();
properties.put(NonNullUtils.checkNotNull(Messages.TmfStateSystemAnalysisModule_PropertiesBackend), backend.name());
switch (backend) {
case FULL:
case PARTIAL:
File htFile = getSsFile();
if (htFile != null) {
if (htFile.exists()) {
properties.put(NonNullUtils.checkNotNull(Messages.TmfStateSystemAnalysisModule_PropertiesFileSize), FileUtils.byteCountToDisplaySize(htFile.length()));
} else {
properties.put(NonNullUtils.checkNotNull(Messages.TmfStateSystemAnalysisModule_PropertiesFileSize), NonNullUtils.checkNotNull(Messages.TmfStateSystemAnalysisModule_PropertiesAnalysisNotExecuted));
}
}
break;
case INMEM:
case NULL:
default:
break;
}
return properties;
}
}