Example #1
0
        /// <nodoc />
        internal CacheInitializationTask(
            LoggingContext loggingContext,
            DateTime initializationStart,
            Task <Possible <CacheInitializer> > initializationTask,
            CancellationToken cancellationToken)
        {
            m_loggingContext      = loggingContext;
            m_initializationStart = initializationStart;

            // initializationTask might be done already; safe to call ContinueWith now since we initialized everything else.
            m_initializationTask = initializationTask.ContinueWith(
                t =>
            {
                if (t.IsCanceled)
                {
                    return(new Failure <string>("Cache initialization has been cancelled"));
                }

                // Abstractly, there are two orders possible:
                // {m_initializationStart -> [firstAwaited} -> completionTime] (some sync wait time)
                // {m_initializationStart -> completionTime} -> firstAwaited (no sync wait time)
                // [ ] part is sync wait time - in the second case it is zero (timeWaitedMs below)
                // { } part was overlapped with other processing (i.e., initialization before first wait).
                // Since we arrive here at task completion time, we only care about the first case;
                // if an await hasn't happened by completionTime, we pretend that firstAwaited == completionTime.
                DateTime completionTime = DateTime.UtcNow;

                long firstWaitTimeTicksOrNegativeOne = Volatile.Read(ref m_firstAwaitTimeTicks);
                DateTime firstAwaitTime = firstWaitTimeTicksOrNegativeOne == -1
                        ? completionTime
                        : new DateTime(firstWaitTimeTicksOrNegativeOne, DateTimeKind.Utc);

                if (firstAwaitTime > completionTime)
                {
                    firstAwaitTime = completionTime;
                }

                // If an await hasn't happened yet, timeWaitedMs is zero (completionTime == firstAwaitTime; see above)
                int timeWaitedMs = (int)Math.Round(Math.Max(0, (completionTime - firstAwaitTime).TotalMilliseconds));
                Contract.Assert(timeWaitedMs >= 0);

                InitializationTime = completionTime - m_initializationStart;
                if (InitializationTime < TimeSpan.Zero)
                {
                    InitializationTime = TimeSpan.Zero;
                }

                int overlappedInitializationMs = (int)Math.Round(Math.Max(0, InitializationTime.TotalMilliseconds - timeWaitedMs));

                Tracing.Logger.Log.SynchronouslyWaitedForCache(loggingContext, timeWaitedMs, overlappedInitializationMs);

                LoggingHelpers.LogCategorizedStatistic(m_loggingContext, "CacheInitialization", "TimeWaitedMs", timeWaitedMs);
                LoggingHelpers.LogCategorizedStatistic(m_loggingContext, "CacheInitialization", "OverlappedInitializationMs", overlappedInitializationMs);
                return(t.Result);
            });

            // Timer will start if someone actually waiting on the task (called GetAwaiter()).
            m_cacheInitWatchdog = new Timer(o => CheckIfCacheIsStillInitializing(cancellationToken));
        }
Example #2
0
        /// <summary>
        /// Cleans output files and directories.
        /// </summary>
        public static bool DeleteOutputs(
            LoggingContext loggingContext,
            Func <DirectoryArtifact, bool> isOutputDir,
            IList <FileOrDirectoryArtifact> filesOrDirectoriesToDelete,
            PathTable pathTable,
            ITempCleaner tempDirectoryCleaner = null)
        {
            int fileFailCount         = 0;
            int fileSuccessCount      = 0;
            int directoryFailCount    = 0;
            int directorySuccessCount = 0;

            using (PerformanceMeasurement.Start(
                       loggingContext,
                       Category,
                       Tracing.Logger.Log.CleaningStarted,
                       localLoggingContext =>
            {
                Tracing.Logger.Log.CleaningFinished(loggingContext, fileSuccessCount, fileFailCount);
                LoggingHelpers.LogCategorizedStatistic(loggingContext, Category, "FilesDeleted", fileSuccessCount);
                LoggingHelpers.LogCategorizedStatistic(loggingContext, Category, "FilesFailed", fileFailCount);
                LoggingHelpers.LogCategorizedStatistic(loggingContext, Category, "DirectoriesDeleted", directorySuccessCount);
                LoggingHelpers.LogCategorizedStatistic(loggingContext, Category, "DirectoriesFailed", directoryFailCount);
            }))
            {
                // Note: filesOrDirectoriesToDelete better be an IList<...> in order to get good Parallel.ForEach performance
                Parallel.ForEach(
                    filesOrDirectoriesToDelete,
                    fileOrDirectory =>
                {
                    string path = fileOrDirectory.Path.ToString(pathTable);
                    Tracing.Logger.Log.CleaningOutputFile(loggingContext, path);

                    try
                    {
                        if (fileOrDirectory.IsFile)
                        {
                            Contract.Assume(fileOrDirectory.FileArtifact.IsOutputFile, "Encountered non-output file");
                            if (FileUtilities.FileExistsNoFollow(path))
                            {
                                FileUtilities.DeleteFile(path, waitUntilDeletionFinished: true, tempDirectoryCleaner: tempDirectoryCleaner);
                                Interlocked.Increment(ref fileSuccessCount);
                            }
                        }
                        else
                        {
                            if (FileUtilities.DirectoryExistsNoFollow(path))
                            {
                                // TODO:1011977 this is a hacky fix for a bug where we delete SourceSealDirectories in /cleanonly mode
                                // The bug stems from the fact that FilterOutputs() returns SourceSealDirectories, which aren't inputs.
                                // Once properly addressed, this check should remain in here as a safety precaution and turn into
                                // a Contract.Assume() like the check above
                                if (isOutputDir(fileOrDirectory.DirectoryArtifact))
                                {
                                    FileUtilities.DeleteDirectoryContents(path, deleteRootDirectory: false, tempDirectoryCleaner: tempDirectoryCleaner);
                                    Interlocked.Increment(ref directorySuccessCount);
                                }
                            }
                        }
                    }
                    catch (BuildXLException ex)
                    {
                        if (fileOrDirectory.IsFile)
                        {
                            Interlocked.Increment(ref fileFailCount);
                            Tracing.Logger.Log.CleaningFileFailed(loggingContext, path, ex.LogEventMessage);
                        }
                        else
                        {
                            Interlocked.Increment(ref directoryFailCount);
                            Tracing.Logger.Log.CleaningDirectoryFailed(loggingContext, path, ex.LogEventMessage);
                        }
                    }
                });
            }

            return(fileFailCount + directoryFailCount == 0);
        }