[ 
https://issues.apache.org/jira/browse/GROOVY-8097?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15907001#comment-15907001
 ] 

Ion Alberdi edited comment on GROOVY-8097 at 3/14/17 8:33 AM:
--------------------------------------------------------------

[~jexler] Please find in [grab.groovy 
|https://github.com/yetanotherion/code_snippets/blob/master/groovy/groovy_8097/grab.groovy]
 / ([grapeConfig.xml| 
https://github.com/yetanotherion/code_snippets/blob/master/groovy/groovy_8097/grapeConfig.xml],
 to put in $HOME/.groovy) the test we used to reproduce/validate the concurrent 
access-es to repository/resolution cache dirs. This test launches 200 threads
that each download different versions of org.jenkins-ci.main:jenkins-core and 
org.codehaus.groovy:groovy-all. As said earlier,
- the global lock strategy will be slower than the different resolution cache 
dir solution (as we'll get a lock even if different artifacts should be 
downloaded)
- the solution we're looking for, should work for both *same jvm* and *multiple 
jvm scenarios* (launching two groovy grab.groovy should work too, even though 
the current state of grab.groovy does not handle it (a prefix should be added 
so that the two jvm compute different paths for the resolution cache dir of the 
200 threads in the same jvm)).

For these reasons the solution proposed by [~paulk] seems more 
efficient/maintanable  (Regarding maintainability: "The call would have to be 
made at least once per VM resp. per loaded Grape.class, preferably before you 
do any grabs. Instead of passing Date.class as a lock, you can pass any class 
in the JDK, it just has to be something that is not loaded multiple times in 
the VMs.", seems harder to guess than "one resolution cache dir per concurrent 
job").

[~paulk] sorry for having made you repeat something you already said in the 
first answer of the post. 

If you all agree, the first version of the PR will 
- follow [~paulk] suggestion and among others, 
- "Grape will switch from a singleton to a map of <string: resolutionCacheDir, 
GrapeIvy.class: grapeIvy,> each grapeIvy pointing to a different 
resolutionCacheDir."





was (Author: yetanotherion):
[~jexler] Please find in [grab.groovy 
|https://github.com/yetanotherion/code_snippets/blob/master/groovy/groovy_8097/grab.groovy]
 / ([grapeConfig.xml| 
https://github.com/yetanotherion/code_snippets/blob/master/groovy/groovy_8097/grapeConfig.xml],
 to put in $HOME/.groovy) the test we used to reproduce/validate the concurrent 
access-es to repository/resolution cache dirs. This test launches 200 threads
that each download different versions of org.jenkins-ci.main:jenkins-core and 
org.codehaus.groovy:groovy-all. As said earlier,
- the global lock strategy will be slower than the different resolution cache 
dir solution (as we'll get a lock even if different artifacts should be 
downloaded)
- the solution we're looking for, should work for both *same jvm* and *multiple 
jvm scenarios* (launching two groovy grab.groovy should work too, even though 
the current state of grab.groovy does not handle it (a prefix should be added 
so that the two jvm compute different paths for the resolution cache dir of the 
200 threads in the same jvm)).

For these reasons the solution proposed by [~paulk] seems more 
efficient/maintanable  (Regarding maintainability: "The call would have to be 
made at least once per VM resp. per loaded Grape.class, preferably before you 
do any grabs. Instead of passing Date.class as a lock, you can pass any class 
in the JDK, it just has to be something that is not loaded multiple times in 
the VMs.", seems harder to guess than "one resolution cache dir per concurrent 
job").

[~paulk] sorry for having made you repeat something you already said in the 
first answer of the post. 

If you all agree, the first version of the PR will 
- follow [~paulk] suggestion and among others, 
- "Grape will switch from a singleton to a map of <string: resolutionCacheDir, 
GrapeIvy.class: grapeIvy,> each grapeIvy pointing to a different 
resolutionCacheDir."




> Add an argument to set the resolution cache path in @Grab
> ---------------------------------------------------------
>
>                 Key: GROOVY-8097
>                 URL: https://issues.apache.org/jira/browse/GROOVY-8097
>             Project: Groovy
>          Issue Type: New Feature
>          Components: Grape
>    Affects Versions: 2.4.8
>            Reporter: Ion Alberdi
>            Priority: Minor
>
> Ivy does not support concurrent access to its resolution cache 
> https://issues.apache.org/jira/browse/IVY-654
> Grape relies on Ivy. For this reason, Grape cannot support concurrent access 
> to its resolution cache neither.
> When using the @Grab annotation in jenkins groovyCommand or 
> systemGroovyCommand, the related code is vulnerable to race conditions. When 
> the race condition appears in a systemGroovyCommand, we have no choice but to 
> reboot jenkins as all consecutive calls to @Grab fail.
> Among the two solutions we tried: 
> - Protect the calls to grab with a lock similar to ivy's "artifact-lock-nio" 
> strategy. Works but slow.
> - Set Ivy's lock on the repository cache and setup Grab to use a different 
> cache resolution cache for each concurrent jobs. The following code permits 
> to fix a test we did to reproduce the race condition.
> {code}
>     static IvySettings createIvySettings(String resolutionPath, boolean 
> dumpSettings) {
>         // Copy/Paste/Purged from GrapeIvy.groovy
>         IvySettings settings = new IvySettings()
>         settings.load(new File(GROOVY_HOME, "grapeConfig.xml"))
>         // set up the cache dirs
>         settings.defaultCache = new File(GRAPES_HOME)
>         settings.setVariable("ivy.default.configuration.m2compatible", "true")
>         settings.setDefaultResolutionCacheBasedir(resolutionPath)
>         return settings
>     }
>     static GrapeIvy ivyWithCustomResolutionPath(String resolutionPath) {
>         Class<?> grapeIvyClass = Class.forName("groovy.grape.GrapeIvy");
>         Object instance = grapeIvyClass.newInstance()
>         Field field = grapeIvyClass.getDeclaredField("ivyInstance");
>         field.setAccessible(true);
>         field.set(instance, 
> Ivy.newInstance(createIvySettings(resolutionPath)));
>         return ((GrapeIvy)instance)
>     }
> {code}
> We'd like to propose to add an additional argument to Grab to setup Ivy's 
> resolution cache directory.
> Note that this solution seems to have been adopted by these users too
> https://rbcommons.com/s/twitter/r/3436/
> Would you agree on such a feature ? We'd be glad to propose a PR.



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

Reply via email to