]> source.dussan.org Git - archiva.git/commitdiff
PR: MRM-39
authorEdwin L. Punzalan <epunzalan@apache.org>
Tue, 13 Dec 2005 07:52:22 +0000 (07:52 +0000)
committerEdwin L. Punzalan <epunzalan@apache.org>
Tue, 13 Dec 2005 07:52:22 +0000 (07:52 +0000)
Added Cache class, and revised CachedRepositoryQueryLayer to use it.

git-svn-id: https://svn.apache.org/repos/asf/maven/repository-manager/trunk@356503 13f79535-47bb-0310-9956-ffa450edef68

maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/AbstractRepositoryQueryLayer.java
maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/Cache.java [new file with mode: 0644]
maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/CachedRepositoryQueryLayer.java
maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/AbstractRepositoryQueryLayerTest.java
maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/CacheTest.java [new file with mode: 0644]
maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/CachedRepositoryQueryLayerTest.java

index f6fb93645d9adb7ce8a36a86956a7520e84a0f0f..7f2d4e43c36417707ab359f3f734b2726ed700aa 100644 (file)
@@ -60,7 +60,7 @@ public abstract class AbstractRepositoryQueryLayer
     protected String getSnapshotArtifactRepositoryPath( Artifact artifact, Snapshot snapshot )
     {
         File f = new File( repository.getBasedir(), repository.pathOf( artifact ) );
-        String snapshotInfo = artifact.getVersion().replaceAll( "SNAPSHOT", snapshot.getTimestamp() + "-" + 
+        String snapshotInfo = artifact.getVersion().replaceFirst( "SNAPSHOT", snapshot.getTimestamp() + "-" + 
                                                                             snapshot.getBuildNumber() + ".pom" );
         File snapshotFile = new File( f.getParentFile(), artifact.getArtifactId() + "-" + snapshotInfo );
         return snapshotFile.getAbsolutePath();
diff --git a/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/Cache.java b/maven-repository-reports-standard/src/main/java/org/apache/maven/repository/reporting/Cache.java
new file mode 100644 (file)
index 0000000..b7bd0dd
--- /dev/null
@@ -0,0 +1,190 @@
+package org.apache.maven.repository.reporting;
+
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ */
+public class Cache
+{
+    private Map cache;
+
+    private DblLinkedList mostRecent;
+    private double cacheHitRatio = 0;
+    private long cacheMaxSize = 0;
+    
+    private long cacheHits = 0;
+    private long cacheMiss = 0;
+
+    public Cache( double cacheHitRatio )
+    {
+        this( cacheHitRatio, 0 );
+    }
+
+    public Cache( double cacheHitRatio, long cacheMaxSize )
+    {
+        this.cacheHitRatio = cacheHitRatio;
+        this.cacheMaxSize = cacheMaxSize;
+        
+        cache = new HashMap();
+    }
+
+    public Object get( Object key )
+    {
+        Object retValue = null;
+        
+        if ( cache.containsKey( key ) )
+        {
+            DblLinkedList cacheEntry = (DblLinkedList) cache.get( key );
+            
+            makeMostRecent( cacheEntry );
+            
+            retValue = cacheEntry.cacheValue;
+            
+            cacheHits++;
+        }
+        else
+        {
+            cacheMiss++;
+        }
+
+        return retValue;
+    }
+
+    public void put( Object key, Object value )
+    {
+        DblLinkedList entry;
+        if ( !cache.containsKey( key ) )
+        {
+            entry = new DblLinkedList( key, value );
+            cache.put( key, entry );
+            manageCache();
+        }
+        else
+        {
+            entry = (DblLinkedList) cache.get( key );
+        }
+
+        makeMostRecent( entry );
+    }
+
+    public double getHitRate()
+    {
+        return ( cacheHits == 0 && cacheMiss == 0 ) ? 0 : ( (double) cacheHits ) / (double) ( cacheHits + cacheMiss );
+    }
+    
+    public long size()
+    {
+        return cache.size();
+    }
+    
+    public void flush()
+    {
+        while ( cache.size() > 0 )
+            trimCache();
+        cacheHits = 0;
+        cacheMiss = 0;
+        cache = new HashMap();
+    }
+
+    private void makeMostRecent( DblLinkedList list )
+    {
+        if ( mostRecent != list )
+        {
+            removeFromLinks( list );
+
+            if ( mostRecent != null )
+            {
+                list.next = mostRecent;
+                mostRecent.prev = list;
+            }
+            mostRecent = list;
+        }
+    }
+
+    private void removeFromLinks( DblLinkedList list )
+    {
+        if ( list.prev != null )
+            list.prev.next = list.next;
+        if ( list.next != null )
+            list.next.prev = list.prev;
+        
+        list.prev = null;
+        list.next = null;
+    }
+
+    private void manageCache()
+    {
+        if ( cacheMaxSize == 0 )
+        {
+            //if desired HitRatio is reached, we can trim the cache to conserve memory
+            if ( cacheHitRatio <= getHitRate() )
+            {
+                trimCache();
+            }
+        }
+        else if ( cache.size() > cacheMaxSize )
+        {
+            //trim cache regardless of cacheHitRatio
+            while( cache.size() > cacheMaxSize )
+            {
+                trimCache();
+            }
+        }
+    }
+
+    private void trimCache()
+    {
+        DblLinkedList leastRecent = getLeastRecent();
+        cache.remove( leastRecent.cacheKey );
+        if ( cache.size() > 0 )
+        {
+            removeFromLinks( leastRecent );
+        }
+        else
+        {
+            mostRecent = null;
+        }
+    }
+    
+    private DblLinkedList getLeastRecent()
+    {
+        DblLinkedList trail = mostRecent;
+
+        while( trail.next != null )
+            trail = trail.next;
+
+        return trail;
+    }
+
+    private class DblLinkedList {
+        Object cacheKey;
+        Object cacheValue;
+        DblLinkedList prev;
+        DblLinkedList next;
+        
+        public DblLinkedList( Object key, Object value )
+        {
+            this.cacheKey = key;
+            this.cacheValue = value;
+        }
+    }
+}
index 2b98ab57093ce2409e137af2ebe38e32b5041143..fa2485ff1b53a7fe3d6489c99906c7c0354ac306 100644 (file)
@@ -18,17 +18,15 @@ package org.apache.maven.repository.reporting;
  */
 
 import java.io.File;
-import java.io.FileReader;
 import java.util.HashMap;
-import java.util.List;
+import java.util.LinkedList;
 import java.util.Map;
 
 import org.apache.maven.artifact.Artifact;
 import org.apache.maven.artifact.repository.ArtifactRepository;
-import org.apache.maven.artifact.repository.metadata.ArtifactRepositoryMetadata;
 import org.apache.maven.artifact.repository.metadata.Metadata;
 import org.apache.maven.artifact.repository.metadata.Snapshot;
-import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
+
 
 
 /**
@@ -37,44 +35,34 @@ import org.apache.maven.artifact.repository.metadata.io.xpp3.MetadataXpp3Reader;
 public class CachedRepositoryQueryLayer
     extends AbstractRepositoryQueryLayer
 {
-    //@todo caches should expire    
-    //cache for metadata
-    private Map cacheMetadata;
+    private Cache cache;
 
-    //cache for repository files, all types
-    //@todo ???should also cache missing files
-    private Map cacheFile;
     
-    //@todo ???should a listener be required???
-    private long cacheHits = 0;
-
     public CachedRepositoryQueryLayer( ArtifactRepository repository )
     {
         this.repository = repository;
         
-        cacheMetadata = new HashMap();
-        
-        cacheFile = new HashMap();
+        cache = new Cache( 0.5 );
     }
     
-    public long getCacheHits()
+    public double getCacheHitRate()
     {
-        return cacheHits;
+        return cache.getHitRate();
     }
-
+    
     public boolean containsArtifact( Artifact artifact )
     {
         boolean artifactFound = true;
         
         // @todo should check for snapshot artifacts
-        File artifactFile = new File( repository.pathOf( artifact ) );
+        String artifactPath = repository.getBasedir() + "/" + repository.pathOf( artifact );
 
-        if ( !checkFileCache( artifactFile ) )
+        if ( cache.get( artifactPath ) == null )
         {
             artifactFound = super.containsArtifact( artifact );
             if ( artifactFound )
             {
-                addToFileCache( artifactFile );
+                cache.put( artifactPath, artifactPath );
             }
         }
 
@@ -87,63 +75,38 @@ public class CachedRepositoryQueryLayer
 
         String path = getSnapshotArtifactRepositoryPath( artifact, snapshot );
 
-        if ( !checkFileCache( path ) )
+        if ( cache.get( path ) == null )
         {
             artifactFound = super.containsArtifact( artifact, snapshot );
             if ( artifactFound )
             {
-                addToFileCache( new File( repository.getBasedir(), path ) );
+                cache.put( path, path );
             }
         }
 
         return artifactFound;
     }
 
-    /**
-     * Method to utilize the cache
-     */
-    private boolean checkFileCache( File file )
-    {
-        boolean existing = false;
-
-        if ( cacheFile.containsKey( file ) )
-        {
-            cacheHits++;
-            existing = true;
-        }
-
-        return existing;
-    }
-
-    private boolean checkFileCache( String repositoryPath )
-    {
-        return checkFileCache(  new File( repository.getBasedir(), repositoryPath ) );
-    }
-    
-    private void addToFileCache( File file )
-    {
-        cacheFile.put( file, file );
-    }
-
     /**
      * Override method to utilize the cache
      */
     protected Metadata getMetadata( Artifact artifact )
         throws RepositoryQueryLayerException
     {
-        Metadata metadata = null;
+        Metadata metadata = (Metadata) cache.get( artifact.getId() );
         
-        if ( cacheMetadata.containsKey( artifact.getId() ) )
-        {
-            cacheHits++;
-            metadata = (Metadata) cacheMetadata.get( artifact.getId() );
-        }
-        else
+        if ( metadata == null )
         {
             metadata = super.getMetadata( artifact );
-            cacheMetadata.put( artifact.getId(), metadata );
+            cache.put( artifact.getId(), metadata );
         }
         
         return metadata;
     }
+
+    private class DblLinkedList {
+        DblLinkedList prev;
+        Object cacheObject;
+        DblLinkedList next;
+    }
 }
index b6be1f5385dcccb8994335a86b65572c51f09f07..b1633a826bf6c67c0f75bef42fbb3fb631500df1 100644 (file)
@@ -129,7 +129,6 @@ public abstract class AbstractRepositoryQueryLayerTest
 
     protected Artifact getArtifact( String groupId, String artifactId, String version )
     {
-        if ( artifactFactory == null ) System.out.println("NULL");
         return artifactFactory.createBuildArtifact( groupId, artifactId, version, "pom" );
     }
 
diff --git a/maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/CacheTest.java b/maven-repository-reports-standard/src/test/java/org/apache/maven/repository/reporting/CacheTest.java
new file mode 100644 (file)
index 0000000..878819d
--- /dev/null
@@ -0,0 +1,105 @@
+package org.apache.maven.repository.reporting;
+
+/*
+ * Copyright 2001-2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import junit.framework.TestCase;
+
+/**
+ *
+ */
+public class CacheTest
+    extends TestCase
+{
+    private Cache cache;
+
+    public void testCacheManagementBasedOnHitsRatio()
+    {
+        cache = new Cache( 0.5 );
+        newCacheObjectTests();
+        
+        String key = "key";
+        String value = "value";
+        for( int ctr=1; ctr<10; ctr++ )
+        {
+            cache.put( key + ctr, value + ctr );
+        }
+        
+        while ( cache.getHitRate() < 0.75 )
+        {
+            cache.get( "key2" );
+        }
+        cache.put( "key10", "value10");
+        assertNull( "first key must be expired", cache.get( "key1" ) );
+    }
+
+    public void testCacheManagementBasedOnCacheSize()
+    {
+        cache = new Cache( 0.5, 9 );
+        newCacheObjectTests();
+        
+        String key = "key";
+        String value = "value";
+        for( int ctr=1; ctr<10; ctr++ )
+        {
+            cache.put( key + ctr, value + ctr );
+        }
+        
+        cache.put( "key10", "value10");
+        assertNull( "first key must be expired", cache.get( "key1" ) );
+        assertEquals( "check cache size to be max size", 9, cache.size() );
+    }
+
+    public void testCacheOnRedundantData()
+    {
+        cache = new Cache( 0.5, 9 );
+        newCacheObjectTests();
+        
+        String key = "key";
+        String value = "value";
+        for( int ctr=1; ctr<10; ctr++ )
+        {
+            cache.put( key + ctr, value + ctr );
+        }
+        
+        cache.put( "key1", "value1");
+        cache.put( "key10", "value10");
+        assertNull( "second key must be gone", cache.get( "key2" ) );
+        assertEquals( "check cache size to be max size", 9, cache.size() );
+    }
+
+    private void newCacheObjectTests()
+    {
+        assertEquals( (double) 0, cache.getHitRate(), 0 );
+        assertEquals( "check cache size", 0, cache.size() );
+
+        String value = "value";
+        String key = "key";
+
+        cache.put( key, value );
+        assertEquals( "check cache hit", value, cache.get( key ) );
+        assertEquals( (double) 1, cache.getHitRate(), 0 );
+        assertEquals( "check cache size", 1, cache.size() );
+        assertNull( "check cache miss", cache.get( "none" ) );
+        assertEquals( (double) 0.5, cache.getHitRate(), 0 );
+        cache.flush();
+        assertNull( "check flushed object", cache.get( "key" ) );
+        assertEquals( (double) 0, cache.getHitRate(), 0 );
+        assertEquals( "check flushed cache size", 0, cache.size() );
+        cache.flush();
+    }
+}
index f6774b53a1e09240bcda9d9aad2e84cf6c1a0dff..984f07ddddb91ef1d56761be908ae3c80ee98659 100644 (file)
@@ -33,25 +33,25 @@ public class CachedRepositoryQueryLayerTest
     public void testUseFileCache()
     {
         testContainsArtifactTrue();
-        assertEquals( "check cache usage", 0, queryLayer.getCacheHits() );
+        assertEquals( 0, queryLayer.getCacheHitRate(), 0 );
         testContainsArtifactTrue();
-        assertEquals( "check cache usage", 1, queryLayer.getCacheHits() );
+        assertEquals( 0.50, queryLayer.getCacheHitRate(), 0 );
     }
     
     public void testUseMetadataCache()
         throws Exception
     {
         testArtifactVersionsTrue();
-        assertEquals( "check cache usage", 0, queryLayer.getCacheHits() );
+        assertEquals( 0, queryLayer.getCacheHitRate(), 0 );
         testArtifactVersionsTrue();
-        assertEquals( "check cache usage", 1, queryLayer.getCacheHits() );
+        assertEquals( 0.50, queryLayer.getCacheHitRate(), 0 );
     }
     
     public void testUseFileCacheOnSnapshot()
     {
         testContainsSnapshotArtifactTrue();
-        assertEquals( "check cache usage", 0, queryLayer.getCacheHits() );
+        assertEquals( 0, queryLayer.getCacheHitRate(), 0 );
         testContainsSnapshotArtifactTrue();
-        assertEquals( "check cache usage", 1, queryLayer.getCacheHits() );
+        assertEquals( 0.50, queryLayer.getCacheHitRate(), 0 );
     }
 }