changeset 919:31c6026714f5

Send all numa-node data in one NumaStat. Reviewed-by: omajid, jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-January/005217.html
author Roman Kennke <rkennke@redhat.com>
date Fri, 18 Jan 2013 18:42:04 +0100
parents 2d4685205bd5
children ce04776b8b81
files distribution/config/commands/webservice.properties numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaBackend.java numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaStatBuilder.java numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaBackendTest.java numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaCollectorTest.java numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaStatBuilderTest.java numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaNodeStat.java numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaStat.java numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaDAOTest.java numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaNodeStatTest.java numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaStatTest.java numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java storage/core/pom.xml web/server/pom.xml
diffstat 16 files changed, 356 insertions(+), 185 deletions(-) [+]
line wrap: on
line diff
--- a/distribution/config/commands/webservice.properties	Wed Jan 16 12:20:36 2013 +0100
+++ b/distribution/config/commands/webservice.properties	Fri Jan 18 18:42:04 2013 +0100
@@ -3,8 +3,9 @@
 bundles = thermostat-web-cmd-@project.version@.jar, \
           thermostat-web-server-@project.version@.jar, \
           thermostat-web-common-@project.version@.jar, \
+          thermostat-storage-mongodb-${project.version}.jar, \
           thermostat-thread-collector-@project.version@.jar, \
-          thermostat-storage-mongodb-${project.version}.jar, \
+          thermostat-numa-common-@project.version@.jar, \
           mongo.jar, \
           commons-beanutils.jar, \
           commons-codec.jar, \
--- a/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaBackend.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaBackend.java	Fri Jan 18 18:42:04 2013 +0100
@@ -50,6 +50,7 @@
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.numa.common.NumaDAO;
+import com.redhat.thermostat.numa.common.NumaNodeStat;
 import com.redhat.thermostat.numa.common.NumaStat;
 
 public class NumaBackend extends Backend {
@@ -88,12 +89,13 @@
 
             @Override
             public void run() {
-                NumaStat[] stats;
+                NumaNodeStat[] stats;
                 try {
                     stats = numaCollector.collectData();
-                    for (NumaStat stat : stats) {
-                        numaDAO.putNumaStat(stat);
-                    }
+                    NumaStat numaStat = new NumaStat();
+                    numaStat.setTimeStamp(System.currentTimeMillis());
+                    numaStat.setNodeStats(stats);
+                    numaDAO.putNumaStat(numaStat);
                 } catch (IOException e) {
                     log.log(Level.WARNING, e.getMessage(), e);
                 }
--- a/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaCollector.java	Fri Jan 18 18:42:04 2013 +0100
@@ -44,7 +44,7 @@
 import java.io.InputStreamReader;
 import java.io.Reader;
 
-import com.redhat.thermostat.numa.common.NumaStat;
+import com.redhat.thermostat.numa.common.NumaNodeStat;
 
 class NumaCollector {
 
@@ -75,8 +75,8 @@
         numberOfNodes = nodeFiles.length;
     }
 
-    NumaStat[] collectData() throws IOException {
-        NumaStat[] stat = new NumaStat[numberOfNodes];
+    NumaNodeStat[] collectData() throws IOException {
+        NumaNodeStat[] stat = new NumaNodeStat[numberOfNodes];
         for (int i = 0; i < numberOfNodes; i++) {
             File nodeDir = new File(baseDir, NODE_DIR_PREFIX + i);
             File numaStatFile = new File(nodeDir, NUMA_STAT_FILE);
@@ -84,7 +84,7 @@
                 Reader reader = new InputStreamReader(in);
                 NumaStatBuilder builder = new NumaStatBuilder(reader);
                 stat[i] = builder.build();
-                stat[i].setNode(i);
+                stat[i].setNodeId(i);
             }
         }
         return stat;
--- a/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaStatBuilder.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/agent/src/main/java/com/redhat/thermostat/numa/agent/internal/NumaStatBuilder.java	Fri Jan 18 18:42:04 2013 +0100
@@ -40,7 +40,7 @@
 import java.io.IOException;
 import java.io.Reader;
 
-import com.redhat.thermostat.numa.common.NumaStat;
+import com.redhat.thermostat.numa.common.NumaNodeStat;
 
 class NumaStatBuilder {
 
@@ -50,13 +50,13 @@
         this.in = in;
     }
 
-    NumaStat build() throws IOException {
-        NumaStat numaStat = new NumaStat();
+    NumaNodeStat build() throws IOException {
+        NumaNodeStat numaStat = new NumaNodeStat();
         readNumaData(numaStat);
         return numaStat;
     }
 
-    private void readNumaData(NumaStat numaStat) throws IOException {
+    private void readNumaData(NumaNodeStat numaStat) throws IOException {
         BufferedReader bufIn = new BufferedReader(in);
         String line = bufIn.readLine();
         while (line != null) {
--- a/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaBackendTest.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaBackendTest.java	Fri Jan 18 18:42:04 2013 +0100
@@ -38,6 +38,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.doNothing;
@@ -62,6 +63,7 @@
 import com.redhat.thermostat.common.TimerFactory;
 import com.redhat.thermostat.common.Version;
 import com.redhat.thermostat.numa.common.NumaDAO;
+import com.redhat.thermostat.numa.common.NumaNodeStat;
 import com.redhat.thermostat.numa.common.NumaStat;
 
 public class NumaBackendTest {
@@ -96,14 +98,17 @@
     }
 
     @Test
-    public void testActivate() throws IOException {
+    public void testActivate() throws IOException, InterruptedException {
+
         ArgumentCaptor<Runnable> actionCaptor = ArgumentCaptor.forClass(Runnable.class);
         doNothing().when(timer).setAction(actionCaptor.capture());
-        NumaStat stat1 = mock(NumaStat.class);
-        NumaStat stat2 = mock(NumaStat.class);
-        NumaStat[] stats = new NumaStat[] { stat1, stat2 };
+        NumaNodeStat stat1 = mock(NumaNodeStat.class);
+        NumaNodeStat stat2 = mock(NumaNodeStat.class);
+        NumaNodeStat[] stats = new NumaNodeStat[] { stat1, stat2 };
         when(collector.collectData()).thenReturn(stats);
-
+        ArgumentCaptor<NumaStat> statCaptor = ArgumentCaptor.forClass(NumaStat.class);
+        doNothing().when(numaDAO).putNumaStat(statCaptor.capture());
+        
         boolean activated = backend.activate();
         assertTrue(activated);
         assertTrue(backend.isActive());
@@ -121,14 +126,30 @@
 
         action.run();
         verify(collector).collectData();
-        verify(numaDAO).putNumaStat(stat1);
-        verify(numaDAO).putNumaStat(stat2);
+        verify(numaDAO).putNumaStat(any(NumaStat.class));
+        NumaStat stat = statCaptor.getValue();
+        assertSame(stat1, stat.getNodeStats()[0]);
+        assertSame(stat2, stat.getNodeStats()[1]);
+        long time1 = stat.getTimeStamp();
+        verifyNoMoreInteractions(numaDAO);
+        verifyNoMoreInteractions(collector);
+
+        Thread.sleep(10);
+
+        action.run();
+        verify(collector, times(2)).collectData();
+        verify(numaDAO, times(2)).putNumaStat(any(NumaStat.class));
+        stat = statCaptor.getValue();
+        assertSame(stat1, stat.getNodeStats()[0]);
+        assertSame(stat2, stat.getNodeStats()[1]);
+        long time2 = stat.getTimeStamp();
+        assertTrue(time2 > time1);
         verifyNoMoreInteractions(numaDAO);
         verifyNoMoreInteractions(collector);
 
         when(collector.collectData()).thenThrow(new IOException());
         action.run();
-        verify(collector, times(2)).collectData();
+        verify(collector, times(3)).collectData();
         verifyNoMoreInteractions(collector);
         verifyNoMoreInteractions(numaDAO);
 
--- a/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaCollectorTest.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaCollectorTest.java	Fri Jan 18 18:42:04 2013 +0100
@@ -52,7 +52,7 @@
 import org.junit.Before;
 import org.junit.Test;
 
-import com.redhat.thermostat.numa.common.NumaStat;
+import com.redhat.thermostat.numa.common.NumaNodeStat;
 
 public class NumaCollectorTest {
 
@@ -128,11 +128,11 @@
     @Test
     public void testStats() throws IOException {
         NumaCollector coll = new NumaCollector(tmpDir.getAbsolutePath());
-        NumaStat[] stats = coll.collectData();
+        NumaNodeStat[] stats = coll.collectData();
 
         assertEquals(3, stats.length);
 
-        assertEquals(0, stats[0].getNode());
+        assertEquals(0, stats[0].getNodeId());
         assertEquals(11, stats[0].getNumaHit());
         assertEquals(12, stats[0].getNumaMiss());
         assertEquals(13, stats[0].getNumaForeign());
@@ -140,7 +140,7 @@
         assertEquals(15, stats[0].getLocalNode());
         assertEquals(16, stats[0].getOtherNode());
 
-        assertEquals(1, stats[1].getNode());
+        assertEquals(1, stats[1].getNodeId());
         assertEquals(21, stats[1].getNumaHit());
         assertEquals(22, stats[1].getNumaMiss());
         assertEquals(23, stats[1].getNumaForeign());
@@ -148,7 +148,7 @@
         assertEquals(25, stats[1].getLocalNode());
         assertEquals(26, stats[1].getOtherNode());
 
-        assertEquals(2, stats[2].getNode());
+        assertEquals(2, stats[2].getNodeId());
         assertEquals(31, stats[2].getNumaHit());
         assertEquals(32, stats[2].getNumaMiss());
         assertEquals(33, stats[2].getNumaForeign());
--- a/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaStatBuilderTest.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/agent/src/test/java/com/redhat/thermostat/numa/agent/internal/NumaStatBuilderTest.java	Fri Jan 18 18:42:04 2013 +0100
@@ -44,7 +44,7 @@
 
 import org.junit.Test;
 
-import com.redhat.thermostat.numa.common.NumaStat;
+import com.redhat.thermostat.numa.common.NumaNodeStat;
 
 public class NumaStatBuilderTest {
 
@@ -59,7 +59,7 @@
     public void test() throws IOException {
         Reader in = new StringReader(TEST_STAT);
         NumaStatBuilder builder = new NumaStatBuilder(in);
-        NumaStat stat = builder.build();
+        NumaNodeStat stat = builder.build();
         assertEquals(32931L, stat.getNumaHit());
         assertEquals(819L, stat.getNumaMiss());
         assertEquals(918L, stat.getNumaForeign());
--- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaDAO.java	Fri Jan 18 18:42:04 2013 +0100
@@ -41,16 +41,9 @@
 
 public interface NumaDAO {
 
-    static final Key<Integer> nodeKey = new Key<>("node", true);
-    static final Key<Long> numaHitKey = new Key<>("numaHit", false);
-    static final Key<Long> numaMissKey = new Key<>("numaMiss", false);
-    static final Key<Long> numaForeignKey = new Key<>("numaForeign", false);
-    static final Key<Long> interleaveHitKey = new Key<>("interleaveHit", false);
-    static final Key<Long> localNodeKey = new Key<>("localNode", false);
-    static final Key<Long> otherNodeKey = new Key<>("otherNode", false);
+    static final Key<NumaNodeStat[]> nodeStats = new Key<>("nodeStats", false);
     
-    static final Category<NumaStat> numaStatCategory = new Category<>("numa-stat", NumaStat.class, Key.AGENT_ID, Key.TIMESTAMP,
-            nodeKey, numaHitKey, numaMissKey, numaForeignKey, interleaveHitKey, localNodeKey, otherNodeKey);
+    static final Category<NumaStat> numaStatCategory = new Category<>("numa-stat", NumaStat.class, Key.AGENT_ID, Key.TIMESTAMP, nodeStats);
 
     void putNumaStat(NumaStat stat);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaNodeStat.java	Fri Jan 18 18:42:04 2013 +0100
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2013 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.numa.common;
+
+import com.redhat.thermostat.storage.core.Entity;
+import com.redhat.thermostat.storage.core.Persist;
+import com.redhat.thermostat.storage.model.Pojo;
+
+/**
+ * Statistics about a NUMA node.
+ *
+ * The <code>nodeId</code> is an integer that identifies a node. The other properties
+ * correspond to properties of the same name from
+ *
+ * <code>/sys/devices/system/node/node${nodeId}/numastat</code>
+ *
+ * or <code>man 8 numastat</code>.
+ */
+@Entity
+public class NumaNodeStat implements Pojo {
+
+    private long numaHit = -1;
+    private long numaMiss = -1;
+    private long numaForeign = -1;
+    private long interleaveHit = -1;
+    private long localNode = -1;
+    private long otherNode = -1;
+    private int nodeId = -1;
+
+    @Persist
+    public long getNumaHit() {
+        return numaHit;
+    }
+
+    @Persist
+    public void setNumaHit(long numaHit) {
+        this.numaHit = numaHit;
+    }
+
+    @Persist
+    public long getNumaMiss() {
+        return numaMiss;
+    }
+
+    @Persist
+    public void setNumaMiss(long numaMiss) {
+        this.numaMiss = numaMiss;
+    }
+
+    @Persist
+    public long getNumaForeign() {
+        return numaForeign;
+    }
+
+    @Persist
+    public void setNumaForeign(long numaForeign) {
+        this.numaForeign = numaForeign;
+    }
+
+    @Persist
+    public long getInterleaveHit() {
+        return interleaveHit;
+    }
+
+    @Persist
+    public void setInterleaveHit(long interleaveHit) {
+        this.interleaveHit = interleaveHit;
+    }
+
+    @Persist
+    public long getLocalNode() {
+        return localNode;
+    }
+
+    @Persist
+    public void setLocalNode(long localNode) {
+        this.localNode = localNode;
+    }
+
+    @Persist
+    public long getOtherNode() {
+        return otherNode;
+    }
+
+    @Persist
+    public void setOtherNode(long otherNode) {
+        this.otherNode = otherNode;
+    }
+
+    @Persist
+    public int getNodeId() {
+        return nodeId;
+    }
+
+    @Persist
+    public void setNodeId(int nodeId) {
+        this.nodeId = nodeId;
+    }
+
+    public String toString() {
+        return "NumaStat: nodeId: " + nodeId + ", numaHit: " + numaHit + ", numaMiss: " + numaMiss + ", numaForeign: " + numaForeign + ", interleaveHit: " + interleaveHit + ", localNode: " + localNode + ", otherNode: " + otherNode;
+    }
+}
--- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaStat.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/NumaStat.java	Fri Jan 18 18:42:04 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Red Hat, Inc.
+ * Copyright 2012 Red Hat, Inc.
  *
  * This file is part of Thermostat.
  *
@@ -34,77 +34,37 @@
  * to do so, delete this exception statement from your version.
  */
 
+
 package com.redhat.thermostat.numa.common;
 
+import com.redhat.thermostat.storage.core.Entity;
+import com.redhat.thermostat.storage.core.Persist;
 import com.redhat.thermostat.storage.model.BasePojo;
 
+@Entity
 public class NumaStat extends BasePojo {
 
-    private long numaHit = -1;
-    private long numaMiss = -1;
-    private long numaForeign = -1;
-    private long interleaveHit = -1;
-    private long localNode = -1;
-    private long otherNode = -1;
-    private int node = -1;
-
-    public long getNumaHit() {
-        return numaHit;
-    }
+    private long timeStamp = -1;
+    private NumaNodeStat[] nodeStats = new NumaNodeStat[0];
 
-    public void setNumaHit(long numaHit) {
-        this.numaHit = numaHit;
-    }
-
-    public long getNumaMiss() {
-        return numaMiss;
-    }
-
-    public void setNumaMiss(long numaMiss) {
-        this.numaMiss = numaMiss;
-    }
-
-    public long getNumaForeign() {
-        return numaForeign;
+    @Persist
+    public long getTimeStamp() {
+        return timeStamp;
     }
 
-    public void setNumaForeign(long numaForeign) {
-        this.numaForeign = numaForeign;
-    }
-
-    public long getInterleaveHit() {
-        return interleaveHit;
-    }
-
-    public void setInterleaveHit(long interleaveHit) {
-        this.interleaveHit = interleaveHit;
-    }
-
-    public long getLocalNode() {
-        return localNode;
-    }
-
-    public void setLocalNode(long localNode) {
-        this.localNode = localNode;
+    @Persist
+    public void setTimeStamp(long timeStamp) {
+        this.timeStamp = timeStamp;
     }
 
-    public long getOtherNode() {
-        return otherNode;
-    }
-
-    public void setOtherNode(long otherNode) {
-        this.otherNode = otherNode;
+    @Persist
+    public NumaNodeStat[] getNodeStats() {
+        return nodeStats;
     }
 
-    public int getNode() {
-        return node;
+    @Persist
+    public void setNodeStats(NumaNodeStat[] nodeStats) {
+        this.nodeStats = nodeStats;
     }
 
-    public void setNode(int node) {
-        this.node = node;
-    }
-
-    public String toString() {
-        return "NumaStat: node: " + node + ", numaHit: " + numaHit + ", numaMiss: " + numaMiss + ", numaForeign: " + numaForeign + ", interleaveHit: " + interleaveHit + ", localNode: " + localNode + ", otherNode: " + otherNode;
-    }
 }
--- a/numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaDAOTest.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaDAOTest.java	Fri Jan 18 18:42:04 2013 +0100
@@ -52,27 +52,15 @@
         Category<?> cat = NumaDAO.numaStatCategory;
         assertEquals("numa-stat", cat.getName());
         assertEquals(NumaStat.class, cat.getDataClass());
-        assertEquals(9, cat.getKeys().size());
+        assertEquals(3, cat.getKeys().size());
 
         assertEquals("agentId", cat.getKey("agentId").getName());
         assertTrue(cat.getKey("agentId").isPartialCategoryKey());
         assertEquals("timeStamp", cat.getKey("timeStamp").getName());
         assertFalse(cat.getKey("timeStamp").isPartialCategoryKey());
 
-        assertEquals("node", cat.getKey("node").getName());
-        assertTrue(cat.getKey("node").isPartialCategoryKey());
+        assertEquals("nodeStats", cat.getKey("nodeStats").getName());
+        assertFalse(cat.getKey("nodeStats").isPartialCategoryKey());
 
-        assertEquals("numaHit", cat.getKey("numaHit").getName());
-        assertFalse(cat.getKey("numaHit").isPartialCategoryKey());
-        assertEquals("numaMiss", cat.getKey("numaMiss").getName());
-        assertFalse(cat.getKey("numaMiss").isPartialCategoryKey());
-        assertEquals("numaForeign", cat.getKey("numaForeign").getName());
-        assertFalse(cat.getKey("numaForeign").isPartialCategoryKey());
-        assertEquals("interleaveHit", cat.getKey("interleaveHit").getName());
-        assertFalse(cat.getKey("interleaveHit").isPartialCategoryKey());
-        assertEquals("localNode", cat.getKey("localNode").getName());
-        assertFalse(cat.getKey("localNode").isPartialCategoryKey());
-        assertEquals("otherNode", cat.getKey("otherNode").getName());
-        assertFalse(cat.getKey("otherNode").isPartialCategoryKey());
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaNodeStatTest.java	Fri Jan 18 18:42:04 2013 +0100
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2013 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.numa.common;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NumaNodeStatTest {
+
+    private NumaNodeStat stat;
+
+    @Before
+    public void setUp() {
+        stat = new NumaNodeStat();
+        stat.setNodeId(1);
+        stat.setNumaHit(2);
+        stat.setNumaMiss(3);
+        stat.setNumaForeign(4);
+        stat.setInterleaveHit(5);
+        stat.setLocalNode(6);
+        stat.setOtherNode(7);
+    }
+
+    @After
+    public void tearDown() {
+        stat = null;
+    }
+
+    @Test
+    public void testDefaults() {
+        NumaNodeStat stat = new NumaNodeStat();
+        assertEquals(-1, stat.getNodeId());
+        assertEquals(-1, stat.getNumaHit());
+        assertEquals(-1, stat.getNumaMiss());
+        assertEquals(-1, stat.getNumaForeign());
+        assertEquals(-1, stat.getInterleaveHit());
+        assertEquals(-1, stat.getLocalNode());
+        assertEquals(-1, stat.getOtherNode());
+    }
+
+    @Test
+    public void testProperties() {
+
+        assertEquals(1, stat.getNodeId());
+        assertEquals(2, stat.getNumaHit());
+        assertEquals(3, stat.getNumaMiss());
+        assertEquals(4, stat.getNumaForeign());
+        assertEquals(5, stat.getInterleaveHit());
+        assertEquals(6, stat.getLocalNode());
+        assertEquals(7, stat.getOtherNode());
+        
+    }
+
+    @Test
+    public void testToString() {
+        NumaNodeStat stat = new NumaNodeStat();
+        stat.setNodeId(1);
+        stat.setNumaHit(2);
+        stat.setNumaMiss(3);
+        stat.setNumaForeign(4);
+        stat.setInterleaveHit(5);
+        stat.setLocalNode(6);
+        stat.setOtherNode(7);
+
+        String str = stat.toString();
+        String expected = "NumaStat: nodeId: 1, numaHit: 2, numaMiss: 3, numaForeign: 4, interleaveHit: 5, localNode: 6, otherNode: 7";
+        assertEquals(expected, str);
+    }
+}
--- a/numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaStatTest.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/NumaStatTest.java	Fri Jan 18 18:42:04 2013 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright 2013 Red Hat, Inc.
+ * Copyright 2012 Red Hat, Inc.
  *
  * This file is part of Thermostat.
  *
@@ -37,71 +37,32 @@
 
 package com.redhat.thermostat.numa.common;
 
-import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.*;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 
 public class NumaStatTest {
 
-    private NumaStat stat;
-
-    @Before
-    public void setUp() {
-        stat = new NumaStat();
-        stat.setNode(1);
-        stat.setNumaHit(2);
-        stat.setNumaMiss(3);
-        stat.setNumaForeign(4);
-        stat.setInterleaveHit(5);
-        stat.setLocalNode(6);
-        stat.setOtherNode(7);
-    }
-
-    @After
-    public void tearDown() {
-        stat = null;
+    @Test
+    public void testDefaults() {
+        NumaStat numaStat = new NumaStat();
+        assertEquals(-1, numaStat.getTimeStamp());
+        assertNotNull(numaStat.getNodeStats());
+        assertEquals(0, numaStat.getNodeStats().length);
     }
 
     @Test
-    public void testDefaults() {
-        NumaStat stat = new NumaStat();
-        assertEquals(-1, stat.getNode());
-        assertEquals(-1, stat.getNumaHit());
-        assertEquals(-1, stat.getNumaMiss());
-        assertEquals(-1, stat.getNumaForeign());
-        assertEquals(-1, stat.getInterleaveHit());
-        assertEquals(-1, stat.getLocalNode());
-        assertEquals(-1, stat.getOtherNode());
-    }
-
-    @Test
-    public void testProperties() {
+    public void testGetSetValues() {
+        NumaStat numaStat = new NumaStat();
+        numaStat.setTimeStamp(12345);
+        NumaNodeStat nodeStat1 = new NumaNodeStat();
+        NumaNodeStat nodeStat2 = new NumaNodeStat();
+        numaStat.setNodeStats(new NumaNodeStat[] { nodeStat1, nodeStat2 });
 
-        assertEquals(1, stat.getNode());
-        assertEquals(2, stat.getNumaHit());
-        assertEquals(3, stat.getNumaMiss());
-        assertEquals(4, stat.getNumaForeign());
-        assertEquals(5, stat.getInterleaveHit());
-        assertEquals(6, stat.getLocalNode());
-        assertEquals(7, stat.getOtherNode());
-        
-    }
-
-    @Test
-    public void testToString() {
-        NumaStat stat = new NumaStat();
-        stat.setNode(1);
-        stat.setNumaHit(2);
-        stat.setNumaMiss(3);
-        stat.setNumaForeign(4);
-        stat.setInterleaveHit(5);
-        stat.setLocalNode(6);
-        stat.setOtherNode(7);
-
-        String str = stat.toString();
-        String expected = "NumaStat: node: 1, numaHit: 2, numaMiss: 3, numaForeign: 4, interleaveHit: 5, localNode: 6, otherNode: 7";
-        assertEquals(expected, str);
+        assertEquals(12345, numaStat.getTimeStamp());
+        assertNotNull(numaStat.getNodeStats());
+        assertEquals(2, numaStat.getNodeStats().length);
+        assertSame(nodeStat1, numaStat.getNodeStats()[0]);
+        assertSame(nodeStat2, numaStat.getNodeStats()[1]);
     }
 }
--- a/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java	Wed Jan 16 12:20:36 2013 +0100
+++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplTest.java	Fri Jan 18 18:42:04 2013 +0100
@@ -47,6 +47,7 @@
 import org.junit.Test;
 
 import com.redhat.thermostat.numa.common.NumaDAO;
+import com.redhat.thermostat.numa.common.NumaNodeStat;
 import com.redhat.thermostat.numa.common.NumaStat;
 import com.redhat.thermostat.storage.core.Add;
 import com.redhat.thermostat.storage.core.Storage;
@@ -79,8 +80,8 @@
         Add add = mock(Add.class);
         when(storage.createAdd(NumaDAO.numaStatCategory)).thenReturn(add);
 
-        NumaStat stat = new NumaStat();
-        stat.setNode(1);
+        NumaNodeStat stat = new NumaNodeStat();
+        stat.setNodeId(1);
         stat.setNumaHit(2);
         stat.setNumaMiss(3);
         stat.setNumaForeign(4);
@@ -88,12 +89,15 @@
         stat.setLocalNode(6);
         stat.setOtherNode(7);
 
-        numaDAO.putNumaStat(stat);
+        NumaStat numaStat = new NumaStat();
+        numaStat.setTimeStamp(12345);
+        numaStat.setNodeStats(new NumaNodeStat[] { stat });
+        numaDAO.putNumaStat(numaStat);
 
         verify(storage).registerCategory(NumaDAO.numaStatCategory);
         verify(storage).createAdd(NumaDAO.numaStatCategory);
         verifyNoMoreInteractions(storage);
-        verify(add).setPojo(stat);
+        verify(add).setPojo(numaStat);
         verify(add).apply();
         verifyNoMoreInteractions(add);
     }
--- a/storage/core/pom.xml	Wed Jan 16 12:20:36 2013 +0100
+++ b/storage/core/pom.xml	Fri Jan 18 18:42:04 2013 +0100
@@ -66,6 +66,15 @@
               com.redhat.thermostat.storage.config,
               com.redhat.thermostat.storage.model,
             </Export-Package>
+            <!-- TODO: For the thread tab (i.e. thread plug-in) the web server
+                 bundle requires model classes provided by said bundle. Since
+                 no explicit imports (in the Java import sense) are in our code,
+                 the maven bundle plugin seems to fail on us. Therefore we need
+                 these explicit Import-Package instructions. If not there, this
+                 results in class not found exceptions. This may be a problem
+                 for user-provided bundles which contribute DAOs/models in the
+                 same way. -->
+            <DynamicImport-Package>com.redhat.thermostat.*</DynamicImport-Package>
             <!-- Do not autogenerate uses clauses in Manifests -->
             <_nouses>true</_nouses>
           </instructions>
--- a/web/server/pom.xml	Wed Jan 16 12:20:36 2013 +0100
+++ b/web/server/pom.xml	Fri Jan 18 18:42:04 2013 +0100
@@ -137,18 +137,6 @@
             <Export-Package>
               com.redhat.thermostat.web.server
             </Export-Package>
-            <!-- TODO: For the thread tab (i.e. thread plug-in) the web server
-                 bundle requires model classes provided by said bundle. Since
-                 no explicit imports (in the Java import sense) are in our code,
-                 the maven bundle plugin seems to fail on us. Therefore we need
-                 these explicit Import-Package instructions. If not there, this
-                 results in class not found exceptions. This may be a problem
-                 for user-provided bundles which contribute DAOs/models in the
-                 same way. -->
-            <Import-Package>
-              com.redhat.thermostat.thread.model,
-              *
-            </Import-Package>
             <Private-Package>
               com.redhat.thermostat.web.server.internal
             </Private-Package>