blob: 4f82f7d74e8845e01e789ebbfc47d8c48be1db0c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2021 IBM Corporation
* 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:
* IBM Corporation - initial implementation
*******************************************************************************/
package org.eclipse.mat.ibmvm.acquire;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.List;
import org.eclipse.mat.SnapshotException;
import org.eclipse.mat.util.IProgressListener;
/**
* Helper dump provider - the IBMDumpProvider delegates to this to do the work for system dumps.
* @author ajohnson
*/
class IBMSystemDumpProvider extends IBMDumpProvider
{
IBMSystemDumpProvider()
{}
@Override
String dumpName()
{
return "core.YYmmdd.HHMMSS.%pid%.seq.dmp"; //$NON-NLS-1$
}
int files()
{
return 1;
}
@Override
long averageFileSize(Collection<File> files)
{
long l = 0;
int i = 0;
for (File f : files)
{
if (f.isFile() && f.getName().endsWith(".dmp")) { //$NON-NLS-1$
l += f.length();
++i;
}
}
if (i > 0)
return l / i;
else
// guess 100MB
return 100000000L;
}
/**
* Run jextract and move the files to the target directory
* @param preferredDump
* @param dumps
* @param udir
* @param home
* @param listener
* @return
* @throws IOException
* @throws InterruptedException
* @throws SnapshotException
*/
@Override
File jextract(File preferredDump, boolean compress, List<File>dumps, File udir, File home, IProgressListener listener) throws IOException,
InterruptedException, SnapshotException
{
File dump = dumps.get(0);
File result;
String encoding = System.getProperty("file.encoding", "UTF-8"); //$NON-NLS-1$//$NON-NLS-2$
String encodingOpt = "-J-Dfile.encoding="+encoding; //$NON-NLS-1$
result = mergeFileNames(preferredDump, dump);
if (compress && !result.getName().endsWith(".zip")) //$NON-NLS-1$
{
result = new File(result.getPath()+".zip"); //$NON-NLS-1$;
}
int work = 1000;
listener.beginTask(MessageFormat.format(Messages.getString("IBMSystemDumpProvider.FormattingDump"), //$NON-NLS-1$
dump, result), work);
final boolean zip = result.getName().endsWith(".zip"); //$NON-NLS-1$
// Only need to run jextract to zip a dump - DTFJ can now read dumps directly
if (zip)
{
String dumpname = dump.getName();
if (dumpname.endsWith(".zip")) //$NON-NLS-1$
{
// JExtract might get confused by a dump ending in zip
File newname = new File(dump.getParentFile(), dumpname.substring(0, dumpname.length() - 4));
if (dump.renameTo(newname))
dump = newname;
}
File dumpout = result.getCanonicalFile().equals(dump.getCanonicalFile()) ?
File.createTempFile(dump.getName(), null, dump.getParentFile())
: result;
long dumpLen = dump.length();
ProcessBuilder pb = new ProcessBuilder();
File jextract;
if (home != null)
{
File homebin = new File(home, "bin"); //$NON-NLS-1$
jextract = new File(homebin, "jextract"); //$NON-NLS-1$
}
else
{
jextract = new File("jextract"); //$NON-NLS-1$
}
pb.command(jextract.getAbsolutePath(), encodingOpt, dump.getAbsolutePath(), dumpout.getAbsolutePath());
pb.redirectErrorStream(true);
pb.directory(udir);
StringBuilder errorBuf = new StringBuilder();
int exitCode = 0;
Process p = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream(), encoding));
long outlen = 0;
// space for DLLs plus dump compression
long estimatedZipLen = 64*1024*1024 + dumpLen / 5;
long maxEstimatedZipLen = estimatedZipLen * 2;
// Fraction of estimate length to then switch to maxEstimatedLength
int f1 = 3;
int f2 = 4;
try
{
for (;;)
{
while (br.ready())
{
int t = br.read();
if (t < 0)
break;
errorBuf.append((char) t);
}
listener.subTask("\n" + errorBuf.toString()); //$NON-NLS-1$
long newlen = dumpout.length();
long step;
if (newlen < f1 * estimatedZipLen / f2)
{
step = estimatedZipLen / work;
}
else
{
// Slow progress down when the zip file keeps growing
// past 3/4 of expected length.
step = (maxEstimatedZipLen - f1*estimatedZipLen/f2) * f2 / (f2 - f1) / work;
}
if (newlen - outlen > step)
{
listener.worked((int) ((newlen - outlen) / step));
outlen += (newlen - outlen) / step * step;
}
if (listener.isCanceled())
{
p.destroy();
return null;
}
try
{
p.exitValue();
break;
}
catch (IllegalThreadStateException e)
{
Thread.sleep(SLEEP_TIMEOUT);
}
}
}
finally
{
br.close();
}
exitCode = p.waitFor();
if (exitCode != 0) { throw new SnapshotException(MessageFormat.format(Messages
.getString("IBMSystemDumpProvider.ReturnCode"), jextract.getAbsolutePath(), exitCode, errorBuf.toString())); //$NON-NLS-1$
}
if (!dumpout.canRead()) { throw new FileNotFoundException(MessageFormat.format(Messages
.getString("IBMSystemDumpProvider.ReturnCode"), result.getPath(), errorBuf.toString())); //$NON-NLS-1$
}
// Tidy up
// No need to keep the uncompressed dump
if (dump.delete())
{
if (!dumpout.getCanonicalFile().equals(result.getCanonicalFile()) && !dumpout.renameTo(result))
{
throw new IOException(result.getPath());
}
}
else
{
if (!dumpout.delete())
{
throw new IOException(dumpout.getPath());
}
// Return uncompressed
result = dump;
}
}
else
{
// Move dump
if (dump.renameTo(preferredDump))
{
// Success
dump = preferredDump;
}
else
{
// Failed, use original dump
}
result = dump;
}
listener.done();
return result;
}
}