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