--- old/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthList.java 2018-02-23 09:48:44.000000000 +0800 +++ new/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthList.java 2018-02-23 09:48:44.000000000 +0800 @@ -1,5 +1,5 @@ /* - * 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. * * This code is free software; you can redistribute it and/or modify it @@ -55,6 +55,9 @@ private final LinkedList entries; private final int lifespan; + // entries.getLast().ctime, updated after each cleanup. + private volatile int oldestTime = Integer.MIN_VALUE; + /** * Constructs a AuthList. */ @@ -72,6 +75,8 @@ if (entries.isEmpty()) { entries.addFirst(t); + oldestTime = t.ctime; + return; } else { AuthTimeWithHash temp = entries.getFirst(); int cmp = temp.compareTo(t); @@ -106,24 +111,34 @@ // let us cleanup while we are here long timeLimit = currentTime.getSeconds() - lifespan; + long veryOld = timeLimit - (lifespan > 60 ? 60 : lifespan); + + // Only trigger a cleanup when very old entries exist + // (lifespan + 1 min ago). This ensures a cleanup is done + // at most every minute. + if (oldestTime > veryOld) { + return; + } + + // and we remove the *enough* old ones (1 lifetime ago) ListIterator it = entries.listIterator(0); - AuthTimeWithHash temp = null; - int index = -1; + AuthTimeWithHash temp; while (it.hasNext()) { // search expired timestamps. temp = it.next(); if (temp.ctime < timeLimit) { - index = entries.indexOf(temp); + // It would be nice if ListIterator has a method called stripHere() + while (!entries.isEmpty()) { + if (entries.removeLast() == temp) { + break; + } + } break; } } - // It would be nice if LinkedList has a method called truncate(index). - if (index > -1) { - do { - // remove expired timestamps from the list. - entries.removeLast(); - } while(entries.size() > index); - } + + AuthTimeWithHash last = entries.peekLast(); + oldestTime = last == null ? Integer.MIN_VALUE : last.ctime; } public boolean isEmpty() {