Пример #1
0
 /// <nodoc />
 public void Store(OperationContext context, ShortHash hash, ContentLocationEntry entry)
 {
     using (_exchangeLock.AcquireReadLock())
     {
         _cache[hash] = entry;
     }
 }
Пример #2
0
        /// <summary>
        /// Tries to resolve <see cref="MachineLocation"/> by a machine id (<paramref name="machine"/>).
        /// </summary>
        public bool TryResolve(MachineId machine, out MachineLocation machineLocation)
        {
            using (_lock.AcquireReadLock())
            {
                if (machine.Index < _locationByIdMap.Length)
                {
                    machineLocation = _locationByIdMap[machine.Index];
                    return(machineLocation.Data != null);
                }

                machineLocation = default;
                return(false);
            }
        }
Пример #3
0
        [System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions] // allows catching exceptions from unmanaged code
        public Possible <TResult> Use <TState, TResult>(Func <IBuildXLKeyValueStore, TState, TResult> use, TState state)
        {
            using (m_rwl.AcquireReadLock())
            {
                // All RocksDb usages are checked for exceptions and handled according to a user-provided handler.
                // The handler decides whether the store should be permanently invalidated or not. It also has the
                // opportunity to do whatever side-effects the user needs. If the store is invalidated, the
                // invalidation handler is called after the store has been invalidated.
                // The default policy is to always invalidate the store if an exception happens, as it is the safest
                // option.
                if (Disabled)
                {
                    return(DisposedOrDisabledFailure);
                }

                try
                {
                    return(use(m_store, state));
                }
                catch (Exception ex)
                {
                    var result = HandleException(ex, out var rethrow);
                    if (rethrow)
                    {
                        throw;
                    }

                    return(result);
                }
            }
        }
Пример #4
0
        protected void TogglePauseChooseWorkerQueue(bool pause, RunnablePip blockedPip = null)
        {
            Contract.Requires(pause == (blockedPip != null), "Must specify blocked pip if and only if pausing the choose worker queue");

            if (pause)
            {
                using (m_chooseWorkerTogglePauseLock.AcquireWriteLock())
                {
                    // Compare with the captured sequence number before the pip re-entered the queue
                    // to avoid race conditions where pip cannot acquire worker resources become available then queue is paused
                    // potentially indefinitely (not likely but theoretically possilbe)
                    if (Volatile.Read(ref WorkerEnableSequenceNumber) == blockedPip.ChooseWorkerSequenceNumber)
                    {
                        SetQueueMaxParallelDegree(0);
                    }
                }
            }
            else
            {
                using (m_chooseWorkerTogglePauseLock.AcquireReadLock())
                {
                    // Update the sequence number. This essentially is called for every increase in resources
                    // and successful acquisition of workers to track changes in resource state that invalidate
                    // decision to pause choose worker queue.
                    Interlocked.Increment(ref WorkerEnableSequenceNumber);

                    // Unpause the queue
                    SetQueueMaxParallelDegree(MaxParallelDegree);
                }
            }
        }
Пример #5
0
        [System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptions] // allows catching exceptions from unmanaged code
        public Possible <TResult> Use <TState, TResult>(Func <IBuildXLKeyValueStore, TState, TResult> use, TState state)
        {
            using (m_rwl.AcquireReadLock())
            {
                try
                {
                    if (Disabled)
                    {
                        return(DisposedOrDisabledFailure);
                    }

                    return(use(m_store, state));
                }
                catch (RocksDbSharpException ex)
                {
                    return(HandleException(ex));
                }
                // The SEHException class handles SEH (structured exception handling) errors that are thrown from unmanaged code,
                // but that have not been mapped to another .NET Framework exception. The SEHException class also corresponds to the HRESULT E_FAIL (0x80004005).
                catch (System.Runtime.InteropServices.SEHException ex)
                {
                    return(HandleException(ex));
                }
                // Provide an opportunity for caller to handle any unknown exception type, including unmanaged ones, then rethrow
                catch (Exception ex)
                {
                    HandleException(ex);
                    throw;
                }
            }
        }
Пример #6
0
        public bool TryAcquireCacheLookup(ProcessRunnablePip runnablePip, bool force)
        {
            using (EarlyReleaseLock.AcquireReadLock())
            {
                if (!IsAvailable)
                {
                    return(false);
                }

                if (force)
                {
                    Interlocked.Increment(ref m_acquiredCacheLookupSlots);
                    runnablePip.AcquiredResourceWorker = this;
                    return(true);
                }

                // Atomically acquire a cache lookup slot, being sure to not increase above the limit
                while (true)
                {
                    int acquiredCacheLookupSlots = AcquiredCacheLookupSlots;
                    if (acquiredCacheLookupSlots < TotalCacheLookupSlots)
                    {
                        if (Interlocked.CompareExchange(ref m_acquiredCacheLookupSlots, acquiredCacheLookupSlots + 1, acquiredCacheLookupSlots) == acquiredCacheLookupSlots)
                        {
                            OnWorkerResourcesChanged(WorkerResource.AvailableCacheLookupSlots, increased: false);
                            runnablePip.AcquiredResourceWorker = this;
                            return(true);
                        }
                        else
                        {
                            // Failed to update value. Retry.
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
        }
Пример #7
0
        private (JobObject, uint[]) GetJobObjectWithChildProcessIds()
        {
            using (m_queryJobDataLock.AcquireReadLock())
            {
                var detouredProcess = m_detouredProcess;
                if (detouredProcess == null ||
                    !detouredProcess.HasStarted ||
                    detouredProcess.HasExited ||
                    m_disposeStarted)
                {
                    return(null, null);
                }

                var jobObject = detouredProcess.GetJobObject();
                if (jobObject == null || !jobObject.TryGetProcessIds(m_loggingContext, out uint[] childProcessIds) || childProcessIds.Length == 0)
Пример #8
0
        /// <inheritdoc />
        /// <remarks>
        /// Gets the peak memory usage for the job object associated with the detoured process while the process is active.
        /// </remarks>
        public ulong?GetActivePeakMemoryUsage()
        {
            using (m_queryJobDataLock.AcquireReadLock())
            {
                var detouredProcess = m_detouredProcess;
                if (detouredProcess == null ||
                    !detouredProcess.HasStarted ||
                    detouredProcess.HasExited ||
                    m_disposeStarted)
                {
                    return(null);
                }

                return(detouredProcess.GetJobObject()?.GetPeakMemoryUsage());
            }
        }
Пример #9
0
        /// <summary>
        /// Iterates through the job object processes executing an action for each one.
        /// </summary>
        public VisitJobObjectResult TryVisitJobObjectProcesses(Action <SafeProcessHandle, uint> actionForProcess)
        {
            Contract.Requires(HasStarted);

            // Accessing jobObject needs to be protected by m_queryJobDataLock.
            // After we collected the child process ids, we might dispose the job object and the child process might be invalid.
            // Acquiring the reader lock will prevent the job object from disposing.
            using (m_queryJobDataLock.AcquireReadLock())
            {
                var jobObject = GetJobObject();
                if (m_killed)
                {
                    // Terminated before starting the operation
                    return(VisitJobObjectResult.TerminatedBeforeVisitation);
                }

                if (!jobObject.TryGetProcessIds(m_loggingContext, out uint[] childProcessIds))
Пример #10
0
        /// <inheritdoc />
        public ulong?GetActivePeakWorkingSet()
        {
            using (m_queryJobDataLock.AcquireReadLock())
            {
                var detouredProcess = m_detouredProcess;
                if (detouredProcess == null ||
                    !detouredProcess.HasStarted ||
                    detouredProcess.HasExited ||
                    m_disposeStarted)
                {
                    return(null);
                }

                ulong?currentPeakWorkingSet    = null;
                ulong?currentPeakPagefileUsage = null;

                var jobObject = detouredProcess.GetJobObject();
                if (jobObject == null || !jobObject.TryGetProcessIds(m_loggingContext, out uint[] childProcessIds) || childProcessIds.Length == 0)
Пример #11
0
        /// <inheritdoc />
        public EmptyWorkingSetResult TryEmptyWorkingSet(bool isSuspend)
        {
            // Accessing jobObject needs to be protected by m_queryJobDataLock.
            // After we collected the child process ids, we might dispose the job object and the child process might be invalid.
            // Acquiring the reader lock will prevent the job object from disposing.
            using (m_queryJobDataLock.AcquireReadLock())
            {
                (JobObject jobObject, uint[] childProcesses) = GetJobObjectWithChildProcessIds();

                if (jobObject == null)
                {
                    return(EmptyWorkingSetResult.None);
                }

                EmptyWorkingSetResult result = EmptyWorkingSetResult.Success;

                VisitJobObjectProcesses(jobObject, childProcesses, (processHandle, pid) =>
                {
                    if (isSuspend)
                    {
                        bool isSuspendFailed = false;
                        try
                        {
                            isSuspendFailed = !Interop.Windows.Process.Suspend(System.Diagnostics.Process.GetProcessById((int)pid));
                        }
#pragma warning disable ERP022
                        catch (Exception)
                        {
                            isSuspendFailed = true;
                        }
#pragma warning restore ERP022

                        if (isSuspendFailed)
                        {
                            // If suspending the process fails, no need to continue going through the other processes.
                            result |= EmptyWorkingSetResult.SuspendFailed;
                        }
                    }

                    if (!Interop.Windows.Memory.EmptyWorkingSet(processHandle.DangerousGetHandle()))
                    {
                        result |= EmptyWorkingSetResult.EmptyWorkingSetFailed;
                    }

                    if (EngineEnvironmentSettings.SetMaxWorkingSetToMin)
                    {
                        if (!Interop.Windows.Memory.SetProcessWorkingSetSizeEx(
                                processHandle.DangerousGetHandle(),
                                s_defaultMin, // the default on systems with 4k pages
                                s_defaultMin,
                                Interop.Windows.Memory.WorkingSetSizeFlags.MaxEnable | Interop.Windows.Memory.WorkingSetSizeFlags.MinDisable))
                        {
                            result |= EmptyWorkingSetResult.SetMaxWorkingSetFailed;
                        }
                    }
                });


                return(result);
            }
        }
Пример #12
0
        /// <inheritdoc />
        public ulong?GetActivePeakWorkingSet()
        {
            using (m_queryJobDataLock.AcquireReadLock())
            {
                var detouredProcess = m_detouredProcess;
                if (detouredProcess == null ||
                    !detouredProcess.HasStarted ||
                    detouredProcess.HasExited ||
                    m_disposeStarted)
                {
                    return(null);
                }

                ulong?currentPeakWorkingSet    = null;
                ulong?currentPeakPagefileUsage = null;

                var jobObject = detouredProcess.GetJobObject();
                if (jobObject == null || !jobObject.TryGetProcessIds(out uint[] childProcessIds) || childProcessIds.Length == 0)
                {
                    return(null);
                }

                foreach (uint processId in childProcessIds)
                {
                    using (SafeProcessHandle processHandle = ProcessUtilities.OpenProcess(
                               ProcessSecurityAndAccessRights.PROCESS_QUERY_INFORMATION,
                               false,
                               processId))
                    {
                        if (processHandle.IsInvalid)
                        {
                            // we are too late: could not open process
                            continue;
                        }

                        if (!jobObject.ContainsProcess(processHandle))
                        {
                            // we are too late: process id got reused by another process
                            continue;
                        }

                        int exitCode;
                        if (!ProcessUtilities.GetExitCodeProcess(processHandle, out exitCode))
                        {
                            // we are too late: process id got reused by another process
                            continue;
                        }

                        var memoryUsage = Interop.Dispatch.GetMemoryUsageCounters(processHandle.DangerousGetHandle());
                        if (memoryUsage != null)
                        {
                            currentPeakWorkingSet    = (currentPeakWorkingSet ?? 0) + memoryUsage.PeakWorkingSetSize;
                            currentPeakPagefileUsage = (currentPeakPagefileUsage ?? 0) + memoryUsage.PeakPagefileUsage;
                        }
                    }
                }

                m_peakWorkingSet.RegisterSample(currentPeakWorkingSet ?? 0);
                m_peakPagefileUsage.RegisterSample(currentPeakPagefileUsage ?? 0);

                return(currentPeakWorkingSet);
            }
        }
Пример #13
0
        /// <inheritdoc />
        public EmptyWorkingSetResult TryEmptyWorkingSet(bool isSuspend)
        {
            // Accessing jobObject needs to be protected by m_queryJobDataLock.
            // After we collected the child process ids, we might dispose the job object and the child process might be invalid.
            // Acquiring the reader lock will prevent the job object from disposing.
            using (m_queryJobDataLock.AcquireReadLock())
            {
                if (!IsDetouredProcessUsable())
                {
                    return(EmptyWorkingSetResult.None);
                }

                var result                 = EmptyWorkingSetResult.Success;
                var suspendSuccess         = true;
                var emptyWorkingSetSuccess = true;

                var visited = m_detouredProcess.TryVisitJobObjectProcesses((processHandle, pid) =>
                {
                    emptyWorkingSetSuccess &= Interop.Windows.Memory.EmptyWorkingSet(processHandle.DangerousGetHandle());

                    if (isSuspend)
                    {
                        try
                        {
                            suspendSuccess &= Interop.Windows.Process.Suspend(System.Diagnostics.Process.GetProcessById((int)pid));
                        }
                        catch (Exception e)
                        {
                            suspendSuccess = false;
                            Tracing.Logger.Log.ResumeOrSuspendException(m_loggingContext, "Suspend", e.ToStringDemystified());
                        }
                    }
                });

                if (!visited)
                {
                    // Couldn't visit
                    result |= EmptyWorkingSetResult.EmptyWorkingSetFailed;

                    if (isSuspend)
                    {
                        result |= EmptyWorkingSetResult.SuspendFailed;
                    }

                    return(result);
                }

                if (!emptyWorkingSetSuccess)
                {
                    result |= EmptyWorkingSetResult.EmptyWorkingSetFailed;
                }

                if (isSuspend)
                {
                    if (suspendSuccess)
                    {
                        m_detouredProcess.OnSuspensionStart();
                    }
                    else
                    {
                        result |= EmptyWorkingSetResult.SuspendFailed;
                    }
                }

                return(result);
            }
        }