< prev index next >

src/share/classes/sun/security/util/Cache.java

Print this page
rev 14405 : 8259886: Improve SSL session cache performance and scalability
Reviewed-by: erikj, xuelei
Contributed-by: djelinski <djelinski1@gmail.com>
   1 /*
   2  * Copyright (c) 2002, 2020, 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


 235     public void setTimeout(int timeout) {
 236         // empty
 237     }
 238 
 239     public void accept(CacheVisitor<K,V> visitor) {
 240         // empty
 241     }
 242 
 243 }
 244 
 245 class MemoryCache<K,V> extends Cache<K,V> {
 246 
 247     private final static float LOAD_FACTOR = 0.75f;
 248 
 249     // XXXX
 250     private final static boolean DEBUG = false;
 251 
 252     private final Map<K, CacheEntry<K,V>> cacheMap;
 253     private int maxSize;
 254     private long lifetime;

 255 
 256     // ReferenceQueue is of type V instead of Cache<K,V>
 257     // to allow SoftCacheEntry to extend SoftReference<V>
 258     private final ReferenceQueue<V> queue;
 259 
 260     public MemoryCache(boolean soft, int maxSize) {
 261         this(soft, maxSize, 0);
 262     }
 263 
 264     public MemoryCache(boolean soft, int maxSize, int lifetime) {
 265         this.maxSize = maxSize;
 266         this.lifetime = lifetime * 1000;
 267         if (soft)
 268             this.queue = new ReferenceQueue<>();
 269         else
 270             this.queue = null;
 271 
 272         cacheMap = new LinkedHashMap<>(1, LOAD_FACTOR, true);
 273     }
 274 


 304         }
 305         if (DEBUG) {
 306             int endSize = cacheMap.size();
 307             if (startSize != endSize) {
 308                 System.out.println("*** Expunged " + (startSize - endSize)
 309                         + " entries, " + endSize + " entries left");
 310             }
 311         }
 312     }
 313 
 314     /**
 315      * Scan all entries and remove all expired ones.
 316      */
 317     private void expungeExpiredEntries() {
 318         emptyQueue();
 319         if (lifetime == 0) {
 320             return;
 321         }
 322         int cnt = 0;
 323         long time = System.currentTimeMillis();




 324         for (Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
 325                 t.hasNext(); ) {
 326             CacheEntry<K,V> entry = t.next();
 327             if (entry.isValid(time) == false) {
 328                 t.remove();
 329                 cnt++;


 330             }
 331         }
 332         if (DEBUG) {
 333             if (cnt != 0) {
 334                 System.out.println("Removed " + cnt
 335                         + " expired entries, remaining " + cacheMap.size());
 336             }
 337         }
 338     }
 339 
 340     public synchronized int size() {
 341         expungeExpiredEntries();
 342         return cacheMap.size();
 343     }
 344 
 345     public synchronized void clear() {
 346         if (queue != null) {
 347             // if this is a SoftReference cache, first invalidate() all
 348             // entries so that GC does not have to enqueue them
 349             for (CacheEntry<K,V> entry : cacheMap.values()) {
 350                 entry.invalidate();
 351             }
 352             while (queue.poll() != null) {
 353                 // empty
 354             }
 355         }
 356         cacheMap.clear();
 357     }
 358 
 359     public synchronized void put(K key, V value) {
 360         emptyQueue();
 361         long expirationTime = (lifetime == 0) ? 0 :
 362                                         System.currentTimeMillis() + lifetime;



 363         CacheEntry<K,V> newEntry = newEntry(key, value, expirationTime, queue);
 364         CacheEntry<K,V> oldEntry = cacheMap.put(key, newEntry);
 365         if (oldEntry != null) {
 366             oldEntry.invalidate();
 367             return;
 368         }
 369         if (maxSize > 0 && cacheMap.size() > maxSize) {
 370             expungeExpiredEntries();
 371             if (cacheMap.size() > maxSize) { // still too large?
 372                 Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
 373                 CacheEntry<K,V> lruEntry = t.next();
 374                 if (DEBUG) {
 375                     System.out.println("** Overflow removal "
 376                         + lruEntry.getKey() + " | " + lruEntry.getValue());
 377                 }
 378                 t.remove();
 379                 lruEntry.invalidate();
 380             }
 381         }
 382     }


 457 
 458     protected CacheEntry<K,V> newEntry(K key, V value,
 459             long expirationTime, ReferenceQueue<V> queue) {
 460         if (queue != null) {
 461             return new SoftCacheEntry<>(key, value, expirationTime, queue);
 462         } else {
 463             return new HardCacheEntry<>(key, value, expirationTime);
 464         }
 465     }
 466 
 467     private static interface CacheEntry<K,V> {
 468 
 469         boolean isValid(long currentTime);
 470 
 471         void invalidate();
 472 
 473         K getKey();
 474 
 475         V getValue();
 476 

 477     }
 478 
 479     private static class HardCacheEntry<K,V> implements CacheEntry<K,V> {
 480 
 481         private K key;
 482         private V value;
 483         private long expirationTime;
 484 
 485         HardCacheEntry(K key, V value, long expirationTime) {
 486             this.key = key;
 487             this.value = value;
 488             this.expirationTime = expirationTime;
 489         }
 490 
 491         public K getKey() {
 492             return key;
 493         }
 494 
 495         public V getValue() {
 496             return value;
 497         }
 498 




 499         public boolean isValid(long currentTime) {
 500             boolean valid = (currentTime <= expirationTime);
 501             if (valid == false) {
 502                 invalidate();
 503             }
 504             return valid;
 505         }
 506 
 507         public void invalidate() {
 508             key = null;
 509             value = null;
 510             expirationTime = -1;
 511         }
 512     }
 513 
 514     private static class SoftCacheEntry<K,V>
 515             extends SoftReference<V>
 516             implements CacheEntry<K,V> {
 517 
 518         private K key;
 519         private long expirationTime;
 520 
 521         SoftCacheEntry(K key, V value, long expirationTime,
 522                 ReferenceQueue<V> queue) {
 523             super(value, queue);
 524             this.key = key;
 525             this.expirationTime = expirationTime;
 526         }
 527 
 528         public K getKey() {
 529             return key;
 530         }
 531 
 532         public V getValue() {
 533             return get();




 534         }
 535 
 536         public boolean isValid(long currentTime) {
 537             boolean valid = (currentTime <= expirationTime) && (get() != null);
 538             if (valid == false) {
 539                 invalidate();
 540             }
 541             return valid;
 542         }
 543 
 544         public void invalidate() {
 545             clear();
 546             key = null;
 547             expirationTime = -1;
 548         }
 549     }
 550 
 551 }
   1 /*
   2  * Copyright (c) 2002, 2021, 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


 235     public void setTimeout(int timeout) {
 236         // empty
 237     }
 238 
 239     public void accept(CacheVisitor<K,V> visitor) {
 240         // empty
 241     }
 242 
 243 }
 244 
 245 class MemoryCache<K,V> extends Cache<K,V> {
 246 
 247     private final static float LOAD_FACTOR = 0.75f;
 248 
 249     // XXXX
 250     private final static boolean DEBUG = false;
 251 
 252     private final Map<K, CacheEntry<K,V>> cacheMap;
 253     private int maxSize;
 254     private long lifetime;
 255     private long nextExpirationTime = Long.MAX_VALUE;
 256 
 257     // ReferenceQueue is of type V instead of Cache<K,V>
 258     // to allow SoftCacheEntry to extend SoftReference<V>
 259     private final ReferenceQueue<V> queue;
 260 
 261     public MemoryCache(boolean soft, int maxSize) {
 262         this(soft, maxSize, 0);
 263     }
 264 
 265     public MemoryCache(boolean soft, int maxSize, int lifetime) {
 266         this.maxSize = maxSize;
 267         this.lifetime = lifetime * 1000;
 268         if (soft)
 269             this.queue = new ReferenceQueue<>();
 270         else
 271             this.queue = null;
 272 
 273         cacheMap = new LinkedHashMap<>(1, LOAD_FACTOR, true);
 274     }
 275 


 305         }
 306         if (DEBUG) {
 307             int endSize = cacheMap.size();
 308             if (startSize != endSize) {
 309                 System.out.println("*** Expunged " + (startSize - endSize)
 310                         + " entries, " + endSize + " entries left");
 311             }
 312         }
 313     }
 314 
 315     /**
 316      * Scan all entries and remove all expired ones.
 317      */
 318     private void expungeExpiredEntries() {
 319         emptyQueue();
 320         if (lifetime == 0) {
 321             return;
 322         }
 323         int cnt = 0;
 324         long time = System.currentTimeMillis();
 325         if (nextExpirationTime > time) {
 326             return;
 327         }
 328         nextExpirationTime = Long.MAX_VALUE;
 329         for (Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
 330                 t.hasNext(); ) {
 331             CacheEntry<K,V> entry = t.next();
 332             if (entry.isValid(time) == false) {
 333                 t.remove();
 334                 cnt++;
 335             } else if (nextExpirationTime > entry.getExpirationTime()) {
 336                 nextExpirationTime = entry.getExpirationTime();
 337             }
 338         }
 339         if (DEBUG) {
 340             if (cnt != 0) {
 341                 System.out.println("Removed " + cnt
 342                         + " expired entries, remaining " + cacheMap.size());
 343             }
 344         }
 345     }
 346 
 347     public synchronized int size() {
 348         expungeExpiredEntries();
 349         return cacheMap.size();
 350     }
 351 
 352     public synchronized void clear() {
 353         if (queue != null) {
 354             // if this is a SoftReference cache, first invalidate() all
 355             // entries so that GC does not have to enqueue them
 356             for (CacheEntry<K,V> entry : cacheMap.values()) {
 357                 entry.invalidate();
 358             }
 359             while (queue.poll() != null) {
 360                 // empty
 361             }
 362         }
 363         cacheMap.clear();
 364     }
 365 
 366     public synchronized void put(K key, V value) {
 367         emptyQueue();
 368         long expirationTime = (lifetime == 0) ? 0 :
 369                                         System.currentTimeMillis() + lifetime;
 370         if (expirationTime < nextExpirationTime) {
 371             nextExpirationTime = expirationTime;
 372         }
 373         CacheEntry<K,V> newEntry = newEntry(key, value, expirationTime, queue);
 374         CacheEntry<K,V> oldEntry = cacheMap.put(key, newEntry);
 375         if (oldEntry != null) {
 376             oldEntry.invalidate();
 377             return;
 378         }
 379         if (maxSize > 0 && cacheMap.size() > maxSize) {
 380             expungeExpiredEntries();
 381             if (cacheMap.size() > maxSize) { // still too large?
 382                 Iterator<CacheEntry<K,V>> t = cacheMap.values().iterator();
 383                 CacheEntry<K,V> lruEntry = t.next();
 384                 if (DEBUG) {
 385                     System.out.println("** Overflow removal "
 386                         + lruEntry.getKey() + " | " + lruEntry.getValue());
 387                 }
 388                 t.remove();
 389                 lruEntry.invalidate();
 390             }
 391         }
 392     }


 467 
 468     protected CacheEntry<K,V> newEntry(K key, V value,
 469             long expirationTime, ReferenceQueue<V> queue) {
 470         if (queue != null) {
 471             return new SoftCacheEntry<>(key, value, expirationTime, queue);
 472         } else {
 473             return new HardCacheEntry<>(key, value, expirationTime);
 474         }
 475     }
 476 
 477     private static interface CacheEntry<K,V> {
 478 
 479         boolean isValid(long currentTime);
 480 
 481         void invalidate();
 482 
 483         K getKey();
 484 
 485         V getValue();
 486 
 487         long getExpirationTime();
 488     }
 489 
 490     private static class HardCacheEntry<K,V> implements CacheEntry<K,V> {
 491 
 492         private K key;
 493         private V value;
 494         private long expirationTime;
 495 
 496         HardCacheEntry(K key, V value, long expirationTime) {
 497             this.key = key;
 498             this.value = value;
 499             this.expirationTime = expirationTime;
 500         }
 501 
 502         public K getKey() {
 503             return key;
 504         }
 505 
 506         public V getValue() {
 507             return value;
 508         }
 509 
 510         public long getExpirationTime() {
 511             return expirationTime;
 512         }
 513 
 514         public boolean isValid(long currentTime) {
 515             boolean valid = (currentTime <= expirationTime);
 516             if (valid == false) {
 517                 invalidate();
 518             }
 519             return valid;
 520         }
 521 
 522         public void invalidate() {
 523             key = null;
 524             value = null;
 525             expirationTime = -1;
 526         }
 527     }
 528 
 529     private static class SoftCacheEntry<K,V>
 530             extends SoftReference<V>
 531             implements CacheEntry<K,V> {
 532 
 533         private K key;
 534         private long expirationTime;
 535 
 536         SoftCacheEntry(K key, V value, long expirationTime,
 537                 ReferenceQueue<V> queue) {
 538             super(value, queue);
 539             this.key = key;
 540             this.expirationTime = expirationTime;
 541         }
 542 
 543         public K getKey() {
 544             return key;
 545         }
 546 
 547         public V getValue() {
 548             return get();
 549         }
 550 
 551         public long getExpirationTime() {
 552             return expirationTime;
 553         }
 554 
 555         public boolean isValid(long currentTime) {
 556             boolean valid = (currentTime <= expirationTime) && (get() != null);
 557             if (valid == false) {
 558                 invalidate();
 559             }
 560             return valid;
 561         }
 562 
 563         public void invalidate() {
 564             clear();
 565             key = null;
 566             expirationTime = -1;
 567         }
 568     }
 569 
 570 }
< prev index next >