43
43
import java .util .LinkedHashMap ;
44
44
import java .util .List ;
45
45
import java .util .Map ;
46
- import java .util .Set ;
47
46
import java .util .TreeMap ;
47
+ import java .util .concurrent .ConcurrentHashMap ;
48
+ import java .util .concurrent .locks .ReentrantReadWriteLock ;
48
49
import java .util .logging .Level ;
49
50
import java .util .logging .Logger ;
50
51
import edu .umd .cs .findbugs .annotations .CheckForNull ;
65
66
@ Extension public class LibraryAdder extends ClasspathAdder {
66
67
67
68
private static final Logger LOGGER = Logger .getLogger (LibraryAdder .class .getName ());
69
+
70
+ private static ConcurrentHashMap <String , ReentrantReadWriteLock > cacheRetrieveLock = new ConcurrentHashMap <>();
68
71
72
+ static @ NonNull ReentrantReadWriteLock getReadWriteLockFor (@ NonNull String name ) {
73
+ return cacheRetrieveLock .computeIfAbsent (name , s -> new ReentrantReadWriteLock (true ));
74
+ }
75
+
69
76
@ Override public List <Addition > add (CpsFlowExecution execution , List <String > libraries , HashMap <String , Boolean > changelogs ) throws Exception {
70
77
Queue .Executable executable = execution .getOwner ().getExecutable ();
71
78
Run <?,?> build ;
156
163
}
157
164
}
158
165
166
+ private enum CacheStatus {
167
+ VALID ,
168
+ DOES_NOT_EXIST ,
169
+ EXPIRED ;
170
+ }
171
+
172
+ private static CacheStatus getCacheStatus (@ NonNull LibraryCachingConfiguration cachingConfiguration , @ NonNull final FilePath versionCacheDir )
173
+ throws IOException , InterruptedException
174
+ {
175
+ if (cachingConfiguration .isRefreshEnabled ()) {
176
+ final long cachingMilliseconds = cachingConfiguration .getRefreshTimeMilliseconds ();
177
+
178
+ if (versionCacheDir .exists ()) {
179
+ if ((versionCacheDir .lastModified () + cachingMilliseconds ) > System .currentTimeMillis ()) {
180
+ return CacheStatus .VALID ;
181
+ } else {
182
+ return CacheStatus .EXPIRED ;
183
+ }
184
+ } else {
185
+ return CacheStatus .DOES_NOT_EXIST ;
186
+ }
187
+ } else {
188
+ if (versionCacheDir .exists ()) {
189
+ return CacheStatus .VALID ;
190
+ } else {
191
+ return CacheStatus .DOES_NOT_EXIST ;
192
+ }
193
+ }
194
+ }
195
+
159
196
/** Retrieve library files. */
160
197
static List <URL > retrieve (@ NonNull LibraryRecord record , @ NonNull LibraryRetriever retriever , @ NonNull TaskListener listener , @ NonNull Run <?,?> run , @ NonNull CpsFlowExecution execution ) throws Exception {
161
198
String name = record .name ;
@@ -165,42 +202,60 @@ static List<URL> retrieve(@NonNull LibraryRecord record, @NonNull LibraryRetriev
165
202
FilePath libDir = new FilePath (execution .getOwner ().getRootDir ()).child ("libs/" + record .getDirectoryName ());
166
203
Boolean shouldCache = cachingConfiguration != null ;
167
204
final FilePath versionCacheDir = new FilePath (LibraryCachingConfiguration .getGlobalLibrariesCacheDir (), record .getDirectoryName ());
168
- final FilePath retrieveLockFile = new FilePath ( versionCacheDir , LibraryCachingConfiguration . RETRIEVE_LOCK_FILE );
205
+ ReentrantReadWriteLock retrieveLock = getReadWriteLockFor ( record . getDirectoryName () );
169
206
final FilePath lastReadFile = new FilePath (versionCacheDir , LibraryCachingConfiguration .LAST_READ_FILE );
170
207
171
208
if (shouldCache && cachingConfiguration .isExcluded (version )) {
172
209
listener .getLogger ().println ("Library " + name + "@" + version + " is excluded from caching." );
173
210
shouldCache = false ;
174
211
}
175
212
176
- if (shouldCache && retrieveLockFile .exists ()) {
177
- listener .getLogger ().println ("Library " + name + "@" + version + " is currently being cached by another job, retrieving without cache." );
178
- shouldCache = false ;
179
- }
180
-
181
213
if (shouldCache ) {
182
- if (cachingConfiguration .isRefreshEnabled ()) {
183
- final long cachingMinutes = cachingConfiguration .getRefreshTimeMinutes ();
184
- final long cachingMilliseconds = cachingConfiguration .getRefreshTimeMilliseconds ();
185
-
186
- if (versionCacheDir .exists () && (versionCacheDir .lastModified () + cachingMilliseconds ) < System .currentTimeMillis ()) {
187
- listener .getLogger ().println ("Library " + name + "@" + version + " is due for a refresh after " + cachingMinutes + " minutes, clearing." );
188
- versionCacheDir .deleteRecursive ();
214
+ retrieveLock .readLock ().lockInterruptibly ();
215
+ try {
216
+ CacheStatus cacheStatus = getCacheStatus (cachingConfiguration , versionCacheDir );
217
+ if (cacheStatus == CacheStatus .DOES_NOT_EXIST || cacheStatus == CacheStatus .EXPIRED ) {
218
+ retrieveLock .readLock ().unlock ();
219
+ retrieveLock .writeLock ().lockInterruptibly ();
220
+ try {
221
+ boolean retrieve = false ;
222
+ switch (getCacheStatus (cachingConfiguration , versionCacheDir )) {
223
+ case VALID :
224
+ listener .getLogger ().println ("Library " + name + "@" + version + " is cached. Copying from home." );
225
+ break ;
226
+ case DOES_NOT_EXIST :
227
+ retrieve = true ;
228
+ break ;
229
+ case EXPIRED :
230
+ long cachingMinutes = cachingConfiguration .getRefreshTimeMinutes ();
231
+ listener .getLogger ().println ("Library " + name + "@" + version + " is due for a refresh after " + cachingMinutes + " minutes, clearing." );
232
+ if (versionCacheDir .exists ()) {
233
+ versionCacheDir .deleteRecursive ();
234
+ versionCacheDir .withSuffix ("-name.txt" ).delete ();
235
+ }
236
+ retrieve = true ;
237
+ break ;
238
+ }
239
+
240
+ if (retrieve ) {
241
+ listener .getLogger ().println ("Caching library " + name + "@" + version );
242
+ versionCacheDir .mkdirs ();
243
+ retriever .retrieve (name , version , changelog , versionCacheDir , run , listener );
244
+ }
245
+ retrieveLock .readLock ().lock ();
246
+ } finally {
247
+ retrieveLock .writeLock ().unlock ();
248
+ }
249
+ } else {
250
+ listener .getLogger ().println ("Library " + name + "@" + version + " is cached. Copying from home." );
189
251
}
252
+
253
+ lastReadFile .touch (System .currentTimeMillis ());
254
+ versionCacheDir .withSuffix ("-name.txt" ).write (name , "UTF-8" );
255
+ versionCacheDir .copyRecursiveTo (libDir );
256
+ } finally {
257
+ retrieveLock .readLock ().unlock ();
190
258
}
191
-
192
- if (versionCacheDir .exists ()) {
193
- listener .getLogger ().println ("Library " + name + "@" + version + " is cached. Copying from home." );
194
- } else {
195
- listener .getLogger ().println ("Caching library " + name + "@" + version );
196
- versionCacheDir .mkdirs ();
197
- retrieveLockFile .touch (System .currentTimeMillis ());
198
- retriever .retrieve (name , version , changelog , versionCacheDir , run , listener );
199
- retrieveLockFile .delete ();
200
- }
201
- lastReadFile .touch (System .currentTimeMillis ());
202
- versionCacheDir .withSuffix ("-name.txt" ).write (name , "UTF-8" );
203
- versionCacheDir .copyRecursiveTo (libDir );
204
259
} else {
205
260
retriever .retrieve (name , version , changelog , libDir , run , listener );
206
261
}
0 commit comments