Пример #1
0
        /// <inheritdoc />
        public Task <PlaceFileResult> PlaceFileAsync(Context context, FullPath path, VfsFilePlacementData placementData, CancellationToken token)
        {
            return(WithOperationContext(context, token, async operationContext =>
            {
                var result = await operationContext.PerformOperationAsync(
                    Tracer,
                    async() =>
                {
                    var virtualPath = ToVirtualPath(placementData, path);

                    var node = Tree.AddFileNode(virtualPath, placementData, path.Path);

                    var vfsPath = _configuration.VfsRootPath / virtualPath;

                    // TODO: Faster path for getting size of file. Also would be good to batch somehow.
                    // Maybe have FileContentManager batch pin files
                    var pinResult = await _placer.PinAsync(context, node.Hash, operationContext.Token);
                    if (pinResult.ContentSize > 0)
                    {
                        node.Size = pinResult.ContentSize;
                    }
                    else
                    {
                        return new PlaceFileResult($"Pin file size = {pinResult.ContentSize}");
                    }

                    if (placementData.AccessMode == FileAccessMode.ReadOnly)
                    {
                        // NOTE: This should cause the placeholder to get created under vfs root
                        _fileSystem.DenyFileWrites(vfsPath);
                    }

                    var result = _fileSystem.CreateHardLink(vfsPath, path, replaceExisting: true);
                    if (result != CreateHardLinkResult.Success)
                    {
                        if (result == CreateHardLinkResult.FailedDestinationDirectoryDoesNotExist)
                        {
                            _fileSystem.CreateDirectory(path.Parent);
                            result = _fileSystem.CreateHardLink(vfsPath, path, replaceExisting: true);
                        }

                        if (result != CreateHardLinkResult.Success)
                        {
                            return new PlaceFileResult($"Failed to create hardlink: {result}");
                        }
                    }

                    return new PlaceFileResult(GetPlaceResultCode(placementData.RealizationMode, placementData.AccessMode), fileSize: pinResult.ContentSize /* Unknown */);
                },
                    caller: "PlaceVirtualFile",
                    extraEndMessage: r => $"Hash={placementData.Hash}");

                if (!result.Succeeded)
                {
                    return await _placer.PlaceFileAsync(context, path, placementData, token);
                }

                return result;
            }));
        }
Пример #2
0
        /// <inheritdoc />
        protected override async Task <PlaceFileResult> PlaceFileCoreAsync(OperationContext operationContext, ContentHash contentHash, AbsolutePath path, FileAccessMode accessMode, FileReplacementMode replacementMode, FileRealizationMode realizationMode, UrgencyHint urgencyHint, Counter retryCounter)
        {
            if (replacementMode != FileReplacementMode.ReplaceExisting && _fileSystem.FileExists(path))
            {
                if (replacementMode == FileReplacementMode.SkipIfExists)
                {
                    return(new PlaceFileResult(PlaceFileResult.ResultCode.NotPlacedAlreadyExists));
                }
                else if (replacementMode == FileReplacementMode.FailIfExists)
                {
                    return(new PlaceFileResult(
                               PlaceFileResult.ResultCode.Error,
                               $"File exists at destination {path} with FailIfExists specified"));
                }
            }

            var placementData = new VfsFilePlacementData(contentHash, realizationMode, accessMode);

            var virtualPath = _store.Configuration.UseSymlinks
                ? _contentManager.TryCreateSymlink(operationContext, path, placementData, replace: replacementMode == FileReplacementMode.ReplaceExisting).ThrowIfFailure()
                : _contentManager.ToVirtualPath(path);

            if (virtualPath == null)
            {
                return(await _innerSession.PlaceFileAsync(operationContext, contentHash, path, accessMode, replacementMode, realizationMode, operationContext.Token, urgencyHint));
            }

            _contentManager.Tree.AddFileNode(virtualPath, placementData);
            return(new PlaceFileResult(GetPlaceResultCode(realizationMode, accessMode), fileSize: -1 /* Unknown */));
        }
Пример #3
0
        /// <inheritdoc />
        protected override async Task <PlaceFileResult> PlaceFileCoreAsync(OperationContext operationContext, ContentHash contentHash, AbsolutePath path, FileAccessMode accessMode, FileReplacementMode replacementMode, FileRealizationMode realizationMode, UrgencyHint urgencyHint, Counter retryCounter)
        {
            if (!path.IsVirtual)
            {
                return(await _innerSession.PlaceFileAsync(
                           operationContext,
                           contentHash,
                           path,
                           accessMode,
                           replacementMode,
                           realizationMode,
                           operationContext.Token,
                           urgencyHint));
            }

            if (replacementMode != FileReplacementMode.ReplaceExisting && _fileSystem.FileExists(path))
            {
                if (replacementMode == FileReplacementMode.SkipIfExists)
                {
                    return(new PlaceFileResult(PlaceFileResult.ResultCode.NotPlacedAlreadyExists));
                }
                else if (replacementMode == FileReplacementMode.FailIfExists)
                {
                    return(new PlaceFileResult(
                               PlaceFileResult.ResultCode.Error,
                               $"File exists at destination {path} with FailIfExists specified"));
                }
            }

            var placementData = new VfsFilePlacementData(contentHash, realizationMode, accessMode);

            return(await _contentManager.PlaceFileAsync(operationContext, path, placementData, operationContext.Token));
        }
Пример #4
0
        /// <inheritdoc />
        public Task <PlaceFileResult> PlaceFileAsync(Context context, FullPath path, VfsFilePlacementData placementData, CancellationToken token)
        {
            return(WithOperationContext(context, token, async operationContext =>
            {
                var virtualPath = _configuration.UseSymlinks
                    ? TryCreateSymlink(operationContext, path, placementData, replaceExisting: true).ThrowIfFailure()
                    : ToVirtualPath(path);

                if (virtualPath == null)
                {
                    return await _placer.PlaceFileAsync(context, path, placementData, token);
                }

                Tree.AddFileNode(virtualPath, placementData, path.Path);
                return new PlaceFileResult(GetPlaceResultCode(placementData.RealizationMode, placementData.AccessMode), fileSize: -1 /* Unknown */);
            }));
        }
Пример #5
0
        /// <summary>
        /// Converts the full path to a VFS root relative path
        /// </summary>
        internal VirtualPath ToVirtualPath(VfsFilePlacementData data, FullPath path)
        {
            // Use the same index (0) for ReadOnly/Hardlink files
            var shouldHardlink = FileSystemContentStoreInternal.ShouldAttemptHardLink(path, data.AccessMode, data.RealizationMode);

            // All hardlinks of a hash share the same file under the vfs root so just
            // use index 0 to represent that file. Otherwise, create a unique index so
            // that copies get unique files
            var index = shouldHardlink
                ? 0
                : Interlocked.Increment(ref _nextVfsCasTargetFileUniqueId);

            VirtualPath casRelativePath = VfsUtilities.CreateCasRelativePath(data, index);

            var virtualPath = _configuration.VfsCasRelativeRoot / casRelativePath;

            return(virtualPath.Path);
        }
Пример #6
0
        /// <summary>
        /// Adds a file node (and any needed parent directory nodes) at the VFS root relative path
        /// </summary>
        public VfsFileNode AddFileNode(string relativePath, VfsFilePlacementData data, string realPath)
        {
            var timestamp = DateTime.UtcNow;

            if (_nodeMap.TryGetValue(relativePath, out var node))
            {
                return((VfsFileNode)node);
            }
            else
            {
                var parent = GetOrAddDirectoryNode(Path.GetDirectoryName(relativePath), allowAdd: true);
                var result = _nodeMap.GetOrAdd(relativePath, (parent, timestamp, data), (l_relativePath, l_data) =>
                {
                    return(new VfsFileNode(Path.GetFileName(l_relativePath), l_data.timestamp, l_data.parent, l_data.data, RealPath.Create(PathTable, realPath)));
                });

                node = result.Item.Value;

                return((VfsFileNode)node);
            }
        }
Пример #7
0
        /// <summary>
        /// Places a hydrated file at the given VFS root relative path
        /// </summary>
        /// <param name="relativePath">the vfs root relative path</param>
        /// <param name="data">the content and placement data for the file</param>
        /// <param name="token">the cancellation token</param>
        /// <returns>a task which completes when the operation is complete or throws an exception if error is encountered during operation</returns>
        public Task PlaceHydratedFileAsync(VirtualPath relativePath, VfsFilePlacementData data, CancellationToken token)
        {
            var context = new OperationContext(new Context(_logger), token);

            return(context.PerformOperationAsync(
                       _tracer,
                       async() =>
            {
                var tempFilePath = _tempDirectory.CreateRandomFileName();
                var result = await _contentSession.PlaceFileAsync(
                    context,
                    data.Hash,
                    tempFilePath,
                    data.AccessMode,
                    FileReplacementMode.ReplaceExisting,
                    data.RealizationMode,
                    token).ThrowIfFailure();

                var fullPath = ToFullPath(relativePath);

                _fileSystem.MoveFile(tempFilePath, fullPath, true);

                if (result.FileSize >= 0)
                {
                    Counters[VfsCounters.PlaceHydratedFileBytes].Add(result.FileSize);
                }
                else
                {
                    Counters[VfsCounters.PlaceHydratedFileUnknownSizeCount].Increment();
                }

                return BoolResult.Success;
            },
                       extraStartMessage: $"RelativePath={relativePath}, Hash={data.Hash}",
                       counter: Counters[VfsCounters.PlaceHydratedFile]));
        }
Пример #8
0
 public VfsFileNode(string name, DateTime timestamp, VfsDirectoryNode parent, VfsFilePlacementData data, RealPath realPath)
     : base(name, timestamp, parent)
 {
     Data     = data;
     RealPath = realPath;
 }
 /// <inheritdoc />
 public static Task <PlaceFileResult> PlaceFileAsync(this IReadOnlyContentSession session, Context context, AbsolutePath path, VfsFilePlacementData placementData, CancellationToken token)
 {
     return(session.PlaceFileAsync(
                context,
                placementData.Hash,
                path,
                placementData.AccessMode,
                FileReplacementMode.ReplaceExisting,
                placementData.RealizationMode,
                token));
 }
Пример #10
0
        internal Result <VirtualPath> TryCreateSymlink(OperationContext context, AbsolutePath sourcePath, VfsFilePlacementData data, bool replace)
        {
            return(context.PerformOperation(
                       _tracer,
                       () =>
            {
                _fileSystem.CreateDirectory(sourcePath.Parent);

                if (replace)
                {
                    FileUtilities.DeleteFile(sourcePath.Path);
                }

                var index = Interlocked.Increment(ref _nextVfsCasTargetFileUniqueId);
                VirtualPath casRelativePath = VfsUtilities.CreateCasRelativePath(data, index);

                var virtualPath = _configuration.VfsCasRelativeRoot / casRelativePath;

                Tree.AddFileNode(virtualPath.Path, data);
                // Ensure existence of the virtual directory in the VFS CAS root
                //Tree.GetOrAddDirectoryNode((_configuration.VfsCasRelativeRoot / casRelativePath).Parent.Path);

                var fullTargetPath = _configuration.VfsCasRootPath / casRelativePath;
                var result = FileUtilities.TryCreateSymbolicLink(symLinkFileName: sourcePath.Path, targetFileName: fullTargetPath.Path, isTargetFile: true);
                if (result.Succeeded)
                {
                    return Result.Success(virtualPath.Path);
                }
                else
                {
                    return Result.FromErrorMessage <VirtualPath>(result.Failure.DescribeIncludingInnerFailures());
                }
            },
                       extraStartMessage: $"SourcePath={sourcePath}, Hash={data.Hash}",
                       messageFactory: r => $"SourcePath={sourcePath}, Hash={data.Hash}, TargetPath={r.GetValueOrDefault()}",
                       counter: Counters[VfsCounters.TryCreateSymlink]));
        }
Пример #11
0
        /// <summary>
        /// Attempts to create a symlink which points to a virtualized file materialized with the given data
        /// </summary>
        public Result <VirtualPath> TryCreateSymlink(OperationContext context, AbsolutePath sourcePath, VfsFilePlacementData data, bool replaceExisting)
        {
            return(context.PerformOperation(
                       Tracer,
                       () =>
            {
                _fileSystem.CreateDirectory(sourcePath.Parent);

                if (replaceExisting)
                {
                    FileUtilities.DeleteFile(sourcePath.Path);
                }

                var index = Interlocked.Increment(ref _nextVfsCasTargetFileUniqueId);
                VirtualPath casRelativePath = VfsUtilities.CreateCasRelativePath(data, index);

                var virtualPath = _configuration.VfsCasRelativeRoot / casRelativePath;

                var fullTargetPath = _configuration.VfsCasRootPath / casRelativePath;

                var now = DateTime.UtcNow;

                var tempFilePath = _tempDirectory.CreateRandomFileName();

                var result = FileUtilities.TryCreateSymbolicLink(symLinkFileName: tempFilePath.Path, targetFileName: fullTargetPath.Path, isTargetFile: true);
                if (result.Succeeded)
                {
                    var attributes = FileUtilities.GetFileAttributes(tempFilePath.Path);
                    attributes |= FileAttributes.Offline;
                    FileUtilities.SetFileAttributes(tempFilePath.Path, attributes);

                    _fileSystem.MoveFile(tempFilePath, sourcePath, replaceExisting: replaceExisting);
                    return Result.Success(virtualPath.Path);
                }
                else
                {
                    return Result.FromErrorMessage <VirtualPath>(result.Failure.DescribeIncludingInnerFailures());
                }
            },
                       extraStartMessage: $"SourcePath={sourcePath}, Hash={data.Hash}",
                       messageFactory: r => $"SourcePath={sourcePath}, Hash={data.Hash}, TargetPath={r.GetValueOrDefault()}",
                       counter: Counters[VfsCounters.TryCreateSymlink]));
        }