Skip to content

Commit

Permalink
Use AtomicReferenceFieldUpdater as it works better for large numbers …
Browse files Browse the repository at this point in the history
…of instances (#46)

* Rename variables to clarify these are snapshots
* Use AtomicReferenceFieldUpdater in RankedSequence as it works better for large numbers of instances
* Use AtomicReferenceFieldUpdater in BeanCache as it works better for large numbers of instances
  • Loading branch information
mcculls authored Jan 24, 2022
1 parent c265d29 commit a77b0c0
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 43 deletions.
20 changes: 12 additions & 8 deletions org.eclipse.sisu.inject/src/org/eclipse/sisu/inject/BeanCache.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import org.eclipse.sisu.BeanEntry;

Expand All @@ -28,18 +28,22 @@
*/
@SuppressWarnings( { "rawtypes", "unchecked" } )
final class BeanCache<Q extends Annotation, T>
extends AtomicReference<Object>
{
// ----------------------------------------------------------------------
// Constants
// ----------------------------------------------------------------------

private static final long serialVersionUID = 1L;

private static final AtomicReferenceFieldUpdater<BeanCache, Object> MAPPING_UPDATER =
AtomicReferenceFieldUpdater.newUpdater( BeanCache.class, Object.class, "mapping" );

// ----------------------------------------------------------------------
// Implementation fields
// ----------------------------------------------------------------------

private volatile Object mapping;

private Map<Binding<T>, BeanEntry<Q, T>> readCache;

private volatile boolean mutated;
Expand Down Expand Up @@ -67,7 +71,7 @@ public BeanEntry<Q, T> create( final Q qualifier, final Binding<T> binding, fina
*/
do
{
o = get();
o = mapping;
if ( null == o )
{
// most common case: adding the one (and-only) entry
Expand Down Expand Up @@ -96,7 +100,7 @@ else if ( o instanceof LazyBeanEntry )
}
}
}
while ( !compareAndSet( o, n ) );
while ( !MAPPING_UPDATER.compareAndSet( this, o, n ) );

if ( n instanceof IdentityHashMap )
{
Expand All @@ -117,7 +121,7 @@ public Map<Binding<T>, BeanEntry<Q, T>> flush()
{
if ( mutated )
{
readCache = (Map) ( (IdentityHashMap) get() ).clone();
readCache = (Map) ( (IdentityHashMap) mapping ).clone();
mutated = false;
}
}
Expand All @@ -132,7 +136,7 @@ public Map<Binding<T>, BeanEntry<Q, T>> flush()
*/
public Iterable<Binding<T>> bindings()
{
final Object o = get();
final Object o = mapping;
if ( null == o )
{
return Collections.EMPTY_SET;
Expand Down Expand Up @@ -164,7 +168,7 @@ public BeanEntry<Q, T> remove( final Binding<T> binding )
*/
do
{
o = get();
o = mapping;
if ( null == o )
{
return null;
Expand All @@ -191,7 +195,7 @@ else if ( o instanceof LazyBeanEntry )
}
}
}
while ( !compareAndSet( o, n ) );
while ( !MAPPING_UPDATER.compareAndSet( this, o, n ) );

return oldBean;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
* Ordered {@link List} that arranges elements by descending rank; supports concurrent iteration and modification.
*/
final class RankedSequence<T>
extends AtomicReference<RankedSequence.Content>
implements Iterable<T>
{
// ----------------------------------------------------------------------
Expand All @@ -30,6 +29,16 @@ final class RankedSequence<T>

private static final long serialVersionUID = 1L;

@SuppressWarnings( "rawtypes" )
private static final AtomicReferenceFieldUpdater<RankedSequence, Content> CONTENT_UPDATER =
AtomicReferenceFieldUpdater.newUpdater( RankedSequence.class, Content.class, "content" );

// ----------------------------------------------------------------------
// Implementation fields
// ----------------------------------------------------------------------

volatile Content content;

// ----------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------
Expand All @@ -43,7 +52,7 @@ final class RankedSequence<T>
{
if ( null != sequence )
{
set( sequence.get() );
content = sequence.content;
}
}

Expand All @@ -64,28 +73,28 @@ public void insert( final T element, final int rank )
Content o, n;
do
{
n = null != ( o = get() ) ? o.insert( element, rank ) : new Content( element, rank );
n = null != ( o = content ) ? o.insert( element, rank ) : new Content( element, rank );
}
while ( !compareAndSet( o, n ) );
while ( !CONTENT_UPDATER.compareAndSet( this, o, n ) );
}

@SuppressWarnings( "unchecked" )
public T peek()
{
final Content content = get();
return null != content ? (T) content.objs[0] : null;
final Content snapshot = content;
return null != snapshot ? (T) snapshot.objs[0] : null;
}

public boolean contains( final Object element )
{
final Content content = get();
return null != content && content.indexOf( element ) >= 0;
final Content snapshot = content;
return null != snapshot && snapshot.indexOf( element ) >= 0;
}

public boolean containsThis( final Object element )
{
final Content content = get();
return null != content && content.indexOfThis( element ) >= 0;
final Content snapshot = content;
return null != snapshot && snapshot.indexOfThis( element ) >= 0;
}

@SuppressWarnings( "unchecked" )
Expand All @@ -95,13 +104,13 @@ public T remove( final Object element )
int index;
do
{
if ( null == ( o = get() ) || ( index = o.indexOf( element ) ) < 0 )
if ( null == ( o = content ) || ( index = o.indexOf( element ) ) < 0 )
{
return null;
}
n = o.remove( index );
}
while ( !compareAndSet( o, n ) );
while ( !CONTENT_UPDATER.compareAndSet( this, o, n ) );

return (T) o.objs[index];
}
Expand All @@ -112,38 +121,38 @@ public boolean removeThis( final T element )
do
{
final int index;
if ( null == ( o = get() ) || ( index = o.indexOfThis( element ) ) < 0 )
if ( null == ( o = content ) || ( index = o.indexOfThis( element ) ) < 0 )
{
return false;
}
n = o.remove( index );
}
while ( !compareAndSet( o, n ) );
while ( !CONTENT_UPDATER.compareAndSet( this, o, n ) );

return true;
}

@SuppressWarnings( { "rawtypes", "unchecked" } )
public Iterable<T> snapshot()
{
final Content content = get();
return null != content ? (List) Arrays.asList( content.objs ) : Collections.EMPTY_SET;
final Content snapshot = content;
return null != snapshot ? (List) Arrays.asList( snapshot.objs ) : Collections.EMPTY_SET;
}

public void clear()
{
set( null );
content = null;
}

public boolean isEmpty()
{
return null == get();
return null == content;
}

public int size()
{
final Content content = get();
return null != content ? content.objs.length : 0;
final Content snapshot = content;
return null != snapshot ? snapshot.objs.length : 0;
}

public Itr iterator()
Expand Down Expand Up @@ -349,7 +358,7 @@ final class Itr
// Implementation fields
// ----------------------------------------------------------------------

private Content content;
private Content snapshot;

private T nextObj;

Expand All @@ -368,16 +377,16 @@ public boolean hasNext()
{
return true;
}
final Content newContent = get();
if ( content != newContent )
final Content newSnapshot = content;
if ( snapshot != newSnapshot )
{
index = null != newContent ? safeBinarySearch( newContent.uids, nextUID ) : -1;
content = newContent;
index = null != newSnapshot ? safeBinarySearch( newSnapshot.uids, nextUID ) : -1;
snapshot = newSnapshot;
}
if ( index >= 0 && index < content.objs.length )
if ( index >= 0 && index < snapshot.objs.length )
{
nextObj = (T) content.objs[index];
nextUID = content.uids[index];
nextObj = (T) snapshot.objs[index];
nextUID = snapshot.uids[index];
return true;
}
return false;
Expand All @@ -392,15 +401,15 @@ public boolean hasNext( final int rank )
{
return uid2rank( nextUID ) >= rank;
}
final Content newContent = get();
if ( content != newContent )
final Content newSnapshot = content;
if ( snapshot != newSnapshot )
{
index = null != newContent ? safeBinarySearch( newContent.uids, nextUID ) : -1;
content = newContent;
index = null != newSnapshot ? safeBinarySearch( newSnapshot.uids, nextUID ) : -1;
snapshot = newSnapshot;
}
if ( index >= 0 && index < content.uids.length )
if ( index >= 0 && index < snapshot.uids.length )
{
return uid2rank( content.uids[index] ) >= rank;
return uid2rank( snapshot.uids[index] ) >= rank;
}
return false;
}
Expand Down

0 comments on commit a77b0c0

Please sign in to comment.