blob: 556763a723e667b0d63ec8d03e82cae966d8ef80 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 Ericsson
*
* 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
******************************************************************************/
package org.eclipse.tracecompass.internal.tmf.analysis.xml.core.pattern.stateprovider;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.analysis.timing.core.segmentstore.AbstractSegmentStoreAnalysisModule;
import org.eclipse.tracecompass.analysis.timing.core.segmentstore.IAnalysisProgressListener;
import org.eclipse.tracecompass.datastore.core.interval.IHTIntervalReader;
import org.eclipse.tracecompass.internal.tmf.analysis.xml.core.segment.TmfXmlPatternSegment;
import org.eclipse.tracecompass.segmentstore.core.ISegment;
import org.eclipse.tracecompass.segmentstore.core.ISegmentStore;
import org.eclipse.tracecompass.segmentstore.core.SegmentStoreFactory.SegmentStoreType;
import org.eclipse.tracecompass.tmf.core.exceptions.TmfAnalysisException;
import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
/**
* Segment store module for pattern analysis defined in XML. This module will
* receive all the segments provided by an external source and will build a
* segment store
*
* @author Jean-Christian Kouame
*/
public class XmlPatternSegmentStoreModule extends AbstractSegmentStoreAnalysisModule implements ISegmentListener {
/**
* Fake segment indicated that the last segment have been received
*/
public static final @NonNull EndSegment END_SEGMENT = new EndSegment();
private final List<@NonNull ISegment> fCachedSegments = new ArrayList<>();
private ISegmentStore<@NonNull ISegment> fFinalSegments;
private final CountDownLatch fFinished = new CountDownLatch(1);
private final @NonNull XmlPatternAnalysis fParent;
private boolean fSegmentStoreCompleted;
/**
* Constructor
*
* @param parent
* The parent analysis
*/
public XmlPatternSegmentStoreModule(@NonNull XmlPatternAnalysis parent) {
super();
fParent = parent;
}
@Override
protected boolean buildAnalysisSegments(@NonNull ISegmentStore<@NonNull ISegment> segments, @NonNull IProgressMonitor monitor) throws TmfAnalysisException {
final @Nullable ITmfTrace trace = getTrace();
if (trace == null) {
/* This analysis was cancelled in the meantime */
segmentStoreReady(false);
segments.close(true);
return false;
}
fFinalSegments = segments;
if (waitForSegmentStoreCompletion()) {
fFinalSegments.close(false);
return true;
}
fFinalSegments.close(true);
return false;
}
@Override
protected void canceling() {
super.cancel();
segmentStoreReady(false);
}
@Override
protected String getDataFileName() {
return getId() + XmlPatternAnalysis.SEGMENT_STORE_EXTENSION;
}
@Override
protected @NonNull SegmentStoreType getSegmentStoreType() {
return SegmentStoreType.OnDisk;
}
@Override
protected @NonNull IHTIntervalReader<@NonNull ISegment> getSegmentReader() {
return TmfXmlPatternSegment.READER;
}
/**
* Broadcast the segment store to its listeners. Since this analysis is not
* directly register to the trace, the parent analysis is used as the source.
*
* @param store
* The store to broadcast
*/
@Override
protected void sendUpdate(final ISegmentStore<@NonNull ISegment> store) {
for (IAnalysisProgressListener listener : getListeners()) {
listener.onComplete(fParent, store);
}
}
@Override
public void onNewSegment(@NonNull ISegment segment) {
// We can accept segments until the first END_SEGMENT arrives. Nothing
// should be accept after it. This prevents to receive new segments if
// the analysis that generates the segments is rescheduled
if (!fSegmentStoreCompleted) {
if (segment == END_SEGMENT) {
segmentStoreReady(true);
return;
}
if (fFinalSegments == null) {
getCachedSegments().add(segment);
} else {
if (!getCachedSegments().isEmpty()) {
fFinalSegments.addAll(getCachedSegments());
getCachedSegments().clear();
}
fFinalSegments.add(segment);
}
}
}
/**
* Get the internal segment store of this module
*
* @return The segment store
*/
private synchronized List<@NonNull ISegment> getCachedSegments() {
return fCachedSegments;
}
/**
* Wait until internal segment store of the module is fully filled. If all
* the segments have been received, the completion succeeded, otherwise it
* is not.
*
* @return True if the completion succeeded, false otherwise
*/
public boolean waitForSegmentStoreCompletion() {
try {
fFinished.await();
} catch (InterruptedException e) {
return false;
}
return fSegmentStoreCompleted;
}
/**
* Make the module available and set whether the segment store completion
* succeeded or not. If not, no segment store is available and
* {@link #waitForSegmentStoreCompletion()} should return false.
*
* @param success
* True if the segment store completion succeeded, false
* otherwise
*/
private void segmentStoreReady(boolean succeeded) {
fSegmentStoreCompleted = succeeded;
fFinished.countDown();
}
/**
* Fake segment indicating the build is over, and the segment store is fully
* filled
*/
public static class EndSegment implements ISegment {
/**
* The serial version UID
*/
private static final long serialVersionUID = 7834984029618274707L;
@Override
public long getStart() {
return Long.MIN_VALUE;
}
@Override
public long getEnd() {
return Long.MIN_VALUE;
}
}
}