blob: b24f997eb98b6dae1b1bdf66eff3384ea8f01c77 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015 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
*
* Contributors:
* Bernd Hufmann - Initial API and implementation
*******************************************************************************/
package org.eclipse.tracecompass.ctf.core.trace;
import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
import java.io.File;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.tracecompass.ctf.core.CTFException;
import org.eclipse.tracecompass.ctf.core.CTFStrings;
import org.eclipse.tracecompass.internal.ctf.core.trace.StreamInputPacketIndex;
/**
* A CTF Stream output writer. Reads the packets of a given CTFStreamInput and
* writes packets that are within a given time range to output stream file.
*
* @author Bernd Hufmann
* @since 1.0
*/
public class CTFStreamOutputWriter {
// ------------------------------------------------------------------------
// Attributes
// ------------------------------------------------------------------------
// Stream input when copying stream from an input
// It is @Nullable for future implementations that doesn't use an input
// stream
@Nullable
private final CTFStreamInput fStreamInput;
@NonNull
private final CTFStreamPacketOutputWriter fStreamPacketOutputWriter;
@NonNull
private final File fOutFile;
// ------------------------------------------------------------------------
// Constructors
// ------------------------------------------------------------------------
/**
* Constructs a StreamInput.
*
* @param streamInput
* The stream to which this StreamInput belongs to.
* @param file
* The output trace directory.
* @throws CTFException
* If a reading or writing error occurs
*/
public CTFStreamOutputWriter(@NonNull CTFStreamInput streamInput, @NonNull File file) throws CTFException {
fStreamInput = streamInput;
String inFileName = streamInput.getFile().getName();
Path outFilePath = FileSystems.getDefault().getPath(file.getAbsolutePath(), inFileName);
try {
fOutFile = checkNotNull(Files.createFile(outFilePath).toFile());
} catch (IOException e) {
throw new CTFIOException("Output file can't be created: " + outFilePath, e); //$NON-NLS-1$
}
fStreamPacketOutputWriter = new CTFStreamPacketOutputWriter(streamInput);
}
/**
* Copies packets from the relevant input this input stream to a corresponding
* output stream based on a given time range. The following condition has to be
* met so that a packet is written to the output stream:
*
* startTime <= packet.getTimestampEnd() && packet.getTimestampStart() <=
* endTime
*
* @param startTime
* the start time for packets to be written
* @param endTime
* the end time for packets to be written
* @throws CTFException
* if a reading or writing error occurs
* @since 1.0
*/
public void copyPackets(long startTime, long endTime) throws CTFException {
CTFStreamInput streamInput = fStreamInput;
if (streamInput == null) {
throw new CTFIOException("StreamInput is null. Can't copy packets"); //$NON-NLS-1$
}
try (FileChannel fc = checkNotNull(FileChannel.open(fOutFile.toPath(), StandardOpenOption.WRITE));
FileChannel source = FileChannel.open(streamInput.getFile().toPath(), StandardOpenOption.READ);) {
StreamInputPacketIndex index = streamInput.getIndex();
int count = 0;
long initialLost = 0;
for (int i = 0; i < index.size(); i++) {
ICTFPacketDescriptor entry = index.getElement(i);
/*
* Entire packet is contained
*/
long packetStart = entry.getTimestampBegin();
long packetEnd = entry.getTimestampEnd();
if (count == 0) {
initialLost = (long) entry.getAttributes().getOrDefault(CTFStrings.EVENTS_DISCARDED, 0L);
}
if (startTime <= packetStart && endTime >= packetEnd) {
// MUCH faster
fStreamPacketOutputWriter.writePacket(entry, fc, initialLost);
count++;
} else if (startTime <= packetEnd && endTime >= packetStart) {
fStreamPacketOutputWriter.writePacket(entry, startTime, endTime, initialLost, fc);
count++;
} else if (entry.getTimestampBegin() > endTime) {
break;
}
}
if (count == 0 && fOutFile.exists() || fOutFile.length() == 0) {
boolean deleteResult = fOutFile.delete();
if (!deleteResult) {
throw new CTFIOException("Could not delete " + fOutFile.getAbsolutePath()); //$NON-NLS-1$
}
}
} catch (IOException e) {
throw new CTFIOException("Error copying packets: " + e.toString(), e); //$NON-NLS-1$
}
}
/**
* Get the stream file to write.
*
* @return the stream file to write
*/
public File getOutFile() {
return fOutFile;
}
}