@@ -182,15 +182,16 @@ internal static async Task<ObservedInputProcessingResult> ProcessInternalAsync<T
182182
183183 // Compute the set of all shared dynamic outputs. This is only done if there is a chance we end up using MinimalGraphWithAlienFiles
184184 // for this pip, otherwise we keep the set empty to avoid unnecessary computations
185- HashSet < AbsolutePath > sharedOpaqueOutputs = processingState . SharedOpaqueOutputs ;
185+ Dictionary < AbsolutePath , bool > sharedOpaqueOutputs = processingState . SharedOpaqueOutputs ;
186+
186187 if ( unPopulatedSharedOpaqueOutputs != null && envAdapter . MayDetermineMinimalGraphWithAlienFiles ( allowUndeclaredSourceReads ) )
187188 {
188- // We filter out artifacts that are allowed file rewrites since that information is not available
189- // when processing a prior path set. The final result will be that allowed rewrites, even though outputs,
190- // will be part of the directory fingerprint when using minimal with alien files. This is the desired outcome
191- // since those files existed before the build begun.
189+ // Let's distinguish rewrites vs not. We want rewritten files to be part of the fingerprint (those files
190+ // existed before the build begun) so we could exclude them from the just-produced outputs we pass to the
191+ // fingerprint enumeration computation, but on the other hand we need to know about them for the creation time
192+ // check
192193 sharedOpaqueOutputs . AddRange ( unPopulatedSharedOpaqueOutputs . Values . SelectMany ( fileArtifacts =>
193- fileArtifacts . Where ( fa => ! fa . IsUndeclaredFileRewrite ) . Select ( fa => fa . Path ) ) ) ;
194+ fileArtifacts . Select ( fa => new KeyValuePair < AbsolutePath , bool > ( fa . Path , fa . IsUndeclaredFileRewrite ) ) ) ) ;
194195 }
195196
196197 using ( operationContext . StartOperation ( PipExecutorCounter . ObservedInputProcessorPreProcessDuration ) )
@@ -1264,7 +1265,7 @@ internal interface IObservedInputProcessingEnvironment
12641265 DirectoryMembershipFilter filter ,
12651266 bool isReadOnlyDirectory ,
12661267 DirectoryMembershipHashedEventData eventData ,
1267- IReadOnlyCollection < AbsolutePath > sharedOpaqueOutputs ,
1268+ IReadOnlyDictionary < AbsolutePath , bool > sharedOpaqueOutputs ,
12681269 IReadOnlyCollection < AbsolutePath > createdDirectories ,
12691270 ConcurrentBigMap < AbsolutePath , IReadOnlyList < DirectoryMemberEntry > > alienFileEnumerationCache ,
12701271 out DirectoryEnumerationMode enumerationMode ,
@@ -1938,7 +1939,7 @@ internal DirectoryEnumerationMode DetermineEnumerationModeAndRule(AbsolutePath d
19381939 DirectoryMembershipFilter filter ,
19391940 bool isReadOnlyDirectory ,
19401941 DirectoryMembershipHashedEventData eventData ,
1941- IReadOnlyCollection < AbsolutePath > sharedOpaqueOutputs ,
1942+ IReadOnlyDictionary < AbsolutePath , bool > sharedOpaqueOutputs ,
19421943 IReadOnlyCollection < AbsolutePath > createdDirectories ,
19431944 ConcurrentBigMap < AbsolutePath , IReadOnlyList < DirectoryMemberEntry > > alienFileEnumerationCache ,
19441945 out DirectoryEnumerationMode enumerationMode ,
@@ -2106,7 +2107,7 @@ private Action<AbsolutePath, string> FilteredHandledEntry(AbsolutePath directory
21062107 }
21072108
21082109 private Func < EnumerationRequest , PathExistence ? > TryEnumerateDirectoryWithMinimalGraphWithAlienFiles (
2109- IReadOnlyCollection < AbsolutePath > sharedDynamicOutputs ,
2110+ IReadOnlyDictionary < AbsolutePath , bool > sharedDynamicOutputs ,
21102111 IReadOnlyCollection < AbsolutePath > createdDirectories ,
21112112 ConcurrentBigMap < AbsolutePath , IReadOnlyList < DirectoryMemberEntry > > alienFileEnumerationCache )
21122113 {
@@ -2216,7 +2217,9 @@ private Action<AbsolutePath, string> FilteredHandledEntry(AbsolutePath directory
22162217
22172218 // Rule out all shared opaques produced by this pip. These files may not be part yet of the output file system since those get registered
22182219 // in a post-execution step which is not reached yet on cache miss, so the output file system may have not captured them yet
2219- if ( sharedDynamicOutputs . Contains ( realFileEntryPath ) )
2220+ // Only exclude the ones that are not a file rewrite, in consonance with the check we did above against the output file system
2221+ var isOutputProducedByThisPip = sharedDynamicOutputs . TryGetValue ( realFileEntryPath , out var isFileRewrite ) ;
2222+ if ( isOutputProducedByThisPip && ! isFileRewrite )
22202223 {
22212224 continue ;
22222225 }
@@ -2241,7 +2244,10 @@ private Action<AbsolutePath, string> FilteredHandledEntry(AbsolutePath directory
22412244 // Some considerations here: the correctness of this check relies on making sure outputs get to the output
22422245 // file system before they are either hardlinked from the cache or (on Windows) made shared opaque by virtue of timestamp flagging.
22432246 // Otherwise, we run the risk of altering the file creation original timestamp.
2244- if ( m_env . State . FileTimestampTracker . IsFileCreationTrackingSupported && m_env . State . FileTimestampTracker . PathCreatedAfterEngineStarted ( realFileEntryPath ) )
2247+ // We could have here an output produced by this pip that is a file rewrite (and whose creation will therefore had occurred after the engine
2248+ // started. We do want those as part of the fingerprint, so don't rule it out here.
2249+ if ( m_env . State . FileTimestampTracker . IsFileCreationTrackingSupported && ! isOutputProducedByThisPip &&
2250+ m_env . State . FileTimestampTracker . PathCreatedAfterEngineStarted ( realFileEntryPath ) )
22452251 {
22462252 continue ;
22472253 }
0 commit comments