Example #1
0
        internal static CacheEntry CreateFromStream(BinaryReader reader)
        {
            CacheEntryTypes entryType = (CacheEntryTypes)reader.ReadByte();
            CacheEntry      entry     = null;

            switch (entryType)
            {
            case CacheEntryTypes.BuildItem:
                entry = new BuildItemCacheEntry();
                break;

            case CacheEntryTypes.BuildResult:
                entry = new BuildResultCacheEntry();
                break;

            case CacheEntryTypes.Property:
                entry = new PropertyCacheEntry();
                break;

            default:
                ErrorUtilities.VerifyThrow(false, "Should not get to the default of CacheEntryCustomSerializer CreateFromStream");
                break;
            }

            entry.CreateFromStream(reader);
            return(entry);
        }
Example #2
0
        /// <summary>
        /// Get a cached build result if available for the given request. This method is thread safe.
        /// </summary>
        /// <param name="buildRequest"></param>
        /// <param name="actuallyBuiltTargets"></param>
        /// <returns></returns>
        internal BuildResult GetCachedBuildResult(BuildRequest buildRequest, out ArrayList actuallyBuiltTargets)
        {
            actuallyBuiltTargets = null;

            PropertyCacheEntry defaultTargetsCacheEntry, initialTargetsCacheEntry, projectIdCacheEntry;

            // No writes here, but since we're reading multiple values we want to get a consistent view of the cache
            cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            try
            {
                defaultTargetsCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.defaultTargetCacheName);
                initialTargetsCacheEntry = (PropertyCacheEntry)GetCacheEntry(Constants.initialTargetCacheName);
                projectIdCacheEntry      = (PropertyCacheEntry)GetCacheEntry(Constants.projectIdCacheName);
            }
            finally
            {
                cacheScopeReaderWriterLock.ReleaseReaderLock();
            }

            // If we ever built anything in this project we must have the default and initial targets.
            if (defaultTargetsCacheEntry == null && initialTargetsCacheEntry == null)
            {
                return(null);
            }

            ErrorUtilities.VerifyThrow(projectIdCacheEntry != null, "We should always have the projectId cache entry");

            ErrorUtilities.VerifyThrow(defaultTargetsCacheEntry != null && initialTargetsCacheEntry != null,
                                       "We should have both the initial and default targets in the cache");

            ArrayList targetsToBuild = new ArrayList(initialTargetsCacheEntry.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));

            if (buildRequest.TargetNames == null || buildRequest.TargetNames.Length == 0)
            {
                targetsToBuild.AddRange(defaultTargetsCacheEntry.Value.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries));
            }
            else
            {
                targetsToBuild.AddRange(buildRequest.TargetNames);
            }

            // Create variable to hold the cached outputs
            Hashtable outputsByTargetName = new Hashtable(targetsToBuild.Count);
            Hashtable resultByTarget      = new Hashtable(targetsToBuild.Count, StringComparer.OrdinalIgnoreCase);

            bool overallSuccess = true;
            bool missingValues  = false;

            // No writes here, but since we're reading multiple values we want to get a consistent view of the cache
            cacheScopeReaderWriterLock.AcquireReaderLock(Timeout.Infinite);

            try
            {
                for (int i = 0; i < targetsToBuild.Count; i++)
                {
                    string targetName = EscapingUtilities.UnescapeAll((string)targetsToBuild[i]);
                    if (ContainsCacheEntry(targetName))
                    {
                        BuildResultCacheEntry cacheEntry = (BuildResultCacheEntry)GetCacheEntry(targetName);
                        overallSuccess             = overallSuccess && cacheEntry.BuildResult;
                        resultByTarget[targetName] = (cacheEntry.BuildResult) ?
                                                     Target.BuildState.CompletedSuccessfully : Target.BuildState.CompletedUnsuccessfully;

                        // Restore output items for successful targets
                        if (cacheEntry.BuildResult)
                        {
                            outputsByTargetName[targetName] = cacheEntry.BuildItems;
                        }
                        // We found a failed target - cut the loop short
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        missingValues = true;
                        break;
                    }
                }
            }
            finally
            {
                cacheScopeReaderWriterLock.ReleaseReaderLock();
            }

            if (missingValues)
            {
                return(null);
            }

            actuallyBuiltTargets = targetsToBuild;

            return(new BuildResult(outputsByTargetName, resultByTarget, overallSuccess, buildRequest.HandleId, buildRequest.RequestId,
                                   int.Parse(projectIdCacheEntry.Value, CultureInfo.InvariantCulture), false /* use results cache */,
                                   defaultTargetsCacheEntry.Value, initialTargetsCacheEntry.Value, 0, 0, 0));
        }
Example #3
0
        /// <summary>
        /// This method adds cached results for each target results for which are contained inside
        /// the build result. This method is thread safe.
        /// </summary>
        internal void AddCacheEntryForBuildResults(BuildResult buildResult)
        {
            ErrorUtilities.VerifyThrow(buildResult != null, "Expect a non-null build result");

            // Don't cache results if they are marked as uncacheable
            if (!buildResult.UseResultCache)
            {
                return;
            }

            cacheScopeReaderWriterLock.AcquireWriterLock(Timeout.Infinite);

            try
            {
                if (!ContainsCacheEntry(Constants.defaultTargetCacheName))
                {
                    // If the project file is malformed the build may fail without initializing the initialtargets or
                    // the default targests fields. The retrieval code expects non-null values
                    // so it is necessary to replace null with empty string
                    ErrorUtilities.VerifyThrow(buildResult.EvaluationResult == false || buildResult.InitialTargets != null &&
                                               buildResult.DefaultTargets != null,
                                               "Expect initial targets to be non-null for successful builds");
                    string             defaultTargets           = buildResult.DefaultTargets == null ? String.Empty : buildResult.DefaultTargets;
                    PropertyCacheEntry defaultTargetsCacheEntry = new PropertyCacheEntry(Constants.defaultTargetCacheName, defaultTargets);
                    AddCacheEntryInternal(defaultTargetsCacheEntry);

                    string             initialTargets           = buildResult.InitialTargets == null ? String.Empty : buildResult.InitialTargets;
                    PropertyCacheEntry initialTargetsCacheEntry = new PropertyCacheEntry(Constants.initialTargetCacheName, initialTargets);
                    AddCacheEntryInternal(initialTargetsCacheEntry);
                }

                if (!ContainsCacheEntry(Constants.projectIdCacheName))
                {
                    PropertyCacheEntry projectIdCacheEntry = new PropertyCacheEntry(Constants.projectIdCacheName, buildResult.ProjectId.ToString(CultureInfo.InvariantCulture));
                    AddCacheEntryInternal(projectIdCacheEntry);
                }

                IDictionary outputsByTargetName = buildResult.OutputsByTarget;

                //Create single entry for each target in the request
                foreach (DictionaryEntry entry in buildResult.ResultByTarget)
                {
                    Target.BuildState buildState = (Target.BuildState)entry.Value;

                    // Only cache successful and failed targets
                    if ((buildState == Target.BuildState.CompletedSuccessfully) ||
                        (buildState == Target.BuildState.CompletedUnsuccessfully))
                    {
                        BuildItem[] targetOutputs = null;

                        // Only cache output items for successful targets
                        if (buildState == Target.BuildState.CompletedSuccessfully)
                        {
                            ErrorUtilities.VerifyThrow(buildResult.OutputsByTarget.Contains(entry.Key),
                                                       "We must have build results for successful targets");

                            BuildItem[] outputItems = (BuildItem[])buildResult.OutputsByTarget[entry.Key];

                            // It's essential that we clear out any pointers to the project from the BuildItem;
                            // otherwise the cache will hold onto the project, and not save any memory.
                            if (outputItems != null)
                            {
                                for (int i = 0; i < outputItems.Length; i++)
                                {
                                    outputItems[i] = outputItems[i].VirtualClone(true /* remove references to minimise transitive size */);
                                }
                            }

                            targetOutputs = (BuildItem[])buildResult.OutputsByTarget[entry.Key];
                        }

                        BuildResultCacheEntry cacheEntry = new BuildResultCacheEntry((string)entry.Key, targetOutputs,
                                                                                     (buildState == Target.BuildState.CompletedSuccessfully));

                        if (Engine.debugMode)
                        {
                            Console.WriteLine("+++Adding cache entry for " + (string)entry.Key + " in " +
                                              this.ScopeName + " result: " + (buildState == Target.BuildState.CompletedSuccessfully));
                        }

                        AddCacheEntryInternal(cacheEntry);
                    }
                }
            }
            finally
            {
                cacheScopeReaderWriterLock.ReleaseWriterLock();
            }
        }