< prev index next >

src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/AuthList.java

Print this page
rev 48936 : 8197518: Kerberos krb5 authentication: AuthList's put method leads to performance issue
   1 /*
   2  * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


  38 import java.util.ListIterator;
  39 import sun.security.krb5.internal.KerberosTime;
  40 import sun.security.krb5.internal.KrbApErrException;
  41 
  42 /**
  43  * This class provides an efficient caching mechanism to store AuthTimeWithHash
  44  * from client authenticators. The cache minimizes the memory usage by doing
  45  * self-cleanup of expired items in the cache.
  46  *
  47  * AuthTimeWithHash objects inside a cache are always sorted from big (new) to
  48  * small (old) as determined by {@link AuthTimeWithHash#compareTo}. In the most
  49  * common case a newcomer should be newer than the first element.
  50  *
  51  * @author Yanni Zhang
  52  */
  53 public class AuthList {
  54 
  55     private final LinkedList<AuthTimeWithHash> entries;
  56     private final int lifespan;
  57 



  58     /**
  59      * Constructs a AuthList.
  60      */
  61     public AuthList(int lifespan) {
  62         this.lifespan = lifespan;
  63         entries = new LinkedList<>();
  64     }
  65 
  66     /**
  67      * Puts the authenticator timestamp into the cache in descending order,
  68      * and throw an exception if it's already there.
  69      */
  70     public void put(AuthTimeWithHash t, KerberosTime currentTime)
  71             throws KrbApErrException {
  72 
  73         if (entries.isEmpty()) {
  74             entries.addFirst(t);


  75         } else {
  76             AuthTimeWithHash temp = entries.getFirst();
  77             int cmp = temp.compareTo(t);
  78             if (cmp < 0) {
  79                 // This is the most common case, newly received authenticator
  80                 // has larger timestamp.
  81                 entries.addFirst(t);
  82             } else if (cmp == 0) {
  83                 throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);
  84             } else {
  85                 //unless client clock being re-adjusted.
  86                 ListIterator<AuthTimeWithHash> it = entries.listIterator(1);
  87                 boolean found = false;
  88                 while (it.hasNext()) {
  89                     temp = it.next();
  90                     cmp = temp.compareTo(t);
  91                     if (cmp < 0) {
  92                         // Find an older one, put in front of it
  93                         entries.add(entries.indexOf(temp), t);
  94                         found = true;
  95                         break;
  96                     } else if (cmp == 0) {
  97                         throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);
  98                     }
  99                 }
 100                 if (!found) {
 101                     // All is newer than the newcomer. Sigh.
 102                     entries.addLast(t);
 103                 }
 104             }
 105         }
 106 
 107         // let us cleanup while we are here
 108         long timeLimit = currentTime.getSeconds() - lifespan;
 109         ListIterator<AuthTimeWithHash> it = entries.listIterator(0);
 110         AuthTimeWithHash temp = null;
 111         int index = -1;
 112         while (it.hasNext()) {
 113             // search expired timestamps.
 114             temp = it.next();
 115             if (temp.ctime < timeLimit) {
 116                 index = entries.indexOf(temp);
 117                 break;
 118             }








 119         }
 120         // It would be nice if LinkedList has a method called truncate(index).
 121         if (index > -1) {
 122             do {
 123                 // remove expired timestamps from the list.
 124                 entries.removeLast();
 125             } while(entries.size() > index);
 126         }


 127     }
 128 
 129     public boolean isEmpty() {
 130         return entries.isEmpty();
 131     }
 132 
 133     public String toString() {
 134         StringBuilder sb = new StringBuilder();
 135         Iterator<AuthTimeWithHash> iter = entries.descendingIterator();
 136         int pos = entries.size();
 137         while (iter.hasNext()) {
 138             AuthTimeWithHash at = iter.next();
 139             sb.append('#').append(pos--).append(": ")
 140                     .append(at.toString()).append('\n');
 141         }
 142         return sb.toString();
 143     }
 144 }
   1 /*
   2  * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


  38 import java.util.ListIterator;
  39 import sun.security.krb5.internal.KerberosTime;
  40 import sun.security.krb5.internal.KrbApErrException;
  41 
  42 /**
  43  * This class provides an efficient caching mechanism to store AuthTimeWithHash
  44  * from client authenticators. The cache minimizes the memory usage by doing
  45  * self-cleanup of expired items in the cache.
  46  *
  47  * AuthTimeWithHash objects inside a cache are always sorted from big (new) to
  48  * small (old) as determined by {@link AuthTimeWithHash#compareTo}. In the most
  49  * common case a newcomer should be newer than the first element.
  50  *
  51  * @author Yanni Zhang
  52  */
  53 public class AuthList {
  54 
  55     private final LinkedList<AuthTimeWithHash> entries;
  56     private final int lifespan;
  57 
  58     // entries.getLast().ctime, updated after each cleanup.
  59     private volatile int oldestTime = Integer.MIN_VALUE;
  60 
  61     /**
  62      * Constructs a AuthList.
  63      */
  64     public AuthList(int lifespan) {
  65         this.lifespan = lifespan;
  66         entries = new LinkedList<>();
  67     }
  68 
  69     /**
  70      * Puts the authenticator timestamp into the cache in descending order,
  71      * and throw an exception if it's already there.
  72      */
  73     public synchronized void put(AuthTimeWithHash t, KerberosTime currentTime)
  74             throws KrbApErrException {
  75 
  76         if (entries.isEmpty()) {
  77             entries.addFirst(t);
  78             oldestTime = t.ctime;
  79             return;
  80         } else {
  81             AuthTimeWithHash temp = entries.getFirst();
  82             int cmp = temp.compareTo(t);
  83             if (cmp < 0) {
  84                 // This is the most common case, newly received authenticator
  85                 // has larger timestamp.
  86                 entries.addFirst(t);
  87             } else if (cmp == 0) {
  88                 throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);
  89             } else {
  90                 //unless client clock being re-adjusted.
  91                 ListIterator<AuthTimeWithHash> it = entries.listIterator(1);
  92                 boolean found = false;
  93                 while (it.hasNext()) {
  94                     temp = it.next();
  95                     cmp = temp.compareTo(t);
  96                     if (cmp < 0) {
  97                         // Find an older one, put in front of it
  98                         entries.add(entries.indexOf(temp), t);
  99                         found = true;
 100                         break;
 101                     } else if (cmp == 0) {
 102                         throw new KrbApErrException(Krb5.KRB_AP_ERR_REPEAT);
 103                     }
 104                 }
 105                 if (!found) {
 106                     // All is newer than the newcomer. Sigh.
 107                     entries.addLast(t);
 108                 }
 109             }
 110         }
 111 
 112         // let us cleanup while we are here
 113         long timeLimit = currentTime.getSeconds() - lifespan;
 114 
 115         // Only trigger a cleanup when the earliest entry is
 116         // lifespan + 5 sec ago. This ensures a cleanup is done
 117         // at most every 5 seconds so that we don't always
 118         // addLast(removeLast).
 119         if (oldestTime > timeLimit - 5) {
 120             return;


 121         }
 122 
 123         // and we remove the *enough* old ones (1 lifetime ago)
 124         while (!entries.isEmpty()) {
 125             AuthTimeWithHash removed = entries.removeLast();
 126             if (removed.ctime >= timeLimit) {
 127                 entries.addLast(removed);
 128                 oldestTime = removed.ctime;
 129                 return;
 130             }






 131         }
 132 
 133         oldestTime = Integer.MIN_VALUE;
 134     }
 135 
 136     public boolean isEmpty() {
 137         return entries.isEmpty();
 138     }
 139 
 140     public String toString() {
 141         StringBuilder sb = new StringBuilder();
 142         Iterator<AuthTimeWithHash> iter = entries.descendingIterator();
 143         int pos = entries.size();
 144         while (iter.hasNext()) {
 145             AuthTimeWithHash at = iter.next();
 146             sb.append('#').append(pos--).append(": ")
 147                     .append(at.toString()).append('\n');
 148         }
 149         return sb.toString();
 150     }
 151 }
< prev index next >