changeset 378:19a83468b64f

Initial HeapDAO implementation. Reviewed-by: neugens Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2012-June/001854.html PR 1032
author Roman Kennke <rkennke@redhat.com>
date Mon, 18 Jun 2012 16:14:07 +0200
parents 8b0c224f1d88
children 3fad23440030
files client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpAction.java common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAO.java common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAOImpl.java common/core/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java common/core/src/main/java/com/redhat/thermostat/common/model/HeapInfo.java common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java common/core/src/test/java/com/redhat/thermostat/common/dao/HeapDAOTest.java common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java common/core/src/test/java/com/redhat/thermostat/common/model/HeapInfoTest.java common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java distribution/config/osgi-export.properties
diffstat 13 files changed, 291 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpAction.java	Wed Jun 13 21:34:41 2012 +0200
+++ b/client/heapdumper/src/main/java/com/redhat/thermostat/client/heap/HeapDumpAction.java	Mon Jun 18 16:14:07 2012 +0200
@@ -37,6 +37,8 @@
 package com.redhat.thermostat.client.heap;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.util.logging.Level;
@@ -45,8 +47,10 @@
 import com.redhat.thermostat.client.osgi.service.Filter;
 import com.redhat.thermostat.client.osgi.service.VMContextAction;
 import com.redhat.thermostat.common.dao.DAOFactory;
+import com.redhat.thermostat.common.dao.HeapDAO;
 import com.redhat.thermostat.common.dao.Ref;
 import com.redhat.thermostat.common.dao.VmRef;
+import com.redhat.thermostat.common.model.HeapInfo;
 import com.redhat.thermostat.common.model.VmInfo;
 
 /**
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java	Wed Jun 13 21:34:41 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/DAOFactory.java	Mon Jun 18 16:14:07 2012 +0200
@@ -64,4 +64,6 @@
 
     public VmGcStatDAO getVmGcStatDAO();
 
+    public HeapDAO getHeapDAO();
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAO.java	Mon Jun 18 16:14:07 2012 +0200
@@ -0,0 +1,15 @@
+package com.redhat.thermostat.common.dao;
+
+import com.redhat.thermostat.common.model.HeapInfo;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Key;
+
+public interface HeapDAO {
+
+    static final Key<String> heapDumpIdKey = new Key<String>("heap-dump-id", false);
+
+    public static final Category heapInfoCategory = new Category("vm-heap-info", Key.AGENT_ID, Key.VM_ID, Key.TIMESTAMP, heapDumpIdKey);
+
+    void putHeapInfo(HeapInfo heapInfo);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/HeapDAOImpl.java	Mon Jun 18 16:14:07 2012 +0200
@@ -0,0 +1,38 @@
+package com.redhat.thermostat.common.dao;
+
+import java.io.InputStream;
+
+import com.redhat.thermostat.common.model.HeapInfo;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Storage;
+
+class HeapDAOImpl implements HeapDAO {
+
+    private Storage storage;
+
+    HeapDAOImpl(Storage storage) {
+        this.storage = storage;
+    }
+
+    @Override
+    public void putHeapInfo(HeapInfo heapInfo) {
+        VmRef vm = heapInfo.getVm();
+        Chunk chunk = new Chunk(heapInfoCategory, false);
+        
+        chunk.put(Key.AGENT_ID, vm.getAgent().getStringID());
+        chunk.put(Key.VM_ID, vm.getId());
+        chunk.put(Key.TIMESTAMP, heapInfo.getTimestamp());
+        InputStream heapDumpData = heapInfo.getHeapDump();
+        String heapDumpId = "heapdump-" + vm.getAgent().getStringID() + "-" + vm.getId() + "-" + heapInfo.getTimestamp();
+        if (heapDumpData != null) {
+            chunk.put(heapDumpIdKey, heapDumpId);
+        }
+        storage.createConnectionKey(heapInfoCategory);
+        storage.putChunk(chunk);
+        if (heapDumpData != null) {
+            storage.saveFile(heapDumpId, heapDumpData);
+        }
+    }
+
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java	Wed Jun 13 21:34:41 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/dao/MongoDAOFactory.java	Mon Jun 18 16:14:07 2012 +0200
@@ -116,4 +116,10 @@
             throw new IllegalStateException("Set up connection before accessing DAO");
         }
     }
+
+    @Override
+    public HeapDAO getHeapDAO() {
+        ensureStorageConnected();
+        return new HeapDAOImpl(storage);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/main/java/com/redhat/thermostat/common/model/HeapInfo.java	Mon Jun 18 16:14:07 2012 +0200
@@ -0,0 +1,33 @@
+package com.redhat.thermostat.common.model;
+
+import java.io.InputStream;
+
+import com.redhat.thermostat.common.dao.VmRef;
+
+public class HeapInfo {
+
+    private VmRef vm;
+    private long timestamp;
+    private InputStream heapDump;
+
+    public HeapInfo(VmRef vm, long timestamp) {
+        this.vm = vm;
+        this.timestamp = timestamp;
+    }
+
+    public VmRef getVm() {
+        return vm;
+    }
+
+    public long getTimestamp() {
+        return timestamp;
+    }
+
+    public InputStream getHeapDump() {
+        return heapDump;
+    }
+
+    public void setHeapDump(InputStream heapDump) {
+        this.heapDump = heapDump;
+    }
+}
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Wed Jun 13 21:34:41 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/MongoStorage.java	Mon Jun 18 16:14:07 2012 +0200
@@ -36,6 +36,7 @@
 
 package com.redhat.thermostat.common.storage;
 
+import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -50,6 +51,8 @@
 import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
 import com.mongodb.WriteConcern;
+import com.mongodb.gridfs.GridFS;
+import com.mongodb.gridfs.GridFSInputFile;
 import com.redhat.thermostat.common.config.StartupConfiguration;
 import com.redhat.thermostat.common.storage.Connection.ConnectionListener;
 import com.redhat.thermostat.common.storage.Connection.ConnectionStatus;
@@ -101,17 +104,27 @@
         return new BasicDBObject(KEY_AGENT_ID, agentId.toString());
     }
 
+    private BasicDBObject getAgentDBObject(Chunk chunk) {
+        if (agentId != null) {
+            return getAgentDBObject();
+        } else if (chunk.get(Key.AGENT_ID) != null) {
+            return new BasicDBObject(KEY_AGENT_ID, chunk.get(Key.AGENT_ID));
+        } else {
+            return null;
+        }
+    }
+
     @Override
     public void putChunk(Chunk chunk) {
         Category cat = chunk.getCategory();
         DBCollection coll = getCachedCollection(cat.getName());
-        BasicDBObject toInsert = getAgentDBObject();
+        BasicDBObject toInsert = getAgentDBObject(chunk);
         BasicDBObject replaceKey = null;
         boolean replace = chunk.getReplace();
         Map<String, BasicDBObject> nestedParts = new HashMap<String, BasicDBObject>();
         Map<String, BasicDBObject> replaceKeyNestedParts = null;
         if (replace) {
-            replaceKey = getAgentDBObject();
+            replaceKey = getAgentDBObject(chunk);
             replaceKeyNestedParts = new HashMap<String, BasicDBObject>();
         }
         for (Key<?> key : cat.getKeys()) {
@@ -167,7 +180,7 @@
         Category cat = chunk.getCategory();
         DBCollection coll = getCachedCollection(cat.getName());
         BasicDBObject toUpdate = new BasicDBObject();
-        BasicDBObject updateKey = getAgentDBObject();
+        BasicDBObject updateKey = getAgentDBObject(chunk);
         Map<String, BasicDBObject> nestedParts = new HashMap<String, BasicDBObject>();
         Map<String, BasicDBObject> updateKeyNestedParts = new HashMap<String, BasicDBObject>();
         for (Key<?> key : cat.getKeys()) {
@@ -368,4 +381,11 @@
         }
         return null;
     }
+
+    @Override
+    public void saveFile(String filename, InputStream data) {
+        GridFS gridFS = new GridFS(db);
+        GridFSInputFile inputFile = gridFS.createFile(data, filename);
+        inputFile.save();
+    }
 }
--- a/common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Wed Jun 13 21:34:41 2012 +0200
+++ b/common/core/src/main/java/com/redhat/thermostat/common/storage/Storage.java	Mon Jun 18 16:14:07 2012 +0200
@@ -36,6 +36,8 @@
 
 package com.redhat.thermostat.common.storage;
 
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
 import java.util.UUID;
 
 
@@ -84,4 +86,6 @@
      */
     public abstract String getBackendConfig(String backendName, String configurationKey);
 
+    public abstract void saveFile(String filename, InputStream data);
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/HeapDAOTest.java	Mon Jun 18 16:14:07 2012 +0200
@@ -0,0 +1,92 @@
+package com.redhat.thermostat.common.dao;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.Collection;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.model.HeapInfo;
+import com.redhat.thermostat.common.storage.Category;
+import com.redhat.thermostat.common.storage.Chunk;
+import com.redhat.thermostat.common.storage.Key;
+import com.redhat.thermostat.common.storage.Storage;
+
+
+public class HeapDAOTest {
+
+    private HeapDAO dao;
+    private Storage storage;
+    private HeapInfo heapInfo;
+    private InputStream dataStream;
+
+    @Before
+    public void setUp() {
+        storage = mock(Storage.class);
+        dao = new HeapDAOImpl(storage);
+        HostRef host = new HostRef("987", "test-host");
+        VmRef vm = new VmRef(host, 123, "test-vm");
+        heapInfo = new HeapInfo(vm, 12345);
+        byte[] data = new byte[] { 1, 2, 3 };
+        dataStream = new ByteArrayInputStream(data);
+        heapInfo.setHeapDump(dataStream);
+    }
+
+    @After
+    public void tearDown() {
+        dataStream = null;
+        heapInfo = null;
+        dao = null;
+        storage = null;
+    }
+
+    @Test
+    public void testCategory() {
+        Category category = HeapDAO.heapInfoCategory;
+        assertNotNull(category);
+        assertEquals("vm-heap-info", category.getName());
+        Collection<Key<?>> keys = category.getKeys();
+        assertEquals(4, keys.size());
+        assertTrue(keys.contains(new Key<>("agent-id", false)));
+        assertTrue(keys.contains(new Key<>("vm-id", false)));
+        assertTrue(keys.contains(new Key<>("timestamp", false)));
+        assertTrue(keys.contains(new Key<>("heap-dump-id", false)));
+    }
+
+    @Test
+    public void testPutHeapInfo() {
+        dao.putHeapInfo(heapInfo);
+
+        Chunk expectedChunk = new Chunk(HeapDAO.heapInfoCategory, false);
+        expectedChunk.put(Key.AGENT_ID, "987");
+        expectedChunk.put(Key.VM_ID, 123);
+        expectedChunk.put(Key.TIMESTAMP, 12345L);
+        expectedChunk.put(HeapDAO.heapDumpIdKey, "heapdump-987-123-12345");
+        verify(storage).putChunk(expectedChunk);
+        verify(storage).saveFile(eq("heapdump-987-123-12345"), same(dataStream));
+    }
+
+    @Test
+    public void testPutHeapInfoWithoutDump() {
+        heapInfo.setHeapDump(null);
+        dao.putHeapInfo(heapInfo);
+
+        Chunk expectedChunk = new Chunk(HeapDAO.heapInfoCategory, false);
+        expectedChunk.put(Key.AGENT_ID, "987");
+        expectedChunk.put(Key.VM_ID, 123);
+        expectedChunk.put(Key.TIMESTAMP, 12345L);
+
+        verify(storage).putChunk(expectedChunk);
+        verify(storage, never()).saveFile(anyString(), any(InputStream.class));
+    }
+}
--- a/common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java	Wed Jun 13 21:34:41 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/dao/MongoDAOFactoryTest.java	Mon Jun 18 16:14:07 2012 +0200
@@ -122,4 +122,10 @@
         NetworkInterfaceInfoDAO dao = daoFactory.getNetworkInterfaceInfoDAO();
         assertNotNull(dao);
     }
+
+    @Test
+    public void testGetHeapDAO() {
+        HeapDAO dao = daoFactory.getHeapDAO();
+        assertNotNull(dao);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common/core/src/test/java/com/redhat/thermostat/common/model/HeapInfoTest.java	Mon Jun 18 16:14:07 2012 +0200
@@ -0,0 +1,45 @@
+package com.redhat.thermostat.common.model;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import com.redhat.thermostat.common.dao.HostRef;
+import com.redhat.thermostat.common.dao.VmRef;
+
+public class HeapInfoTest {
+
+    private HeapInfo heapInfo;
+    private VmRef vm;
+
+    @Before
+    public void setUp() {
+        HostRef hostRef = new HostRef("321", "test-host");
+        vm = new VmRef(hostRef, 123, "test-vm");
+        heapInfo = new HeapInfo(vm, 12345);
+    }
+
+    @Test
+    public void testProperties() {
+        assertSame(vm, heapInfo.getVm());
+        assertEquals(12345, heapInfo.getTimestamp());
+    }
+
+    @Test
+    public void testHeapDump() throws IOException {
+        assertNull(heapInfo.getHeapDump());
+        byte[] test = new byte[]{ 1 , 2 ,3 };
+        heapInfo.setHeapDump(new ByteArrayInputStream(test));
+        InputStream in = heapInfo.getHeapDump();
+        assertNotNull(in);
+        assertEquals(1, in.read());
+        assertEquals(2, in.read());
+        assertEquals(3, in.read());
+        assertEquals(-1, in.read());
+    }
+}
--- a/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Wed Jun 13 21:34:41 2012 +0200
+++ b/common/core/src/test/java/com/redhat/thermostat/common/storage/MongoStorageTest.java	Mon Jun 18 16:14:07 2012 +0200
@@ -44,10 +44,15 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -64,6 +69,8 @@
 import com.mongodb.DBObject;
 import com.mongodb.Mongo;
 import com.mongodb.MongoURI;
+import com.mongodb.gridfs.GridFS;
+import com.mongodb.gridfs.GridFSInputFile;
 import com.redhat.thermostat.common.config.StartupConfiguration;
 
 @RunWith(PowerMockRunner.class)
@@ -337,4 +344,19 @@
         assertFalse(cursor.hasNext());
         assertNull(cursor.next());
     }
+
+    @Test
+    public void verifySaveFile() throws Exception {
+        GridFSInputFile gridFSFile = mock(GridFSInputFile.class);
+        GridFS gridFS = mock(GridFS.class);
+        when(gridFS.createFile(any(InputStream.class), anyString())).thenReturn(gridFSFile);
+        PowerMockito.whenNew(GridFS.class).withArguments(any()).thenReturn(gridFS);
+        PowerMockito.whenNew(Mongo.class).withParameterTypes(MongoURI.class).withArguments(any(MongoURI.class)).thenReturn(m);
+        MongoStorage storage = makeStorage();
+        byte[] data = new byte[] { 1, 2, 3 };
+        InputStream dataStream = new ByteArrayInputStream(data);
+        storage.saveFile("test", dataStream);
+        verify(gridFS).createFile(same(dataStream), eq("test"));
+        verify(gridFSFile).save();
+    }
 }
--- a/distribution/config/osgi-export.properties	Wed Jun 13 21:34:41 2012 +0200
+++ b/distribution/config/osgi-export.properties	Mon Jun 18 16:14:07 2012 +0200
@@ -34,6 +34,7 @@
 
 # OSGi public API
 com.mongodb
+com.mongodb.gridfs
 org.apache.commons.cli=1.2.0
 org.bson
 org.jfree.chart