1
package com.eucalyptus.util;
3
import java.util.Collection;
4
import java.util.Comparator;
5
import java.util.Iterator;
6
import java.util.NavigableSet;
8
import java.util.SortedSet;
9
import java.util.concurrent.ConcurrentSkipListSet;
10
import java.util.concurrent.TimeUnit;
11
import java.util.concurrent.atomic.AtomicBoolean;
12
import org.apache.log4j.Logger;
14
public class TimedEvictionSet<E extends Comparable> implements Set<E> {
15
private static Logger LOG = Logger.getLogger( TimedEvictionSet.class );
16
private NavigableSet<E> entries = new ConcurrentSkipListSet<E>();
17
private NavigableSet<TimestampedElement> timestamps = new ConcurrentSkipListSet<TimestampedElement>();
18
private Long evictionMillis = 15*1000*60l;
19
private AtomicBoolean busy = new AtomicBoolean( false );
21
class TimestampedElement implements Comparable<TimestampedElement> {
23
private Long timeNanos;
24
public TimestampedElement( E element ) {
26
this.element = element;
27
this.timeNanos = System.nanoTime( );
30
public int hashCode( ) {
33
result = prime * result + ( ( this.element == null ) ? 0 : this.element.hashCode( ) );
34
result = prime * result + ( ( this.timeNanos == null ) ? 0 : this.timeNanos.hashCode( ) );
39
public boolean equals( Object obj ) {
40
if ( this == obj ) return true;
41
if ( obj == null ) return false;
42
if ( getClass( ) != obj.getClass( ) ) return false;
43
TimestampedElement other = ( TimestampedElement ) obj;
44
if ( this.element == null ) {
45
if ( other.element != null ) return false;
46
} else if ( !this.element.equals( other.element ) ) return false;
47
if ( this.timeNanos == null ) {
48
if ( other.timeNanos != null ) return false;
49
} else if ( !this.timeNanos.equals( other.timeNanos ) ) return false;
54
public int compareTo( TimestampedElement that ) {
55
if( !this.equals( that ) && this.timeNanos.compareTo( that.timeNanos ) == 0 ) {
56
return this.element.compareTo( that.element );
58
return this.timeNanos.compareTo( that.timeNanos );
61
public boolean isExpired( ) {
62
return System.nanoTime( ) > ( this.timeNanos + TimedEvictionSet.this.evictionMillis );
67
public Long getTimestamp( ) {
68
return this.timeNanos;
71
private boolean timestamp( E e ) {
73
if( this.entries.add( e ) ) {
74
TimestampedElement elem = new TimestampedElement( e );
75
this.timestamps.add( elem );
78
TimestampedElement elem = new TimestampedElement( e );
79
if( this.timestamps.contains( elem ) && TimeUnit.SECONDS.convert( System.nanoTime( ) - elem.getTimestamp( ), TimeUnit.NANOSECONDS ) < 2 ) {
86
public TimedEvictionSet( Long evictionMillis ) {
88
this.evictionMillis = evictionMillis;
91
private void scavenge() {
92
if( this.busy.compareAndSet( false, true ) ) {
94
TimestampedElement elem = null;
95
while( !this.timestamps.isEmpty( ) && this.timestamps.first( ).isExpired( ) && ( elem = this.timestamps.pollFirst( ) )!= null ) {
96
this.entries.remove( elem.get( ) );
97
LOG.debug( "Evicting previous entry: " + elem.get( ) + " " + elem.getTimestamp( ) );
100
this.busy.lazySet( false );
105
public boolean add( E e ) {
106
return timestamp( e );
110
public boolean addAll( Collection<? extends E> c ) {
114
public void clear( ) {
115
this.timestamps.clear( );
116
this.entries.clear( );
117
this.busy.set( false );
120
public Comparator<? super E> comparator( ) {
121
return this.entries.comparator( );
124
public boolean contains( Object o ) {
126
return this.entries.contains( o );
129
public boolean containsAll( Collection<?> c ) {
130
return this.entries.containsAll( c );
134
return this.entries.first( );
137
public SortedSet<E> headSet( E toElement ) {
138
return this.entries.headSet( toElement );
141
public boolean isEmpty( ) {
142
return this.entries.isEmpty( );
145
public Iterator<E> iterator( ) {
146
return this.entries.iterator( );
150
return this.entries.last( );
154
public boolean remove( Object o ) {
159
public boolean removeAll( Collection<?> c ) {
164
public boolean retainAll( Collection<?> c ) {
169
return this.entries.size( );
172
public SortedSet<E> subSet( E fromElement, E toElement ) {
173
return this.entries.subSet( fromElement, toElement );
176
public SortedSet<E> tailSet( E fromElement ) {
177
return this.entries.tailSet( fromElement );
180
public Object[] toArray( ) {
181
return this.entries.toArray( );
184
public <T> T[] toArray( T[] a ) {
185
return this.entries.toArray( a );