Mercurial > hg > release > thermostat-1.0
changeset 390:7a5ea4137f04
Some more heap fixes
review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-June/001894.html
reviewed-by: rkennke
line wrap: on
line diff
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDump.java Tue Jun 19 19:00:28 2012 +0200 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDump.java Tue Jun 19 19:11:24 2012 +0200 @@ -38,29 +38,26 @@ import java.util.Date; +import com.redhat.thermostat.common.model.HeapInfo; + public class HeapDump { - private String name; - private Date timestamp; + private HeapInfo info; - void setTimestamp(long currentTimeMillis) { - this.timestamp = new Date(currentTimeMillis); - } - - void setVMName(String name) { - this.name = name; + public String getName() { + return info.getVm().getName(); } - public String getName() { - return name; - } - - public Date getTimestamp() { - return timestamp; + public long getTimestamp() { + return info.getTimestamp(); } @Override public String toString() { - return "[" + getTimestamp() +"] "; + return "[" + new Date(getTimestamp()) +"] "; + } + + public void setHeapInfo(HeapInfo info) { + this.info = info; } }
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java Tue Jun 19 19:00:28 2012 +0200 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpController.java Tue Jun 19 19:11:24 2012 +0200 @@ -41,6 +41,7 @@ import java.text.DecimalFormat; import java.text.NumberFormat; +import java.util.Collection; import java.util.List; import java.util.concurrent.TimeUnit; @@ -54,12 +55,16 @@ import com.redhat.thermostat.common.BasicView.Action; import com.redhat.thermostat.common.Timer.SchedulingType; import com.redhat.thermostat.common.appctx.ApplicationContext; + +import com.redhat.thermostat.common.dao.HeapDAO; import com.redhat.thermostat.common.dao.VmMemoryStatDAO; import com.redhat.thermostat.common.dao.VmRef; + +import com.redhat.thermostat.common.model.HeapInfo; import com.redhat.thermostat.common.model.VmMemoryStat; import com.redhat.thermostat.common.model.VmMemoryStat.Generation; import com.redhat.thermostat.common.model.VmMemoryStat.Space; -import com.redhat.thermostat.common.utils.DisplayableValues; + import com.redhat.thermostat.common.utils.DisplayableValues.Scale; public class HeapDumpController implements VmInformationServiceController { @@ -67,6 +72,8 @@ private final VmMemoryStatDAO vmDao; private final VmRef ref; + private final HeapDAO heapDAO; + private HeapView<JComponent> view; private final Timer timer; @@ -76,6 +83,7 @@ this.ref = ref; this.vmDao = ApplicationContext.getInstance().getDAOFactory().getVmMemoryStatDAO(); + this.heapDAO = ApplicationContext.getInstance().getDAOFactory().getHeapDAO(); model = new OverviewChart("Heap Used vs. Current Capacity Difference", "Time", "Heap"); @@ -88,6 +96,16 @@ timer.setSchedulingType(SchedulingType.FIXED_RATE); view = ApplicationContext.getInstance().getViewFactory().getView(HeapView.class); + + HeapDump dump = null; + view.clearHeapDumpList(); + Collection<HeapInfo> infos = heapDAO.getAllHeapInfo(ref); + for (HeapInfo info : infos) { + dump = new HeapDump(); + dump.setHeapInfo(info); + view.addHeapDump(dump); + } + view.addActionListener(new ActionListener<Action>() { @Override public void actionPerformed(ActionEvent<Action> actionEvent) { @@ -96,7 +114,7 @@ timer.stop(); break; - case VISIBLE: + case VISIBLE: timer.start(); break; @@ -110,8 +128,17 @@ view.addDumperListener(new ActionListener<HeapView.HeadDumperAction>() { @Override public void actionPerformed(ActionEvent<HeadDumperAction> actionEvent) { - HeapDump dump = command.execute(ref); - view.addHeapDump(dump); + HeapDump dump = null; + switch (actionEvent.getActionId()) { + case DUMP_REQUESTED: + dump = command.execute(ref); + view.addHeapDump(dump); + break; + + case ANALYSE: + view.openDumpView(dump); + break; + } } }); }
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumperCommand.java Tue Jun 19 19:00:28 2012 +0200 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumperCommand.java Tue Jun 19 19:11:24 2012 +0200 @@ -37,18 +37,24 @@ package com.redhat.thermostat.client.heap; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.util.logging.Level; import java.util.logging.Logger; +import com.redhat.thermostat.common.appctx.ApplicationContext; +import com.redhat.thermostat.common.dao.HeapDAO; import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.common.model.HeapInfo; public class HeapDumperCommand { - private static final Logger log = Logger.getLogger(HeapDumpAction.class.getName()); + private static final Logger log = Logger.getLogger(HeapDumperCommand.class.getName()); public HeapDump execute(VmRef reference) { + try { File tempFile = Files.createTempFile("thermostat-", "-heapdump").toFile(); String tempFileName = tempFile.getAbsolutePath(); @@ -57,13 +63,15 @@ try { proc.waitFor(); log.info("Heap dump written to: " + tempFileName); + } catch (InterruptedException e) { Thread.currentThread().interrupt(); } + HeapInfo info = saveHeapDumpInfo(reference, tempFile); + HeapDump dump = new HeapDump(); - dump.setTimestamp(System.currentTimeMillis()); - dump.setVMName(reference.getName()); + dump.setHeapInfo(info); return dump; @@ -73,4 +81,15 @@ return null; } } + + private HeapInfo saveHeapDumpInfo(VmRef reference, File tempFile) throws FileNotFoundException { + + HeapDAO heapDAO = ApplicationContext.getInstance().getDAOFactory().getHeapDAO(); + HeapInfo heapInfo = new HeapInfo(reference, System.currentTimeMillis()); + heapInfo.setHeapDumpId(reference.getStringID() + "-" + reference.getAgent().getAgentId() + "-" + heapInfo.getTimestamp()); + + heapDAO.putHeapInfo(heapInfo, new FileInputStream(tempFile)); + + return heapInfo; + } }
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapView.java Tue Jun 19 19:00:28 2012 +0200 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapView.java Tue Jun 19 19:11:24 2012 +0200 @@ -40,12 +40,12 @@ import com.redhat.thermostat.common.ActionListener; import com.redhat.thermostat.common.ActionNotifier; import com.redhat.thermostat.common.BasicView; -import com.redhat.thermostat.common.BasicView.Action; public abstract class HeapView<E> extends BasicView { public enum HeadDumperAction { DUMP_REQUESTED, + ANALYSE, REQUEST_ABORTED } @@ -66,4 +66,7 @@ abstract public void updateOverview(OverviewChart model, String used, String capacity); abstract public void addHeapDump(HeapDump dump); + abstract public void clearHeapDumpList(); + + abstract public void openDumpView(HeapDump dump); }
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapPanel.java Tue Jun 19 19:00:28 2012 +0200 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapPanel.java Tue Jun 19 19:11:24 2012 +0200 @@ -67,6 +67,10 @@ setLayout(groupLayout); } + void divideView() { + splitPane.setDividerLocation(.5d); + } + void hideBottom() { splitPane.getBottomComponent().setMinimumSize(new Dimension(0, 0)); splitPane.setDividerLocation(1.0d);
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java Tue Jun 19 19:00:28 2012 +0200 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/HeapSwingView.java Tue Jun 19 19:11:24 2012 +0200 @@ -39,8 +39,13 @@ import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.BoxLayout; import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; @@ -50,12 +55,16 @@ import com.redhat.thermostat.client.ui.ComponentVisibleListener; public class HeapSwingView extends HeapView<JComponent> { + + private boolean heapDetailIsShowing; private StatsPanel stats; - private HeapPanel panel; + private HeapPanel heapDetailPanel; private HeaderPanel overview; + private JPanel visiblePane; + public HeapSwingView() { stats = new StatsPanel(); @@ -81,18 +90,32 @@ } }); - panel = new HeapPanel(); + stats.addDumpListListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + HeapDump dump = stats.getSelectedHeapDump(); + heapDumperNotifier.fireAction(HeadDumperAction.ANALYSE, dump); + } + } + }); + + visiblePane = new JPanel(); + visiblePane.setLayout(new BoxLayout(visiblePane, BoxLayout.X_AXIS)); + + heapDetailPanel = new HeapPanel(); overview = new HeaderPanel("Heap Usage Overview"); overview.setContent(stats); overview.addHierarchyListener(new ViewVisibleListener()); - panel.setTop(overview); + // at the beginning, only the overview is visible + visiblePane.add(overview); } @Override public JComponent getComponent() { - return overview; + return visiblePane; } private class ViewVisibleListener extends ComponentVisibleListener { @@ -133,4 +156,58 @@ } }); } + + @Override + public void clearHeapDumpList() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + stats.clearDumpList(); + } + }); + } + + @Override + public void openDumpView(final HeapDump dump) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (!heapDetailIsShowing) { + visiblePane.removeAll(); + + heapDetailIsShowing = true; + + heapDetailPanel.divideView(); + heapDetailPanel.setTop(overview); + + String[] columnNames = {"First Name", + "Last Name", + "Sport", + "# of Years", + "Vegetarian"}; + Object[][] data = { + {"Kathy", "Smith", + "Snowboarding", new Integer(5), new Boolean(false)}, + {"John", "Doe", + "Rowing", new Integer(3), new Boolean(true)}, + {"Sue", "Black", + "Knitting", new Integer(2), new Boolean(false)}, + {"Jane", "White", + "Speed reading", new Integer(20), new Boolean(true)}, + {"Joe", "Brown", + "Pool", new Integer(10), new Boolean(false)} + }; + JTable table = new JTable(data, columnNames); + JPanel bottom = new JPanel(); + bottom.setLayout(new BoxLayout(bottom, BoxLayout.X_AXIS)); + bottom.add(table); + heapDetailPanel.setBottom(bottom); + + visiblePane.add(heapDetailPanel); + + visiblePane.revalidate(); + } + } + }); + } }
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/StatsPanel.java Tue Jun 19 19:00:28 2012 +0200 +++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/swing/StatsPanel.java Tue Jun 19 19:11:24 2012 +0200 @@ -37,6 +37,7 @@ package com.redhat.thermostat.client.heap.swing; import java.awt.event.ActionListener; +import java.awt.event.MouseListener; import javax.swing.BoxLayout; import javax.swing.DefaultListModel; @@ -46,10 +47,12 @@ import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.LayoutStyle.ComponentPlacement; +import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import com.redhat.thermostat.client.heap.HeapDump; import javax.swing.JList; +import javax.swing.event.ListSelectionListener; public class StatsPanel extends JPanel { @@ -98,6 +101,7 @@ dumpList = new JList<>(); listModel = new DefaultListModel<>(); + dumpList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); dumpList.setModel(listModel); GroupLayout gl_rightPanel = new GroupLayout(rightPanel); @@ -161,6 +165,10 @@ heapDumpButton.addActionListener(listener); } + void addDumpListListener(MouseListener listener) { + dumpList.addMouseListener(listener); + } + public void disableHeapDumperControl() { heapDumpButton.setText("dumping..."); heapDumpButton.setEnabled(false); @@ -178,4 +186,15 @@ dumpList.setVisible(true); } } + + public void clearDumpList() { + listModel.clear(); + if (dumpList.isVisible()) { + dumpList.setVisible(false); + } + } + + public HeapDump getSelectedHeapDump() { + return dumpList.getSelectedValue(); + } }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/heapdumper/src/test/java/com/redhat/thermostat/client/heap/HeapDumpControllerTest.java Tue Jun 19 19:11:24 2012 +0200 @@ -0,0 +1,151 @@ +/* + * Copyright 2012 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.client.heap; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.JComponent; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.mockito.ArgumentCaptor; + +import com.redhat.thermostat.common.ActionEvent; +import com.redhat.thermostat.common.ActionListener; +import com.redhat.thermostat.common.Timer; +import com.redhat.thermostat.common.TimerFactory; +import com.redhat.thermostat.common.ViewFactory; +import com.redhat.thermostat.common.appctx.ApplicationContext; +import com.redhat.thermostat.common.appctx.ApplicationContextUtil; +import com.redhat.thermostat.common.dao.DAOFactory; +import com.redhat.thermostat.common.dao.HeapDAO; +import com.redhat.thermostat.common.dao.MongoDAOFactory; +import com.redhat.thermostat.common.dao.VmClassStatDAO; +import com.redhat.thermostat.common.dao.VmRef; +import com.redhat.thermostat.common.model.VmClassStat; + +public class HeapDumpControllerTest { + + private ActionListener<HeapView.Action> actionListener; + private ActionListener<HeapView.HeadDumperAction> heapDumperListener; + + private Timer timer; + + private HeapView<JComponent> view; + + private HeapDumpController controller; + + @Before + public void setUp() { + + VmClassStatDAO vmClassStatDAO = mock(VmClassStatDAO.class); + + DAOFactory daoFactory = mock(MongoDAOFactory.class); + when(daoFactory.getVmClassStatsDAO()).thenReturn(vmClassStatDAO); + + HeapDAO heapDao = mock(HeapDAO.class); + when(daoFactory.getHeapDAO()).thenReturn(heapDao); + + ApplicationContext.getInstance().setDAOFactory(daoFactory); + + setUpTimers(); + setUpView(); + + setUpListeners(); + } + + private void setUpTimers() { + timer = mock(Timer.class); + ArgumentCaptor<Runnable> timerActionCaptor = ArgumentCaptor.forClass(Runnable.class); + doNothing().when(timer).setAction(timerActionCaptor.capture()); + + TimerFactory timerFactory = mock(TimerFactory.class); + when(timerFactory.createTimer()).thenReturn(timer); + ApplicationContext.getInstance().setTimerFactory(timerFactory); + } + + private void setUpView() { + ViewFactory viewFactory = mock(ViewFactory.class); + + view = mock(HeapView.class); + when(viewFactory.getView(eq(HeapView.class))).thenReturn(view); + + ApplicationContext.getInstance().setViewFactory(viewFactory); + } + + private void setUpListeners() { + ArgumentCaptor<ActionListener> viewArgumentCaptor1 = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(view).addActionListener(viewArgumentCaptor1.capture()); + + ArgumentCaptor<ActionListener> viewArgumentCaptor2 = ArgumentCaptor.forClass(ActionListener.class); + doNothing().when(view).addDumperListener(viewArgumentCaptor2.capture()); + + VmRef ref = mock(VmRef.class); + controller = new HeapDumpController(ref); + + actionListener = viewArgumentCaptor1.getValue(); + heapDumperListener = viewArgumentCaptor2.getValue(); + } + + @Test + public void testTimerStartOnViewVisible() { + actionListener.actionPerformed(new ActionEvent<>(view, HeapView.Action.VISIBLE)); + verify(timer).start(); + } + + @Test + public void testTimerStopsOnViewHidden() { + actionListener.actionPerformed(new ActionEvent<>(view, HeapView.Action.HIDDEN)); + verify(timer).stop(); + } + + @After + public void tearDown() { + ApplicationContextUtil.resetApplicationContext(); + } +}
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmRef.java Tue Jun 19 19:00:28 2012 +0200 +++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmRef.java Tue Jun 19 19:11:24 2012 +0200 @@ -63,6 +63,9 @@ return uid; } + /** + * Equivalent to {@link #getStringID()}. + */ public String getIdString() { return uidString; }