From 6c79dba9aa1a510620f453999b27fa297e389b2e Mon Sep 17 00:00:00 2001
From: Michel Marti <mma@objectxp.com>
Date: Thu, 9 Jan 2014 15:50:42 +0100
Subject: [PATCH] Cache preprocessed JMeter Reports (JENKINS-9031)

Instead of parsing all available JTL results upon each request,
we now save the parsed report as a serialized Java object for later
reuse. The file will be next to the JTL file with a '.serialized'
suffix. Additionally the report also gets added to a in-memory cache
with a maximum capacity of 100 reports. This considerably speeds up the
performance trend display.

Signed-off-by: Michel Marti <mma@objectxp.com>
---
 .../hudson/plugins/performance/HttpSample.java     |    2 +
 .../hudson/plugins/performance/JMeterParser.java   |   50 +++++++++++++++++++-
 .../plugins/performance/PerformanceReport.java     |    2 +
 .../java/hudson/plugins/performance/UriReport.java |    2 +
 4 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/src/main/java/hudson/plugins/performance/HttpSample.java b/src/main/java/hudson/plugins/performance/HttpSample.java
index f635769..2d0e438 100644
--- a/src/main/java/hudson/plugins/performance/HttpSample.java
+++ b/src/main/java/hudson/plugins/performance/HttpSample.java
@@ -10,6 +10,8 @@
  */
 public class HttpSample implements Serializable, Comparable<HttpSample> {
 
+  private static final long serialVersionUID = -1980997520755400556L;
+
 	private long duration;
 
 	private boolean successful;
diff --git a/src/main/java/hudson/plugins/performance/JMeterParser.java b/src/main/java/hudson/plugins/performance/JMeterParser.java
index 5edcfa0..0c35fa3 100644
--- a/src/main/java/hudson/plugins/performance/JMeterParser.java
+++ b/src/main/java/hudson/plugins/performance/JMeterParser.java
@@ -10,13 +10,22 @@
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.DefaultHandler;
 
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
+import java.util.logging.Logger;
 
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParser;
@@ -29,6 +38,9 @@
  */
 public class JMeterParser extends PerformanceReportParser {
 
+  private static final Logger LOGGER = Logger.getLogger(JMeterParser.class.getName());
+  private static final Cache<String, PerformanceReport> cache = CacheBuilder.newBuilder().maximumSize(100).build();
+
   @Extension
   public static class DescriptorImpl extends PerformanceReportParserDescriptor {
     @Override
@@ -59,10 +71,31 @@ public String getDefaultGlobPattern() {
 
     for (File f : reports) {
       try {
+                String fser = f.getPath() + ".serialized";
+                  ObjectInputStream in = null;
+                synchronized (JMeterParser.class) {
+                  try {
+                    PerformanceReport r = cache.getIfPresent(fser);
+                    if (r == null) {
+                      in = new ObjectInputStream(new FileInputStream(fser));
+                      r = (PerformanceReport) in.readObject();
+                    }
+                    result.add(r);
+                    continue;
+                  } catch (FileNotFoundException fne) {
+                    // That's OK
+                  } catch (Exception unknown) {
+                    LOGGER.warning("Deserialization failed. " + unknown);
+                  } finally {
+                    if (in != null) {
+                      in.close();
+                    }
+                  }
+                }
                 SAXParser parser = factory.newSAXParser();
                 final PerformanceReport r = new PerformanceReport();
                 r.setReportFileName(f.getName());
-                logger.println("Performance: Parsing JMeter report file " + f.getName());
+                logger.println("Performance: Parsing JMeter report file " + f.getPath());
                 parser.parse(f, new DefaultHandler() {
                 HttpSample currentSample;
                 int counter = 0;
@@ -123,6 +156,21 @@ public void endElement(String uri, String localName, String qName) {
                 }
                 });
                 result.add(r);
+                ObjectOutputStream out = null;
+                synchronized(JMeterParser.class) {
+                  try {
+                    cache.put(fser, r);
+                    out = new ObjectOutputStream(new FileOutputStream(fser));
+                    out.writeObject(r);
+                  } catch (Exception unknown) {
+                    LOGGER.warning("Serialization failed. " + unknown);
+                  } finally {
+                    if (out != null) {
+                      out.close();
+                    }
+                  }
+                }
+
       } catch (ParserConfigurationException e) {
         throw new IOException2("Failed to create parser ", e);
       } catch (SAXException e) {
diff --git a/src/main/java/hudson/plugins/performance/PerformanceReport.java b/src/main/java/hudson/plugins/performance/PerformanceReport.java
index 69a57e3..8710531 100644
--- a/src/main/java/hudson/plugins/performance/PerformanceReport.java
+++ b/src/main/java/hudson/plugins/performance/PerformanceReport.java
@@ -25,6 +25,8 @@
 public class PerformanceReport extends AbstractReport implements Serializable,
     Comparable<PerformanceReport>{
 
+  private static final long serialVersionUID = -1422875677867003355L;
+
   private transient PerformanceBuildAction buildAction;
 
   private HttpSample httpSample;
diff --git a/src/main/java/hudson/plugins/performance/UriReport.java b/src/main/java/hudson/plugins/performance/UriReport.java
index a110e46..8f07c9b 100644
--- a/src/main/java/hudson/plugins/performance/UriReport.java
+++ b/src/main/java/hudson/plugins/performance/UriReport.java
@@ -27,6 +27,8 @@
 public class UriReport extends AbstractReport implements  Serializable, ModelObject,
     Comparable<UriReport> {
 
+  private static final long serialVersionUID = 6377220939528230222L;
+
   public final static String END_PERFORMANCE_PARAMETER = ".endperformanceparameter";
 
   /**
-- 
1.7.10.4

