You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by cs...@apache.org on 2021/05/02 09:04:11 UTC

[maven-resolver] branch MRESOLVER-176-tracking-file-manager created (now 1decd98)

This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a change to branch MRESOLVER-176-tracking-file-manager
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git.


      at 1decd98  [MRESOLVER-153] Make TrackingFileManager use named locks as well

This branch includes the following new commits:

     new 1decd98  [MRESOLVER-153] Make TrackingFileManager use named locks as well

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[maven-resolver] 01/01: [MRESOLVER-153] Make TrackingFileManager use named locks as well

Posted by cs...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch MRESOLVER-176-tracking-file-manager
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git

commit 1decd98cf6e1a6892a3e4757167c8c24f7de7b4f
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Fri Apr 30 10:46:10 2021 +0200

    [MRESOLVER-153] Make TrackingFileManager use named locks as well
    
    Depends on components introduced in https://github.com/apache/maven-resolver/pull/101/files
    
    Use selected NamedLocksFactory in DefaultTrackingFileManager as well
    to protected property file reads/writes.
---
 .../internal/impl/DefaultTrackingFileManager.java  | 211 ++++++++++++++-------
 .../internal/impl/DefaultArtifactResolverTest.java |   5 +-
 .../impl/DefaultTrackingFileManagerTest.java       |  14 +-
 .../impl/DefaultUpdateCheckManagerTest.java        |   4 +-
 .../impl/EnhancedLocalRepositoryManagerTest.java   |   4 +-
 5 files changed, 152 insertions(+), 86 deletions(-)

diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManager.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManager.java
index e6e2e65..c4d8a72 100644
--- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManager.java
+++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManager.java
@@ -27,11 +27,18 @@ import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Properties;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 import javax.inject.Singleton;
 
+import org.eclipse.aether.internal.impl.synccontext.NamedLockFactorySelector;
+import org.eclipse.aether.named.NamedLock;
+import org.eclipse.aether.named.NamedLockFactory;
+import org.eclipse.aether.spi.locator.Service;
+import org.eclipse.aether.spi.locator.ServiceLocator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -41,100 +48,170 @@ import org.slf4j.LoggerFactory;
 @Singleton
 @Named
 public final class DefaultTrackingFileManager
-    implements TrackingFileManager
+    implements TrackingFileManager, Service
 {
     private static final Logger LOGGER = LoggerFactory.getLogger( DefaultTrackingFileManager.class );
 
+    private static final String LOCK_PREFIX = "tracking:";
+
+    private NamedLockFactory namedLockFactory;
+
+    public DefaultTrackingFileManager()
+    {
+        // ctor for ServiceLocator
+    }
+
+    @Inject
+    public DefaultTrackingFileManager( final NamedLockFactorySelector selector )
+    {
+        this.namedLockFactory = selector.getSelectedNamedLockFactory();
+    }
+
+    @Override
+    public void initService( final ServiceLocator locator )
+    {
+        NamedLockFactorySelector select = Objects.requireNonNull(
+            locator.getService( NamedLockFactorySelector.class ) );
+        this.namedLockFactory = select.getSelectedNamedLockFactory();
+    }
+
+    private String getFileKey( final File file )
+    {
+        return LOCK_PREFIX + file.getAbsolutePath();
+    }
+
     @Override
     public Properties read( File file )
     {
-        FileInputStream stream = null;
-        try
+        try ( NamedLock lock = namedLockFactory.getLock( getFileKey( file ) ) )
         {
-            if ( !file.exists() )
+            if ( lock.lockShared( NamedLockFactorySelector.TIME, NamedLockFactorySelector.TIME_UNIT ) )
             {
-                return null;
+                try
+                {
+                    FileInputStream stream = null;
+                    try
+                    {
+                        if ( !file.exists() )
+                        {
+                            return null;
+                        }
+
+                        stream = new FileInputStream( file );
+
+                        Properties props = new Properties();
+                        props.load( stream );
+
+                        return props;
+                    }
+                    catch ( IOException e )
+                    {
+                        LOGGER.warn( "Failed to read tracking file {}", file, e );
+                    }
+                    finally
+                    {
+                        close( stream, file );
+                    }
+
+                    return null;
+                }
+                finally
+                {
+                    lock.unlock();
+                }
+            }
+            else
+            {
+                throw new IllegalStateException( "Could not acquire read lock for: " + file );
             }
-
-            stream = new FileInputStream( file );
-
-            Properties props = new Properties();
-            props.load( stream );
-
-            return props;
-        }
-        catch ( IOException e )
-        {
-            LOGGER.warn( "Failed to read tracking file {}", file, e );
         }
-        finally
+        catch ( InterruptedException e )
         {
-            close( stream, file );
+            throw new IllegalStateException( e );
         }
-
-        return null;
     }
 
     @Override
     public Properties update( File file, Map<String, String> updates )
     {
-        Properties props = new Properties();
-
-        File directory = file.getParentFile();
-        if ( !directory.mkdirs() && !directory.exists() )
-        {
-            LOGGER.warn( "Failed to create parent directories for tracking file {}", file );
-            return props;
-        }
-
-        RandomAccessFile raf = null;
-        try
+        try ( NamedLock lock = namedLockFactory.getLock( getFileKey( file ) ) )
         {
-            raf = new RandomAccessFile( file, "rw" );
-
-            if ( file.canRead() )
+            if ( lock.lockExclusively( NamedLockFactorySelector.TIME, NamedLockFactorySelector.TIME_UNIT ) )
             {
-                byte[] buffer = new byte[(int) raf.length()];
-
-                raf.readFully( buffer );
-
-                ByteArrayInputStream stream = new ByteArrayInputStream( buffer );
-
-                props.load( stream );
-            }
-
-            for ( Map.Entry<String, String> update : updates.entrySet() )
-            {
-                if ( update.getValue() == null )
+                try
                 {
-                    props.remove( update.getKey() );
+                    Properties props = new Properties();
+
+                    File directory = file.getParentFile();
+                    if ( !directory.mkdirs() && !directory.exists() )
+                    {
+                        LOGGER.warn( "Failed to create parent directories for tracking file {}", file );
+                        return props;
+                    }
+
+                    RandomAccessFile raf = null;
+                    try
+                    {
+                        raf = new RandomAccessFile( file, "rw" );
+
+                        if ( file.canRead() )
+                        {
+                            byte[] buffer = new byte[(int) raf.length()];
+
+                            raf.readFully( buffer );
+
+                            ByteArrayInputStream stream = new ByteArrayInputStream( buffer );
+
+                            props.load( stream );
+                        }
+
+                        for ( Map.Entry<String, String> update : updates.entrySet() )
+                        {
+                            if ( update.getValue() == null )
+                            {
+                                props.remove( update.getKey() );
+                            }
+                            else
+                            {
+                                props.setProperty( update.getKey(), update.getValue() );
+                            }
+                        }
+
+                        ByteArrayOutputStream stream = new ByteArrayOutputStream( 1024 * 2 );
+
+                        LOGGER.debug( "Writing tracking file {}", file );
+                        props.store( stream, "NOTE: This is a Maven Resolver internal implementation file"
+                            + ", its format can be changed without prior notice." );
+
+                        raf.seek( 0 );
+                        raf.write( stream.toByteArray() );
+                        raf.setLength( raf.getFilePointer() );
+                    }
+                    catch ( IOException e )
+                    {
+                        LOGGER.warn( "Failed to write tracking file {}", file, e );
+                    }
+                    finally
+                    {
+                        close( raf, file );
+                    }
+
+                    return props;
                 }
-                else
+                finally
                 {
-                    props.setProperty( update.getKey(), update.getValue() );
+                    lock.unlock();
                 }
             }
-
-            ByteArrayOutputStream stream = new ByteArrayOutputStream( 1024 * 2 );
-
-            LOGGER.debug( "Writing tracking file {}", file );
-            props.store( stream, "NOTE: This is a Maven Resolver internal implementation file"
-                + ", its format can be changed without prior notice." );
-
-            raf.seek( 0 );
-            raf.write( stream.toByteArray() );
-            raf.setLength( raf.getFilePointer() );
-        }
-        catch ( IOException e )
-        {
-            LOGGER.warn( "Failed to write tracking file {}", file, e );
+            else
+            {
+                throw new IllegalStateException( "Could not acquire write lock for: " + file );
+            }
         }
-        finally
+        catch ( InterruptedException e )
         {
-            close( raf, file );
+            throw new IllegalStateException( e );
         }
-
-        return props;
     }
 
     private void close( Closeable closeable, File file )
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java
index 3c27f98..13f3de5 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultArtifactResolverTest.java
@@ -38,8 +38,7 @@ import org.eclipse.aether.artifact.ArtifactProperties;
 import org.eclipse.aether.artifact.DefaultArtifact;
 import org.eclipse.aether.impl.UpdateCheckManager;
 import org.eclipse.aether.impl.VersionResolver;
-import org.eclipse.aether.internal.impl.DefaultArtifactResolver;
-import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager;
+import org.eclipse.aether.internal.impl.synccontext.NamedLockFactorySelector;
 import org.eclipse.aether.internal.test.util.TestFileProcessor;
 import org.eclipse.aether.internal.test.util.TestFileUtils;
 import org.eclipse.aether.internal.test.util.TestLocalRepositoryManager;
@@ -274,7 +273,7 @@ public class DefaultArtifactResolverTest
         repositoryConnectorProvider.setConnector( connector );
         resolver.setUpdateCheckManager( new DefaultUpdateCheckManager()
             .setUpdatePolicyAnalyzer( new DefaultUpdatePolicyAnalyzer() )
-            .setTrackingFileManager( new DefaultTrackingFileManager() )
+            .setTrackingFileManager( new DefaultTrackingFileManager( new NamedLockFactorySelector() ) )
         );
 
         session.setResolutionErrorPolicy( new SimpleResolutionErrorPolicy( true, false ) );
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManagerTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManagerTest.java
index e3745aa..ac241cb 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManagerTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultTrackingFileManagerTest.java
@@ -23,14 +23,11 @@ import static org.junit.Assert.*;
 
 import java.io.File;
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
-import org.eclipse.aether.internal.impl.TrackingFileManager;
+import org.eclipse.aether.internal.impl.synccontext.NamedLockFactorySelector;
 import org.eclipse.aether.internal.test.util.TestFileUtils;
 import org.junit.Test;
 
@@ -38,13 +35,12 @@ import org.junit.Test;
  */
 public class DefaultTrackingFileManagerTest
 {
+    private final TrackingFileManager tfm = new DefaultTrackingFileManager( new NamedLockFactorySelector() );
 
     @Test
     public void testRead()
         throws Exception
     {
-        TrackingFileManager tfm = new DefaultTrackingFileManager();
-
         File propFile = TestFileUtils.createTempFile( "#COMMENT\nkey1=value1\nkey2 : value2" );
         Properties props = tfm.read( propFile );
 
@@ -63,8 +59,6 @@ public class DefaultTrackingFileManagerTest
     public void testReadNoFileLeak()
         throws Exception
     {
-        TrackingFileManager tfm = new DefaultTrackingFileManager();
-
         for ( int i = 0; i < 1000; i++ )
         {
             File propFile = TestFileUtils.createTempFile( "#COMMENT\nkey1=value1\nkey2 : value2" );
@@ -77,8 +71,6 @@ public class DefaultTrackingFileManagerTest
     public void testUpdate()
         throws Exception
     {
-        TrackingFileManager tfm = new DefaultTrackingFileManager();
-
         // NOTE: The excessive repetitions are to check the update properly truncates the file
         File propFile = TestFileUtils.createTempFile( "key1=value1\nkey2 : value2\n".getBytes( StandardCharsets.UTF_8 ), 1000 );
 
@@ -100,8 +92,6 @@ public class DefaultTrackingFileManagerTest
     public void testUpdateNoFileLeak()
         throws Exception
     {
-        TrackingFileManager tfm = new DefaultTrackingFileManager();
-
         Map<String, String> updates = new HashMap<>();
         updates.put( "k", "v" );
 
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManagerTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManagerTest.java
index 111aca7..e9261b6 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManagerTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/DefaultUpdateCheckManagerTest.java
@@ -32,7 +32,7 @@ import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.DefaultArtifact;
 import org.eclipse.aether.impl.UpdateCheck;
-import org.eclipse.aether.internal.impl.DefaultUpdateCheckManager;
+import org.eclipse.aether.internal.impl.synccontext.NamedLockFactorySelector;
 import org.eclipse.aether.internal.test.util.TestFileUtils;
 import org.eclipse.aether.internal.test.util.TestUtils;
 import org.eclipse.aether.metadata.DefaultMetadata;
@@ -82,7 +82,7 @@ public class DefaultUpdateCheckManagerTest
             new RemoteRepository.Builder( "id", "default", TestFileUtils.createTempDir().toURI().toURL().toString() ).build();
         manager = new DefaultUpdateCheckManager()
             .setUpdatePolicyAnalyzer( new DefaultUpdatePolicyAnalyzer() )
-            .setTrackingFileManager( new DefaultTrackingFileManager() );
+            .setTrackingFileManager( new DefaultTrackingFileManager( new NamedLockFactorySelector() ) );
         metadata =
             new DefaultMetadata( "gid", "aid", "ver", "maven-metadata.xml", Metadata.Nature.RELEASE_OR_SNAPSHOT,
                                  metadataFile );
diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerTest.java
index 1dae789..598e712 100644
--- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerTest.java
+++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/EnhancedLocalRepositoryManagerTest.java
@@ -31,7 +31,7 @@ import java.util.Collections;
 import org.eclipse.aether.RepositorySystemSession;
 import org.eclipse.aether.artifact.Artifact;
 import org.eclipse.aether.artifact.DefaultArtifact;
-import org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManager;
+import org.eclipse.aether.internal.impl.synccontext.NamedLockFactorySelector;
 import org.eclipse.aether.internal.test.util.TestFileUtils;
 import org.eclipse.aether.internal.test.util.TestUtils;
 import org.eclipse.aether.metadata.DefaultMetadata;
@@ -98,7 +98,7 @@ public class EnhancedLocalRepositoryManagerTest
 
         basedir = TestFileUtils.createTempDir( "enhanced-repo" );
         session = TestUtils.newSession();
-        trackingFileManager = new DefaultTrackingFileManager();
+        trackingFileManager = new DefaultTrackingFileManager( new NamedLockFactorySelector() );
         manager = new EnhancedLocalRepositoryManager( basedir, session, trackingFileManager );
 
         artifactFile = new File( basedir, manager.getPathForLocalArtifact( artifact ) );