Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use AtomicReferenceFieldUpdater as it works better for large numbers of instances #46

Merged
merged 4 commits into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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