JCR-4000: More event stats in EventListenerMBean

git-svn-id: https://svn.apache.org/repos/asf/jackrabbit/trunk@1754365 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/EventListenerMBean.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/EventListenerMBean.java
index 210a94d..cbcd8d0 100644
--- a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/EventListenerMBean.java
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/EventListenerMBean.java
@@ -71,6 +71,9 @@
     /** Ratio of time spent in event processing */
     double getRatioOfTimeSpentProcessingEvents();
 
+    /** Ratio of time spent in event listener vs. the overall event processing */
+    double getEventConsumerTimeRatio();
+
     /** Is user information accessed without checking if an event is external? */
     boolean isUserInfoAccessedWithoutExternalsCheck();
 
@@ -84,6 +87,13 @@
     boolean isDateAccessedFromExternalEvent();
 
     /**
+     * The time difference between the current system time and the head (oldest)
+     * element in the queue in milliseconds. This method returns zero if the
+     * queue is empty.
+     */
+    long getQueueBacklogMillis();
+
+    /**
      * {@link org.apache.jackrabbit.api.stats.TimeSeries time series} of the number of
      * items related to generating observation events that are currently queued by the
      * system. The exact nature of these items is implementation specific and might not
diff --git a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/package-info.java b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/package-info.java
index 61c6ee9..f400610 100644
--- a/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/package-info.java
+++ b/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/jmx/package-info.java
@@ -18,5 +18,5 @@
 /**
  * JMX management interfaces for JCR.
  */
-@aQute.bnd.annotation.Version("2.1.0")
+@aQute.bnd.annotation.Version("2.2.0")
 package org.apache.jackrabbit.api.jmx;
diff --git a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/observation/ListenerTracker.java b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/observation/ListenerTracker.java
index d4cb68d..1bfa281 100644
--- a/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/observation/ListenerTracker.java
+++ b/jackrabbit-jcr-commons/src/main/java/org/apache/jackrabbit/commons/observation/ListenerTracker.java
@@ -71,6 +71,8 @@
 
     private final AtomicLong eventDeliveryTime = new AtomicLong();
 
+    private final AtomicLong headTimestamp = new AtomicLong();
+
     private final TimeSeriesMax queueLength = new TimeSeriesMax();
 
     private final TimeSeriesRecorder eventCount = new TimeSeriesRecorder(true);
@@ -142,6 +144,19 @@
     }
 
     /**
+     * Applications should call this to report the current queue length when an
+     * item is removed from the queue.
+     *
+     * @param length        the length of the queue after the item was removed.
+     * @param headTimestamp the time in milliseconds when the head item was
+     *                      created and put into the queue.
+     */
+    public void recordQueueLength(long length, long headTimestamp) {
+        queueLength.recordValue(length);
+        this.headTimestamp.set(length == 0 ? 0 : headTimestamp);
+    }
+
+    /**
      * Records the number of measured values over the past second and resets
      * the counter. This method should be scheduled to be called once per
      * second.
@@ -279,6 +294,12 @@
                         / Math.max(currentTimeMillis() - startTime, 1);
             }
             @Override
+            public double getEventConsumerTimeRatio() {
+                double consumerTime = sum(eventConsumerTime.getValuePerSecond());
+                double producerTime = sum(eventProducerTime.getValuePerSecond());
+                return consumerTime / Math.max(consumerTime + producerTime, 1);
+            }
+            @Override
             public boolean isUserInfoAccessedWithoutExternalsCheck() {
                 return userInfoAccessedWithoutExternalsCheck.get();
             }
@@ -295,6 +316,14 @@
                 return dateAccessedFromExternalEvent.get();
             }
             @Override
+            public long getQueueBacklogMillis() {
+                long t = headTimestamp.get();
+                if (t > 0) {
+                    t = currentTimeMillis() - t;
+                }
+                return t;
+            }
+            @Override
             public CompositeData getQueueLength() {
                 return asCompositeData(queueLength, "queueLength");
             }
@@ -361,4 +390,12 @@
         }
     }
 
+    private static long sum(long[] values) {
+        long sum = 0;
+        for (long v : values) {
+            sum += v;
+        }
+        return sum;
+    }
+
 }