8259886: Improve SSL session cache performance and scalability

Reviewed-by: erikj, xuelei
This commit is contained in:
djelinski 2021-03-07 01:13:24 +00:00 committed by Xue-Lei Andrew Fan
parent 3844ce400d
commit 18fc35053c
3 changed files with 150 additions and 1 deletions

View file

@ -84,6 +84,7 @@ $(eval $(call SetupJavaCompilation, BUILD_INDIFY, \
#### Compile Targets
# Building microbenchmark requires the jdk.unsupported and java.management modules.
# sun.security.util is required to compile Cache benchmark
# Build microbenchmark suite for the current JDK
$(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
@ -93,6 +94,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \
DISABLED_WARNINGS := processing rawtypes cast serial, \
SRC := $(MICROBENCHMARK_SRC), \
BIN := $(MICROBENCHMARK_CLASSES), \
JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED, \
JAVA_FLAGS := --add-modules jdk.unsupported --limit-modules java.management, \
))

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -248,6 +248,7 @@ class MemoryCache<K,V> extends Cache<K,V> {
private final Map<K, CacheEntry<K,V>> cacheMap;
private int maxSize;
private long lifetime;
private long nextExpirationTime = Long.MAX_VALUE;
// ReferenceQueue is of type V instead of Cache<K,V>
// to allow SoftCacheEntry to extend SoftReference<V>
@ -317,12 +318,18 @@ class MemoryCache<K,V> extends Cache<K,V> {
}
int cnt = 0;
long time = System.currentTimeMillis();
if (nextExpirationTime > time) {
return;
}
nextExpirationTime = Long.MAX_VALUE;
for (Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
t.hasNext(); ) {
CacheEntry<K,V> entry = t.next();
if (entry.isValid(time) == false) {
t.remove();
cnt++;
} else if (nextExpirationTime > entry.getExpirationTime()) {
nextExpirationTime = entry.getExpirationTime();
}
}
if (DEBUG) {
@ -356,6 +363,9 @@ class MemoryCache<K,V> extends Cache<K,V> {
emptyQueue();
long expirationTime = (lifetime == 0) ? 0 :
System.currentTimeMillis() + lifetime;
if (expirationTime < nextExpirationTime) {
nextExpirationTime = expirationTime;
}
CacheEntry<K,V> newEntry = newEntry(key, value, expirationTime, queue);
CacheEntry<K,V> oldEntry = cacheMap.put(key, newEntry);
if (oldEntry != null) {
@ -470,6 +480,7 @@ class MemoryCache<K,V> extends Cache<K,V> {
V getValue();
long getExpirationTime();
}
private static class HardCacheEntry<K,V> implements CacheEntry<K,V> {
@ -492,6 +503,10 @@ class MemoryCache<K,V> extends Cache<K,V> {
return value;
}
public long getExpirationTime() {
return expirationTime;
}
public boolean isValid(long currentTime) {
boolean valid = (currentTime <= expirationTime);
if (valid == false) {
@ -529,6 +544,10 @@ class MemoryCache<K,V> extends Cache<K,V> {
return get();
}
public long getExpirationTime() {
return expirationTime;
}
public boolean isValid(long currentTime) {
boolean valid = (currentTime <= expirationTime) && (get() != null);
if (valid == false) {

View file

@ -0,0 +1,128 @@
/*
* Copyright (c) 2021, Dynatrace LLC. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package org.openjdk.bench.java.security;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Param;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
import sun.security.util.Cache;
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Fork(jvmArgsAppend = {"--add-exports", "java.base/sun.security.util=ALL-UNNAMED", "-Xmx1g"})
public class CacheBench {
@State(Scope.Benchmark)
public static class SharedState {
Cache<Integer, Integer> cache;
@Param({"20480", "204800", "5120000"})
int size;
@Param({"86400", "0"})
int timeout;
@Setup
public void setup() {
cache = Cache.newSoftMemoryCache(size, timeout);
IntStream.range(0, size).boxed().forEach(i -> cache.put(i, i));
}
}
@State(Scope.Thread)
public static class GetPutState {
Integer[] intArray;
int index;
@Setup
public void setup(SharedState benchState) {
intArray = IntStream.range(0, benchState.size + 1).boxed().toArray(Integer[]::new);
index = 0;
}
@TearDown(Level.Invocation)
public void tearDown() {
index++;
if (index >= intArray.length) {
index = 0;
}
}
}
@Benchmark
public void put(SharedState benchState, GetPutState state) {
Integer i = state.intArray[state.index];
benchState.cache.put(i, i);
}
@Benchmark
public Integer get(SharedState benchState, GetPutState state) {
Integer i = state.intArray[state.index];
return benchState.cache.get(i);
}
@State(Scope.Thread)
public static class RemoveState {
Integer[] intArray;
int index;
SharedState benchState;
@Setup
public void setup(SharedState benchState) {
this.benchState = benchState;
intArray = IntStream.range(0, benchState.size).boxed().toArray(Integer[]::new);
index = 0;
}
@TearDown(Level.Invocation)
public void tearDown() {
// add back removed item
Integer i = intArray[index];
benchState.cache.put(i, i);
index++;
if (index >= intArray.length) {
index = 0;
}
}
}
@Benchmark
public void remove(SharedState benchState, RemoveState state) {
Integer i = state.intArray[state.index];
benchState.cache.remove(i);
}
}