-
Notifications
You must be signed in to change notification settings - Fork 292
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Install files in parallel #1256
Open
Thomas1664
wants to merge
40
commits into
microsoft:main
Choose a base branch
from
Thomas1664:parallel-file-install
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
6cd56a7
Install files in parallel
Thomas1664 7dad374
optimize + fixes
Thomas1664 05bc1f0
async create listfile dir
Thomas1664 ba36960
format
Thomas1664 4dab20c
Remove unneeded optional
Thomas1664 dc14e81
fix format of error message
Thomas1664 c8cd17b
noexcept + constexpr for fs one-liners
Thomas1664 80af37d
inline + noexcept for one-liners in InstallDir
Thomas1664 0e09c92
decouple installation from list file creation
Thomas1664 4fe1e0f
fixes
Thomas1664 188d451
initialize member
Thomas1664 65b8c3e
format
Thomas1664 f7bd6d5
investigate unit test failure
Thomas1664 23aae9b
Merge branch 'parallel-file-install' of https://github.com/Thomas1664…
Thomas1664 2cd0e1b
revert
Thomas1664 0b44c21
format
Thomas1664 284ac35
format
Thomas1664 4e787dd
revert
Thomas1664 c0cba4b
Merge branch 'microsoft:main' into parallel-file-install
Thomas1664 69fbb7d
invert if
Thomas1664 e6c094a
unify duplicated if
Thomas1664 4684372
Merge branch 'microsoft:main' into parallel-file-install
Thomas1664 99106d3
Fix merge
Thomas1664 85a9ae9
Merge branch 'microsoft:main' into parallel-file-install
Thomas1664 d0c1c3a
Merge branch 'microsoft:main' into parallel-file-install
Thomas1664 599ecf4
Fix comments
Thomas1664 d04f108
Merge branch 'parallel-file-install' of https://github.com/Thomas1664…
Thomas1664 376829c
Fix most CR comments
Thomas1664 68ba04e
format
Thomas1664 4179d0e
Merge branch 'microsoft:main' into parallel-file-install
Thomas1664 b211761
Merge branch 'microsoft:main' into parallel-file-install
Thomas1664 9b676c4
include future
Thomas1664 670d164
use partition instead of custom sort
Thomas1664 cac8672
remove compairson operator
Thomas1664 f109858
format
Thomas1664 f0048c6
Merge remote-tracking branch 'origin/main' into parallel-file-install
Thomas1664 247c957
Merge branch 'microsoft:main' into parallel-file-install
Thomas1664 0927c90
Merge remote-tracking branch 'upstream/main' into parallel-file-install
Thomas1664 8a44030
Merge branch 'microsoft:main' into parallel-file-install
Thomas1664 42c406e
Only parallelize symlink_status
Thomas1664 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
#include <vcpkg/base/files.h> | ||
#include <vcpkg/base/hash.h> | ||
#include <vcpkg/base/messages.h> | ||
#include <vcpkg/base/parallel-algorithms.h> | ||
#include <vcpkg/base/system.debug.h> | ||
#include <vcpkg/base/system.h> | ||
#include <vcpkg/base/util.h> | ||
|
@@ -29,6 +30,9 @@ | |
#include <vcpkg/xunitwriter.h> | ||
|
||
#include <iterator> | ||
#ifdef _WIN32 | ||
#include <execution> | ||
#endif | ||
|
||
namespace vcpkg | ||
{ | ||
|
@@ -55,15 +59,13 @@ namespace vcpkg | |
Strings::concat("Source directory ", source_dir, "does not exist")); | ||
auto files = fs.get_files_recursive(source_dir, VCPKG_LINE_INFO); | ||
Util::erase_remove_if(files, [](Path& path) { return path.filename() == ".DS_Store"; }); | ||
install_files_and_write_listfile(fs, source_dir, files, destination_dir); | ||
install_files_and_write_listfile(fs, source_dir, std::move(files), destination_dir); | ||
} | ||
void install_files_and_write_listfile(const Filesystem& fs, | ||
const Path& source_dir, | ||
const std::vector<Path>& files, | ||
std::vector<Path>&& files, | ||
const InstallDir& destination_dir) | ||
{ | ||
std::vector<std::string> output; | ||
|
||
const size_t prefix_length = source_dir.native().size(); | ||
const Path& destination = destination_dir.destination(); | ||
std::string destination_subdirectory = destination.filename().to_string(); | ||
|
@@ -73,60 +75,99 @@ namespace vcpkg | |
const auto listfile_parent = listfile.parent_path(); | ||
fs.create_directories(listfile_parent, VCPKG_LINE_INFO); | ||
|
||
output.push_back(destination_subdirectory + "/"); | ||
for (auto&& file : files) | ||
std::vector<Optional<FileType>> symlink_statuses(files.size()); | ||
|
||
parallel_transform( | ||
files.begin(), files.size(), symlink_statuses.begin(), [&fs](auto&& file) -> Optional<FileType> { | ||
std::error_code ec; | ||
auto status = fs.symlink_status(file, ec); | ||
if (ec) | ||
{ | ||
msg::println_warning(format_filesystem_call_error(ec, "symlink_status", {file})); | ||
return nullopt; | ||
} | ||
return status; | ||
}); | ||
|
||
std::vector<std::string> dir_output; | ||
dir_output.push_back(destination_subdirectory + "/"); | ||
|
||
std::vector<std::pair<Path, Optional<FileType>>> files_and_status; | ||
files_and_status.reserve(files.size()); | ||
|
||
for (size_t i = 0; i < files.size(); ++i) | ||
{ | ||
std::error_code ec; | ||
const auto status = fs.symlink_status(file, ec); | ||
if (ec) | ||
if (!symlink_statuses[i].has_value()) | ||
{ | ||
continue; | ||
} | ||
auto status = *symlink_statuses[i].get(); | ||
|
||
if (is_directory(status)) | ||
{ | ||
msg::println_warning(format_filesystem_call_error(ec, "symlink_status", {file})); | ||
const auto suffix = files[i].generic_u8string().substr(prefix_length + 1); | ||
const auto target = destination / suffix; | ||
auto this_output = Strings::concat(destination_subdirectory, "/", suffix); | ||
|
||
std::error_code ec; | ||
fs.create_directory(target, ec); | ||
if (ec) | ||
{ | ||
msg::println_error(msgInstallFailed, msg::path = target, msg::error_msg = ec.message()); | ||
} | ||
|
||
// Trailing backslash for directories | ||
this_output.push_back('/'); | ||
dir_output.push_back(std::move(this_output)); | ||
continue; | ||
} | ||
|
||
const auto filename = file.filename(); | ||
if (vcpkg::is_regular_file(status) && | ||
const auto filename = files[i].filename(); | ||
|
||
if (is_regular_file(status) && | ||
(filename == "CONTROL" || filename == "vcpkg.json" || filename == "BUILD_INFO")) | ||
{ | ||
// Do not copy the control file or manifest file | ||
continue; | ||
} | ||
|
||
const auto suffix = file.generic_u8string().substr(prefix_length + 1); | ||
const auto target = destination / suffix; | ||
|
||
bool use_hard_link = true; | ||
auto this_output = Strings::concat(destination_subdirectory, "/", suffix); | ||
switch (status) | ||
if (!is_regular_file(status) && !is_symlink(status)) | ||
{ | ||
case FileType::directory: | ||
{ | ||
fs.create_directory(target, ec); | ||
if (ec) | ||
{ | ||
msg::println_error(msgInstallFailed, msg::path = target, msg::error_msg = ec.message()); | ||
} | ||
msg::println_error(msgInvalidFileType, msg::path = files[i]); | ||
continue; | ||
} | ||
files_and_status.emplace_back(std::move(files[i]), std::move(symlink_statuses[i])); | ||
} | ||
|
||
// Trailing backslash for directories | ||
this_output.push_back('/'); | ||
output.push_back(std::move(this_output)); | ||
break; | ||
} | ||
case FileType::regular: | ||
std::vector<std::string> output(files_and_status.size()); | ||
|
||
parallel_transform( | ||
files_and_status.begin(), files_and_status.size(), output.begin(), [&](auto&& file_and_status) { | ||
auto&& [file, maybe_status] = file_and_status; | ||
|
||
const auto status = *maybe_status.get(); | ||
std::error_code ec; | ||
|
||
const auto suffix = file.generic_u8string().substr(prefix_length + 1); | ||
const auto target = destination / suffix; | ||
|
||
bool use_hard_link = true; | ||
auto this_output = Strings::concat(destination_subdirectory, "/", suffix); | ||
if (is_regular_file(status)) | ||
{ | ||
if (fs.exists(target, IgnoreErrors{})) | ||
{ | ||
msg::println_warning(msgOverwritingFile, msg::path = target); | ||
fs.remove_all(target, IgnoreErrors{}); | ||
fs.remove(target, IgnoreErrors{}); | ||
} | ||
if (use_hard_link) | ||
{ | ||
fs.create_hard_link(file, target, ec); | ||
if (ec) | ||
{ | ||
Debug::println("Install from packages to installed: Fallback to copy " | ||
"instead creating hard links because of: ", | ||
ec.message()); | ||
"instead creating hard links because of: ", | ||
ec.message()); | ||
use_hard_link = false; | ||
} | ||
} | ||
|
@@ -139,12 +180,8 @@ namespace vcpkg | |
{ | ||
msg::println_error(msgInstallFailed, msg::path = target, msg::error_msg = ec.message()); | ||
} | ||
|
||
output.push_back(std::move(this_output)); | ||
break; | ||
} | ||
case FileType::symlink: | ||
case FileType::junction: | ||
else if (is_symlink(status)) | ||
{ | ||
if (fs.exists(target, IgnoreErrors{})) | ||
{ | ||
|
@@ -156,15 +193,20 @@ namespace vcpkg | |
{ | ||
msg::println_error(msgInstallFailed, msg::path = target, msg::error_msg = ec.message()); | ||
} | ||
|
||
output.push_back(std::move(this_output)); | ||
break; | ||
} | ||
default: msg::println_error(msgInvalidFileType, msg::path = file); break; | ||
} | ||
} | ||
else | ||
{ | ||
Checks::unreachable(VCPKG_LINE_INFO); | ||
} | ||
return this_output; | ||
}); | ||
|
||
std::move(dir_output.begin(), dir_output.end(), std::back_inserter(output)); | ||
#ifdef _WIN32 | ||
std::sort(std::execution::par_unseq, output.begin(), output.end()); | ||
#else | ||
std::sort(output.begin(), output.end()); | ||
#endif | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm open for suggestions on how to implement parallel sorting for all platforms |
||
fs.write_lines(listfile, output, VCPKG_LINE_INFO); | ||
} | ||
|
||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no difference for regular files between
remove_all
andremove
(provided that vcpkg's implementation is identical to the STL): https://en.cppreference.com/w/cpp/filesystem/remove