Mercurial > hg > release > thermostat-1.0
view vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/HeapDump.java @ 1412:a0592d702416
Update copyright year in release branch.
reviewed-by: neugens
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2014-June/009965.html
PR1821
author | Jon VanAlten <jon.vanalten@redhat.com> |
---|---|
date | Tue, 03 Jun 2014 11:55:56 -0600 |
parents | c70ab9ec00f5 |
children |
line wrap: on
line source
/* * Copyright 2012-2014 Red Hat, Inc. * * This file is part of Thermostat. * * Thermostat is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published * by the Free Software Foundation; either version 2, or (at your * option) any later version. * * Thermostat is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Thermostat; see the file COPYING. If not see * <http://www.gnu.org/licenses/>. * * Linking this code with other modules is making a combined work * based on this code. Thus, the terms and conditions of the GNU * General Public License cover the whole combination. * * As a special exception, the copyright holders of this code give * you permission to link this code with independent modules to * produce an executable, regardless of the license terms of these * independent modules, and to copy and distribute the resulting * executable under terms of your choice, provided that you also * meet, for each linked independent module, the terms and conditions * of the license of that module. An independent module is a module * which is not derived from or based on this code. If you modify * this code, you may extend this exception to your version of the * library, but you are not obligated to do so. If you do not wish * to do so, delete this exception statement from your version. */ package com.redhat.thermostat.vm.heap.analysis.common; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; import java.nio.file.attribute.PosixFilePermissions; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.Enumeration; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.lucene.analysis.SimpleAnalyzer; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.index.CorruptIndexException; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.Term; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.ScoreDoc; import org.apache.lucene.search.TopDocs; import org.apache.lucene.search.WildcardQuery; import org.apache.lucene.store.Directory; import org.apache.lucene.store.LockObtainFailedException; import org.apache.lucene.store.RAMDirectory; import org.apache.lucene.util.Version; import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.vm.heap.analysis.common.model.HeapInfo; import com.sun.tools.hat.internal.model.JavaHeapObject; import com.sun.tools.hat.internal.model.Snapshot; import com.sun.tools.hat.internal.parser.Reader; /** * NOTE: This class is thread-safe with respect to loading the heapdump and creating the index. */ public class HeapDump { private static final String INDEX_FIELD_OBJECT_ID = "objectId"; private static final String INDEX_FIELD_CLASSNAME = "classname"; private static final Logger log = LoggingUtils.getLogger(HeapDump.class); private final HeapInfo heapInfo; private final HeapDAO heapDAO; private Snapshot snapshot; private Directory luceneIndex; public HeapDump(HeapInfo heapInfo, HeapDAO heapDAO) { this.heapInfo = heapInfo; this.heapDAO = heapDAO; } public long getTimestamp() { return heapInfo.getTimeStamp(); } @Override public String toString() { return "[" + new Date(getTimestamp()) +"] "; } public ObjectHistogram getHistogram() throws IOException { return heapDAO.getHistogram(heapInfo); } public HeapInfo getInfo() { return heapInfo; } private synchronized Directory getLuceneIndex() { if (luceneIndex == null) { try { luceneIndex = createLuceneIndex(); } catch (IOException ex) { log.log(Level.SEVERE, "Unexpected IO Exception while creating heap dump index", ex); return null; } } return luceneIndex; } private Directory createLuceneIndex() throws IOException, CorruptIndexException, LockObtainFailedException { loadHeapDumpIfNecessary(); Enumeration<JavaHeapObject> thingos = snapshot.getThings(); Directory dir = new RAMDirectory(); IndexWriterConfig indexWriterConfig = new IndexWriterConfig(Version.LUCENE_36, new SimpleAnalyzer(Version.LUCENE_36)); IndexWriter writer = new IndexWriter(dir, indexWriterConfig); while (thingos.hasMoreElements()) { JavaHeapObject thingo = thingos.nextElement(); Document doc = new Document(); doc.add(new Field(INDEX_FIELD_CLASSNAME, thingo.getClazz().getName(), Field.Store.YES, Field.Index.NOT_ANALYZED)); doc.add(new Field(INDEX_FIELD_OBJECT_ID, thingo.getIdString(), Field.Store.YES, Field.Index.NOT_ANALYZED)); writer.addDocument(doc); } writer.close(); return dir; } public Snapshot getSnapshot() { loadHeapDumpIfNecessary(); return snapshot; } private synchronized void loadHeapDumpIfNecessary() { if (snapshot == null) { try { loadHeapDump(); } catch (IOException e) { log.log(Level.SEVERE, "Unexpected IO Exception while loading heap dump", e); } } } private void loadHeapDump() throws IOException { String filename = "heapdump-" + heapInfo.getHeapId(); File tmpDir = getOrCreateHeapDumpDir(); File tmpFile = new File(tmpDir, filename); if (! tmpFile.exists()) { try (InputStream in = heapDAO.getHeapDumpData(heapInfo);) { Files.copy(in, tmpFile.toPath()); } } snapshot = Reader.readFile(tmpFile.getAbsolutePath(), true, 0); snapshot.resolve(true); } private File getOrCreateHeapDumpDir() throws IOException { String dirname = "thermostat-" + System.getProperty("user.name"); File tmpFile = new File(System.getProperty("java.io.tmpdir"), dirname); if (! tmpFile.exists()) { Files.createDirectory(tmpFile.toPath(), PosixFilePermissions.asFileAttribute(PosixFilePermissions.fromString("rwx------"))); return tmpFile; } else { if (tmpFile.isDirectory()) { return tmpFile; } else { throw new FileAlreadyExistsException(tmpFile.getAbsolutePath()); } } } /** * Find objects with class names matching the given pattern * @param wildCardClassNamePattern a case-sensitive wildcard pattern to match class names against * @param limit the maximum number of results to return * @return a collection of object ids that can be used with {@link #findObject(String)} */ public Collection<String> searchObjects(String wildCardClassNamePattern, int limit) { Directory searchIndex = getLuceneIndex(); WildcardQuery query = new WildcardQuery(new Term(INDEX_FIELD_CLASSNAME, wildCardClassNamePattern)); Collection<String> results = new ArrayList<String>(); try { IndexReader indexReader = IndexReader.open(searchIndex); IndexSearcher searcher = new IndexSearcher(indexReader); TopDocs found = searcher.search(query, limit); for (ScoreDoc scoreDoc : found.scoreDocs) { Document doc = searcher.doc(scoreDoc.doc); String objectId = doc.get(INDEX_FIELD_OBJECT_ID); results.add(objectId); } searcher.close(); } catch (IOException e) { log.log(Level.SEVERE, "Unexpected IO Exception while searching heap dump index", e); } return results; } public JavaHeapObject findObject(String id) { loadHeapDumpIfNecessary(); return snapshot.findThing(id); } public boolean equals(Object o) { return o instanceof HeapDump && ((HeapDump) o).heapInfo.equals(heapInfo); } public int hashCode() { return heapInfo.hashCode(); } public String getType() { return "hprof"; } }