Configurable COLLISION_BUFFER_POWER

Signed-off-by: Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com>
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java b/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java
index 391d063..6055e2c 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/ServerProperties.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2020 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2021 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -741,6 +741,14 @@
     public static final String UNWRAP_COMPLETION_STAGE_IN_WRITER_ENABLE =
             "jersey.config.server.unwrap.completion.stage.writer.enable";
 
+    /**
+     * JVM argument to define the value of
+     * {@link org.glassfish.jersey.server.internal.monitoring.core.ReservoirConstants#COLLISION_BUFFER_POWER}.
+     * Lower values reduce the memory footprint.
+     */
+    public static final String COLLISION_BUFFER_POWER_JVM_ARG =
+            "jersey.config.server.monitoring.collision.buffer.power";
+
     private ServerProperties() {
         // prevents instantiation
     }
diff --git a/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/core/ReservoirConstants.java b/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/core/ReservoirConstants.java
index a161fdc..fe0a7ad 100644
--- a/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/core/ReservoirConstants.java
+++ b/core-server/src/main/java/org/glassfish/jersey/server/internal/monitoring/core/ReservoirConstants.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2015, 2021 Oracle and/or its affiliates. All rights reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,13 @@
 
 package org.glassfish.jersey.server.internal.monitoring.core;
 
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.glassfish.jersey.server.ServerProperties;
+
 /**
  * The constants that determine the behaviour of sliding windows and their trimmers.
  *
@@ -23,21 +30,36 @@
  */
 public final class ReservoirConstants {
 
+    private static final int DEFAULT_COLLISION_BUFFER_POWER = 8;
+
     /**
      * Allow for 2^that many duplicate ticks before throwing away measurements.
+     * This value is by default {@link DEFAULT_COLLISION_BUFFER_POWER}, but it can be configured
+     * with {@link COLLISION_BUFFER_POWER_JVM_ARG} JVM argument
      */
-    public static final int COLLISION_BUFFER_POWER = 8;
+    public static final int COLLISION_BUFFER_POWER;
 
     /**
      * The size of the collision buffer derived from the collision buffer power.
      */
-    public static final int COLLISION_BUFFER = 1 << COLLISION_BUFFER_POWER; // 256
+    public static final int COLLISION_BUFFER;
 
     /**
      * Only trim on updating once every N.
      */
     public static final int TRIM_THRESHOLD = 256;
 
+    static {
+        PrivilegedAction<Integer> action = new PrivilegedAction<Integer>() {
+            @Override
+            public Integer run() {
+                return Integer.getInteger(ServerProperties.COLLISION_BUFFER_POWER_JVM_ARG, DEFAULT_COLLISION_BUFFER_POWER);
+            }
+        };
+        COLLISION_BUFFER_POWER = AccessController.doPrivileged(action);
+        COLLISION_BUFFER = 1 << COLLISION_BUFFER_POWER; // 256
+    }
+
     private ReservoirConstants() {
         throw new AssertionError("Instantiation not allowed.");
     }
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/AbstractNanosReservoirTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/AbstractNanosReservoirTest.java
index 8feaf59..abdc102 100644
--- a/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/AbstractNanosReservoirTest.java
+++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/AbstractNanosReservoirTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2021 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -16,11 +16,12 @@
 
 package org.glassfish.jersey.server.internal.monitoring;
 
+import java.util.concurrent.TimeUnit;
+
+import org.glassfish.jersey.server.internal.monitoring.core.ReservoirConstants;
 import org.glassfish.jersey.server.internal.monitoring.core.TimeReservoir;
 import org.glassfish.jersey.server.internal.monitoring.core.UniformTimeSnapshot;
 
-import java.util.concurrent.TimeUnit;
-
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -29,7 +30,7 @@
 public class AbstractNanosReservoirTest {
 
     protected static final double DELTA = 0.0001;
-    protected static final int COLLISION_BUFFER = 256;
+    protected static final int COLLISION_BUFFER = ReservoirConstants.COLLISION_BUFFER;
 
     protected void reservoirUpdateInNanos(TimeReservoir reservoir, long value, long time) {
         reservoir.update(value, time, TimeUnit.NANOSECONDS);
diff --git a/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/TimeWindowStatisticsImplTest.java b/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/TimeWindowStatisticsImplTest.java
index b6ca7c4..d92393e 100644
--- a/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/TimeWindowStatisticsImplTest.java
+++ b/core-server/src/test/java/org/glassfish/jersey/server/internal/monitoring/TimeWindowStatisticsImplTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2021 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -18,8 +18,12 @@
 
 import java.util.concurrent.TimeUnit;
 
+import org.glassfish.jersey.server.ServerProperties;
+import org.glassfish.jersey.server.internal.monitoring.core.ReservoirConstants;
 import org.glassfish.jersey.server.internal.monitoring.core.UniformTimeReservoir;
+import org.junit.BeforeClass;
 import org.junit.Test;
+
 import static org.junit.Assert.assertEquals;
 
 /**
@@ -30,8 +34,21 @@
  */
 public class TimeWindowStatisticsImplTest {
 
+    private static final int COLLISION_BUFFER_POWER = 3;
     private static final double DELTA = 0.0001;
 
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ServerProperties.COLLISION_BUFFER_POWER_JVM_ARG,
+                Integer.toString(COLLISION_BUFFER_POWER));
+    }
+
+    @Test
+    public void jvmLoaded() {
+        assertEquals(COLLISION_BUFFER_POWER, ReservoirConstants.COLLISION_BUFFER_POWER);
+        assertEquals(8, ReservoirConstants.COLLISION_BUFFER);
+    }
+
     @Test
     public void test() {
         final long now = System.currentTimeMillis();
@@ -173,30 +190,30 @@
         final TimeWindowStatisticsImpl.Builder<Long> builder = new TimeWindowStatisticsImpl.Builder<>(
                 new SlidingWindowTimeReservoir(1, TimeUnit.SECONDS, now, TimeUnit.MILLISECONDS));
         // put multiple requests at the beginning so that even the COLLISION_BUFFER bounds is tested
-        for (int i = 0; i < 256; ++i) {
+        for (int i = 0; i < ReservoirConstants.COLLISION_BUFFER; ++i) {
             builder.addRequest(now, 10L);
         }
         // add one more request which should be visible at 'now + 1001'
         builder.addRequest(now + 1, 10L);
 
         // put multiple requests in the middle of the window
-        for (int i = 0; i < 256; ++i) {
+        for (int i = 0; i < ReservoirConstants.COLLISION_BUFFER; ++i) {
             builder.addRequest(now + 500, 10L);
         }
-        check(builder, now + 500, 256 * 2 + 1, 10, 10, 10, 256 * 2 * 2 + 1 * 2);
+        check(builder, now + 500, ReservoirConstants.COLLISION_BUFFER * 2 + 1, 10, 10, 10, ReservoirConstants.COLLISION_BUFFER * 2 * 2 + 1 * 2);
 
         // put multiple requests at the end of the window
-        for (int i = 0; i < 256; ++i) {
+        for (int i = 0; i < ReservoirConstants.COLLISION_BUFFER; ++i) {
             builder.addRequest(now + 1000, 10L);
         }
 
-        check(builder, now + 1000, 256 * 3 + 1, 10, 10, 10, 256 * 3 + 1);
+        check(builder, now + 1000, ReservoirConstants.COLLISION_BUFFER * 3 + 1, 10, 10, 10, ReservoirConstants.COLLISION_BUFFER * 3 + 1);
 
         // at 'now + 1001' all the requests from 'now' should be gone
-        check(builder, now + 1001, 256 * 2 + 1, 10, 10, 10, 256 * 2 + 1);
+        check(builder, now + 1001, ReservoirConstants.COLLISION_BUFFER * 2 + 1, 10, 10, 10, ReservoirConstants.COLLISION_BUFFER * 2 + 1);
 
         // at 'now + 1002' the one additional request we added is gone
-        check(builder, now + 1002, 256 * 2, 10, 10, 10, 256 * 2);
+        check(builder, now + 1002, ReservoirConstants.COLLISION_BUFFER * 2, 10, 10, 10, ReservoirConstants.COLLISION_BUFFER * 2);
     }
 
     /**
diff --git a/core-server/src/test/resources/server.policy b/core-server/src/test/resources/server.policy
index e37eeda..a8c8303 100644
--- a/core-server/src/test/resources/server.policy
+++ b/core-server/src/test/resources/server.policy
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2019 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2021 Oracle and/or its affiliates. All rights reserved.
  *
  * This program and the accompanying materials are made available under the
  * terms of the Eclipse Public License v. 2.0, which is available at
@@ -60,6 +60,9 @@
   permission java.lang.RuntimePermission "accessClassInPackage.sun.misc.*";
   permission java.lang.RuntimePermission "accessClassInPackage.sun.reflect";
   permission java.lang.RuntimePermission "reflectionFactoryAccess";
+  
+  // Needed by TimeWindowStatisticsImplTest
+  permission java.util.PropertyPermission "jersey.config.server.monitoring.collision.buffer.power", "read,write";
 };
 
 grant codebase "file:${project.build.directory}/classes/-" {