You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by hi...@apache.org on 2015/09/06 14:15:13 UTC
ant-ivy git commit: IVY-1430 : dynamic revisions are not cached per
resolver
Repository: ant-ivy
Updated Branches:
refs/heads/master 12d3f2818 -> 5240c8825
IVY-1430 : dynamic revisions are not cached per resolver
Thanks to Stephen Haberman
Project: http://git-wip-us.apache.org/repos/asf/ant-ivy/repo
Commit: http://git-wip-us.apache.org/repos/asf/ant-ivy/commit/5240c882
Tree: http://git-wip-us.apache.org/repos/asf/ant-ivy/tree/5240c882
Diff: http://git-wip-us.apache.org/repos/asf/ant-ivy/diff/5240c882
Branch: refs/heads/master
Commit: 5240c8825896997f0845e354a51b1ac725dfe06b
Parents: 12d3f28
Author: Nicolas Lalevée <ni...@hibnet.org>
Authored: Sun Sep 6 14:14:58 2015 +0200
Committer: Nicolas Lalevée <ni...@hibnet.org>
Committed: Sun Sep 6 14:14:58 2015 +0200
----------------------------------------------------------------------
doc/release-notes.html | 1 +
.../cache/DefaultRepositoryCacheManager.java | 41 +++++++++-
.../ivy/core/cache/RepositoryCacheManager.java | 15 ++++
.../ivy/plugins/resolver/AbstractResolver.java | 10 +--
.../DefaultRepositoryCacheManagerTest.java | 80 +++++++++++++++++++-
5 files changed, 134 insertions(+), 13 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/5240c882/doc/release-notes.html
----------------------------------------------------------------------
diff --git a/doc/release-notes.html b/doc/release-notes.html
index 63c4fcf..12624af 100644
--- a/doc/release-notes.html
+++ b/doc/release-notes.html
@@ -60,6 +60,7 @@ List of changes since Ivy 2.4.0:
- FIX: ArrayIndexOutOfBoundsException when using a p2 repository for dependencies (IVY-1504)
- FIX: fixdeps remove transitive 'kept' dependencies
- FIX: PomModuleDescriptorParser should parse licenses from parent POM (IVY-1526) (Thanks to Jaikiran Pai)
+- FIX: dynamic revisions are not cached per resolver (IVY-1430) (Thanks to Stephen Haberman)
- IMPROVEMENT: Optimization: limit the revision numbers scanned if revision prefix is specified (Thanks to Ernestas Vaiciukevičius)
http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/5240c882/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java b/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java
index a950c0b..f6b2206 100644
--- a/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java
+++ b/src/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManager.java
@@ -667,6 +667,17 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
getDataFilePattern(), mRevId)), "ivy cached data file for " + mRevId);
}
+ /**
+ * A resolver-specific ivydata file, only used for caching dynamic revisions, e.g.
+ * integration-repo.
+ */
+ private PropertiesFile getCachedDataFile(String resolverName, ModuleRevisionId mRevId) {
+ // we append ".${resolverName} onto the end of the regular ivydata location
+ return new PropertiesFile(new File(getRepositoryCacheRoot(),
+ IvyPatternHelper.substitute(getDataFilePattern(), mRevId) + "." + resolverName),
+ "ivy cached data file for " + mRevId);
+ }
+
public ResolvedModuleRevision findModuleInCache(DependencyDescriptor dd,
ModuleRevisionId requestedRevisionId, CacheMetadataOptions options,
String expectedResolver) {
@@ -693,7 +704,7 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
try {
if (settings.getVersionMatcher().isDynamic(mrid)) {
- String resolvedRevision = getResolvedRevision(mrid, options);
+ String resolvedRevision = getResolvedRevision(expectedResolver, mrid, options);
if (resolvedRevision != null) {
Message.verbose("found resolved revision in cache: " + mrid + " => "
+ resolvedRevision);
@@ -832,7 +843,11 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
return cache.getStale(ivyFile, settings, options.isValidate(), mdProvider);
}
- private String getResolvedRevision(ModuleRevisionId mrid, CacheMetadataOptions options) {
+ /**
+ * Called by doFindModuleInCache to lookup the dynamic {@code mrid} in the ivycache's ivydata
+ * file.
+ */
+ private String getResolvedRevision(String expectedResolver, ModuleRevisionId mrid, CacheMetadataOptions options) {
if (!lockMetadataArtifact(mrid)) {
Message.error("impossible to acquire lock for " + mrid);
return null;
@@ -843,7 +858,13 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
Message.verbose("refresh mode: no check for cached resolved revision for " + mrid);
return null;
}
- PropertiesFile cachedResolvedRevision = getCachedDataFile(mrid);
+ // If a resolver is asking for its specific dynamic revision, avoid looking at a different one
+ PropertiesFile cachedResolvedRevision;
+ if (expectedResolver != null) {
+ cachedResolvedRevision = getCachedDataFile(expectedResolver, mrid);
+ } else {
+ cachedResolvedRevision = getCachedDataFile(mrid);
+ }
resolvedRevision = cachedResolvedRevision.getProperty("resolved.revision");
if (resolvedRevision == null) {
Message.verbose(getName() + ": no cached resolved revision for " + mrid);
@@ -873,15 +894,27 @@ public class DefaultRepositoryCacheManager implements RepositoryCacheManager, Iv
}
public void saveResolvedRevision(ModuleRevisionId mrid, String revision) {
+ saveResolvedRevision(null, mrid, revision);
+ }
+
+ public void saveResolvedRevision(String resolverName, ModuleRevisionId mrid, String revision) {
if (!lockMetadataArtifact(mrid)) {
Message.error("impossible to acquire lock for " + mrid);
return;
}
try {
- PropertiesFile cachedResolvedRevision = getCachedDataFile(mrid);
+ PropertiesFile cachedResolvedRevision;
+ if (resolverName == null) {
+ cachedResolvedRevision = getCachedDataFile(mrid);
+ } else {
+ cachedResolvedRevision = getCachedDataFile(resolverName, mrid);
+ }
cachedResolvedRevision.setProperty("resolved.time",
String.valueOf(System.currentTimeMillis()));
cachedResolvedRevision.setProperty("resolved.revision", revision);
+ if (resolverName != null) {
+ cachedResolvedRevision.setProperty("resolver", resolverName);
+ }
cachedResolvedRevision.save();
} finally {
unlockMetadataArtifact(mrid);
http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/5240c882/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java b/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java
index f6c5c24..a5effa1 100644
--- a/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java
+++ b/src/java/org/apache/ivy/core/cache/RepositoryCacheManager.java
@@ -188,7 +188,22 @@ public interface RepositoryCacheManager {
* the dynamic module revision id
* @param revision
* the resolved revision
+ * @deprecated See {@link #saveResolvedRevision(String, ModuleRevisionId, String)} which
+ * prevents cache + * thrashing when multiple resolvers store the same dynamicMrid
*/
public void saveResolvedRevision(ModuleRevisionId dynamicMrid, String revision);
+ /**
+ * Caches a dynamic revision constraint resolution for a specific resolver.
+ *
+ * @param resolverName
+ * the resolver in which this dynamic revision was resolved
+ * @param dynamicMrid
+ * the dynamic module revision id
+ * @param revision
+ * the resolved revision
+ */
+ public void saveResolvedRevision(String resolverName, ModuleRevisionId dynamicMrid,
+ String revision);
+
}
http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/5240c882/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java b/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java
index 6030c9f..ef422d4 100644
--- a/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java
+++ b/src/java/org/apache/ivy/plugins/resolver/AbstractResolver.java
@@ -513,22 +513,22 @@ public abstract class AbstractResolver implements DependencyResolver, HasLatestS
Checks.checkNotNull(dd, "dd");
Checks.checkNotNull(data, "data");
+ // always cache dynamic mrids because we can store per-resolver values
+ saveModuleRevisionIfNeeded(dd, newModuleFound);
+
// check if latest is asked and compare to return the most recent
ResolvedModuleRevision previousModuleFound = data.getCurrentResolvedModuleRevision();
String newModuleDesc = describe(newModuleFound);
Message.debug("\tchecking " + newModuleDesc + " against " + describe(previousModuleFound));
if (previousModuleFound == null) {
Message.debug("\tmodule revision kept as first found: " + newModuleDesc);
- saveModuleRevisionIfNeeded(dd, newModuleFound);
return newModuleFound;
} else if (isAfter(newModuleFound, previousModuleFound, data.getDate())) {
Message.debug("\tmodule revision kept as younger: " + newModuleDesc);
- saveModuleRevisionIfNeeded(dd, newModuleFound);
return newModuleFound;
} else if (!newModuleFound.getDescriptor().isDefault()
&& previousModuleFound.getDescriptor().isDefault()) {
Message.debug("\tmodule revision kept as better (not default): " + newModuleDesc);
- saveModuleRevisionIfNeeded(dd, newModuleFound);
return newModuleFound;
} else {
Message.debug("\tmodule revision discarded as older: " + newModuleDesc);
@@ -540,8 +540,8 @@ public abstract class AbstractResolver implements DependencyResolver, HasLatestS
ResolvedModuleRevision newModuleFound) {
if (newModuleFound != null
&& getSettings().getVersionMatcher().isDynamic(dd.getDependencyRevisionId())) {
- getRepositoryCacheManager().saveResolvedRevision(dd.getDependencyRevisionId(),
- newModuleFound.getId().getRevision());
+ getRepositoryCacheManager().saveResolvedRevision(getName(),
+ dd.getDependencyRevisionId(), newModuleFound.getId().getRevision());
}
}
http://git-wip-us.apache.org/repos/asf/ant-ivy/blob/5240c882/test/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManagerTest.java
----------------------------------------------------------------------
diff --git a/test/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManagerTest.java b/test/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManagerTest.java
index 0e1b147..61ac601 100644
--- a/test/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManagerTest.java
+++ b/test/java/org/apache/ivy/core/cache/DefaultRepositoryCacheManagerTest.java
@@ -18,16 +18,33 @@
package org.apache.ivy.core.cache;
import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.ParseException;
import java.util.Date;
import junit.framework.TestCase;
import org.apache.ivy.Ivy;
+import org.apache.ivy.core.IvyContext;
import org.apache.ivy.core.module.descriptor.Artifact;
import org.apache.ivy.core.module.descriptor.DefaultArtifact;
+import org.apache.ivy.core.module.descriptor.DefaultDependencyDescriptor;
+import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
+import org.apache.ivy.core.module.descriptor.ModuleDescriptor;
import org.apache.ivy.core.module.id.ModuleId;
import org.apache.ivy.core.module.id.ModuleRevisionId;
+import org.apache.ivy.core.resolve.ResolvedModuleRevision;
import org.apache.ivy.core.settings.IvySettings;
+import org.apache.ivy.plugins.parser.xml.XmlModuleDescriptorWriter;
+import org.apache.ivy.plugins.repository.BasicResource;
+import org.apache.ivy.plugins.repository.Resource;
+import org.apache.ivy.plugins.repository.ResourceDownloader;
+import org.apache.ivy.plugins.resolver.MockResolver;
+import org.apache.ivy.plugins.resolver.util.ResolvedResource;
+import org.apache.ivy.util.DefaultMessageLogger;
+import org.apache.ivy.util.Message;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Delete;
@@ -35,16 +52,19 @@ import org.apache.tools.ant.taskdefs.Delete;
* @see DefaultResolutionCacheManager
*/
public class DefaultRepositoryCacheManagerTest extends TestCase {
+
private DefaultRepositoryCacheManager cacheManager;
-
private Artifact artifact;
-
private ArtifactOrigin origin;
+ private Ivy ivy;
protected void setUp() throws Exception {
File f = File.createTempFile("ivycache", ".dir");
- Ivy ivy = new Ivy();
+ ivy = new Ivy();
ivy.configureDefault();
+ ivy.getLoggerEngine().setDefaultLogger(new DefaultMessageLogger(Message.MSG_DEBUG));
+ IvyContext.pushNewContext().setIvy(ivy);
+
IvySettings settings = ivy.getSettings();
f.delete(); // we want to use the file as a directory, so we delete the file itself
cacheManager = new DefaultRepositoryCacheManager();
@@ -62,6 +82,7 @@ public class DefaultRepositoryCacheManagerTest extends TestCase {
}
protected void tearDown() throws Exception {
+ IvyContext.popContext();
Delete del = new Delete();
del.setProject(new Project());
del.setDir(cacheManager.getRepositoryCacheRoot());
@@ -106,7 +127,58 @@ public class DefaultRepositoryCacheManagerTest extends TestCase {
assertTrue(ArtifactOrigin.isUnknown(found));
}
- protected Artifact createArtifact(String org, String module, String rev, String name,
+ public void testLatestIntegrationIsCachedPerResolver() throws Exception {
+ // given a module org#module
+ ModuleId mi = new ModuleId("org", "module");
+
+ // and a latest.integration mrid/dd
+ ModuleRevisionId mridLatest = new ModuleRevisionId(mi, "trunk", "latest.integration");
+ DependencyDescriptor ddLatest = new DefaultDependencyDescriptor(mridLatest, false);
+
+ // and some random options
+ CacheMetadataOptions options = new CacheMetadataOptions().setCheckTTL(false);
+
+ // setup resolver1 to download the static content so we can call cacheModuleDescriptor
+ MockResolver resolver1 = new MockResolver();
+ resolver1.setName("resolver1");
+ resolver1.setSettings(ivy.getSettings());
+ ivy.getSettings().addResolver(resolver1);
+ ResourceDownloader downloader = new ResourceDownloader() {
+ public void download(Artifact artifact, Resource resource, File dest)
+ throws IOException {
+ String content = "<ivy-module version=\"2.0\"><info organisation=\"org\" module=\"module\" status=\"integration\" revision=\"1.1\" branch=\"trunk\"/></ivy-module>";
+ dest.getParentFile().mkdirs();
+ FileOutputStream out = new FileOutputStream(dest);
+ PrintWriter pw = new PrintWriter(out);
+ pw.write(content);
+ pw.flush();
+ out.close();
+ }
+ };
+ ModuleDescriptorWriter writer = new ModuleDescriptorWriter() {
+ public void write(ResolvedResource originalMdResource, ModuleDescriptor md, File src, File dest) throws IOException, ParseException {
+ XmlModuleDescriptorWriter.write(md, dest);
+ }
+ };
+
+ // latest.integration will resolve to 1.1 in resolver1
+ ModuleRevisionId mrid11 = new ModuleRevisionId(mi, "trunk", "1.1");
+ DependencyDescriptor dd11 = new DefaultDependencyDescriptor(mrid11, false);
+ DefaultArtifact artifact11 = new DefaultArtifact(mrid11, new Date(), "module-1.1.ivy", "ivy", "ivy", true);
+ BasicResource resource11 = new BasicResource("/module-1-1.ivy", true, 1, 0, true);
+ ResolvedResource mdRef11 = new ResolvedResource(resource11, "1.1");
+
+ // tell the cache about 1.1
+ ResolvedModuleRevision rmr11 = cacheManager.cacheModuleDescriptor(resolver1, mdRef11, dd11, artifact11, downloader, options);
+ cacheManager.originalToCachedModuleDescriptor(resolver1, mdRef11, artifact11, rmr11, writer);
+ // and use the new overload that passes in resolver name
+ cacheManager.saveResolvedRevision("resolver1", mridLatest, "1.1");
+
+ ResolvedModuleRevision rmrFromCache = cacheManager.findModuleInCache(ddLatest, mridLatest, options, "resolver1");
+ assertEquals(rmr11, rmrFromCache);
+ }
+
+ protected static DefaultArtifact createArtifact(String org, String module, String rev, String name,
String type, String ext) {
ModuleId mid = new ModuleId(org, module);
ModuleRevisionId mrid = new ModuleRevisionId(mid, rev);