MNG-5677 hooks to allow fine-grained cache management

Also fixed broken cache #flush() and missing #dispose() in
couple of places.

Signed-off-by: Igor Fedorenko <igor@ifedorenko.com>
This commit is contained in:
Igor Fedorenko 2014-08-08 22:28:02 +04:00
parent 8980f67b9b
commit 693f8f6604
11 changed files with 127 additions and 48 deletions

View File

@ -21,14 +21,16 @@
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.maven.project.ExtensionDescriptor; import org.apache.maven.project.ExtensionDescriptor;
import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProject;
import org.codehaus.plexus.classworlds.realm.ClassRealm; import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.artifact.Artifact;
/** /**
@ -36,10 +38,11 @@
*/ */
@Component( role = ExtensionRealmCache.class ) @Component( role = ExtensionRealmCache.class )
public class DefaultExtensionRealmCache public class DefaultExtensionRealmCache
implements ExtensionRealmCache implements ExtensionRealmCache, Disposable
{ {
private static class CacheKey protected static class CacheKey
implements Key
{ {
private final List<File> files; private final List<File> files;
@ -97,28 +100,36 @@ public boolean equals( Object o )
&& sizes.equals( other.sizes ); && sizes.equals( other.sizes );
} }
@Override
public String toString()
{
return files.toString();
}
} }
private final Map<CacheKey, CacheRecord> cache = new HashMap<CacheKey, CacheRecord>(); protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<Key, CacheRecord>();
public CacheRecord get( List<? extends Artifact> extensionArtifacts ) @Override
public Key createKey( List<? extends Artifact> extensionArtifacts )
{ {
return cache.get( new CacheKey( extensionArtifacts ) ); return new CacheKey( extensionArtifacts );
} }
public CacheRecord put( List<? extends Artifact> extensionArtifacts, ClassRealm extensionRealm, public CacheRecord get( Key key )
ExtensionDescriptor extensionDescriptor ) {
return cache.get( key );
}
public CacheRecord put( Key key, ClassRealm extensionRealm, ExtensionDescriptor extensionDescriptor )
{ {
if ( extensionRealm == null ) if ( extensionRealm == null )
{ {
throw new NullPointerException(); throw new NullPointerException();
} }
CacheKey key = new CacheKey( extensionArtifacts );
if ( cache.containsKey( key ) ) if ( cache.containsKey( key ) )
{ {
throw new IllegalStateException( "Duplicate extension realm for extension " + extensionArtifacts ); throw new IllegalStateException( "Duplicate extension realm for extension " + key );
} }
CacheRecord record = new CacheRecord( extensionRealm, extensionDescriptor ); CacheRecord record = new CacheRecord( extensionRealm, extensionDescriptor );
@ -130,12 +141,29 @@ public CacheRecord put( List<? extends Artifact> extensionArtifacts, ClassRealm
public void flush() public void flush()
{ {
for ( CacheRecord record : cache.values() )
{
ClassRealm realm = record.realm;
try
{
realm.getWorld().disposeRealm( realm.getId() );
}
catch ( NoSuchRealmException e )
{
// ignore
}
}
cache.clear(); cache.clear();
} }
public void register( MavenProject project, CacheRecord record ) public void register( MavenProject project, Key key, CacheRecord record )
{ {
// default cache does not track extension usage // default cache does not track extension usage
} }
public void dispose()
{
flush();
}
} }

View File

@ -21,9 +21,9 @@
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.maven.model.Plugin; import org.apache.maven.model.Plugin;
import org.apache.maven.project.MavenProject; import org.apache.maven.project.MavenProject;
@ -44,7 +44,7 @@ public class DefaultPluginArtifactsCache
implements PluginArtifactsCache implements PluginArtifactsCache
{ {
private static class CacheKey protected static class CacheKey
implements Key implements Key
{ {
@ -133,7 +133,7 @@ private static <T> boolean eq( T s1, T s2 )
} }
protected final Map<Key, CacheRecord> cache = new HashMap<Key, CacheRecord>(); protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<Key, CacheRecord>();
public Key createKey( Plugin plugin, DependencyFilter extensionFilter, List<RemoteRepository> repositories, public Key createKey( Plugin plugin, DependencyFilter extensionFilter, List<RemoteRepository> repositories,
RepositorySystemSession session ) RepositorySystemSession session )
@ -210,7 +210,7 @@ protected static boolean pluginEquals( Plugin a, Plugin b )
return CacheUtils.pluginEquals( a, b ); return CacheUtils.pluginEquals( a, b );
} }
public void register( MavenProject project, CacheRecord record ) public void register( MavenProject project, Key cacheKey, CacheRecord record )
{ {
// default cache does not track record usage // default cache does not track record usage
} }

View File

@ -206,7 +206,7 @@ protected static boolean pluginEquals( Plugin a, Plugin b )
return CacheUtils.pluginEquals( a, b ); return CacheUtils.pluginEquals( a, b );
} }
public void register( MavenProject project, CacheRecord record ) public void register( MavenProject project, Key key, CacheRecord record )
{ {
// default cache does not track plugin usage // default cache does not track plugin usage
} }

View File

@ -36,6 +36,13 @@
*/ */
public interface ExtensionRealmCache public interface ExtensionRealmCache
{ {
/**
* A cache key.
*/
interface Key
{
// marker interface for cache keys
}
static class CacheRecord static class CacheRecord
{ {
@ -52,10 +59,11 @@ public CacheRecord( ClassRealm realm, ExtensionDescriptor descriptor )
} }
CacheRecord get( List<? extends Artifact> extensionArtifacts ); Key createKey( List<? extends Artifact> extensionArtifacts );
CacheRecord put( List<? extends Artifact> extensionArtifacts, ClassRealm extensionRealm, CacheRecord get( Key key );
ExtensionDescriptor extensionDescriptor );
CacheRecord put( Key key, ClassRealm extensionRealm, ExtensionDescriptor extensionDescriptor );
void flush(); void flush();
@ -67,6 +75,6 @@ CacheRecord put( List<? extends Artifact> extensionArtifacts, ClassRealm extensi
* @param project The project that employs the plugin realm, must not be {@code null}. * @param project The project that employs the plugin realm, must not be {@code null}.
* @param record The cache record being used for the project, must not be {@code null}. * @param record The cache record being used for the project, must not be {@code null}.
*/ */
void register( MavenProject project, CacheRecord record ); void register( MavenProject project, Key key, CacheRecord record );
} }

View File

@ -86,6 +86,6 @@ Key createKey( Plugin plugin, DependencyFilter extensionFilter, List<RemoteRepos
* @param project The project that employs the plugin realm, must not be {@code null}. * @param project The project that employs the plugin realm, must not be {@code null}.
* @param record The cache record being used for the project, must not be {@code null}. * @param record The cache record being used for the project, must not be {@code null}.
*/ */
void register( MavenProject project, CacheRecord record ); void register( MavenProject project, Key cacheKey, CacheRecord record );
} }

View File

@ -80,6 +80,6 @@ Key createKey( Plugin plugin, ClassLoader parentRealm, Map<String, ClassLoader>
* @param project The project that employs the plugin realm, must not be {@code null}. * @param project The project that employs the plugin realm, must not be {@code null}.
* @param record The cache record being used for the project, must not be {@code null}. * @param record The cache record being used for the project, must not be {@code null}.
*/ */
void register( MavenProject project, CacheRecord record ); void register( MavenProject project, Key key, CacheRecord record );
} }

View File

@ -330,7 +330,7 @@ public synchronized void setupPluginRealm( PluginDescriptor pluginDescriptor, Ma
pluginRealmCache.put( cacheKey, pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts() ); pluginRealmCache.put( cacheKey, pluginDescriptor.getClassRealm(), pluginDescriptor.getArtifacts() );
} }
pluginRealmCache.register( project, cacheRecord ); pluginRealmCache.register( project, cacheKey, cacheRecord );
} }
private void createPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session, ClassLoader parent, private void createPluginRealm( PluginDescriptor pluginDescriptor, MavenSession session, ClassLoader parent,

View File

@ -143,6 +143,7 @@ private ProjectBuildingResult build( File pomFile, ModelSource modelSource, Inte
ModelBuildingRequest request = getModelBuildingRequest( config ); ModelBuildingRequest request = getModelBuildingRequest( config );
project = new MavenProject(); project = new MavenProject();
project.setFile( pomFile );
DefaultModelBuildingListener listener = DefaultModelBuildingListener listener =
new DefaultModelBuildingListener( project, projectBuildingHelper, projectBuildingRequest ); new DefaultModelBuildingListener( project, projectBuildingHelper, projectBuildingRequest );

View File

@ -244,18 +244,20 @@ public synchronized ProjectRealmCache.CacheRecord createProjectRealm( MavenProje
{ {
pluginArtifactsCache.put( cacheKey, e ); pluginArtifactsCache.put( cacheKey, e );
pluginArtifactsCache.register( project, recordArtifacts ); pluginArtifactsCache.register( project, cacheKey, recordArtifacts );
throw e; throw e;
} }
} }
pluginArtifactsCache.register( project, recordArtifacts ); pluginArtifactsCache.register( project, cacheKey, recordArtifacts );
ClassRealm extensionRealm; ClassRealm extensionRealm;
ExtensionDescriptor extensionDescriptor = null; ExtensionDescriptor extensionDescriptor = null;
final ExtensionRealmCache.Key extensionKey = extensionRealmCache.createKey( artifacts );
ExtensionRealmCache.CacheRecord recordRealm = extensionRealmCache.get( artifacts ); ExtensionRealmCache.CacheRecord recordRealm = extensionRealmCache.get( extensionKey );
if ( recordRealm != null ) if ( recordRealm != null )
{ {
@ -295,10 +297,10 @@ public synchronized ProjectRealmCache.CacheRecord createProjectRealm( MavenProje
} }
} }
recordRealm = extensionRealmCache.put( artifacts, extensionRealm, extensionDescriptor ); recordRealm = extensionRealmCache.put( extensionKey, extensionRealm, extensionDescriptor );
} }
extensionRealmCache.register( project, recordRealm ); extensionRealmCache.register( project, extensionKey, recordRealm );
extensionRealms.add( extensionRealm ); extensionRealms.add( extensionRealm );
if ( extensionDescriptor != null ) if ( extensionDescriptor != null )
@ -324,7 +326,9 @@ public synchronized ProjectRealmCache.CacheRecord createProjectRealm( MavenProje
logger.debug( "Extension realms for project " + model.getId() + ": " + extensionRealms ); logger.debug( "Extension realms for project " + model.getId() + ": " + extensionRealms );
} }
ProjectRealmCache.CacheRecord record = projectRealmCache.get( extensionRealms ); ProjectRealmCache.Key projectRealmKey = projectRealmCache.createKey( extensionRealms );
ProjectRealmCache.CacheRecord record = projectRealmCache.get( projectRealmKey );
if ( record == null ) if ( record == null )
{ {
@ -365,10 +369,10 @@ public synchronized ProjectRealmCache.CacheRecord createProjectRealm( MavenProje
extensionArtifactFilter = new ExclusionsDependencyFilter( exclusions ); extensionArtifactFilter = new ExclusionsDependencyFilter( exclusions );
} }
record = projectRealmCache.put( extensionRealms, projectRealm, extensionArtifactFilter ); record = projectRealmCache.put( projectRealmKey, projectRealm, extensionArtifactFilter );
} }
projectRealmCache.register( project, record ); projectRealmCache.register( project, projectRealmKey, record );
return record; return record;
} }

View File

@ -20,12 +20,14 @@
*/ */
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.codehaus.plexus.classworlds.realm.ClassRealm; import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
import org.codehaus.plexus.component.annotations.Component; import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable;
import org.eclipse.aether.graph.DependencyFilter; import org.eclipse.aether.graph.DependencyFilter;
/** /**
@ -33,10 +35,11 @@
*/ */
@Component( role = ProjectRealmCache.class ) @Component( role = ProjectRealmCache.class )
public class DefaultProjectRealmCache public class DefaultProjectRealmCache
implements ProjectRealmCache implements ProjectRealmCache, Disposable
{ {
private static class CacheKey protected static class CacheKey
implements Key
{ {
private final List<? extends ClassRealm> extensionRealms; private final List<? extends ClassRealm> extensionRealms;
@ -74,28 +77,36 @@ public boolean equals( Object o )
return extensionRealms.equals( other.extensionRealms ); return extensionRealms.equals( other.extensionRealms );
} }
@Override
public String toString()
{
return extensionRealms.toString();
}
} }
private final Map<CacheKey, CacheRecord> cache = new HashMap<CacheKey, CacheRecord>(); protected final Map<Key, CacheRecord> cache = new ConcurrentHashMap<Key, CacheRecord>();
public CacheRecord get( List<? extends ClassRealm> extensionRealms ) @Override
public Key createKey( List<? extends ClassRealm> extensionRealms )
{ {
return cache.get( new CacheKey( extensionRealms ) ); return new CacheKey( extensionRealms );
} }
public CacheRecord put( List<? extends ClassRealm> extensionRealms, ClassRealm projectRealm, public CacheRecord get( Key key )
DependencyFilter extensionArtifactFilter ) {
return cache.get( key );
}
public CacheRecord put( Key key, ClassRealm projectRealm, DependencyFilter extensionArtifactFilter )
{ {
if ( projectRealm == null ) if ( projectRealm == null )
{ {
throw new NullPointerException(); throw new NullPointerException();
} }
CacheKey key = new CacheKey( extensionRealms );
if ( cache.containsKey( key ) ) if ( cache.containsKey( key ) )
{ {
throw new IllegalStateException( "Duplicate project realm for extensions " + extensionRealms ); throw new IllegalStateException( "Duplicate project realm for extensions " + key );
} }
CacheRecord record = new CacheRecord( projectRealm, extensionArtifactFilter ); CacheRecord record = new CacheRecord( projectRealm, extensionArtifactFilter );
@ -107,12 +118,30 @@ public CacheRecord put( List<? extends ClassRealm> extensionRealms, ClassRealm p
public void flush() public void flush()
{ {
for ( CacheRecord record : cache.values() )
{
ClassRealm realm = record.realm;
try
{
realm.getWorld().disposeRealm( realm.getId() );
}
catch ( NoSuchRealmException e )
{
// ignore
}
}
cache.clear(); cache.clear();
} }
public void register( MavenProject project, CacheRecord record ) public void register( MavenProject project, Key key, CacheRecord record )
{ {
// default cache does not track record usage // default cache does not track record usage
} }
@Override
public void dispose()
{
flush();
}
} }

View File

@ -35,6 +35,14 @@
public interface ProjectRealmCache public interface ProjectRealmCache
{ {
/**
* A cache key.
*/
interface Key
{
// marker interface for cache keys
}
static class CacheRecord static class CacheRecord
{ {
@ -50,10 +58,11 @@ public CacheRecord( ClassRealm realm, DependencyFilter extensionArtifactFilter )
} }
CacheRecord get( List<? extends ClassRealm> extensionRealms ); Key createKey( List<? extends ClassRealm> extensionRealms );
CacheRecord put( List<? extends ClassRealm> extensionRealms, ClassRealm projectRealm, CacheRecord get( Key key );
DependencyFilter extensionArtifactFilter );
CacheRecord put( Key key, ClassRealm projectRealm, DependencyFilter extensionArtifactFilter );
void flush(); void flush();
@ -65,6 +74,6 @@ CacheRecord put( List<? extends ClassRealm> extensionRealms, ClassRealm projectR
* @param project The project that employs the plugin realm, must not be {@code null}. * @param project The project that employs the plugin realm, must not be {@code null}.
* @param record The cache record being used for the project, must not be {@code null}. * @param record The cache record being used for the project, must not be {@code null}.
*/ */
void register( MavenProject project, CacheRecord record ); void register( MavenProject project, Key key, CacheRecord record );
} }