81
81
import com .google .devtools .build .lib .cmdline .RepositoryName ;
82
82
import com .google .devtools .build .lib .events .Event ;
83
83
import com .google .devtools .build .lib .pkgcache .PackageOptions ;
84
+ import com .google .devtools .build .lib .profiler .Profiler ;
85
+ import com .google .devtools .build .lib .profiler .ProfilerTask ;
86
+ import com .google .devtools .build .lib .profiler .SilentCloseable ;
84
87
import com .google .devtools .build .lib .rules .repository .LocalRepositoryFunction ;
85
88
import com .google .devtools .build .lib .rules .repository .LocalRepositoryRule ;
86
89
import com .google .devtools .build .lib .rules .repository .NewLocalRepositoryFunction ;
@@ -214,7 +217,7 @@ private static class RepositoryCacheInfoItem extends InfoItem {
214
217
public byte [] get (
215
218
Supplier <BuildConfigurationValue > configurationSupplier , CommandEnvironment env )
216
219
throws AbruptExitException , InterruptedException {
217
- return print (repositoryCache .getRootPath ());
220
+ return print (repositoryCache .getPath ());
218
221
}
219
222
}
220
223
@@ -245,7 +248,8 @@ public void workspaceInit(
245
248
isFetch ,
246
249
clientEnvironmentSupplier ,
247
250
directories ,
248
- BazelSkyframeExecutorConstants .EXTERNAL_PACKAGE_HELPER );
251
+ BazelSkyframeExecutorConstants .EXTERNAL_PACKAGE_HELPER ,
252
+ repositoryCache .getRepoContentsCache ());
249
253
singleExtensionEvalFunction =
250
254
new SingleExtensionEvalFunction (directories , clientEnvironmentSupplier );
251
255
@@ -311,7 +315,10 @@ public void initializeRuleClasses(ConfiguredRuleClassProvider.Builder builder) {
311
315
@ Override
312
316
public void beforeCommand (CommandEnvironment env ) throws AbruptExitException {
313
317
DownloadManager downloadManager =
314
- new DownloadManager (repositoryCache , env .getDownloaderDelegate (), env .getHttpDownloader ());
318
+ new DownloadManager (
319
+ repositoryCache .getDownloadCache (),
320
+ env .getDownloaderDelegate (),
321
+ env .getHttpDownloader ());
315
322
this .starlarkRepositoryFunction .setDownloadManager (downloadManager );
316
323
this .moduleFileFunction .setDownloadManager (downloadManager );
317
324
this .repoSpecFunction .setDownloadManager (downloadManager );
@@ -339,7 +346,7 @@ public void beforeCommand(CommandEnvironment env) throws AbruptExitException {
339
346
}
340
347
disableNativeRepoRules = repoOptions .disableNativeRepoRules ;
341
348
342
- repositoryCache .setHardlink (repoOptions .useHardlinks );
349
+ repositoryCache .getDownloadCache (). setHardlink (repoOptions .useHardlinks );
343
350
if (repoOptions .experimentalScaleTimeouts > 0.0 ) {
344
351
starlarkRepositoryFunction .setTimeoutScaling (repoOptions .experimentalScaleTimeouts );
345
352
singleExtensionEvalFunction .setTimeoutScaling (repoOptions .experimentalScaleTimeouts );
@@ -352,34 +359,61 @@ public void beforeCommand(CommandEnvironment env) throws AbruptExitException {
352
359
starlarkRepositoryFunction .setTimeoutScaling (1.0 );
353
360
singleExtensionEvalFunction .setTimeoutScaling (1.0 );
354
361
}
355
- if (repoOptions .experimentalRepositoryCache != null ) {
356
- Path repositoryCachePath ;
357
- if (repoOptions .experimentalRepositoryCache .isEmpty ()) {
358
- // A set but empty path indicates a request to disable the repository cache.
359
- repositoryCachePath = null ;
360
- } else if (repoOptions .experimentalRepositoryCache .isAbsolute ()) {
361
- repositoryCachePath = filesystem .getPath (repoOptions .experimentalRepositoryCache );
362
- } else {
363
- repositoryCachePath =
364
- env .getBlazeWorkspace ()
365
- .getWorkspace ()
366
- .getRelative (repoOptions .experimentalRepositoryCache );
367
- }
368
- repositoryCache .setRepositoryCachePath (repositoryCachePath );
362
+ if (repoOptions .repositoryCache != null ) {
363
+ repositoryCache .setPath (toPath (repoOptions .repositoryCache , env ));
369
364
} else {
370
- Path repositoryCachePath =
365
+ repositoryCache . setPath (
371
366
env .getDirectories ()
372
367
.getServerDirectories ()
373
368
.getOutputUserRoot ()
374
- .getRelative (DEFAULT_CACHE_LOCATION );
375
- try {
376
- repositoryCachePath .createDirectoryAndParents ();
377
- repositoryCache .setRepositoryCachePath (repositoryCachePath );
369
+ .getRelative (DEFAULT_CACHE_LOCATION ));
370
+ }
371
+ // Note that the repo contents cache stuff has to happen _after_ the repo cache stuff, because
372
+ // the specific settings about the repo contents cache might overwrite the repo cache
373
+ // settings. In particular, if `--repo_contents_cache` is not set (it's null), we use whatever
374
+ // default set by `repositoryCache.setPath(...)`.
375
+ if (repoOptions .repoContentsCache != null ) {
376
+ repositoryCache .getRepoContentsCache ().setPath (toPath (repoOptions .repoContentsCache , env ));
377
+ }
378
+ Path repoContentsCachePath = repositoryCache .getRepoContentsCache ().getPath ();
379
+ if (repoContentsCachePath != null
380
+ && env .getWorkspace () != null
381
+ && repoContentsCachePath .startsWith (env .getWorkspace ())) {
382
+ // Having the repo contents cache inside the workspace is very dangerous. During the
383
+ // lifetime of a Bazel invocation, we treat files inside the workspace as immutable. This
384
+ // can cause mysterious failures if we write files inside the workspace during the
385
+ // invocation, as is often the case with the repo contents cache.
386
+ // TODO: wyv@ - This is a crude check that disables some use cases (such as when the output
387
+ // base itself is inside the main repo). Investigate a better check.
388
+ repositoryCache .getRepoContentsCache ().setPath (null );
389
+ throw new AbruptExitException (
390
+ detailedExitCode (
391
+ """
392
+ The repo contents cache [%s] is inside the workspace [%s]. This can cause spurious \
393
+ failures. Disable the repo contents cache with `--repo_contents_cache=`, or \
394
+ specify `--repo_contents_cache=<path outside the workspace>`.
395
+ """
396
+ .formatted (repoContentsCachePath , env .getWorkspace ()),
397
+ Code .BAD_REPO_CONTENTS_CACHE ));
398
+ }
399
+ if (repositoryCache .getRepoContentsCache ().isEnabled ()) {
400
+ try (SilentCloseable c =
401
+ Profiler .instance ()
402
+ .profile (ProfilerTask .REPO_CACHE_GC_WAIT , "waiting to acquire repo cache lock" )) {
403
+ repositoryCache .getRepoContentsCache ().acquireSharedLock ();
378
404
} catch (IOException e ) {
379
- env .getReporter ()
380
- .handle (
381
- Event .warn (
382
- "Failed to set up cache at " + repositoryCachePath + ": " + e .getMessage ()));
405
+ throw new AbruptExitException (
406
+ detailedExitCode (
407
+ "could not acquire lock on repo contents cache" , Code .BAD_REPO_CONTENTS_CACHE ),
408
+ e );
409
+ }
410
+ if (!repoOptions .repoContentsCacheGcMaxAge .isZero ()) {
411
+ env .addIdleTask (
412
+ repositoryCache
413
+ .getRepoContentsCache ()
414
+ .createGcIdleTask (
415
+ repoOptions .repoContentsCacheGcMaxAge ,
416
+ repoOptions .repoContentsCacheGcIdleDelay ));
383
417
}
384
418
}
385
419
@@ -626,6 +660,32 @@ private String getAbsolutePath(String path, CommandEnvironment env) {
626
660
return path ;
627
661
}
628
662
663
+ /**
664
+ * An empty path fragment is turned into {@code null}; otherwise, it's treated as relative to the
665
+ * workspace root.
666
+ */
667
+ @ Nullable
668
+ private Path toPath (PathFragment path , CommandEnvironment env ) {
669
+ if (path .isEmpty () || env .getBlazeWorkspace ().getWorkspace () == null ) {
670
+ return null ;
671
+ }
672
+ return env .getBlazeWorkspace ().getWorkspace ().getRelative (path );
673
+ }
674
+
675
+ @ Override
676
+ public void afterCommand () throws AbruptExitException {
677
+ if (repositoryCache .getRepoContentsCache ().isEnabled ()) {
678
+ try {
679
+ repositoryCache .getRepoContentsCache ().releaseSharedLock ();
680
+ } catch (IOException e ) {
681
+ throw new AbruptExitException (
682
+ detailedExitCode (
683
+ "could not release lock on repo contents cache" , Code .BAD_REPO_CONTENTS_CACHE ),
684
+ e );
685
+ }
686
+ }
687
+ }
688
+
629
689
@ Override
630
690
public ImmutableList <Injected > getPrecomputedValues () {
631
691
Instant now = clock .now ();
0 commit comments