Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8259886: Improve SSL session cache performance and scalability
Reviewed-by: erikj, xuelei
  • Loading branch information
djelinski authored and XueleiFan committed Mar 7, 2021
1 parent 3844ce4 commit 18fc35053c2363686d6ecae44ff2d4cce791eef8
Showing with 150 additions and 1 deletion.
  1. +2 −0 make/test/BuildMicrobenchmark.gmk
  2. +20 −1 src/java.base/share/classes/sun/security/util/Cache.java
  3. +128 −0 test/micro/org/openjdk/bench/java/security/CacheBench.java
@@ -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, \
))

@@ -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 @@ public void accept(CacheVisitor<K,V> visitor) {
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 @@ private void expungeExpiredEntries() {
}
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 @@ public synchronized void put(K key, V value) {
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 @@ protected CacheEntry<K,V> newEntry(K key, V value,

V getValue();

long getExpirationTime();
}

private static class HardCacheEntry<K,V> implements CacheEntry<K,V> {
@@ -492,6 +503,10 @@ public V getValue() {
return value;
}

public long getExpirationTime() {
return expirationTime;
}

public boolean isValid(long currentTime) {
boolean valid = (currentTime <= expirationTime);
if (valid == false) {
@@ -529,6 +544,10 @@ public V getValue() {
return get();
}

public long getExpirationTime() {
return expirationTime;
}

public boolean isValid(long currentTime) {
boolean valid = (currentTime <= expirationTime) && (get() != null);
if (valid == false) {
@@ -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);
}
}

0 comments on commit 18fc350

Please sign in to comment.