@@ -112,14 +112,15 @@ ResourceRequest getRequest() {
112
112
113
113
/** Closing the ResourceHandle releases the resources associated with it. */
114
114
@ Override
115
- public void close () throws IOException , InterruptedException {
115
+ public void close () throws IOException , InterruptedException , UserExecException {
116
116
manager .releaseResources (request , worker );
117
117
Profiler .instance ()
118
118
.completeTask (
119
119
resourceAcquiredTime , ProfilerTask .LOCAL_ACTION_COUNTS , "Resources acquired" );
120
120
}
121
121
122
- public void invalidateAndClose (@ Nullable Exception e ) throws IOException , InterruptedException {
122
+ public void invalidateAndClose (@ Nullable Exception e )
123
+ throws IOException , InterruptedException , UserExecException {
123
124
// If there is an exception, we need to set the kill cause before invalidating the object.
124
125
// This ensures that the worker implementation updates their worker metrics accordingly
125
126
// if/when it destroys itself.
@@ -279,14 +280,14 @@ public WindowUpdateRunner(String name) {
279
280
public void run () {
280
281
try {
281
282
windowUpdate ();
282
- } catch (IOException | InterruptedException e ) {
283
+ } catch (IOException | InterruptedException | UserExecException e ) {
283
284
logger .atWarning ().withCause (e ).log (
284
285
"Exception while updating window of locally scheduled action: %s" , e );
285
286
}
286
287
}
287
288
}
288
289
289
- synchronized void windowUpdate () throws IOException , InterruptedException {
290
+ synchronized void windowUpdate () throws IOException , InterruptedException , UserExecException {
290
291
windowRequestIds .clear ();
291
292
windowEstimationCpu = 0.0 ;
292
293
processAllWaitingRequests ();
@@ -468,7 +469,7 @@ public boolean threadHasResources() {
468
469
* @throws java.io.IOException if could not return worker to the workerPool
469
470
*/
470
471
void releaseResources (ResourceRequest request , @ Nullable Worker worker )
471
- throws IOException , InterruptedException {
472
+ throws IOException , InterruptedException , UserExecException {
472
473
Preconditions .checkNotNull (
473
474
request .getResourceSet (),
474
475
"releaseResources called with resources == NULL during %s" ,
@@ -500,7 +501,7 @@ public void acquireResourceOwnership() {
500
501
* wait.
501
502
*/
502
503
private synchronized ResourceLatch acquire (ResourceRequest request )
503
- throws IOException , InterruptedException {
504
+ throws IOException , InterruptedException , UserExecException {
504
505
if (areResourcesAvailable (request .getResourceSet ())) {
505
506
Worker worker = incrementResources (request );
506
507
return new ResourceLatch (/* latch= */ null , worker );
@@ -523,7 +524,7 @@ private synchronized ResourceLatch acquire(ResourceRequest request)
523
524
524
525
/** Release resources and process the queues of waiting threads. */
525
526
private synchronized void release (ResourceRequest request , @ Nullable Worker worker )
526
- throws IOException , InterruptedException {
527
+ throws IOException , InterruptedException , UserExecException {
527
528
if (worker != null ) {
528
529
this .workerPool .returnWorker (worker .getWorkerKey (), worker );
529
530
}
@@ -555,14 +556,15 @@ private synchronized void release(ResourceRequest request, @Nullable Worker work
555
556
processAllWaitingRequests ();
556
557
}
557
558
558
- private synchronized void processAllWaitingRequests () throws IOException , InterruptedException {
559
+ private synchronized void processAllWaitingRequests ()
560
+ throws IOException , InterruptedException , UserExecException {
559
561
processWaitingRequests (localRequests );
560
562
processWaitingRequests (dynamicWorkerRequests );
561
563
processWaitingRequests (dynamicStandaloneRequests );
562
564
}
563
565
564
566
private synchronized void processWaitingRequests (Deque <WaitingRequest > requests )
565
- throws IOException , InterruptedException {
567
+ throws IOException , InterruptedException , UserExecException {
566
568
if (requests .isEmpty ()) {
567
569
return ;
568
570
}
@@ -607,10 +609,29 @@ private void assertResourcesTracked(ResourceSet resources) throws ExecException
607
609
}
608
610
}
609
611
610
- private <T extends Number > boolean isAvailable (T available , T used , T requested ) {
612
+ private <T extends Number > boolean isAvailable (
613
+ T available , T used , T requested , String resourceName ) throws UserExecException {
614
+ if (!allowOneActionOnResourceUnavailable
615
+ && available .doubleValue () + used .doubleValue () < requested .doubleValue ()) {
616
+ throw new UserExecException (
617
+ FailureDetails .FailureDetail .newBuilder ()
618
+ .setMessage (
619
+ String .format (
620
+ "The `%s` resources are not enough to fulfill the request. To allow Bazel to"
621
+ + " bypass this limitation, please adjust the --local_resources flag or"
622
+ + " specify --allow_one_action_on_resource_unavailable in your Bazel"
623
+ + " command." ,
624
+ resourceName ))
625
+ .setLocalExecution (
626
+ FailureDetails .LocalExecution .newBuilder ()
627
+ .setCode (FailureDetails .LocalExecution .Code .NOT_ENOUGH_LOCAL_RESOURCE )
628
+ .build ())
629
+ .build ());
630
+ }
611
631
// Resources are considered available if any one of the conditions below is true:
612
632
// 1) If resource is not requested at all, it is available.
613
- // 2) If resource is not used at the moment, it is considered to be
633
+ // 2) If resource is not used at the moment and the flag
634
+ // "allow_one_action_on_resource_unavailable" is enabled, it is considered to be
614
635
// available regardless of how much is requested. This is necessary to
615
636
// ensure that at any given time, at least one thread is able to acquire
616
637
// resources even if it requests more than available.
@@ -622,7 +643,7 @@ private <T extends Number> boolean isAvailable(T available, T used, T requested)
622
643
623
644
// Method will return true if all requested resources are considered to be available.
624
645
@ VisibleForTesting
625
- synchronized boolean areResourcesAvailable (ResourceSet resources ) {
646
+ synchronized boolean areResourcesAvailable (ResourceSet resources ) throws UserExecException {
626
647
Preconditions .checkNotNull (availableResources );
627
648
// Comparison below is robust, since any calculation errors will be fixed
628
649
// by the release() method.
@@ -640,7 +661,11 @@ synchronized boolean areResourcesAvailable(ResourceSet resources) {
640
661
}
641
662
642
663
int availableLocalTestCount = availableResources .getLocalTestCount ();
643
- if (!isAvailable (availableLocalTestCount , usedLocalTestCount , resources .getLocalTestCount ())) {
664
+ if (!isAvailable (
665
+ availableLocalTestCount ,
666
+ usedLocalTestCount ,
667
+ resources .getLocalTestCount (),
668
+ "local_test_count" )) {
644
669
return false ;
645
670
}
646
671
@@ -662,14 +687,14 @@ synchronized boolean areResourcesAvailable(ResourceSet resources) {
662
687
resource .getValue () * MIN_NECESSARY_RATIO .getOrDefault (key , DEFAULT_MIN_NECESSARY_RATIO );
663
688
double used = usedResources .getOrDefault (key , 0.0 );
664
689
double available = availableResources .get (key );
665
- if (!isAvailable (available , used , requested )) {
690
+ if (!isAvailable (available , used , requested , key )) {
666
691
return false ;
667
692
}
668
693
}
669
694
return true ;
670
695
}
671
696
672
- synchronized boolean isCpuAvailable (Map .Entry <String , Double > resource ) {
697
+ synchronized boolean isCpuAvailable (Map .Entry <String , Double > resource ) throws UserExecException {
673
698
String key = resource .getKey ();
674
699
675
700
double requested =
@@ -684,10 +709,10 @@ synchronized boolean isCpuAvailable(Map.Entry<String, Double> resource) {
684
709
if (runningActions >= MAX_ACTIONS_PER_CPU * availableResources .get (ResourceSet .CPU )) {
685
710
return false ;
686
711
}
687
- return isAvailable (available , windowEstimation + currentUsage , requested );
712
+ return isAvailable (available , windowEstimation + currentUsage , requested , key );
688
713
}
689
714
690
- return isAvailable (available , used , requested );
715
+ return isAvailable (available , used , requested , key );
691
716
}
692
717
693
718
@ VisibleForTesting
0 commit comments