changeset 613:4238b97fc746

Make DAOs stateless Maintaining state in DAOs feels unnatural. It also means DAOs can not be shared or published as OSGi instances. Every user of DAOs must get a unquie instance. Fix that by moving all relevant state (timestamps) out from the DAO into the code that uses the DAOs. DAOs still maintain some Pojo getters (as an optimization) but they are stateless too. Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-September/003221.html
author Omair Majid <omajid@redhat.com>
date Fri, 14 Sep 2012 19:24:10 -0400
parents 8a33215510dc
children 121a91084133 891cb7a0de3a
files client/core/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java client/core/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java client/core/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java client/core/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/HostMemoryControllerTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/VmCpuControllerTest.java client/core/src/test/java/com/redhat/thermostat/client/ui/VmGcControllerTest.java client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatController.java client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/VmClassStatControllerTest.java common/core/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java common/core/src/main/java/com/redhat/thermostat/common/dao/LatestPojoListGetter.java common/core/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/model/TimeStampedPojoComparator.java common/core/src/test/java/com/redhat/thermostat/common/dao/CpuStatDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/MemoryStatDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmClassStatDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmGcStatDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java tools/src/main/java/com/redhat/thermostat/tools/cli/VMStatPrinter.java tools/src/test/java/com/redhat/thermostat/tools/cli/VmStatCommandTest.java
diffstat 36 files changed, 170 insertions(+), 359 deletions(-) [+]
line wrap: on
line diff
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/HostCpuController.java	Fri Sep 14 19:24:10 2012 -0400
@@ -68,6 +68,7 @@
     private final HostRef ref;
 
     private int chartsAdded = 0;
+    private long lastSeenTimeStamp = Long.MIN_VALUE;
 
     public HostCpuController(HostRef ref) {
         this.ref = ref;
@@ -128,7 +129,7 @@
     }
 
     private void doCpuChartUpdate() {
-        List<CpuStat> cpuStats = cpuStatDAO.getLatestCpuStats(ref);
+        List<CpuStat> cpuStats = cpuStatDAO.getLatestCpuStats(ref, lastSeenTimeStamp);
         List<List<DiscreteTimeData<Double>>> results = new ArrayList<>();
         for (CpuStat stat : cpuStats) {
             List<Double> data = stat.getPerProcessorUsage();
@@ -137,6 +138,7 @@
                     results.add(new ArrayList<DiscreteTimeData<Double>>());
                 }
                 results.get(i).add(new DiscreteTimeData<Double>(stat.getTimeStamp(), data.get(i)));
+                lastSeenTimeStamp = Math.max(lastSeenTimeStamp, stat.getTimeStamp());
             }
         }
 
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/HostMemoryController.java	Fri Sep 14 19:24:10 2012 -0400
@@ -72,6 +72,8 @@
     private final Timer backgroundUpdateTimer;
     private final GraphVisibilityChangeListener listener = new ShowHideGraph();
 
+    private long lastSeenTimeStamp = Long.MIN_VALUE;
+
     public HostMemoryController(final HostRef ref) {
         this.ref = ref;
         DAOFactory daos = ApplicationContext.getInstance().getDAOFactory();
@@ -147,7 +149,7 @@
         List<DiscreteTimeData<? extends Number>> swapTotal = new LinkedList<>();
         List<DiscreteTimeData<? extends Number>> swapFree = new LinkedList<>();
 
-        for (MemoryStat stat : memoryStatDAO.getLatestMemoryStats(ref)) {
+        for (MemoryStat stat : memoryStatDAO.getLatestMemoryStats(ref, lastSeenTimeStamp)) {
             long timeStamp = stat.getTimeStamp();
             memFree.add(new DiscreteTimeData<Long>(timeStamp, stat.getFree()));
             memTotal.add(new DiscreteTimeData<Long>(timeStamp, stat.getTotal()));
@@ -155,6 +157,7 @@
             buf.add(new DiscreteTimeData<Long>(timeStamp, stat.getBuffers()));
             swapTotal.add(new DiscreteTimeData<Long>(timeStamp, stat.getSwapTotal()));
             swapFree.add(new DiscreteTimeData<Long>(timeStamp, stat.getSwapFree()));
+            lastSeenTimeStamp = Math.max(lastSeenTimeStamp, stat.getTimeStamp());
         }
 
         view.addMemoryData(MemoryType.MEMORY_FREE.name(), memFree);
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/VmCpuController.java	Fri Sep 14 19:24:10 2012 -0400
@@ -60,6 +60,8 @@
 
     private final Timer timer;
 
+    private long lastSeenTimeStamp = Long.MIN_VALUE;
+
     public VmCpuController(VmRef ref) {
         this.ref = ref;
         dao = ApplicationContext.getInstance().getDAOFactory().getVmCpuStatDAO();
@@ -100,12 +102,13 @@
     }
 
     private void doUpdateVmCpuCharts() {
-        List<VmCpuStat> stats = dao.getLatestVmCpuStats(ref);
+        List<VmCpuStat> stats = dao.getLatestVmCpuStats(ref, lastSeenTimeStamp);
         List<DiscreteTimeData<? extends Number>> toDisplay = new ArrayList<>(stats.size());
         for (VmCpuStat stat: stats) {
             DiscreteTimeData<? extends Number> data =
                     new DiscreteTimeData<Number>(stat.getTimeStamp(), stat.getCpuLoad());
             toDisplay.add(data);
+            lastSeenTimeStamp = Math.max(lastSeenTimeStamp, stat.getTimeStamp());
         }
 
         view.addData(toDisplay);
--- a/client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/client/core/src/main/java/com/redhat/thermostat/client/ui/VmGcController.java	Fri Sep 14 19:24:10 2012 -0400
@@ -40,7 +40,6 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -50,7 +49,6 @@
 import java.util.concurrent.TimeUnit;
 
 import com.redhat.thermostat.client.locale.LocaleResources;
-import com.redhat.thermostat.client.osgi.service.BasicView;
 import com.redhat.thermostat.client.osgi.service.BasicView.Action;
 import com.redhat.thermostat.common.ActionEvent;
 import com.redhat.thermostat.common.ActionListener;
@@ -63,6 +61,7 @@
 import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
 import com.redhat.thermostat.common.dao.VmRef;
 import com.redhat.thermostat.common.model.IntervalTimeData;
+import com.redhat.thermostat.common.model.TimeStampedPojoComparator;
 import com.redhat.thermostat.common.model.VmGcStat;
 import com.redhat.thermostat.common.model.VmMemoryStat;
 import com.redhat.thermostat.common.model.VmMemoryStat.Generation;
@@ -81,12 +80,7 @@
 
     private final Timer timer;
 
-    private final Comparator<VmGcStat> vmGcStatComparator = new Comparator<VmGcStat>() {
-        @Override
-        public int compare(VmGcStat o1, VmGcStat o2) {
-            return Long.compare(o1.getTimeStamp(), o2.getTimeStamp());
-        }
-    };
+    private long lastSeenTimeStamp = Long.MIN_VALUE;
 
     public VmGcController(VmRef ref) {
         this.ref = ref;
@@ -146,8 +140,8 @@
 
     private void doUpdateCollectorData() {
         Map<String, List<IntervalTimeData<Double>>> dataToAdd = new HashMap<>();
-        List<VmGcStat> sortedList = gcDao.getLatestVmGcStats(ref);
-        Collections.sort(sortedList, vmGcStatComparator);
+        List<VmGcStat> sortedList = gcDao.getLatestVmGcStats(ref, lastSeenTimeStamp);
+        Collections.sort(sortedList, new TimeStampedPojoComparator<>());
 
         for (VmGcStat stat : sortedList) {
             String collector = stat.getCollectorName();
@@ -161,6 +155,7 @@
                     System.out.println("new gc collector value is older than previous value");
                 }
                 VmGcStat last = lastValueSeen.get(collector);
+                lastSeenTimeStamp = Math.max(lastSeenTimeStamp, stat.getTimeStamp());
                 long diffInMicro = (stat.getWallTime() - last.getWallTime());
                 double diffInMillis = diffInMicro / 1000.0;
                 // TODO there is not much point in adding data when diff is 0,
@@ -171,7 +166,6 @@
                 // }
             }
             lastValueSeen.put(collector, stat);
-
         }
         for (Map.Entry<String, List<IntervalTimeData<Double>>> entry : dataToAdd.entrySet()) {
             String name = entry.getKey();
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/HostCpuControllerTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -38,6 +38,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isNotNull;
@@ -103,7 +104,7 @@
         CpuStat cpuStat1 = new CpuStat(1l, ArrayUtils.toDoubleList(new double[] {10.0, 20.0, 30.0}));
         CpuStat cpuStat2 = new CpuStat(2l, ArrayUtils.toDoubleList(new double[] {15.0, 25.0, 35.0}));
         CpuStatDAO cpuStatDAO = mock(CpuStatDAO.class);
-        when(cpuStatDAO.getLatestCpuStats(any(HostRef.class))).thenReturn(Arrays.asList(cpuStat1, cpuStat2));
+        when(cpuStatDAO.getLatestCpuStats(any(HostRef.class), anyLong())).thenReturn(Arrays.asList(cpuStat1, cpuStat2));
 
         DAOFactory daoFactory = mock(DAOFactory.class);
         when(daoFactory.getHostInfoDAO()).thenReturn(hostInfoDAO);
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/HostMemoryControllerTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/HostMemoryControllerTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -37,6 +37,7 @@
 package com.redhat.thermostat.client.ui;
 
 import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyLong;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
@@ -85,7 +86,7 @@
         List<MemoryStat> memoryStats = new LinkedList<>();
         memoryStats.add(memoryStat);
         MemoryStatDAO memoryStatDAO = mock(MemoryStatDAO.class);
-        when(memoryStatDAO.getLatestMemoryStats(any(HostRef.class))).thenReturn(memoryStats);
+        when(memoryStatDAO.getLatestMemoryStats(any(HostRef.class), anyLong())).thenReturn(memoryStats);
 
         DAOFactory daoFactory = mock(MongoDAOFactory.class);
         when(daoFactory.getHostInfoDAO()).thenReturn(hostInfoDAO);
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/VmCpuControllerTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/VmCpuControllerTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -80,7 +80,7 @@
         stats.add(stat1);
 
         VmCpuStatDAO vmCpuStatDAO = mock(VmCpuStatDAO.class);
-        when(vmCpuStatDAO.getLatestVmCpuStats(any(VmRef.class))).thenReturn(stats).thenReturn(new ArrayList<VmCpuStat>());
+        when(vmCpuStatDAO.getLatestVmCpuStats(any(VmRef.class), eq(Long.MIN_VALUE))).thenReturn(stats).thenReturn(new ArrayList<VmCpuStat>());
 
         DAOFactory daoFactory = mock(MongoDAOFactory.class);
         when(daoFactory.getVmCpuStatDAO()).thenReturn(vmCpuStatDAO);
--- a/client/core/src/test/java/com/redhat/thermostat/client/ui/VmGcControllerTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/client/core/src/test/java/com/redhat/thermostat/client/ui/VmGcControllerTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -106,7 +106,7 @@
 
         // Setup DAO
         VmGcStatDAO vmGcStatDAO = mock(VmGcStatDAO.class);
-        when(vmGcStatDAO.getLatestVmGcStats(isA(VmRef.class))).thenReturn(stats);
+        when(vmGcStatDAO.getLatestVmGcStats(isA(VmRef.class), eq(Long.MIN_VALUE))).thenReturn(stats);
         VmMemoryStatDAO vmMemoryStatDAO = mock(VmMemoryStatDAO.class);
         when(vmMemoryStatDAO.getLatestMemoryStat(isA(VmRef.class))).thenReturn(memoryStat);
 
--- a/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatController.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/client/vmclassstat/src/main/java/com/redhat/thermostat/client/vmclassstat/VmClassStatController.java	Fri Sep 14 19:24:10 2012 -0400
@@ -61,14 +61,16 @@
     private class UpdateChartData implements Runnable {
         @Override
         public void run() {
-            List<VmClassStat> latestClassStats = dao.getLatestClassStats(ref);
+            long timeStamp = lastSeenTimeStamp;
+            List<VmClassStat> latestClassStats = dao.getLatestClassStats(ref, timeStamp);
             List<DiscreteTimeData<Long>> timeData = new ArrayList<>();
             for (VmClassStat stat : latestClassStats) {
                 timeData.add(new DiscreteTimeData<Long>(stat.getTimeStamp(), stat.getLoadedClasses()));
+                timeStamp = Math.max(timeStamp, stat.getTimeStamp());
             }
             classesView.addClassCount(timeData);
+            lastSeenTimeStamp = timeStamp;
         }
-
     }
 
     private final VmClassStatView classesView;
@@ -76,6 +78,8 @@
     private final VmClassStatDAO dao;
     private final Timer timer;
 
+    private volatile long lastSeenTimeStamp = Long.MIN_VALUE;
+
     public VmClassStatController(VmRef ref, VmClassStatViewProvider viewProvider) {
         this.ref = ref;
         dao = ApplicationContext.getInstance().getDAOFactory().getVmClassStatsDAO();
--- a/client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/VmClassStatControllerTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/client/vmclassstat/src/test/java/com/redhat/thermostat/client/vmclassstat/VmClassStatControllerTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -37,7 +37,7 @@
 package com.redhat.thermostat.client.vmclassstat;
 
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
@@ -53,7 +53,6 @@
 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.dao.DAOFactory;
 import com.redhat.thermostat.common.dao.MongoDAOFactory;
@@ -72,7 +71,7 @@
         stats.add(stat1);
 
         VmClassStatDAO vmClassStatDAO = mock(VmClassStatDAO.class);
-        when(vmClassStatDAO.getLatestClassStats(any(VmRef.class))).thenReturn(stats).thenReturn(new ArrayList<VmClassStat>());
+        when(vmClassStatDAO.getLatestClassStats(any(VmRef.class), anyInt())).thenReturn(stats).thenReturn(new ArrayList<VmClassStat>());
 
         DAOFactory daoFactory = mock(MongoDAOFactory.class);
         when(daoFactory.getVmClassStatsDAO()).thenReturn(vmClassStatDAO);
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAO.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAO.java	Fri Sep 14 19:24:10 2012 -0400
@@ -49,7 +49,7 @@
     static final Category cpuStatCategory = new Category("cpu-stats",
             Key.AGENT_ID, Key.TIMESTAMP, cpuLoadKey);
 
-    List<CpuStat> getLatestCpuStats(HostRef ref);
+    List<CpuStat> getLatestCpuStats(HostRef ref, long since);
 
     void putCpuStat(CpuStat stat);
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/CpuStatDAOImpl.java	Fri Sep 14 19:24:10 2012 -0400
@@ -54,13 +54,13 @@
     }
 
     @Override
-    public List<CpuStat> getLatestCpuStats(HostRef ref) {
+    public List<CpuStat> getLatestCpuStats(HostRef ref, long lastTimeStamp) {
         HostLatestPojoListGetter<CpuStat> getter = getters.get(ref);
         if (getter == null) {
             getter = new HostLatestPojoListGetter<CpuStat>(storage, cpuStatCategory, ref, CpuStat.class);
             getters.put(ref, getter);
         }
-        return getter.getLatest();
+        return getter.getLatest(lastTimeStamp);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetter.java	Fri Sep 14 19:24:10 2012 -0400
@@ -37,9 +37,7 @@
 package com.redhat.thermostat.common.dao;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 import com.redhat.thermostat.common.model.TimeStampedPojo;
 import com.redhat.thermostat.common.storage.Category;
@@ -56,53 +54,36 @@
     private Category cat;
     private HostRef ref;
     private Class<T> resultClass;
-    private Map<HostRef, Long> lastUpdateTimes = new HashMap<>();
 
     HostLatestPojoListGetter(Storage storage, Category cat, HostRef ref, Class<T> resultClass) {
-        this(storage, cat, ref, resultClass, 0);
-    }
-
-    HostLatestPojoListGetter(Storage storage, Category cat, HostRef ref, Class<T> resultClass, long since) {
         this.storage = storage;
         this.cat = cat;
         this.ref = ref;
         this.resultClass = resultClass;
-        if (since > 0) {
-            lastUpdateTimes.put(ref, since);
-        }
     }
 
     @Override
-    public List<T> getLatest() {
-        Query query = buildQuery();
+    public List<T> getLatest(long since) {
+        Query query = buildQuery(since);
         return getLatest(query);
     }
 
     private List<T> getLatest(Query query) {
-        // TODO if multiple threads will be using this utility class, there may be some issues
-        // with the updateTimes
-        Long lastUpdate = lastUpdateTimes.get(ref);
         Cursor<T> cursor = storage.findAllPojos(query, resultClass);
         cursor = cursor.sort(Key.TIMESTAMP, SortDirection.DESCENDING);
         List<T> result = new ArrayList<>();
         while (cursor.hasNext()) {
             T pojo = cursor.next();
             result.add(pojo);
-            lastUpdateTimes.put(ref, Math.max(pojo.getTimeStamp(), lastUpdate));
         }
         return result;
     }
 
-    protected Query buildQuery() {
+    protected Query buildQuery(long since) {
         Query query = storage.createQuery()
                 .from(cat)
                 .where(Key.AGENT_ID, Criteria.EQUALS, ref.getAgentId());
-        Long lastUpdate = lastUpdateTimes.get(ref);
-        if (lastUpdate != null) {
-            query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, lastUpdate);
-        } else {
-            lastUpdateTimes.put(ref, Long.MIN_VALUE);
-        }
+        query.where(Key.TIMESTAMP, Criteria.GREATER_THAN, since);
         return query;
     }
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/LatestPojoListGetter.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/LatestPojoListGetter.java	Fri Sep 14 19:24:10 2012 -0400
@@ -41,5 +41,5 @@
 import com.redhat.thermostat.common.model.Pojo;
 
 interface LatestPojoListGetter<T extends Pojo> {
-    List<T> getLatest();
+    List<T> getLatest(long lastUpdateTimeStamp);
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAO.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAO.java	Fri Sep 14 19:24:10 2012 -0400
@@ -56,7 +56,7 @@
             Key.AGENT_ID, Key.TIMESTAMP, memoryTotalKey, memoryFreeKey, memoryBuffersKey,
             memoryCachedKey, memorySwapTotalKey, memorySwapFreeKey, memoryCommitLimitKey);
 
-    public List<MemoryStat> getLatestMemoryStats(HostRef ref);
+    public List<MemoryStat> getLatestMemoryStats(HostRef ref, long since);
 
     void putMemoryStat(MemoryStat stat);
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAOImpl.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/MemoryStatDAOImpl.java	Fri Sep 14 19:24:10 2012 -0400
@@ -54,13 +54,13 @@
     }
 
     @Override
-    public List<MemoryStat> getLatestMemoryStats(HostRef ref) {
+    public List<MemoryStat> getLatestMemoryStats(HostRef ref, long lastTimeStamp) {
         HostLatestPojoListGetter<MemoryStat> getter = getters.get(ref);
         if (getter == null) {
             getter = new HostLatestPojoListGetter<MemoryStat>(storage, memoryStatCategory, ref, MemoryStat.class);
             getters.put(ref, getter);
         }
-        return getter.getLatest();
+        return getter.getLatest(lastTimeStamp);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAO.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAO.java	Fri Sep 14 19:24:10 2012 -0400
@@ -49,7 +49,7 @@
     static final Category vmClassStatsCategory = new Category(
             "vm-class-stats", Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, loadedClassesKey);
 
-    public List<VmClassStat> getLatestClassStats(VmRef ref);
+    public List<VmClassStat> getLatestClassStats(VmRef ref, long since);
 
     public void putVmClassStat(VmClassStat stat);
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmClassStatDAOImpl.java	Fri Sep 14 19:24:10 2012 -0400
@@ -54,13 +54,13 @@
     }
 
     @Override
-    public List<VmClassStat> getLatestClassStats(VmRef ref) {
+    public List<VmClassStat> getLatestClassStats(VmRef ref, long lastUpdateTime) {
         VmLatestPojoListGetter<VmClassStat> getter = getters.get(ref);
         if (getter == null) {
             getter = new VmLatestPojoListGetter<VmClassStat>(storage, vmClassStatsCategory, ref, VmClassStat.class);
             getters.put(ref, getter);
         }
-        return getter.getLatest();
+        return getter.getLatest(lastUpdateTime);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAO.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAO.java	Fri Sep 14 19:24:10 2012 -0400
@@ -49,7 +49,7 @@
     static final Category vmCpuStatCategory = new Category("vm-cpu-stats",
             Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, vmCpuLoadKey);
 
-    public abstract List<VmCpuStat> getLatestVmCpuStats(VmRef ref);
+    public abstract List<VmCpuStat> getLatestVmCpuStats(VmRef ref, long since);
 
     public abstract void putVmCpuStat(VmCpuStat stat);
 
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmCpuStatDAOImpl.java	Fri Sep 14 19:24:10 2012 -0400
@@ -54,13 +54,13 @@
     }
 
     @Override
-    public List<VmCpuStat> getLatestVmCpuStats(VmRef ref) {
+    public List<VmCpuStat> getLatestVmCpuStats(VmRef ref, long since) {
         VmLatestPojoListGetter<VmCpuStat> getter = getters.get(ref);
         if (getter == null) {
             getter = new VmLatestPojoListGetter<VmCpuStat>(storage, vmCpuStatCategory, ref, VmCpuStat.class);
             getters.put(ref, getter);
         }
-        return getter.getLatest();
+        return getter.getLatest(since);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAO.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAO.java	Fri Sep 14 19:24:10 2012 -0400
@@ -53,7 +53,7 @@
             Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, collectorKey,
             runCountKey, wallTimeKey);
 
-    public List<VmGcStat> getLatestVmGcStats(VmRef ref);
+    public List<VmGcStat> getLatestVmGcStats(VmRef ref, long since);
 
     public void putVmGcStat(VmGcStat stat);
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAOImpl.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmGcStatDAOImpl.java	Fri Sep 14 19:24:10 2012 -0400
@@ -54,13 +54,13 @@
     }
 
     @Override
-    public List<VmGcStat> getLatestVmGcStats(VmRef ref) {
+    public List<VmGcStat> getLatestVmGcStats(VmRef ref, long since) {
         VmLatestPojoListGetter<VmGcStat> getter = getters.get(ref);
         if (getter == null) {
             getter = new VmLatestPojoListGetter<VmGcStat>(storage, vmGcStatCategory, ref, VmGcStat.class);
             getters.put(ref, getter);
         }
-        return getter.getLatest();
+        return getter.getLatest(since);
     }
 
     @Override
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAO.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmInfoDAO.java	Fri Sep 14 19:24:10 2012 -0400
@@ -74,5 +74,5 @@
 
     public void putVmInfo(VmInfo info);
 
-    public void putVmStoppedTime(int vmId, long timestamp);
+    public void putVmStoppedTime(int vmId, long since);
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetter.java	Fri Sep 14 19:24:10 2012 -0400
@@ -48,17 +48,13 @@
     private VmRef vmRef;
 
     VmLatestPojoListGetter(Storage storage, Category cat, VmRef ref, Class<T> resultClass) {
-        this(storage, cat, ref, resultClass, 0);
-    }
-
-    VmLatestPojoListGetter(Storage storage, Category cat, VmRef ref, Class<T> resultClass, long since) {
-        super(storage, cat, ref.getAgent(), resultClass, since);
+        super(storage, cat, ref.getAgent(), resultClass);
         vmRef = ref;
     }
 
     @Override
-    protected Query buildQuery() {
-        Query query = super.buildQuery();
+    protected Query buildQuery(long since) {
+        Query query = super.buildQuery(since);
         query.where(Key.VM_ID, Criteria.EQUALS, vmRef.getId());
         return query;
     }
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAO.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAO.java	Fri Sep 14 19:24:10 2012 -0400
@@ -94,7 +94,6 @@
 
     public VmMemoryStat getLatestMemoryStat(VmRef ref);
 
-    public List<VmMemoryStat> getLatestVmMemoryStats(VmRef vm);
     public List<VmMemoryStat> getLatestVmMemoryStats(VmRef vm, long since);
 
     public void putVmMemoryStat(VmMemoryStat stat);
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOImpl.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/VmMemoryStatDAOImpl.java	Fri Sep 14 19:24:10 2012 -0400
@@ -76,22 +76,13 @@
     }
 
     @Override
-    public List<VmMemoryStat> getLatestVmMemoryStats(VmRef ref) {
+    public List<VmMemoryStat> getLatestVmMemoryStats(VmRef ref, long since) {
         VmLatestPojoListGetter<VmMemoryStat> getter = getters.get(ref);
         if (getter == null) {
             getter = new VmLatestPojoListGetter<VmMemoryStat>(storage, vmMemoryStatsCategory, ref, VmMemoryStat.class);
             getters.put(ref, getter);
         }
-        return getter.getLatest();
+        return getter.getLatest(since);
     }
 
-    @Override
-    public List<VmMemoryStat> getLatestVmMemoryStats(VmRef ref, long since) {
-        VmLatestPojoListGetter<VmMemoryStat> getter = getters.get(ref);
-        if (getter == null) {
-            getter = new VmLatestPojoListGetter<VmMemoryStat>(storage, vmMemoryStatsCategory, ref, VmMemoryStat.class, since);
-            getters.put(ref, getter);
-        }
-        return getter.getLatest();
-    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/TimeStampedPojoComparator.java	Fri Sep 14 19:24:10 2012 -0400
@@ -0,0 +1,45 @@
+/*
+ * 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.common.model;
+
+import java.util.Comparator;
+
+public final class TimeStampedPojoComparator<T extends TimeStampedPojo> implements Comparator<T> {
+    public int compare(T o1, T o2) {
+        return Long.compare(o1.getTimeStamp(), o2.getTimeStamp());
+    }
+}
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/CpuStatDAOTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/CpuStatDAOTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -59,6 +59,7 @@
 import com.redhat.thermostat.common.storage.Cursor.SortDirection;
 import com.redhat.thermostat.common.storage.Key;
 import com.redhat.thermostat.common.storage.Query;
+import com.redhat.thermostat.common.storage.Query.Criteria;
 import com.redhat.thermostat.common.storage.Storage;
 import com.redhat.thermostat.common.utils.ArrayUtils;
 import com.redhat.thermostat.test.MockQuery;
@@ -98,9 +99,9 @@
         when(storage.findAllPojos(query, CpuStat.class)).thenReturn(cursor);
         when(hostRef.getAgentId()).thenReturn("system");
 
-        List<CpuStat> cpuStats = dao.getLatestCpuStats(hostRef);
+        List<CpuStat> cpuStats = dao.getLatestCpuStats(hostRef, Long.MIN_VALUE);
 
-        assertFalse(query.hasWhereClauseFor(Key.TIMESTAMP));
+        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
 
         assertEquals(1, cpuStats.size());
         CpuStat stat = cpuStats.get(0);
@@ -130,8 +131,8 @@
         when(storage.findAllPojos(any(Query.class), same(CpuStat.class))).thenReturn(cursor);
         when(hostRef.getAgentId()).thenReturn("system");
 
-        dao.getLatestCpuStats(hostRef);
-        dao.getLatestCpuStats(hostRef);
+        dao.getLatestCpuStats(hostRef, Long.MIN_VALUE);
+        dao.getLatestCpuStats(hostRef, Long.MIN_VALUE);
 
         verify(storage, times(2)).findAllPojos(query, CpuStat.class);
 
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HostLatestPojoListGetterTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -108,23 +108,7 @@
         when (storage.createQuery()).thenReturn(query);
 
         HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, ref, CpuStat.class);
-        query = (MockQuery) getter.buildQuery();
-
-        assertNotNull(query);
-        assertEquals(cat, query.getCategory());
-        assertEquals(1, query.getWhereClausesCount());
-        assertFalse(query.hasWhereClauseFor(Key.TIMESTAMP));
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
-    }
-
-    @Test
-    public void testBuildQueryWithSince() {
-        Storage storage = mock(Storage.class);
-        MockQuery query = new MockQuery();
-        when (storage.createQuery()).thenReturn(query);
-
-        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, ref, CpuStat.class, 123);
-        query = (MockQuery) getter.buildQuery();
+        query = (MockQuery) getter.buildQuery(123);
 
         assertNotNull(query);
         assertEquals(cat, query.getCategory());
@@ -141,9 +125,9 @@
         when(storage.createQuery()).thenReturn(ignored).thenReturn(query);
 
         HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, ref, CpuStat.class);
-        ignored = (MockQuery) getter.buildQuery(); // Ignore first return value.
+        ignored = (MockQuery) getter.buildQuery(Long.MIN_VALUE); // Ignore first return value.
 
-        query = (MockQuery) getter.buildQuery();
+        query = (MockQuery) getter.buildQuery(Long.MIN_VALUE);
 
         assertNotNull(query);
         assertEquals(cat, query.getCategory());
@@ -161,13 +145,16 @@
         when(cursor.sort(any(Key.class), any(SortDirection.class))).thenReturn(cursor);
 
         Storage storage = mock(Storage.class);
-        Query query = new MockQuery();
+        MockQuery query = new MockQuery();
         when(storage.createQuery()).thenReturn(query);
         when(storage.findAllPojos(query, CpuStat.class)).thenReturn(cursor);
 
         HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, ref, CpuStat.class);
 
-        List<CpuStat> stats = getter.getLatest();
+        List<CpuStat> stats = getter.getLatest(Long.MIN_VALUE);
+
+        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
+        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
 
         assertNotNull(stats);
         assertEquals(2, stats.size());
@@ -179,37 +166,6 @@
         assertArrayEquals(new double[] {load5_2, load10_2, load15_2}, ArrayUtils.toPrimitiveDoubleArray(stat2.getPerProcessorUsage()), 0.001);
     }
 
-    @Test
-    public void testGetLatestMultipleCalls() {
-        @SuppressWarnings("unchecked")
-        Cursor<CpuStat> cursor1 = mock(Cursor.class);
-        when(cursor1.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(cursor1.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
-        when(cursor1.sort(any(Key.class), any(SortDirection.class))).thenReturn(cursor1);
-
-        @SuppressWarnings("unchecked")
-        Cursor<CpuStat> cursor2 = mock(Cursor.class);
-        when(cursor2.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor2.next()).thenReturn(result3);
-        when(cursor2.sort(any(Key.class), any(SortDirection.class))).thenReturn(cursor2);
-
-        Storage storage = mock(Storage.class);
-        MockQuery firstQuery = new MockQuery();
-        MockQuery secondQuery = new MockQuery();
-        when(storage.createQuery()).thenReturn(firstQuery).thenReturn(secondQuery);
-
-        when(storage.findAllPojos(any(Query.class), same(CpuStat.class))).thenReturn(cursor1);
-
-        HostLatestPojoListGetter<CpuStat> getter = new HostLatestPojoListGetter<>(storage, cat, ref, CpuStat.class);
-        getter.getLatest();
-        getter.getLatest();
-
-        verify(storage, times(2)).findAllPojos(any(Query.class), same(CpuStat.class));
-
-        assertTrue(secondQuery.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
-        assertTrue(secondQuery.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, t2));
-    }
-
     @After
     public void tearDown() {
         ref = null;
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/MemoryStatDAOTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/MemoryStatDAOTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -37,12 +37,10 @@
 package com.redhat.thermostat.common.dao;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -66,7 +64,6 @@
 
 public class MemoryStatDAOTest {
 
-
     private static long TIMESTAMP = 1;
     private static long TOTAL = 2;
     private static long FREE = 3;
@@ -90,7 +87,6 @@
         assertTrue(keys.contains(new Key<Long>("swapFree", false)));
         assertTrue(keys.contains(new Key<Long>("commitLimit", false)));
         assertEquals(9, keys.size());
-
     }
 
     @Test
@@ -117,11 +113,11 @@
         when(hostRef.getAgentId()).thenReturn("system");
 
         MemoryStatDAO dao = new MemoryStatDAOImpl(storage);
-        List<MemoryStat> memoryStats = dao.getLatestMemoryStats(hostRef);
+        List<MemoryStat> memoryStats = dao.getLatestMemoryStats(hostRef, Long.MIN_VALUE);
 
         ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
         verify(storage).findAllPojos(arg.capture(), same(MemoryStat.class));
-        assertFalse(arg.getValue().hasWhereClauseFor(Key.TIMESTAMP));
+        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
 
         assertEquals(1, memoryStats.size());
         MemoryStat stat = memoryStats.get(0);
@@ -137,38 +133,6 @@
     }
 
     @Test
-    public void testGetLatestMemoryStatsTwice() {
-
-        MemoryStat memStat = new MemoryStat(TIMESTAMP, TOTAL, FREE, BUFFERS, CACHED, SWAP_TOTAL, SWAP_FREE, COMMIT_LIMIT);
-
-        @SuppressWarnings("unchecked")
-        Cursor<MemoryStat> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(memStat);
-        when(cursor.sort(any(Key.class), any(SortDirection.class))).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(MemoryStat.class))).thenReturn(cursor);
-
-        HostRef hostRef = mock(HostRef.class);
-        when(hostRef.getAgentId()).thenReturn("system");
-
-        MemoryStatDAO dao = new MemoryStatDAOImpl(storage);
-        dao.getLatestMemoryStats(hostRef);
-        dao.getLatestMemoryStats(hostRef);
-
-        ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
-        verify(storage, times(2)).findAllPojos(arg.capture(), same(MemoryStat.class));
-        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, 1l));
-    }
-
-    @Test
     public void testPutMemoryStat() {
         Storage storage = mock(Storage.class);
         MemoryStat stat = new MemoryStat(TIMESTAMP, TOTAL, FREE, BUFFERS, CACHED, SWAP_TOTAL, SWAP_FREE, COMMIT_LIMIT);
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmClassStatDAOTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmClassStatDAOTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -37,12 +37,10 @@
 package com.redhat.thermostat.common.dao;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -78,7 +76,6 @@
         assertTrue(keys.contains(new Key<Long>("timeStamp", false)));
         assertTrue(keys.contains(new Key<Long>("loadedClasses", false)));
         assertEquals(4, keys.size());
-
     }
 
     @Test
@@ -108,13 +105,12 @@
         when(vmRef.getAgent()).thenReturn(hostRef);
         when(vmRef.getId()).thenReturn(321);
 
-
         VmClassStatDAO dao = new VmClassStatDAOImpl(storage);
-        List<VmClassStat> vmClassStats = dao.getLatestClassStats(vmRef);
+        List<VmClassStat> vmClassStats = dao.getLatestClassStats(vmRef, Long.MIN_VALUE);
 
         ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
         verify(storage).findAllPojos(arg.capture(), same(VmClassStat.class));
-        assertFalse(arg.getValue().hasWhereClauseFor(Key.TIMESTAMP));
+        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
 
         assertEquals(1, vmClassStats.size());
         VmClassStat stat = vmClassStats.get(0);
@@ -123,44 +119,6 @@
         assertEquals(VM_ID, (Integer) stat.getVmId());
     }
 
-    @Test
-    public void testGetLatestClassStatsTwice() {
-
-        VmClassStat vmClassStat = getClassStat();
-
-        @SuppressWarnings("unchecked")
-        Cursor<VmClassStat> cursor = mock(Cursor.class);
-
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(vmClassStat);
-        when(cursor.sort(any(Key.class), any(SortDirection.class))).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(VmClassStat.class))).thenReturn(cursor);
-
-        HostRef hostRef = mock(HostRef.class);
-        when(hostRef.getAgentId()).thenReturn("system");
-
-        VmRef vmRef = mock(VmRef.class);
-        when(vmRef.getAgent()).thenReturn(hostRef);
-        when(vmRef.getId()).thenReturn(321);
-
-
-        VmClassStatDAO dao = new VmClassStatDAOImpl(storage);
-        dao.getLatestClassStats(vmRef);
-
-        dao.getLatestClassStats(vmRef);
-        ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
-        verify(storage, times(2)).findAllPojos(arg.capture(), same(VmClassStat.class));
-        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, 1234l));
-    }
-
     private VmClassStat getClassStat() {
         return new VmClassStat(VM_ID, TIMESTAMP, LOADED_CLASSES);
     }
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatDAOTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmCpuStatDAOTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -37,13 +37,10 @@
 package com.redhat.thermostat.common.dao;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -116,11 +113,11 @@
 
 
         VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage);
-        List<VmCpuStat> vmCpuStats = dao.getLatestVmCpuStats(vmRef);
+        List<VmCpuStat> vmCpuStats = dao.getLatestVmCpuStats(vmRef, Long.MIN_VALUE);
 
         ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
         verify(storage).findAllPojos(arg.capture(), same(VmCpuStat.class));
-        assertFalse(arg.getValue().hasWhereClauseFor(Key.TIMESTAMP));
+        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
 
         assertEquals(1, vmCpuStats.size());
         VmCpuStat stat = vmCpuStats.get(0);
@@ -130,41 +127,6 @@
     }
 
     @Test
-    public void testGetLatestCpuStatsTwice() {
-
-        @SuppressWarnings("unchecked")
-        Cursor<VmCpuStat> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(cpuStat);
-        when(cursor.sort(any(Key.class), any(SortDirection.class))).thenReturn(cursor);
-        when(cursor.limit(anyInt())).thenReturn(cursor);
-
-        Storage storage = mock(Storage.class);
-        when(storage.createQuery()).then(new Answer<Query>() {
-            @Override
-            public Query answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(VmCpuStat.class))).thenReturn(cursor);
-
-        HostRef hostRef = mock(HostRef.class);
-        when(hostRef.getAgentId()).thenReturn("system");
-
-        VmRef vmRef = mock(VmRef.class);
-        when(vmRef.getAgent()).thenReturn(hostRef);
-        when(vmRef.getId()).thenReturn(321);
-
-        VmCpuStatDAO dao = new VmCpuStatDAOImpl(storage);
-        dao.getLatestVmCpuStats(vmRef);
-
-        dao.getLatestVmCpuStats(vmRef);
-        ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
-        verify(storage, times(2)).findAllPojos(arg.capture(), same(VmCpuStat.class));
-        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, 1234l));
-    }
-
-    @Test
     public void testPutVmCpuStat() {
         Storage storage = mock(Storage.class);
         VmCpuStat stat = new VmCpuStat(TIMESTAMP, VM_ID, CPU_LOAD);
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmGcStatDAOTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmGcStatDAOTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -108,11 +108,11 @@
 
 
         VmGcStatDAO dao = new VmGcStatDAOImpl(storage);
-        List<VmGcStat> vmGcStats = dao.getLatestVmGcStats(vmRef);
+        List<VmGcStat> vmGcStats = dao.getLatestVmGcStats(vmRef, Long.MIN_VALUE);
 
         ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
         verify(storage).findAllPojos(arg.capture(), same(VmGcStat.class));
-        assertFalse(arg.getValue().hasWhereClauseFor(Key.TIMESTAMP));
+        assertTrue(arg.getValue().hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, Long.MIN_VALUE));
 
         assertEquals(1, vmGcStats.size());
         VmGcStat stat = vmGcStats.get(0);
@@ -124,43 +124,6 @@
     }
 
     @Test
-    public void testGetLatestVmGcStatsTwice() {
-
-        VmGcStat vmGcStat = new VmGcStat(VM_ID, TIMESTAMP, COLLECTOR, RUN_COUNT, WALL_TIME);
-
-        @SuppressWarnings("unchecked")
-        Cursor<VmGcStat> cursor = mock(Cursor.class);
-        when(cursor.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor.next()).thenReturn(vmGcStat);
-        when(cursor.sort(any(Key.class), any(SortDirection.class))).thenReturn(cursor);
-        Storage storage = mock(Storage.class);
-
-        when(storage.createQuery()).then(new Answer<MockQuery>() {
-            @Override
-            public MockQuery answer(InvocationOnMock invocation) throws Throwable {
-                return new MockQuery();
-            }
-        });
-        when(storage.findAllPojos(any(Query.class), same(VmGcStat.class))).thenReturn(cursor);
-
-        HostRef hostRef = mock(HostRef.class);
-        when(hostRef.getAgentId()).thenReturn("system");
-
-        VmRef vmRef = mock(VmRef.class);
-        when(vmRef.getAgent()).thenReturn(hostRef);
-        when(vmRef.getId()).thenReturn(321);
-
-        VmGcStatDAO dao = new VmGcStatDAOImpl(storage);
-        dao.getLatestVmGcStats(vmRef);
-
-        dao.getLatestVmGcStats(vmRef);
-        ArgumentCaptor<MockQuery> arg = ArgumentCaptor.forClass(MockQuery.class);
-        verify(storage, times(2)).findAllPojos(arg.capture(), same(VmGcStat.class));
-        MockQuery query = arg.getValue();
-        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, 456l));
-    }
-
-    @Test
     public void testPutVmGcStat() {
         Storage storage = mock(Storage.class);
         VmGcStat stat = new VmGcStat(VM_ID, TIMESTAMP, COLLECTOR, RUN_COUNT, WALL_TIME);
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/VmLatestPojoListGetterTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -99,23 +99,7 @@
         when(storage.createQuery()).thenReturn(query);
 
         VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, vmRef, VmClassStat.class);
-        query = (MockQuery) getter.buildQuery();
-
-        assertNotNull(query);
-        assertEquals(cat, query.getCategory());
-        assertEquals(2, query.getWhereClausesCount());
-        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
-        assertTrue(query.hasWhereClause(Key.VM_ID, Criteria.EQUALS, VM_PID));
-    }
-
-    @Test
-    public void testBuildQueryWithSince() {
-        Storage storage = mock(Storage.class);
-        MockQuery query = new MockQuery();
-        when(storage.createQuery()).thenReturn(query);
-
-        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, vmRef, VmClassStat.class, 123);
-        query = (MockQuery) getter.buildQuery();
+        query = (MockQuery) getter.buildQuery(123l);
 
         assertNotNull(query);
         assertEquals(cat, query.getCategory());
@@ -133,8 +117,8 @@
         when(storage.createQuery()).thenReturn(ignored).thenReturn(query);
 
         VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, vmRef, VmClassStat.class);
-        getter.buildQuery(); // Ignore first return value.
-        query = (MockQuery) getter.buildQuery();
+        getter.buildQuery(Long.MIN_VALUE); // Ignore first return value.
+        query = (MockQuery) getter.buildQuery(Long.MIN_VALUE);
 
         assertNotNull(query);
         assertEquals(cat, query.getCategory());
@@ -153,12 +137,19 @@
         when(cursor.sort(any(Key.class), any(SortDirection.class))).thenReturn(cursor);
 
         Storage storage = mock(Storage.class);
-        when(storage.createQuery()).thenReturn(new MockQuery());
+        MockQuery query = new MockQuery();
+        when(storage.createQuery()).thenReturn(query);
         when(storage.findAllPojos(any(Query.class), same(VmClassStat.class))).thenReturn(cursor);
 
         VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, vmRef, VmClassStat.class);
 
-        List<VmClassStat> stats = getter.getLatest();
+        List<VmClassStat> stats = getter.getLatest(t2);
+
+        verify(storage).findAllPojos(any(Query.class), same(VmClassStat.class));
+
+        assertTrue(query.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
+        assertTrue(query.hasWhereClause(Key.VM_ID, Criteria.EQUALS, VM_PID));
+        assertTrue(query.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, t2));
 
         assertNotNull(stats);
         assertEquals(2, stats.size());
@@ -170,34 +161,4 @@
         assertEquals(lc2, stat2.getLoadedClasses());
     }
 
-    @Test
-    public void testGetLatestMultipleCalls() {
-        @SuppressWarnings("unchecked")
-        Cursor<VmClassStat> cursor1 = mock(Cursor.class);
-        when(cursor1.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false);
-        when(cursor1.next()).thenReturn(result1).thenReturn(result2).thenReturn(null);
-        when(cursor1.sort(any(Key.class), any(SortDirection.class))).thenReturn(cursor1);
-
-        @SuppressWarnings("unchecked")
-        Cursor<VmClassStat> cursor2 = mock(Cursor.class);
-        when(cursor2.hasNext()).thenReturn(true).thenReturn(false);
-        when(cursor2.next()).thenReturn(result3);
-
-        Storage storage = mock(Storage.class);
-        MockQuery firstQuery = new MockQuery();
-        MockQuery secondQuery = new MockQuery();
-        when(storage.createQuery()).thenReturn(firstQuery).thenReturn(secondQuery);
-
-        when(storage.findAllPojos(any(Query.class), same(VmClassStat.class))).thenReturn(cursor1);
-
-        VmLatestPojoListGetter<VmClassStat> getter = new VmLatestPojoListGetter<>(storage, cat, vmRef, VmClassStat.class);
-        getter.getLatest();
-        getter.getLatest();
-
-        verify(storage, times(2)).findAllPojos(any(Query.class), same(VmClassStat.class));
-
-        assertTrue(secondQuery.hasWhereClause(Key.AGENT_ID, Criteria.EQUALS, AGENT_ID));
-        assertTrue(secondQuery.hasWhereClause(Key.VM_ID, Criteria.EQUALS, VM_PID));
-        assertTrue(secondQuery.hasWhereClause(Key.TIMESTAMP, Criteria.GREATER_THAN, t2));
-    }
 }
--- a/tools/src/main/java/com/redhat/thermostat/tools/cli/VMStatPrinter.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/tools/src/main/java/com/redhat/thermostat/tools/cli/VMStatPrinter.java	Fri Sep 14 19:24:10 2012 -0400
@@ -40,14 +40,19 @@
 import java.text.DateFormat;
 import java.text.DecimalFormat;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
+import java.util.NoSuchElementException;
 
 import com.redhat.thermostat.common.cli.TableRenderer;
 import com.redhat.thermostat.common.dao.VmCpuStatDAO;
 import com.redhat.thermostat.common.dao.VmMemoryStatDAO;
 import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.TimeStampedPojo;
+import com.redhat.thermostat.common.model.TimeStampedPojoComparator;
 import com.redhat.thermostat.common.model.TimeStampedPojoCorrelator;
 import com.redhat.thermostat.common.model.VmCpuStat;
 import com.redhat.thermostat.common.model.VmMemoryStat;
@@ -60,7 +65,6 @@
     private static final String CPU_PERCENT = Translate.localize(LocaleResources.COLUMN_HEADER_CPU_PERCENT);
     private static final String TIME = Translate.localize(LocaleResources.COLUMN_HEADER_TIME);
 
-
     private VmRef vm;
     private VmCpuStatDAO vmCpuStatDAO;
     private VmMemoryStatDAO vmMemoryStatDAO;
@@ -69,6 +73,9 @@
     private TableRenderer table;
     private int numSpaces;
 
+    private long lastCpuStatTimeStamp = Long.MIN_VALUE;
+    private long lastMemoryStatTimeStamp = Long.MIN_VALUE;
+
     VMStatPrinter(VmRef vm, VmCpuStatDAO vmCpuStatDAO, VmMemoryStatDAO vmMemoryStatDAO, PrintStream out) {
         this.vm = vm;
         this.vmCpuStatDAO = vmCpuStatDAO;
@@ -77,19 +84,35 @@
     }
 
     void printStats() {
-        List<VmCpuStat> cpuStats = vmCpuStatDAO.getLatestVmCpuStats(vm);
-        List<VmMemoryStat> memStats = vmMemoryStatDAO.getLatestVmMemoryStats(vm);
+        List<VmCpuStat> cpuStats = vmCpuStatDAO.getLatestVmCpuStats(vm, lastCpuStatTimeStamp);
+        List<VmMemoryStat> memStats = vmMemoryStatDAO.getLatestVmMemoryStats(vm, lastMemoryStatTimeStamp);
+
+        lastCpuStatTimeStamp = getLatestTimeStamp(lastCpuStatTimeStamp, cpuStats);
+        lastMemoryStatTimeStamp = getLatestTimeStamp(lastMemoryStatTimeStamp, memStats);
+
         printStats(cpuStats, memStats);
     }
 
     void printUpdatedStats() {
         correlator.clear();
-        List<VmCpuStat> cpuStats = vmCpuStatDAO.getLatestVmCpuStats(vm);
-        List<VmMemoryStat> memStats = vmMemoryStatDAO.getLatestVmMemoryStats(vm);
+        List<VmCpuStat> cpuStats = vmCpuStatDAO.getLatestVmCpuStats(vm, lastCpuStatTimeStamp);
+        List<VmMemoryStat> memStats = vmMemoryStatDAO.getLatestVmMemoryStats(vm, lastMemoryStatTimeStamp);
+
+        lastCpuStatTimeStamp = getLatestTimeStamp(lastCpuStatTimeStamp, cpuStats);
+        lastMemoryStatTimeStamp = getLatestTimeStamp(lastMemoryStatTimeStamp, memStats);
+
         correlate(cpuStats, memStats);
         printUpdatedStatsImpl();
     }
 
+    private long getLatestTimeStamp(long currentTimeStamp, List<? extends TimeStampedPojo> list) {
+        try {
+            return Math.max(currentTimeStamp, Collections.max(list, new TimeStampedPojoComparator<>()).getTimeStamp());
+        } catch (NoSuchElementException listIsEmpty) {
+            return currentTimeStamp;
+        }
+    }
+
     private void printStats(List<VmCpuStat> cpuStats, List<VmMemoryStat> memStats) {
         correlate(cpuStats, memStats);
         numSpaces = getNumSpaces(memStats);
@@ -190,5 +213,4 @@
         table.render(out);
     }
 
-
 }
--- a/tools/src/test/java/com/redhat/thermostat/tools/cli/VmStatCommandTest.java	Fri Sep 14 10:40:29 2012 +0200
+++ b/tools/src/test/java/com/redhat/thermostat/tools/cli/VmStatCommandTest.java	Fri Sep 14 19:24:10 2012 -0400
@@ -146,7 +146,7 @@
         VmCpuStat cpustat2 = new VmCpuStat(3, vmId, 70);
         List<VmCpuStat> cpuStats = Arrays.asList(cpustat1, cpustat2);
         List<VmCpuStat> cpuStats2 = Collections.emptyList();
-        when(vmCpuStatDAO.getLatestVmCpuStats(vm)).thenReturn(cpuStats).thenReturn(cpuStats2);
+        when(vmCpuStatDAO.getLatestVmCpuStats(vm, Long.MIN_VALUE)).thenReturn(cpuStats).thenReturn(cpuStats2);
         DAOFactory daoFactory = mock(DAOFactory.class);
         when(daoFactory.getVmCpuStatDAO()).thenReturn(vmCpuStatDAO);
         ApplicationContext.getInstance().setDAOFactory(daoFactory);
@@ -208,7 +208,10 @@
         VmMemoryStat memStat4 = new VmMemoryStat(4, vmId, gens4);
 
         vmMemoryStatDAO = mock(VmMemoryStatDAO.class);
-        when(vmMemoryStatDAO.getLatestVmMemoryStats(vm)).thenReturn(Arrays.asList(memStat1, memStat2, memStat3)).thenReturn(Arrays.asList(memStat4));
+        when(vmMemoryStatDAO.getLatestVmMemoryStats(vm, Long.MIN_VALUE))
+            .thenReturn(Arrays.asList(memStat1, memStat2, memStat3));
+
+        when(vmMemoryStatDAO.getLatestVmMemoryStats(vm, memStat3.getTimeStamp())).thenReturn(Arrays.asList(memStat4));
 
         when(daoFactory.getVmMemoryStatDAO()).thenReturn(vmMemoryStatDAO);
     }
@@ -279,7 +282,9 @@
         assertEquals(1, timerFactory.getInitialDelay());
         assertEquals(TimeUnit.SECONDS, timerFactory.getTimeUnit());
         assertEquals(Timer.SchedulingType.FIXED_RATE, timerFactory.getSchedulingType());
-                timerFactory.getAction().run();
+
+        timerFactory.getAction().run();
+
         expected = "TIME        %CPU MEM.space1 MEM.space2 MEM.space3 MEM.space4\n" +
                    "12:00:00 AM      1 B        1 B        1 B        1 B\n" +
                    "12:00:00 AM 65.0 2 B        2 B        3 B        4 B\n" +