提交 112c0916 编写于 作者: W weijun

8197518: Kerberos krb5 authentication: AuthList's put method leads to performance issue

Reviewed-by: coffeys, xuelei
上级 9c85f5e0
/* /*
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -55,6 +55,9 @@ public class AuthList { ...@@ -55,6 +55,9 @@ public class AuthList {
private final LinkedList<AuthTimeWithHash> entries; private final LinkedList<AuthTimeWithHash> entries;
private final int lifespan; private final int lifespan;
// entries.getLast().ctime, updated after each cleanup.
private volatile int oldestTime = Integer.MIN_VALUE;
/** /**
* Constructs a AuthList. * Constructs a AuthList.
*/ */
...@@ -67,11 +70,13 @@ public class AuthList { ...@@ -67,11 +70,13 @@ public class AuthList {
* Puts the authenticator timestamp into the cache in descending order, * Puts the authenticator timestamp into the cache in descending order,
* and throw an exception if it's already there. * and throw an exception if it's already there.
*/ */
public void put(AuthTimeWithHash t, KerberosTime currentTime) public synchronized void put(AuthTimeWithHash t, KerberosTime currentTime)
throws KrbApErrException { throws KrbApErrException {
if (entries.isEmpty()) { if (entries.isEmpty()) {
entries.addFirst(t); entries.addFirst(t);
oldestTime = t.ctime;
return;
} else { } else {
AuthTimeWithHash temp = entries.getFirst(); AuthTimeWithHash temp = entries.getFirst();
int cmp = temp.compareTo(t); int cmp = temp.compareTo(t);
...@@ -106,24 +111,26 @@ public class AuthList { ...@@ -106,24 +111,26 @@ public class AuthList {
// let us cleanup while we are here // let us cleanup while we are here
long timeLimit = currentTime.getSeconds() - lifespan; long timeLimit = currentTime.getSeconds() - lifespan;
ListIterator<AuthTimeWithHash> it = entries.listIterator(0);
AuthTimeWithHash temp = null; // Only trigger a cleanup when the earliest entry is
int index = -1; // lifespan + 5 sec ago. This ensures a cleanup is done
while (it.hasNext()) { // at most every 5 seconds so that we don't always
// search expired timestamps. // addLast(removeLast).
temp = it.next(); if (oldestTime > timeLimit - 5) {
if (temp.ctime < timeLimit) { return;
index = entries.indexOf(temp);
break;
}
} }
// It would be nice if LinkedList has a method called truncate(index).
if (index > -1) { // and we remove the *enough* old ones (1 lifetime ago)
do { while (!entries.isEmpty()) {
// remove expired timestamps from the list. AuthTimeWithHash removed = entries.removeLast();
entries.removeLast(); if (removed.ctime >= timeLimit) {
} while(entries.size() > index); entries.addLast(removed);
oldestTime = removed.ctime;
return;
}
} }
oldestTime = Integer.MIN_VALUE;
} }
public boolean isEmpty() { public boolean isEmpty() {
......
/* /*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -31,7 +31,9 @@ ...@@ -31,7 +31,9 @@
package sun.security.krb5.internal.rcache; package sun.security.krb5.internal.rcache;
import java.util.*; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import sun.security.krb5.internal.KerberosTime; import sun.security.krb5.internal.KerberosTime;
import sun.security.krb5.internal.KrbApErrException; import sun.security.krb5.internal.KrbApErrException;
import sun.security.krb5.internal.ReplayCache; import sun.security.krb5.internal.ReplayCache;
...@@ -48,31 +50,18 @@ public class MemoryCache extends ReplayCache { ...@@ -48,31 +50,18 @@ public class MemoryCache extends ReplayCache {
private static final int lifespan = KerberosTime.getDefaultSkew(); private static final int lifespan = KerberosTime.getDefaultSkew();
private static final boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG; private static final boolean DEBUG = sun.security.krb5.internal.Krb5.DEBUG;
private final Map<String,AuthList> content = new HashMap<>(); private final Map<String,AuthList> content = new ConcurrentHashMap<>();
@Override @Override
public synchronized void checkAndStore(KerberosTime currTime, AuthTimeWithHash time) public synchronized void checkAndStore(KerberosTime currTime, AuthTimeWithHash time)
throws KrbApErrException { throws KrbApErrException {
String key = time.client + "|" + time.server; String key = time.client + "|" + time.server;
AuthList rc = content.get(key); content.computeIfAbsent(key, k -> new AuthList(lifespan))
.put(time, currTime);
if (DEBUG) { if (DEBUG) {
System.out.println("MemoryCache: add " + time + " to " + key); System.out.println("MemoryCache: add " + time + " to " + key);
} }
if (rc == null) { // TODO: clean up AuthList entries with only expired AuthTimeWithHash objects.
rc = new AuthList(lifespan);
rc.put(time, currTime);
if (!rc.isEmpty()) {
content.put(key, rc);
}
} else {
if (DEBUG) {
System.out.println("MemoryCache: Existing AuthList:\n" + rc);
}
rc.put(time, currTime);
if (rc.isEmpty()) {
content.remove(key);
}
}
} }
public String toString() { public String toString() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册