示例#1
0
        /// <nodoc />
        public void SaveFrontEndSnapshot(IWorkspaceBindingSnapshot snapshot)
        {
            try
            {
                ExceptionUtilities.HandleRecoverableIOException(
                    () => DoSaveFrontEndSnapshot(),
                    e => throw new BuildXLException(string.Empty, e));
            }
            catch (BuildXLException e)
            {
                m_logger.SaveFrontEndSnapshotError(m_loggingContext, m_cacheFileName, e.InnerException.ToString());
            }

            void DoSaveFrontEndSnapshot()
            {
                var sw = Stopwatch.StartNew();

                using (var file = FileUtilities.CreateFileStream(m_cacheFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.Delete))
                {
                    var writer = new BuildXLWriter(debug: false, stream: file, leaveOpen: true, logStats: false);
                    writer.WriteCompact(Version);

                    FrontEndSnapshotSerializer.SerializeWorkspaceBindingSnapshot(snapshot, writer, m_pathTable);
                }

                m_frontEndStatistics.FrontEndSnapshotSavingDuration = sw.Elapsed;
                m_logger.SaveFrontEndSnapshot(m_loggingContext, m_cacheFileName, (int)sw.ElapsedMilliseconds);
            }
        }
示例#2
0
        /// <summary>
        /// Reads a file containing versioning information from the provided store directory.
        /// </summary>
        private static Possible <int> ReadStoreVersion(string storeDirectory)
        {
            var versionFile = GetVersionFile(storeDirectory);

            if (!FileUtilities.FileExistsNoFollow(versionFile))
            {
                return(VersionConstants.UnversionedStore);
            }

            using (var stream = FileUtilities.CreateFileStream(
                       versionFile,
                       FileMode.Open,
                       FileAccess.Read,
                       FileShare.Delete))
            {
                try
                {
                    // Check that the accessor version is valid.
                    s_fileEnvelope.ReadHeader(stream);

                    // Check that the current store version must match the persisted store's version.
                    using (var reader = new BuildXLReader(debug: false, stream: stream, leaveOpen: false))
                    {
                        // Represents persisted store version
                        return(reader.ReadInt32());
                    }
                }
                catch (Exception e)
                {
                    return(new Failure <string>($"Error reading existing version file: {e.ToStringDemystified()}"));
                }
            }
        }
示例#3
0
        public async Task ErrorHandling()
        {
            using (var tempFiles = new TempFileStorage(canGetFileNames: true))
            {
                var storage  = (ISandboxedProcessFileStorage)tempFiles;
                var fileName = storage.GetFileName(SandboxedProcessFile.StandardOutput);
                SandboxedProcessOutput output;
                using (var fileStream = FileUtilities.CreateFileStream(fileName, FileMode.CreateNew, FileAccess.Write, FileShare.None, allowExcludeFileShareDelete: true))
                {
                    var content       = new string('S', 100);
                    var outputBuilder =
                        new SandboxedProcessOutputBuilder(Encoding.UTF8, content.Length / 2, tempFiles, SandboxedProcessFile.StandardOutput, null);

                    // NOTE: this only holds on Windows
                    // The specified content plus a NewLine will exceed the max memory length.
                    // Thus, the output builder will try to write the content to a file.
                    // However, the file is not writable (this runs in a using clause that already opened the file).
                    // Thus, this will internally fail, but not yet throw an exception.
                    outputBuilder.AppendLine(content);
                    output = outputBuilder.Freeze();
                    XAssert.IsTrue(output.HasException);
                }

                await Assert.ThrowsAsync <BuildXLException>(() => output.ReadValueAsync());

                await Assert.ThrowsAsync <BuildXLException>(() => output.SaveAsync());

                Assert.Throws <BuildXLException>(() => output.CreateReader());
            }
        }
 /// <summary>
 /// Saves a pip cost hash table to a file.
 /// </summary>
 /// <exception cref="BuildXLException">
 /// Thrown if a recoverable error occurs while operating on the file.
 /// </exception>
 public void Save(string fileName)
 {
     Contract.Requires(fileName != null);
     using (FileStream fileStream = FileUtilities.CreateFileStream(fileName, FileMode.Create, FileAccess.Write, FileShare.Delete))
     {
         Save(fileStream);
     }
 }
示例#5
0
        public WorkspaceBindingSnapshot TryLoadFrontEndSnapshot(int expectedSpecCount)
        {
            try
            {
                return(ExceptionUtilities.HandleRecoverableIOException(
                           () => DoLoadFrontEndSnapshot(),
                           e => throw new BuildXLException(string.Empty, e)));
            }
            catch (BuildXLException e)
            {
                // Recoverable exceptions should not break BuildXL.
                m_logger.FailToReuseFrontEndSnapshot(m_loggingContext, I($"IO exception occurred: {e.InnerException}"));
                return(null);
            }

            WorkspaceBindingSnapshot DoLoadFrontEndSnapshot()
            {
                if (!File.Exists(m_cacheFileName))
                {
                    // Can't reuse the snapshot because the file does not exist.
                    m_logger.FailToReuseFrontEndSnapshot(m_loggingContext, I($"File '{m_cacheFileName}' does not exist"));
                    return(null);
                }

                var sw = Stopwatch.StartNew();

                using (var file = FileUtilities.CreateFileStream(m_cacheFileName, FileMode.Open, FileAccess.ReadWrite, FileShare.Delete))
                {
                    var reader  = new BuildXLReader(debug: false, stream: file, leaveOpen: true);
                    var version = reader.ReadInt32Compact();
                    if (version != Version)
                    {
                        // Version mismatch. Can't reuse the file.
                        m_logger.FailToReuseFrontEndSnapshot(
                            m_loggingContext,
                            I($"Cache version '{version}' does not match an expected version '{Version}'"));
                        return(null);
                    }

                    var specCount = reader.ReadInt32Compact();
                    if (expectedSpecCount != specCount)
                    {
                        // Can't use the cache, because it has different amount of specs in there.
                        m_logger.FailToReuseFrontEndSnapshot(
                            m_loggingContext,
                            I($"Cache contains the data for '{specCount}' specs but current execution requires '{expectedSpecCount}' specs"));
                        return(null);
                    }

                    var specs = FrontEndSnapshotSerializer.DeserializeSpecStates(reader, m_pathTable, specCount);

                    m_frontEndStatistics.FrontEndSnapshotLoadingDuration = sw.Elapsed;

                    m_logger.LoadFrontEndSnapshot(m_loggingContext, specs.Length, (int)sw.ElapsedMilliseconds);
                    return(new WorkspaceBindingSnapshot(specs, m_pathTable));
                }
            }
        }
示例#6
0
        private void Save(FileEnvelopeId atomicSaveToken, string path)
        {
            Contract.Requires(!string.IsNullOrWhiteSpace(path));

            FileUtilities.DeleteFile(path);
            FileUtilities.CreateDirectory(Path.GetDirectoryName(path));

            using (var stream = FileUtilities.CreateFileStream(
                       path,
                       FileMode.Create,
                       FileAccess.Write,
                       FileShare.Delete,
                       // Do not write the file with SequentialScan since it will be reread in the subsequent build
                       FileOptions.None))
            {
                ExceptionUtilities.HandleRecoverableIOException(
                    () =>
                {
                    using (var pm = BuildXL.Tracing.PerformanceMeasurement.StartWithoutStatistic(
                               m_loggingContext,
                               loggingContext => Logger.Log.StartSavingChangeTracker(loggingContext, path),
                               loggingContext => Logger.Log.EndSavingChangeTracker(loggingContext)))
                    {
                        Stopwatch sw = Stopwatch.StartNew();

                        FileEnvelope.WriteHeader(stream, atomicSaveToken);
                        using (var writer = new BuildXLWriter(debug: false, stream: stream, leaveOpen: true, logStats: false))
                        {
                            if (IsDisabledOrNullTrackingSet)
                            {
                                writer.Write(true);
                            }
                            else
                            {
                                writer.Write(false);
                                writer.Write(m_buildEngineFingerprint, (w, s) => w.Write(s));
                                m_changeTrackingSet.Save(writer);
                            }
                        }

                        FileEnvelope.FixUpHeader(stream, atomicSaveToken);

                        Logger.Log.SavingChangeTracker(
                            pm.LoggingContext,
                            path,
                            atomicSaveToken.ToString(),
                            m_changeTrackingSet == null ? "Null" : TrackingState.ToString(),
                            m_changeTrackingSet == null ? 0 : m_changeTrackingSet.TrackedVolumes.Count(),
                            sw.ElapsedMilliseconds);
                    }
                },
                    ex => { throw new BuildXLException("Failed to save file change tracker", ex); });
            }
        }
示例#7
0
        private async Task <ContentHash> GetContentHashAsync(string path, HashType hashType)
        {
            using var fs = FileUtilities.CreateFileStream(
                      path,
                      FileMode.Open,
                      FileAccess.Read,
                      FileShare.Delete | FileShare.Read,
                      FileOptions.SequentialScan);

            ContentHashingUtilities.SetDefaultHashType(hashType);
            return(await ContentHashingUtilities.HashContentStreamAsync(fs, hashType));
        }
示例#8
0
        private TextReader CreateFileReader()
        {
            // This FileStream is not asynchronous due to an intermittant crash we see on some machines when using
            // an asynchronous stream here
            FileStream stream = FileUtilities.CreateFileStream(
                m_fileName,
                FileMode.Open,
                FileAccess.Read,
                FileShare.Read | FileShare.Delete);

            return(new StreamReader(stream));
        }
示例#9
0
 /// <summary>
 /// Opens the stream at the given path with read access
 /// </summary>
 public virtual Disposable <Stream> OpenReadStream(string path)
 {
     return(new Disposable <Stream>(
                FileUtilities.CreateFileStream(
                    path,
                    FileMode.Open,
                    FileAccess.Read,
                    FileShare.Read | FileShare.Delete,
                    // Ok to evict the file from standby since the file will be overwritten and never reread from disk after this point.
                    FileOptions.SequentialScan),
                null));
 }
示例#10
0
 /// <summary>
 /// Opens a pip cost hash table from a file.
 /// </summary>
 /// <exception cref="BuildXLException">
 /// Thrown if a recoverable error occurs while operating on the file.
 /// </exception>
 public static PipRuntimeTimeTable Load(string fileName)
 {
     Contract.Requires(fileName != null);
     using (
         FileStream fileStream = FileUtilities.CreateFileStream(
             fileName,
             FileMode.Open,
             FileAccess.Read,
             FileShare.Read | FileShare.Delete))
     {
         return Load(fileStream);
     }
 }
示例#11
0
 /// <summary>
 /// Opens a pip cost hash table from a file.
 /// </summary>
 /// <exception cref="BuildXLException">
 /// Thrown if a recoverable error occurs while operating on the file.
 /// </exception>
 public static HistoricPerfDataTable Load(LoggingContext loggingContext, string fileName)
 {
     Contract.Requires(fileName != null);
     using (
         FileStream fileStream = FileUtilities.CreateFileStream(
             fileName,
             FileMode.Open,
             FileAccess.Read,
             FileShare.Read | FileShare.Delete))
     {
         return(Load(loggingContext, fileStream));
     }
 }
示例#12
0
        private async Task <ContentHash> GetContentHashAsync(AbsolutePath path, HashType hashType = HashType.Unknown)
        {
            m_frontEndHost.Engine.RecordFrontEndFile(path, Name);

            // We don't call GetFileContentHashAsync() to get the existing hash, since it register the file.
            // This has been done in RecordFrontEndFile with the default hasher, re-register it with the specified hasher will cause error.
            using (
                var fs = FileUtilities.CreateFileStream(
                    path.ToString(m_context.PathTable),
                    FileMode.Open,
                    FileAccess.Read,
                    FileShare.Delete | FileShare.Read,
                    FileOptions.SequentialScan))
            {
                return(await ContentHashingUtilities.HashContentStreamAsync(fs, hashType));
            }
        }
示例#13
0
        private VersionedFileIdentityAndContentInfo RecordContentHash(FileContentTable table, AbsolutePath path, ContentHash hash, bool strict = false)
        {
            Contract.Requires(table != null);

            using (
                FileStream fs = FileUtilities.CreateFileStream(
                    path.ToString(m_pathTable),
                    FileMode.Open,
                    strict ? FileAccess.ReadWrite : FileAccess.Read,
                    FileShare.Read | FileShare.Delete,
                    FileOptions.Asynchronous, true))
            {
                var info = table.RecordContentHash(fs, hash, strict: strict);
                XAssert.AreEqual(hash, info.FileContentInfo.Hash);
                XAssert.IsTrue(info.Identity.Kind == VersionedFileIdentity.IdentityKind.StrongUsn || info.Identity.Kind == VersionedFileIdentity.IdentityKind.Anonymous);
                return(info);
            }
        }
示例#14
0
        public static AppDeployment ReadDeploymentManifest(string baseDir, string fileName, bool skipManifestCheckTestHook = false)
        {
            List <string> fileNames = new List <string>();

            using (FileStream deploymentManifest = FileUtilities.CreateFileStream(
                       Path.Combine(baseDir, fileName),
                       FileMode.Open, FileAccess.Read, FileShare.Delete))
            {
                using (StreamReader reader = new StreamReader(deploymentManifest))
                {
                    while (!reader.EndOfStream)
                    {
                        fileNames.Add(reader.ReadLine());
                    }
                }
            }

            return(new AppDeployment(baseDir, fileNames, skipManifestCheckTestHook));
        }
示例#15
0
        /// <inheritdoc/>
        public override async Task <ContentHash> GetFileContentHashAsync(string path, bool trackFile = true, HashType hashType = HashType.Unknown)
        {
            // If the tracker knows about this file, then we already have the hash
            ContentHash hash;

            if (trackFile)
            {
                if (m_inputTracker.TryGetHashForUnchangedFile(path, out hash))
                {
                    return(hash);
                }
            }

            using (
                var fs = FileUtilities.CreateFileStream(
                    path,
                    FileMode.Open,
                    FileAccess.Read,
                    FileShare.Delete | FileShare.Read,
                    FileOptions.SequentialScan))
            {
                // Otherwise, check if the file content table already knows about this
                var fileContentTable = m_getFileContentTable();

                VersionedFileIdentityAndContentInfo?maybeKnownIdentityAndHash = fileContentTable.TryGetKnownContentHash(fs);

                if (maybeKnownIdentityAndHash?.FileContentInfo.MatchesHashType(hashType) ?? false)
                {
                    return(maybeKnownIdentityAndHash.Value.FileContentInfo.Hash);
                }

                // Finally, if all the above failed, compute the hash and record it for next time
                hash = await ContentHashingUtilities.HashContentStreamAsync(fs, hashType);

                maybeKnownIdentityAndHash = fileContentTable.RecordContentHash(fs, hash);

                m_specCache?.AddFile(fs, maybeKnownIdentityAndHash.Value.FileContentInfo.Hash, path);
                m_inputTracker.RegisterFileAccess(fs.SafeFileHandle, path, maybeKnownIdentityAndHash.Value);

                return(hash);
            }
        }
示例#16
0
        /// <inheritdoc />
        public override bool TryGetFrontEndFile(AbsolutePath path, string frontEnd, out Stream stream)
        {
            var physicalPath = path.ToString(m_pathTable);

            try
            {
                stream = FileUtilities.CreateFileStream(
                    physicalPath,
                    FileMode.Open,
                    FileAccess.Read,
                    FileShare.Delete | FileShare.Read,
                    FileOptions.SequentialScan);

                return(true);
            }
            catch (BuildXLException)
            {
                stream = null;
                return(false);
            }
        }
示例#17
0
        public void StrictModeFlushesDirtyMemoryMappedPages()
        {
            var table = FileContentTable.CreateNew();

            string testFileAExpandedPath = m_testFileA.ToString(m_pathTable);

            // Writing a file via a memory mapping leaves 'dirty' pages in cache that get lazily flushed to FS.
            // We want to verify that passing strict: true flushes those pages, so that the recorded USN is stable (not invalidated due to lazy flushes).
            using (FileStream file = FileUtilities.CreateFileStream(testFileAExpandedPath, FileMode.Create, FileAccess.ReadWrite, FileShare.Delete | FileShare.Read))
            {
                file.SetLength(1024 * 1024);
                using (var memoryMappedFile = MemoryMappedFile.CreateFromFile(
                           file,
                           mapName: null,
                           capacity: 0,
                           access: MemoryMappedFileAccess.ReadWrite,
#if !DISABLE_FEATURE_MEMORYMAP_SECURITY
                           memoryMappedFileSecurity: null,
#endif
                           inheritability: HandleInheritability.None,
                           leaveOpen: false))
                {
                    using (var accessor = memoryMappedFile.CreateViewAccessor())
                    {
                        for (int i = 0; i < 1024 * 1024; i += 4)
                        {
                            accessor.Write(i, (int)0xAB);
                        }
                    }
                }

                RecordContentHash(table, m_testFileA, s_hashA, strict: true);
            }

            for (int i = 0; i < 10; i++)
            {
                Thread.Sleep(10);
                ExpectHashKnown(table, m_testFileA, s_hashA);
            }
        }
示例#18
0
        /// <summary>
        /// Writes a file containing versioning information to the provided store directory.
        /// </summary>
        private static void WriteVersionFile(string storeDirectory, int storeVersion)
        {
            var versionFile = GetVersionFile(storeDirectory);

            using (var stream = FileUtilities.CreateFileStream(
                       versionFile,
                       FileMode.Create,
                       FileAccess.ReadWrite,
                       FileShare.Delete))
            {
                // We don't have anything in particular to correlate this file to,
                // so we are simply creating a unique correlation id that is used as part
                // of the header consistency check.
                var correlationId = FileEnvelopeId.Create();
                s_fileEnvelope.WriteHeader(stream, correlationId);

                using (var writer = new BuildXLWriter(debug: false, stream: stream, leaveOpen: true, logStats: false))
                {
                    writer.Write(storeVersion);
                }

                s_fileEnvelope.FixUpHeader(stream, correlationId);
            }
        }
示例#19
0
        /// <summary>
        /// Extract files to disk
        /// </summary>
        /// <remarks>
        /// At the point of authoring (Jan 2019) the BCL does not implement tar-files or bz2.
        /// https://github.com/dotnet/corefx/issues/3253 has been discussed since Sept 2015
        /// Therefore we rely here on 3rd party library: https://github.com/icsharpcode/SharpZipLib
        /// </remarks>
        private bool TryExtractToDisk(DownloadData downloadData)
        {
            var archive = downloadData.DownloadedFilePath.ToString(m_context.PathTable);
            var target  = downloadData.ContentsFolder.Path.ToString(m_context.PathTable);

            try
            {
                FileUtilities.DeleteDirectoryContents(target, false);
                FileUtilities.CreateDirectory(target);
            }
            catch (BuildXLException e)
            {
                m_logger.ErrorExtractingArchive(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target, e.Message);
                return(false);
            }

            switch (downloadData.Settings.ArchiveType)
            {
            case DownloadArchiveType.Zip:
                try
                {
                    new FastZip().ExtractZip(archive, target, null);
                }
                catch (ZipException e)
                {
                    m_logger.ErrorExtractingArchive(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target, e.Message);
                    return(false);
                }

                break;

            case DownloadArchiveType.Gzip:
                try
                {
                    var targetFile = Path.Combine(
                        target,
                        downloadData.DownloadedFilePath.GetName(m_context.PathTable).RemoveExtension(m_context.StringTable)
                        .ToString(m_context.StringTable));

                    using (var reader = m_context.FileSystem.OpenText(downloadData.DownloadedFilePath))
                        using (var gzipStream = new GZipInputStream(reader.BaseStream))
                            using (var output = FileUtilities.CreateFileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.Read))
                            {
                                byte[] buffer = new byte[4096];
                                StreamUtils.Copy(gzipStream, output, buffer);
                            }
                }
                catch (GZipException e)
                {
                    m_logger.ErrorExtractingArchive(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target, e.Message);
                    return(false);
                }

                break;

            case DownloadArchiveType.Tar:
                try
                {
                    using (var reader = m_context.FileSystem.OpenText(downloadData.DownloadedFilePath))
                        using (var tar = TarArchive.CreateInputTarArchive(reader.BaseStream))
                        {
                            tar.ExtractContents(target);
                        }
                }
                catch (TarException e)
                {
                    m_logger.ErrorExtractingArchive(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target, e.Message);
                    return(false);
                }

                break;

            case DownloadArchiveType.Tgz:
                try
                {
                    using (var reader = m_context.FileSystem.OpenText(downloadData.DownloadedFilePath))
                        using (var gzipStream = new GZipInputStream(reader.BaseStream))
                            using (var tar = TarArchive.CreateInputTarArchive(gzipStream))
                            {
                                tar.ExtractContents(target);
                            }
                }
                catch (GZipException e)
                {
                    m_logger.ErrorExtractingArchive(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target, e.Message);
                    return(false);
                }
                catch (TarException e)
                {
                    m_logger.ErrorExtractingArchive(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target, e.Message);
                    return(false);
                }

                break;

            default:
                throw Contract.AssertFailure("Unexpected archive type");
            }

            try
            {
                if (!FileUtilities.DirectoryExistsNoFollow(target))
                {
                    m_logger.ErrorNothingExtracted(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target);
                    return(false);
                }
            }
            catch (BuildXLException e)
            {
                m_logger.ErrorExtractingArchive(m_context.LoggingContext, downloadData.Settings.ModuleName, archive, target, e.Message);
                return(false);
            }

            return(true);
        }
示例#20
0
        private async Task <Possible <IReadOnlyList <ContentHash> > > TryGetBuildManifestHashFromLocalFileAsync(string fullFilePath, ContentHash hash, IList <HashType> requestedTypes, int retryAttempt = 0)
        {
            Contract.Assert(requestedTypes.Count > 0, "Must request at least one hash type");
            var result = new List <ContentHash>();

            if (retryAttempt >= GetBuildManifestHashFromLocalFileRetryLimit)
            {
                string message = $"GetBuildManifestHashFromLocalFileRetryLimit exceeded at path '{fullFilePath}'";
                Tracing.Logger.Log.ApiServerForwardedIpcServerMessage(m_loggingContext, "BuildManifest", message);
                return(new Failure <string>(message));
            }

            if (retryAttempt > 0)
            {
                await Task.Delay(TimeSpan.FromMilliseconds(Math.Pow(2, retryAttempt) * GetBuildManifestHashFromLocalFileRetryMultiplierMs));
            }

            if (!File.Exists(fullFilePath))
            {
                Tracing.Logger.Log.ApiServerForwardedIpcServerMessage(m_loggingContext, "BuildManifest", $"Local file not found at path '{fullFilePath}' while computing BuildManifest Hash. Trying other methods to obtain hash.");
                return(new Failure <string>($"File doesn't exist: '{fullFilePath}'"));
            }

            var           hashers          = new HashingStream[requestedTypes.Count - 1];
            HashingStream validationStream = null;

            try
            {
                using var fs = FileUtilities.CreateFileStream(fullFilePath, FileMode.Open, FileAccess.Read, FileShare.Delete | FileShare.Read, FileOptions.SequentialScan).AssertHasLength();

                // If enabled, create a hashing stream for content validation. Using HashType.Unknown uses the default hashtype
                validationStream = m_verifyFileContentOnBuildManifestHashComputation ? ContentHashingUtilities.GetContentHasher(HashType.Unknown).CreateReadHashingStream(fs) : null;

                // Create a series of nested ReadHashingStream so we compute all the hashes in parallel
                StreamWithLength outerStream = validationStream?.AssertHasLength() ?? fs;
                for (var i = 0; i < hashers.Length; i++)
                {
                    // Hashers has size (requestedTypes.Count - 1)
                    // requestedTypes[0] will be used to hash+consume the resulting outerStream (see below)
                    var hashType = requestedTypes[i + 1];
                    hashers[i]  = ContentHashingUtilities.GetContentHasher(hashType).CreateReadHashingStream(outerStream);
                    outerStream = hashers[i].AssertHasLength();
                }

                // Hashing the outermost stream will cause all the nested hashers to also do their processing
                var firstManifestHash = await ContentHashingUtilities.HashContentStreamAsync(outerStream, requestedTypes[0]);

                result.Add(firstManifestHash);

                for (int i = 0; i < hashers.Length; i++)
                {
                    result.Add(hashers[i].GetContentHash());
                }

                if (m_verifyFileContentOnBuildManifestHashComputation)
                {
                    var actualHash = validationStream.GetContentHash();
                    if (hash != actualHash)
                    {
                        return(new Failure <string>($"Unexpected file content during build manifest hash computation. Path: '{fullFilePath}', expected hash '{hash}', actual hash '{actualHash}'."));
                    }
                }
            }
            catch (Exception ex) when(ex is BuildXLException || ex is IOException)
            {
                Tracing.Logger.Log.ApiServerForwardedIpcServerMessage(m_loggingContext, "BuildManifest",
                                                                      $"Local file found at path '{fullFilePath}' but threw exception while computing BuildManifest Hash. Retry attempt {retryAttempt} out of {GetBuildManifestHashFromLocalFileRetryLimit}. Exception: {ex}");
                return(await TryGetBuildManifestHashFromLocalFileAsync(fullFilePath, hash, requestedTypes, retryAttempt + 1));
            }
            finally
            {
                validationStream?.Dispose();
                for (var i = 0; i < hashers.Length; i++)
                {
                    hashers[i]?.Dispose();
                }
            }

            return(result);
        }
示例#21
0
        private async Task <SerializationResult> SerializeToFileInternalAsync(GraphCacheFile fileType, Action <BuildXLWriter> serializer, string overrideName)
        {
            // Unblock the caller
            await Task.Yield();

            FileUtilities.CreateDirectory(m_engineCacheLocation);

            string fileName = overrideName ?? GetFileName(fileType);
            string path     = Path.Combine(m_engineCacheLocation, fileName);
            SerializationResult serializationResult = new SerializationResult()
            {
                Success  = false,
                FileType = fileType,
                FullPath = path,
            };

            var fileEnvelope = GetFileEnvelope(fileType);

            Contract.Assume(m_correlationId is FileEnvelopeId, "EngineSerializer must be initialized with a valid correlation id");
            var correlationId = (FileEnvelopeId)m_correlationId;

            try
            {
                // We must delete the existing file in case it was hardlinked from the cache. Opening a filestream
                // that truncates the existing file will fail if it is a hardlink.
                FileUtilities.DeleteFile(path, tempDirectoryCleaner: m_tempDirectoryCleaner);
                using (
                    FileStream fileStream = FileUtilities.CreateFileStream(
                        path,
                        FileMode.Create,
                        FileAccess.Write,
                        FileShare.Delete,
                        // Do not write the file with SequentialScan since it will be reread in the subsequent build
                        FileOptions.None))
                {
                    Stopwatch sw = Stopwatch.StartNew();

                    fileEnvelope.WriteHeader(fileStream, correlationId);

                    // Write whether the file is compressed or not.
                    fileStream.WriteByte(m_useCompression ? (byte)1 : (byte)0);

                    long uncompressedLength = 0;

                    if (m_useCompression)
                    {
                        using (var writer = new BuildXLWriter(m_debug, new TrackedStream(new BufferedStream(new DeflateStream(fileStream, CompressionLevel.Fastest, leaveOpen: true), bufferSize: 64 << 10)), false, false))
                        {
                            // TODO: We can improve performance significantly by parallelizing the compression.
                            // There's no setting to do that, but given you have the entire file content upfront in a memory stream,
                            // it shouldn't be particularly complicated to split the memory stream into reasonably sized chunks (say 100MB)
                            // and compress each of them into separate MemoryStream backed DeflateStreams in separate threads.
                            // Then just write those out to a file. Of course you'll need to write out the position of those streams
                            // into the header when you write out the actual file.
                            serializer(writer);
                            uncompressedLength = writer.BaseStream.Length;
                        }
                    }
                    else
                    {
                        using (var writer = new BuildXLWriter(m_debug, fileStream, leaveOpen: true, logStats: false))
                        {
                            serializer(writer);
                            uncompressedLength = writer.BaseStream.Length;
                        }
                    }

                    Interlocked.Add(ref m_bytesSavedDueToCompression, uncompressedLength - fileStream.Length);

                    fileEnvelope.FixUpHeader(fileStream, correlationId);

                    Tracing.Logger.Log.SerializedFile(LoggingContext, fileName, sw.ElapsedMilliseconds);
                    serializationResult.Success = true;
                    Interlocked.Add(ref m_bytesSerialized, fileStream.Position);
                }
            }
            catch (BuildXLException ex)
            {
                Tracing.Logger.Log.FailedToSerializePipGraph(LoggingContext, ex.LogEventMessage);
            }
            catch (IOException ex)
            {
                Tracing.Logger.Log.FailedToSerializePipGraph(LoggingContext, ex.Message);
            }

            return(serializationResult);
        }
示例#22
0
        private bool TryExtractToDisk(ExtractorArgs arguments)
        {
            var archive = arguments.PathToFileToExtract;
            var target  = arguments.ExtractDirectory;

            try
            {
                FileUtilities.DeleteDirectoryContents(target, false);
                FileUtilities.CreateDirectory(target);
            }
            catch (BuildXLException e)
            {
                ErrorExtractingArchive(archive, target, e.Message);
                return(false);
            }

            switch (arguments.ArchiveType)
            {
            case DownloadArchiveType.Zip:
                try
                {
                    new FastZip().ExtractZip(archive, target, null);
                }
                catch (ZipException e)
                {
                    ErrorExtractingArchive(archive, target, e.Message);
                    return(false);
                }

                break;

            case DownloadArchiveType.Gzip:
                try
                {
                    var targetFile = Path.Combine(target, Path.GetFileNameWithoutExtension(arguments.PathToFileToExtract));

                    using (var reader = new StreamReader(arguments.PathToFileToExtract))
                        using (var gzipStream = new GZipInputStream(reader.BaseStream))
                            using (var output = FileUtilities.CreateFileStream(targetFile, FileMode.Create, FileAccess.Write, FileShare.Read))
                            {
                                byte[] buffer = new byte[4096];
                                StreamUtils.Copy(gzipStream, output, buffer);
                            }
                }
                catch (GZipException e)
                {
                    ErrorExtractingArchive(archive, target, e.Message);
                    return(false);
                }

                break;

            case DownloadArchiveType.Tar:
                try
                {
                    using (var reader = new StreamReader(arguments.PathToFileToExtract))
                        using (var tar = TarArchive.CreateInputTarArchive(reader.BaseStream, nameEncoding: null))
                        {
                            tar.ExtractContents(target);
                        }
                }
                catch (TarException e)
                {
                    ErrorExtractingArchive(archive, target, e.Message);
                    return(false);
                }

                break;

            case DownloadArchiveType.Tgz:
                try
                {
                    using (var reader = new StreamReader(arguments.PathToFileToExtract))
                        using (var gzipStream = new GZipInputStream(reader.BaseStream))
                            using (var tar = TarArchive.CreateInputTarArchive(gzipStream, nameEncoding: null))
                            {
                                tar.ExtractContents(target);
                            }
                }
                catch (GZipException e)
                {
                    ErrorExtractingArchive(archive, target, e.Message);
                    return(false);
                }
                catch (TarException e)
                {
                    ErrorExtractingArchive(archive, target, e.Message);
                    return(false);
                }

                break;

            case DownloadArchiveType.File:
                Console.WriteLine("Specified download archive type is 'File'. Nothing to extract.");
                return(true);

            default:
                throw Contract.AssertFailure($"Unexpected archive type '{arguments.ArchiveType}'");
            }

            try
            {
                if (!FileUtilities.DirectoryExistsNoFollow(target))
                {
                    ErrorNothingExtracted(archive, target);
                    return(false);
                }
            }
            catch (BuildXLException e)
            {
                ErrorExtractingArchive(archive, target, e.Message);
                return(false);
            }

            return(true);
        }