ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 1 | // Copyright 2017 The Bazel Authors. All rights reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | package com.google.devtools.build.lib.remote; |
| 15 | |
Jakob Buchgraber | 321138f | 2018-05-07 05:24:53 -0700 | [diff] [blame] | 16 | import static com.google.common.base.Strings.isNullOrEmpty; |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 17 | import static com.google.devtools.build.lib.profiler.ProfilerTask.REMOTE_DOWNLOAD; |
buchgr | d480c5f | 2019-04-03 00:53:34 -0700 | [diff] [blame] | 18 | import static com.google.devtools.build.lib.remote.util.Utils.createSpawnResult; |
Jakob Buchgraber | 321138f | 2018-05-07 05:24:53 -0700 | [diff] [blame] | 19 | |
Chi Wang | 46c3f17 | 2021-08-05 00:52:44 -0700 | [diff] [blame] | 20 | import com.google.common.annotations.VisibleForTesting; |
George Gensure | 7aa7498 | 2020-04-01 00:54:15 -0700 | [diff] [blame] | 21 | import com.google.common.base.Stopwatch; |
George Gensure | 54b062c | 2020-09-02 05:06:40 -0700 | [diff] [blame] | 22 | import com.google.common.base.Throwables; |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 23 | import com.google.devtools.build.lib.actions.ActionInput; |
| 24 | import com.google.devtools.build.lib.actions.ExecException; |
shahan | 602cc85 | 2018-06-06 20:09:57 -0700 | [diff] [blame] | 25 | import com.google.devtools.build.lib.actions.FileArtifactValue; |
janakr | 300c11e | 2021-05-18 12:10:43 -0700 | [diff] [blame] | 26 | import com.google.devtools.build.lib.actions.ForbiddenActionInputException; |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 27 | import com.google.devtools.build.lib.actions.Spawn; |
George Gensure | 7aa7498 | 2020-04-01 00:54:15 -0700 | [diff] [blame] | 28 | import com.google.devtools.build.lib.actions.SpawnMetrics; |
ruperts | da40fbf | 2017-09-22 05:59:42 +0200 | [diff] [blame] | 29 | import com.google.devtools.build.lib.actions.SpawnResult; |
| 30 | import com.google.devtools.build.lib.actions.SpawnResult.Status; |
Mike Morearty | d8ac06a | 2018-04-12 01:59:34 -0700 | [diff] [blame] | 31 | import com.google.devtools.build.lib.actions.cache.VirtualActionInput; |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 32 | import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe; |
Benjamin Peterson | 3ff87f7 | 2017-08-21 18:41:45 +0200 | [diff] [blame] | 33 | import com.google.devtools.build.lib.events.Event; |
| 34 | import com.google.devtools.build.lib.events.Reporter; |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 35 | import com.google.devtools.build.lib.exec.SpawnCache; |
Chi Wang | f0983dfd | 2021-06-10 21:28:52 -0700 | [diff] [blame] | 36 | import com.google.devtools.build.lib.exec.SpawnCheckingCacheEvent; |
| 37 | import com.google.devtools.build.lib.exec.SpawnExecutingEvent; |
tomlu | 29e306d | 2018-04-19 05:41:44 -0700 | [diff] [blame] | 38 | import com.google.devtools.build.lib.exec.SpawnRunner.SpawnExecutionContext; |
ulfjack | 5f436f3 | 2018-11-06 05:17:23 -0800 | [diff] [blame] | 39 | import com.google.devtools.build.lib.profiler.Profiler; |
Jakob Buchgraber | 4b3c2eb | 2019-04-04 02:01:48 -0700 | [diff] [blame] | 40 | import com.google.devtools.build.lib.profiler.ProfilerTask; |
ulfjack | 5f436f3 | 2018-11-06 05:17:23 -0800 | [diff] [blame] | 41 | import com.google.devtools.build.lib.profiler.SilentCloseable; |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 42 | import com.google.devtools.build.lib.remote.RemoteExecutionService.RemoteAction; |
| 43 | import com.google.devtools.build.lib.remote.RemoteExecutionService.RemoteActionResult; |
Jakob Buchgraber | 1846269 | 2019-11-06 04:34:16 -0800 | [diff] [blame] | 44 | import com.google.devtools.build.lib.remote.common.CacheNotFoundException; |
Jakob Buchgraber | 75b7ed4 | 2019-03-27 10:27:13 -0700 | [diff] [blame] | 45 | import com.google.devtools.build.lib.remote.options.RemoteOptions; |
Jakob Buchgraber | a79a4b6 | 2019-06-23 02:06:20 -0700 | [diff] [blame] | 46 | import com.google.devtools.build.lib.remote.util.Utils; |
buchgr | d480c5f | 2019-04-03 00:53:34 -0700 | [diff] [blame] | 47 | import com.google.devtools.build.lib.remote.util.Utils.InMemoryOutput; |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 48 | import com.google.devtools.build.lib.vfs.Path; |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 49 | import java.io.IOException; |
Jakob Buchgraber | 321138f | 2018-05-07 05:24:53 -0700 | [diff] [blame] | 50 | import java.util.HashSet; |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 51 | import java.util.NoSuchElementException; |
Jakob Buchgraber | 321138f | 2018-05-07 05:24:53 -0700 | [diff] [blame] | 52 | import java.util.Set; |
Benjamin Peterson | 3ff87f7 | 2017-08-21 18:41:45 +0200 | [diff] [blame] | 53 | import javax.annotation.Nullable; |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 54 | |
Jakob Buchgraber | 321138f | 2018-05-07 05:24:53 -0700 | [diff] [blame] | 55 | /** A remote {@link SpawnCache} implementation. */ |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 56 | @ThreadSafe // If the RemoteActionCache implementation is thread-safe. |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 57 | final class RemoteSpawnCache implements SpawnCache { |
Jakob Buchgraber | 50c1004 | 2019-04-11 02:11:19 -0700 | [diff] [blame] | 58 | |
Chi Wang | f0983dfd | 2021-06-10 21:28:52 -0700 | [diff] [blame] | 59 | private static final SpawnCheckingCacheEvent SPAWN_CHECKING_CACHE_EVENT = |
| 60 | SpawnCheckingCacheEvent.create("remote-cache"); |
| 61 | |
| 62 | private static final SpawnExecutingEvent SPAWN_EXECUTING_EVENT = |
| 63 | SpawnExecutingEvent.create("remote-cache"); |
| 64 | |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 65 | private final Path execRoot; |
| 66 | private final RemoteOptions options; |
George Gensure | 54b062c | 2020-09-02 05:06:40 -0700 | [diff] [blame] | 67 | private final boolean verboseFailures; |
Benjamin Peterson | 3ff87f7 | 2017-08-21 18:41:45 +0200 | [diff] [blame] | 68 | @Nullable private final Reporter cmdlineReporter; |
Jakob Buchgraber | 321138f | 2018-05-07 05:24:53 -0700 | [diff] [blame] | 69 | private final Set<String> reportedErrors = new HashSet<>(); |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 70 | private final RemoteExecutionService remoteExecutionService; |
Jakob Buchgraber | 50c1004 | 2019-04-11 02:11:19 -0700 | [diff] [blame] | 71 | |
olaola | 6f32d5a | 2017-09-20 17:12:19 +0200 | [diff] [blame] | 72 | RemoteSpawnCache( |
| 73 | Path execRoot, |
| 74 | RemoteOptions options, |
George Gensure | 54b062c | 2020-09-02 05:06:40 -0700 | [diff] [blame] | 75 | boolean verboseFailures, |
buchgr | 559a07d | 2017-11-30 11:09:35 -0800 | [diff] [blame] | 76 | @Nullable Reporter cmdlineReporter, |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 77 | RemoteExecutionService remoteExecutionService) { |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 78 | this.execRoot = execRoot; |
| 79 | this.options = options; |
George Gensure | 54b062c | 2020-09-02 05:06:40 -0700 | [diff] [blame] | 80 | this.verboseFailures = verboseFailures; |
Benjamin Peterson | 3ff87f7 | 2017-08-21 18:41:45 +0200 | [diff] [blame] | 81 | this.cmdlineReporter = cmdlineReporter; |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 82 | this.remoteExecutionService = remoteExecutionService; |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 83 | } |
| 84 | |
Chi Wang | 46c3f17 | 2021-08-05 00:52:44 -0700 | [diff] [blame] | 85 | @VisibleForTesting |
| 86 | RemoteExecutionService getRemoteExecutionService() { |
| 87 | return remoteExecutionService; |
| 88 | } |
| 89 | |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 90 | @Override |
tomlu | 29e306d | 2018-04-19 05:41:44 -0700 | [diff] [blame] | 91 | public CacheHandle lookup(Spawn spawn, SpawnExecutionContext context) |
janakr | 300c11e | 2021-05-18 12:10:43 -0700 | [diff] [blame] | 92 | throws InterruptedException, IOException, ExecException, ForbiddenActionInputException { |
Chi Wang | 46c3f17 | 2021-08-05 00:52:44 -0700 | [diff] [blame] | 93 | boolean shouldAcceptCachedResult = remoteExecutionService.shouldAcceptCachedResult(spawn); |
| 94 | boolean shouldUploadLocalResults = remoteExecutionService.shouldUploadLocalResults(spawn); |
| 95 | if (!shouldAcceptCachedResult && !shouldUploadLocalResults) { |
Benjamin Peterson | f157053 | 2019-01-24 07:14:18 -0800 | [diff] [blame] | 96 | return SpawnCache.NO_RESULT_NO_STORE; |
| 97 | } |
Benjamin Peterson | 7e1c7bc | 2018-05-03 04:30:19 -0700 | [diff] [blame] | 98 | |
George Gensure | 7aa7498 | 2020-04-01 00:54:15 -0700 | [diff] [blame] | 99 | Stopwatch totalTime = Stopwatch.createStarted(); |
| 100 | |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 101 | RemoteAction action = remoteExecutionService.buildRemoteAction(spawn, context); |
George Gensure | 7aa7498 | 2020-04-01 00:54:15 -0700 | [diff] [blame] | 102 | SpawnMetrics.Builder spawnMetrics = |
Googler | 2b7e71a | 2020-06-04 01:32:01 -0700 | [diff] [blame] | 103 | SpawnMetrics.Builder.forRemoteExec() |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 104 | .setInputBytes(action.getInputBytes()) |
| 105 | .setInputFiles(action.getInputFiles()); |
Benjamin Peterson | 7e1c7bc | 2018-05-03 04:30:19 -0700 | [diff] [blame] | 106 | |
Jakob Buchgraber | 4b3c2eb | 2019-04-04 02:01:48 -0700 | [diff] [blame] | 107 | Profiler prof = Profiler.instance(); |
Chi Wang | 46c3f17 | 2021-08-05 00:52:44 -0700 | [diff] [blame] | 108 | if (shouldAcceptCachedResult) { |
Chi Wang | f0983dfd | 2021-06-10 21:28:52 -0700 | [diff] [blame] | 109 | context.report(SPAWN_CHECKING_CACHE_EVENT); |
Benjamin Peterson | 7e1c7bc | 2018-05-03 04:30:19 -0700 | [diff] [blame] | 110 | // Metadata will be available in context.current() until we detach. |
| 111 | // This is done via a thread-local variable. |
Benjamin Peterson | 7e1c7bc | 2018-05-03 04:30:19 -0700 | [diff] [blame] | 112 | try { |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 113 | RemoteActionResult result; |
Jakob Buchgraber | 4b3c2eb | 2019-04-04 02:01:48 -0700 | [diff] [blame] | 114 | try (SilentCloseable c = prof.profile(ProfilerTask.REMOTE_CACHE_CHECK, "check cache hit")) { |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 115 | result = remoteExecutionService.lookupCache(action); |
ulfjack | 5f436f3 | 2018-11-06 05:17:23 -0800 | [diff] [blame] | 116 | } |
Jakob Buchgraber | 50c1004 | 2019-04-11 02:11:19 -0700 | [diff] [blame] | 117 | // In case the remote cache returned a failed action (exit code != 0) we treat it as a |
| 118 | // cache miss |
ishikhman | 62f5458 | 2019-03-18 03:42:42 -0700 | [diff] [blame] | 119 | if (result != null && result.getExitCode() == 0) { |
George Gensure | 7aa7498 | 2020-04-01 00:54:15 -0700 | [diff] [blame] | 120 | Stopwatch fetchTime = Stopwatch.createStarted(); |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 121 | InMemoryOutput inMemoryOutput; |
| 122 | try (SilentCloseable c = prof.profile(REMOTE_DOWNLOAD, "download outputs")) { |
| 123 | inMemoryOutput = remoteExecutionService.downloadOutputs(action, result); |
ulfjack | 5f436f3 | 2018-11-06 05:17:23 -0800 | [diff] [blame] | 124 | } |
George Gensure | 7aa7498 | 2020-04-01 00:54:15 -0700 | [diff] [blame] | 125 | fetchTime.stop(); |
| 126 | totalTime.stop(); |
| 127 | spawnMetrics |
| 128 | .setFetchTime(fetchTime.elapsed()) |
| 129 | .setTotalTime(totalTime.elapsed()) |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 130 | .setNetworkTime(action.getNetworkTime().getDuration()); |
Benjamin Peterson | 7e1c7bc | 2018-05-03 04:30:19 -0700 | [diff] [blame] | 131 | SpawnResult spawnResult = |
buchgr | d480c5f | 2019-04-03 00:53:34 -0700 | [diff] [blame] | 132 | createSpawnResult( |
George Gensure | 7aa7498 | 2020-04-01 00:54:15 -0700 | [diff] [blame] | 133 | result.getExitCode(), |
janakr | f8dc2eb | 2020-09-30 08:06:53 -0700 | [diff] [blame] | 134 | /*cacheHit=*/ true, |
ron-stripe | cf57d03 | 2021-08-26 06:07:30 -0700 | [diff] [blame^] | 135 | result.cacheName(), |
George Gensure | 7aa7498 | 2020-04-01 00:54:15 -0700 | [diff] [blame] | 136 | inMemoryOutput, |
janakr | f8dc2eb | 2020-09-30 08:06:53 -0700 | [diff] [blame] | 137 | spawnMetrics.build(), |
| 138 | spawn.getMnemonic()); |
Benjamin Peterson | 7e1c7bc | 2018-05-03 04:30:19 -0700 | [diff] [blame] | 139 | return SpawnCache.success(spawnResult); |
| 140 | } |
Benjamin Peterson | 1532df0 | 2019-01-24 08:45:44 -0800 | [diff] [blame] | 141 | } catch (CacheNotFoundException e) { |
| 142 | // Intentionally left blank |
Benjamin Peterson | 7e1c7bc | 2018-05-03 04:30:19 -0700 | [diff] [blame] | 143 | } catch (IOException e) { |
George Gensure | 54b062c | 2020-09-02 05:06:40 -0700 | [diff] [blame] | 144 | if (BulkTransferException.isOnlyCausedByCacheNotFoundException(e)) { |
| 145 | // Intentionally left blank |
| 146 | } else { |
| 147 | String errorMessage; |
| 148 | if (!verboseFailures) { |
| 149 | errorMessage = Utils.grpcAwareErrorMessage(e); |
| 150 | } else { |
| 151 | // On --verbose_failures print the whole stack trace |
| 152 | errorMessage = Throwables.getStackTraceAsString(e); |
| 153 | } |
| 154 | if (isNullOrEmpty(errorMessage)) { |
| 155 | errorMessage = e.getClass().getSimpleName(); |
| 156 | } |
| 157 | errorMessage = "Reading from Remote Cache:\n" + errorMessage; |
| 158 | report(Event.warn(errorMessage)); |
Benjamin Peterson | 1532df0 | 2019-01-24 08:45:44 -0800 | [diff] [blame] | 159 | } |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 160 | } |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 161 | } |
buchgr | d480c5f | 2019-04-03 00:53:34 -0700 | [diff] [blame] | 162 | |
Chi Wang | f0983dfd | 2021-06-10 21:28:52 -0700 | [diff] [blame] | 163 | context.report(SPAWN_EXECUTING_EVENT); |
| 164 | |
buchgr | d480c5f | 2019-04-03 00:53:34 -0700 | [diff] [blame] | 165 | context.prefetchInputs(); |
| 166 | |
Chi Wang | 46c3f17 | 2021-08-05 00:52:44 -0700 | [diff] [blame] | 167 | if (shouldUploadLocalResults) { |
olaola | ba8b0b3 | 2017-10-20 09:48:56 +0200 | [diff] [blame] | 168 | return new CacheHandle() { |
| 169 | @Override |
| 170 | public boolean hasResult() { |
| 171 | return false; |
| 172 | } |
| 173 | |
| 174 | @Override |
| 175 | public SpawnResult getResult() { |
| 176 | throw new NoSuchElementException(); |
| 177 | } |
| 178 | |
| 179 | @Override |
| 180 | public boolean willStore() { |
| 181 | return true; |
| 182 | } |
| 183 | |
| 184 | @Override |
Jakob Buchgraber | bac30fe | 2019-01-28 05:24:23 -0800 | [diff] [blame] | 185 | public void store(SpawnResult result) throws ExecException, InterruptedException { |
| 186 | boolean uploadResults = Status.SUCCESS.equals(result.status()) && result.exitCode() == 0; |
| 187 | if (!uploadResults) { |
| 188 | return; |
| 189 | } |
| 190 | |
ulfjack | 8896d2e | 2018-01-19 02:55:21 -0800 | [diff] [blame] | 191 | if (options.experimentalGuardAgainstConcurrentChanges) { |
Jakob Buchgraber | 4b3c2eb | 2019-04-04 02:01:48 -0700 | [diff] [blame] | 192 | try (SilentCloseable c = prof.profile("RemoteCache.checkForConcurrentModifications")) { |
ulfjack | 8896d2e | 2018-01-19 02:55:21 -0800 | [diff] [blame] | 193 | checkForConcurrentModifications(); |
| 194 | } catch (IOException e) { |
| 195 | report(Event.warn(e.getMessage())); |
| 196 | return; |
| 197 | } |
| 198 | } |
Jakob Buchgraber | bac30fe | 2019-01-28 05:24:23 -0800 | [diff] [blame] | 199 | |
Jakob Buchgraber | 4b3c2eb | 2019-04-04 02:01:48 -0700 | [diff] [blame] | 200 | try (SilentCloseable c = prof.profile(ProfilerTask.UPLOAD_TIME, "upload outputs")) { |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 201 | remoteExecutionService.uploadOutputs(action); |
olaola | ba8b0b3 | 2017-10-20 09:48:56 +0200 | [diff] [blame] | 202 | } catch (IOException e) { |
George Gensure | 54b062c | 2020-09-02 05:06:40 -0700 | [diff] [blame] | 203 | String errorMessage; |
| 204 | if (!verboseFailures) { |
| 205 | errorMessage = Utils.grpcAwareErrorMessage(e); |
| 206 | } else { |
| 207 | // On --verbose_failures print the whole stack trace |
| 208 | errorMessage = Throwables.getStackTraceAsString(e); |
olaola | ba8b0b3 | 2017-10-20 09:48:56 +0200 | [diff] [blame] | 209 | } |
George Gensure | 54b062c | 2020-09-02 05:06:40 -0700 | [diff] [blame] | 210 | if (isNullOrEmpty(errorMessage)) { |
| 211 | errorMessage = e.getClass().getSimpleName(); |
| 212 | } |
| 213 | errorMessage = "Writing to Remote Cache:\n" + errorMessage; |
| 214 | report(Event.warn(errorMessage)); |
olaola | ba8b0b3 | 2017-10-20 09:48:56 +0200 | [diff] [blame] | 215 | } |
| 216 | } |
| 217 | |
| 218 | @Override |
| 219 | public void close() {} |
ulfjack | 8896d2e | 2018-01-19 02:55:21 -0800 | [diff] [blame] | 220 | |
| 221 | private void checkForConcurrentModifications() throws IOException { |
chiwang | ae53991 | 2021-04-23 00:25:02 -0700 | [diff] [blame] | 222 | for (ActionInput input : action.getInputMap().values()) { |
Mike Morearty | d8ac06a | 2018-04-12 01:59:34 -0700 | [diff] [blame] | 223 | if (input instanceof VirtualActionInput) { |
| 224 | continue; |
| 225 | } |
shahan | 499503b | 2018-06-07 18:57:07 -0700 | [diff] [blame] | 226 | FileArtifactValue metadata = context.getMetadataProvider().getMetadata(input); |
olaola | f0aa55d | 2018-08-16 08:51:06 -0700 | [diff] [blame] | 227 | Path path = execRoot.getRelative(input.getExecPath()); |
| 228 | if (metadata.wasModifiedSinceDigest(path)) { |
| 229 | throw new IOException(path + " was modified during execution"); |
ulfjack | 8896d2e | 2018-01-19 02:55:21 -0800 | [diff] [blame] | 230 | } |
| 231 | } |
| 232 | } |
olaola | ba8b0b3 | 2017-10-20 09:48:56 +0200 | [diff] [blame] | 233 | }; |
| 234 | } else { |
| 235 | return SpawnCache.NO_RESULT_NO_STORE; |
| 236 | } |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 237 | } |
Benjamin Peterson | 3ff87f7 | 2017-08-21 18:41:45 +0200 | [diff] [blame] | 238 | |
Benjamin Peterson | 3ff87f7 | 2017-08-21 18:41:45 +0200 | [diff] [blame] | 239 | private void report(Event evt) { |
Jakob Buchgraber | 321138f | 2018-05-07 05:24:53 -0700 | [diff] [blame] | 240 | if (cmdlineReporter == null) { |
| 241 | return; |
| 242 | } |
| 243 | |
| 244 | synchronized (this) { |
| 245 | if (reportedErrors.contains(evt.getMessage())) { |
| 246 | return; |
| 247 | } |
| 248 | reportedErrors.add(evt.getMessage()); |
Benjamin Peterson | 3ff87f7 | 2017-08-21 18:41:45 +0200 | [diff] [blame] | 249 | cmdlineReporter.handle(evt); |
| 250 | } |
| 251 | } |
Sergio Rodriguez Orellana | 8860c3e | 2019-07-25 01:12:58 -0700 | [diff] [blame] | 252 | |
larsrc | 02838a1 | 2020-11-10 03:46:53 -0800 | [diff] [blame] | 253 | @Override |
| 254 | public boolean usefulInDynamicExecution() { |
| 255 | return false; |
| 256 | } |
ulfjack | 9274cba | 2017-08-11 23:19:48 +0200 | [diff] [blame] | 257 | } |