Colm,

On trunk where we've dropped support for Java 5, we could likely use a 
ConcurrentSkipListSet and Map instead of the synchronized collections.   Just a 
thought.  :-)

Dan





On Mar 12, 2013, at 10:53 AM, [email protected] wrote:

> Author: coheigea
> Date: Tue Mar 12 14:53:01 2013
> New Revision: 1455564
> 
> URL: http://svn.apache.org/r1455564
> Log:
> [WSS-431] - Performance bottleneck in MemoryReplayCache on high load
> - Patch applied, thanks!
> 
> 
> Conflicts:
>       
> ws-security-dom/src/main/java/org/apache/wss4j/dom/cache/MemoryReplayCache.java
> 
> Modified:
>    
> webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/cache/MemoryReplayCache.java
> 
> Modified: 
> webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/cache/MemoryReplayCache.java
> URL: 
> http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/cache/MemoryReplayCache.java?rev=1455564&r1=1455563&r2=1455564&view=diff
> ==============================================================================
> --- 
> webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/cache/MemoryReplayCache.java
>  (original)
> +++ 
> webservices/wss4j/trunk/ws-security-dom/src/main/java/org/apache/wss4j/dom/cache/MemoryReplayCache.java
>  Tue Mar 12 14:53:01 2013
> @@ -19,11 +19,16 @@
> 
> package org.apache.wss4j.dom.cache;
> 
> +import java.util.ArrayList;
> import java.util.Collections;
> import java.util.Date;
> import java.util.HashSet;
> import java.util.Iterator;
> +import java.util.List;
> +import java.util.Map.Entry;
> import java.util.Set;
> +import java.util.SortedMap;
> +import java.util.TreeMap;
> 
> /**
>  * A simple in-memory HashSet based cache to prevent against replay attacks. 
> The default TTL is 5 minutes
> @@ -33,8 +38,8 @@ public class MemoryReplayCache implement
> 
>     public static final long DEFAULT_TTL = 60L * 5L;
>     public static final long MAX_TTL = DEFAULT_TTL * 12L;
> -    private final Set<ReplayCacheIdentifier> cache =
> -        Collections.synchronizedSet(new HashSet<ReplayCacheIdentifier>());
> +    private SortedMap<Date, List<String>> cache = new TreeMap<Date, 
> List<String>>();
> +    private Set<String> ids = Collections.synchronizedSet(new 
> HashSet<String>());
> 
>     /**
>      * Add the given identifier to the cache. It will be cached for a default 
> amount of time.
> @@ -53,8 +58,6 @@ public class MemoryReplayCache implement
>         if (identifier == null || "".equals(identifier)) {
>             return;
>         }
> -        ReplayCacheIdentifier cacheIdentifier = new ReplayCacheIdentifier();
> -        cacheIdentifier.setIdentifier(identifier);
> 
>         long ttl = timeToLive;
>         if (ttl < 0 || ttl > MAX_TTL) {
> @@ -64,9 +67,16 @@ public class MemoryReplayCache implement
>         Date expires = new Date();
>         long currentTime = expires.getTime();
>         expires.setTime(currentTime + (ttl * 1000L));
> -        cacheIdentifier.setExpiry(expires);
> 
> -        cache.add(cacheIdentifier);
> +        synchronized (cache) {
> +            List<String> list = cache.get(expires);
> +            if (list == null) {
> +                list = new ArrayList<String>(1);
> +                cache.put(expires, list);
> +            }
> +            list.add(identifier);
> +        }
> +        ids.add(identifier);
>     }
> 
>     /**
> @@ -77,9 +87,7 @@ public class MemoryReplayCache implement
>         processTokenExpiry();
> 
>         if (identifier != null && !"".equals(identifier)) {
> -            ReplayCacheIdentifier cacheIdentifier = new 
> ReplayCacheIdentifier();
> -            cacheIdentifier.setIdentifier(identifier);
> -            return cache.contains(cacheIdentifier);
> +            return ids.contains(identifier);
>         }
>         return false;
>     }
> @@ -87,68 +95,18 @@ public class MemoryReplayCache implement
>     protected void processTokenExpiry() {
>         Date current = new Date();
>         synchronized (cache) {
> -            Iterator<ReplayCacheIdentifier> iterator = cache.iterator();
> -            while (iterator.hasNext()) {
> -                if (iterator.next().getExpiry().before(current)) {
> -                    iterator.remove();
> +            Iterator<Entry<Date, List<String>>> it = 
> cache.entrySet().iterator();
> +            while (it.hasNext()) {
> +                Entry<Date, List<String>> entry = it.next();
> +                if (entry.getKey().before(current)) {
> +                    for (String id : entry.getValue()) {
> +                        ids.remove(id);
> +                    }
> +                    it.remove();
> +                } else {
> +                    break;
>                 }
>             }
>         }
>     }
> -    
> -    private static class ReplayCacheIdentifier {
> -        
> -        private String identifier;
> -        private Date expires;
> -        
> -        /**
> -         * Set the (String) identifier
> -         * @param identifier the (String) identifier
> -         */
> -        public void setIdentifier(String identifier) {
> -            this.identifier = identifier;
> -        }
> -        
> -        /**
> -         * Set when this identifier is to be removed from the cache
> -         * @param expires when this identifier is to be removed from the 
> cache
> -         */
> -        public void setExpiry(Date expires) {
> -            this.expires = expires;
> -        }
> -        
> -        /**
> -         * Get when this identifier is to be removed from the cache
> -         * @return when this identifier is to be removed from the cache
> -         */
> -        public Date getExpiry() {
> -            return expires;
> -        }
> -        
> -        @Override
> -        public boolean equals(Object o) {
> -            if (this == o) {
> -                return true;
> -            }
> -            if (!(o instanceof ReplayCacheIdentifier)) {
> -                return false;
> -            }
> -            
> -            ReplayCacheIdentifier replayCacheIdentifier = 
> (ReplayCacheIdentifier)o;
> -            
> -            if (identifier == null && replayCacheIdentifier.identifier != 
> null) {
> -                return false;
> -            } else if (identifier != null && 
> !identifier.equals(replayCacheIdentifier.identifier)) {
> -                return false;
> -            }
> -            
> -            return true;
> -        }
> -        
> -        @Override
> -        public int hashCode() {
> -            return identifier != null ? identifier.hashCode() : 0;
> -        }
> -    }
> -
> }
> 
> 

-- 
Daniel Kulp
[email protected] - http://dankulp.com/blog
Talend Community Coder - http://coders.talend.com


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to