25
25
import com .google .common .base .Stopwatch ;
26
26
import com .google .common .collect .ImmutableList ;
27
27
import com .google .common .collect .ImmutableMap ;
28
- import com .google .common .collect .Iterables ;
29
28
import com .google .common .eventbus .EventBus ;
30
29
import com .google .common .util .concurrent .ListenableFuture ;
31
30
import com .google .devtools .build .lib .actions .ActionLookupData ;
40
39
import com .google .devtools .build .lib .server .FailureDetails .FailureDetail ;
41
40
import com .google .devtools .build .lib .server .FailureDetails .RemoteAnalysisCaching ;
42
41
import com .google .devtools .build .lib .server .FailureDetails .RemoteAnalysisCaching .Code ;
43
- import com .google .devtools .build .lib .skyframe .PrecomputedValue ;
42
+ import com .google .devtools .build .lib .skyframe .ActionExecutionValue . WithRichData ;
44
43
import com .google .devtools .build .lib .skyframe .SkyframeExecutor ;
45
44
import com .google .devtools .build .lib .skyframe .serialization .ObjectCodecs ;
46
45
import com .google .devtools .build .lib .skyframe .serialization .ProfileCollector ;
@@ -151,6 +150,7 @@ public static Optional<FailureDetail> serializeAndUploadFrontier(
151
150
versionGetter ,
152
151
codecs ,
153
152
frontierVersion ,
153
+ dependenciesProvider ::withinActiveDirectories ,
154
154
selection ,
155
155
dependenciesProvider .getFingerprintValueService (),
156
156
eventBus ,
@@ -214,75 +214,44 @@ private static void dumpUploadManifest(PrintStream out, Map<SkyKey, SelectionMar
214
214
@ VisibleForTesting
215
215
enum SelectionMarking {
216
216
/**
217
- * The entry is marked as a frontier candidate.
217
+ * The entry is a frontier candidate.
218
218
*
219
219
* <p>If a node is still a frontier candidate at the end of the selection process, it is a
220
- * frontier node and should be serialized .
220
+ * frontier node.
221
221
*/
222
222
FRONTIER_CANDIDATE ,
223
- /** The node is in the active set and will not be serialized . */
223
+ /** The node is part of the active set. */
224
224
ACTIVE
225
225
}
226
226
227
- /**
228
- * Iterates over the direct analysis deps of a node, and include them into the frontier if they've
229
- * not been seen before.
230
- */
231
- private static void markAnalysisDirectDepsAsFrontierCandidates (
232
- SkyKey key ,
233
- InMemoryGraph graph ,
234
- ConcurrentHashMap <SkyKey , SelectionMarking > selection ,
235
- Predicate <PackageIdentifier > matcher ) {
236
- graph
237
- .getIfPresent (key )
238
- .getDirectDeps ()
239
- .forEach (
240
- depKey -> {
241
- if (depKey instanceof ActionLookupKey alk
242
- && !matcher .test (alk .getLabel ().getPackageIdentifier ())) {
243
- selection .putIfAbsent (depKey , FRONTIER_CANDIDATE );
244
- }
245
- });
246
- }
247
-
248
- private static boolean dependsOnBuildId (InMemoryNodeEntry node ) {
249
- // This method only checks direct dependencies because it is used to mark nodes as active in
250
- // case they can't be cached and the upwards transitive closure of such nodes is marked as
251
- // active anyway.
252
- return Iterables .contains (node .getDirectDeps (), PrecomputedValue .BUILD_ID );
253
- }
254
-
255
227
@ VisibleForTesting
256
228
static ImmutableMap <SkyKey , SelectionMarking > computeSelection (
257
229
InMemoryGraph graph , Predicate <PackageIdentifier > matcher ) {
258
- ConcurrentHashMap < SkyKey , SelectionMarking > selection = new ConcurrentHashMap <>();
230
+ var selection = new ConcurrentHashMap <SkyKey , SelectionMarking >();
259
231
graph .parallelForEach (
260
232
node -> {
261
233
switch (node .getKey ()) {
262
- case ActionLookupKey key when key .getLabel () != null -> {
263
- if (matcher .test (key .getLabel ().getPackageIdentifier ())) {
234
+ case ActionLookupKey key -> {
235
+ Label label = key .getLabel ();
236
+ if (label != null && matcher .test (label .getPackageIdentifier ())) {
264
237
markActiveAndTraverseEdges (graph , key , selection );
265
238
}
266
239
}
267
240
case ActionLookupData data -> {
268
- if (!dependsOnBuildId (node ) && data .getLabel () != null ) {
269
- selection .putIfAbsent (data , FRONTIER_CANDIDATE );
270
- } else {
271
- // If this is UnshareableActionLookupData, then its value will never be shared and
272
- // the ActionExecutionFunction will be re-evaluated locally. To evaluate it locally,
273
- // it will need the corresponding full ActionLookupKey's value, so that cannot be
274
- // cached as well. So, mark the ActionLookupKey (and its rdeps) as active,
275
- // so the deserializing build will not incorrectly cache hit on a CT/Aspect
276
- // that owns such actions, which should be evaluated locally then.
277
- markActiveAndTraverseEdges (graph , data .getActionLookupKey (), selection );
241
+ if (!data .valueIsShareable () && !(node .getValue () instanceof WithRichData )) {
242
+ // `valueIsShareable` is used by a different system that does not serialize
243
+ // RunfilesArtifactValue, but the FrontierSerializer should do so. A `WithRichData`
244
+ // value type can be used to distinguish this case.
245
+ return ;
278
246
}
247
+ selection .putIfAbsent (data , FRONTIER_CANDIDATE );
279
248
}
280
249
case Artifact artifact -> {
250
+ if (!artifact .valueIsShareable ()) {
251
+ return ;
252
+ }
281
253
switch (artifact ) {
282
254
case DerivedArtifact derived :
283
- if (derived .isConstantMetadata ()) {
284
- return ;
285
- }
286
255
// Artifact#key is the canonical function to produce the SkyKey that will build
287
256
// this artifact. We want to avoid serializing ordinary DerivedArtifacts, which
288
257
// are never built by Skyframe directly, and the function will return
@@ -322,41 +291,39 @@ static ImmutableMap<SkyKey, SelectionMarking> computeSelection(
322
291
// dependencies here. Those SkyValues are entirely derived from the build configuration
323
292
// fragments, and the values themselves look relatively straightforward to serialize.
324
293
case RegisteredExecutionPlatformsValue .Key key ->
325
- markAnalysisDirectDepsAsFrontierCandidates (key , graph , selection , matcher );
294
+ markAnalysisDirectDepsAsFrontierCandidates (key , graph , selection );
326
295
case RegisteredToolchainsValue .Key key ->
327
- markAnalysisDirectDepsAsFrontierCandidates (key , graph , selection , matcher );
296
+ markAnalysisDirectDepsAsFrontierCandidates (key , graph , selection );
328
297
case ToolchainContextKey key ->
329
- markAnalysisDirectDepsAsFrontierCandidates (key , graph , selection , matcher );
298
+ markAnalysisDirectDepsAsFrontierCandidates (key , graph , selection );
330
299
default -> {}
331
300
}
332
301
});
333
302
334
- // Filter for ActionExecutionValues owned by active analysis nodes and skip them, because
335
- // they should be evaluated locally.
303
+ // Marks ActionExecutionValues owned by active analysis nodes ACTIVE.
336
304
return selection .entrySet ().parallelStream ()
337
- .map (
338
- entry -> {
339
- if (!(entry .getKey () instanceof ActionLookupData ald )) {
340
- return entry ;
341
- }
342
- if (entry .getValue () == FRONTIER_CANDIDATE
343
- && selection .get (ald .getActionLookupKey ()) == ACTIVE ) {
344
- return Map .entry (entry .getKey (), ACTIVE );
345
- }
346
- return entry ;
347
- })
348
- .collect (toImmutableMap (Map .Entry ::getKey , Map .Entry ::getValue ));
305
+ .collect (
306
+ toImmutableMap (
307
+ Map .Entry ::getKey ,
308
+ entry ->
309
+ switch (entry .getKey ()) {
310
+ case ActionLookupData lookupData ->
311
+ selection .get (lookupData .getActionLookupKey ()) == ACTIVE
312
+ ? ACTIVE
313
+ : entry .getValue ();
314
+ case DerivedArtifact artifact ->
315
+ selection .get (artifact .getArtifactOwner ()) == ACTIVE
316
+ ? ACTIVE
317
+ : entry .getValue ();
318
+ default -> entry .getValue ();
319
+ }));
349
320
}
350
321
351
322
private static void markActiveAndTraverseEdges (
352
323
InMemoryGraph graph ,
353
324
ActionLookupKey root ,
354
325
ConcurrentHashMap <SkyKey , SelectionMarking > selection ) {
355
- Label label = root .getLabel ();
356
- if (label == null ) {
357
- return ;
358
- }
359
- if (selection .put (root , ACTIVE ) == ACTIVE ) {
326
+ if (root .getLabel () == null ) {
360
327
return ;
361
328
}
362
329
@@ -372,6 +339,10 @@ private static void markActiveAndTraverseEdges(
372
339
return ;
373
340
}
374
341
342
+ if (selection .put (root , ACTIVE ) == ACTIVE ) {
343
+ return ;
344
+ }
345
+
375
346
for (SkyKey dep : node .getDirectDeps ()) {
376
347
if (!(dep instanceof ActionLookupKey actionLookupKey )) {
377
348
continue ;
@@ -402,6 +373,23 @@ private static void markActiveAndTraverseEdges(
402
373
}
403
374
}
404
375
376
+ /**
377
+ * Iterates over the direct analysis deps of a node, and include them into the frontier if they've
378
+ * not been seen before.
379
+ */
380
+ private static void markAnalysisDirectDepsAsFrontierCandidates (
381
+ SkyKey key , InMemoryGraph graph , ConcurrentHashMap <SkyKey , SelectionMarking > selection ) {
382
+ graph
383
+ .getIfPresent (key )
384
+ .getDirectDeps ()
385
+ .forEach (
386
+ depKey -> {
387
+ if (depKey instanceof ActionLookupKey ) {
388
+ selection .putIfAbsent (depKey , FRONTIER_CANDIDATE );
389
+ }
390
+ });
391
+ }
392
+
405
393
/** Stopwatch that resets upon reporting the time via {@link #toString}. */
406
394
private record ResettingStopwatch (Stopwatch stopwatch ) {
407
395
@ Override
0 commit comments