Skip to content
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

Binary cache: async push_success #908

Draft
wants to merge 55 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
95f0438
Binary cache: async push_success
autoantwort Feb 15, 2023
9d999d8
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Feb 28, 2023
163d9cd
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Mar 2, 2023
2a54205
Apply suggestions from code review
autoantwort Mar 2, 2023
0912655
Adapt code review
autoantwort Mar 2, 2023
5d7288c
Update src/vcpkg/binarycaching.cpp
autoantwort Mar 2, 2023
10189ac
Adapt code review
autoantwort Mar 2, 2023
2567607
Remove unnecessary actions_to_push_notifier.notify_all()
autoantwort Mar 2, 2023
ecdd000
Prevent deadlock and don't be on the crtl+c path
autoantwort Mar 2, 2023
8e7ae61
Add and use BGMessageSink to print IBinaryProvider::push_success mess…
autoantwort Mar 3, 2023
850d7c9
Restore old upload message
autoantwort Mar 3, 2023
548be38
Don't join yourself
autoantwort Mar 4, 2023
6dbbf06
Print messages about remaining packages to upload
autoantwort Mar 4, 2023
74b86fd
Localization
autoantwort Mar 5, 2023
5171d3e
Improve messages
autoantwort Mar 5, 2023
d69ed8f
No singleton and explicit calls to wait_for_async_complete()
autoantwort Mar 5, 2023
2df42d5
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Mar 8, 2023
5f1786e
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Mar 10, 2023
93303c3
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Mar 16, 2023
8a26c8b
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Mar 19, 2023
aa7e52f
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Mar 22, 2023
d46a4d6
Apply code review
autoantwort Mar 22, 2023
5e51718
Trigger Build
autoantwort Mar 22, 2023
a9ac558
No rename dance
autoantwort Mar 22, 2023
4faf674
Print upload to provider only once and not once per provider
autoantwort Mar 22, 2023
b9be8c6
Fix tests
autoantwort Mar 22, 2023
78ca081
Don't create unnecessary strings
autoantwort Mar 31, 2023
579bfa9
Rename to m_published_lock
autoantwort Mar 31, 2023
103968e
BinaryPackageInformation use Optional and make BinaryProviderPushRequ…
autoantwort Mar 31, 2023
dd32416
Merge branch 'main' into feature/async-binary-cache-push-success and …
autoantwort May 31, 2023
b666f94
Add missing files
autoantwort May 31, 2023
15bb503
Add missing includes
autoantwort May 31, 2023
d995bfd
Make BianryCache a unique_ptr
autoantwort May 31, 2023
24cd026
Reduce changes
autoantwort May 31, 2023
92fc76b
Fix output
autoantwort May 31, 2023
3527227
Fix bug
autoantwort May 31, 2023
48305b3
Format
autoantwort May 31, 2023
27fa076
Use lock_guard
autoantwort May 31, 2023
bcd459a
Revert "Use lock_guard"
autoantwort May 31, 2023
f958d36
Use enum
autoantwort May 31, 2023
7a24007
BGMessageSink::print_published apply code review
autoantwort May 31, 2023
50114f9
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Jun 14, 2023
ca5f2b1
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Aug 19, 2023
eccd9ee
Fix typo
autoantwort Aug 24, 2023
e7837e0
Fix typo in file name
autoantwort Aug 24, 2023
969e7fc
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Aug 24, 2023
2d5586f
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Oct 11, 2023
809d0b6
Renamings
autoantwort Oct 11, 2023
455e29b
format
autoantwort Oct 12, 2023
03fdfea
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Nov 4, 2023
f4bad8c
BinaryCache and std::unique_ptr
autoantwort Nov 4, 2023
26bbbd5
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Nov 12, 2023
814e434
BinaryCache: save data in std::unique_ptr so that the object can be m…
autoantwort Nov 14, 2023
290e586
fix
autoantwort Nov 14, 2023
3cc3378
Merge branch 'main' into feature/async-binary-cache-push-success
autoantwort Dec 13, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions include/vcpkg/base/batch-queue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#pragma once

#include <condition_variable>
#include <mutex>
#include <vector>

template<class T>
class BatchQueue
{
public:
template<class... Args>
void push(Args&&... args)
{
forward.emplace_back(std::forward<Args>(args)...);
}

bool empty() const { return forward.empty(); }

void pop(std::vector<T>& out)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this thing being called queue given that this is how it works. Given that we expect this to be a multi producer single consumer queue, can we instead put the vector inside and note that only one thread may call pop but any number of threads may call push? That would also resolve the criticism over separate tracking atomics below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BatchQueue alone is not thread safe.

Given that we expect this to be a multi producer single consumer queue, can we instead put the vector inside and note that only one thread may call pop but any number of threads may call push?

I don't get what you have in mind here 😅

I don't like this thing being called queue given that this is how it works.

Do you have an idea for a better name? :)

{
out.clear();
swap(out, forward);
}

private:
std::vector<T> forward;
};

template<class WorkItem>
struct BGThreadBatchQueue
{
template<class... Args>
void push(Args&&... args)
{
std::lock_guard<std::mutex> lock(m_mtx);
m_tasks.push(std::forward<Args>(args)...);
m_cv.notify_all();
}

void wait_for_items(std::vector<WorkItem>& out)
{
std::unique_lock<std::mutex> lock(m_mtx);
m_cv.wait(lock, [this]() { return !m_tasks.empty() || !m_running; });
m_tasks.pop(out);
}

void stop()
{
std::lock_guard<std::mutex> lock(m_mtx);
m_running = false;
m_cv.notify_all();
}

bool stopped() const { return !m_running; }

private:
std::mutex m_mtx;
std::condition_variable m_cv;
BatchQueue<WorkItem> m_tasks;
bool m_running = true;
};
1 change: 1 addition & 0 deletions include/vcpkg/base/fwd/message_sinks.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ namespace vcpkg

struct FileSink;
struct CombiningSink;
struct BGMessageSink;
}
6 changes: 1 addition & 5 deletions include/vcpkg/base/message-data.inc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2640,11 +2640,6 @@ DECLARE_MESSAGE(
(),
"",
"If you are sure you want to rebuild the above packages, run this command with the --no-dry-run option.")
DECLARE_MESSAGE(UploadedBinaries, (msg::count, msg::vendor), "", "Uploaded binaries to {count} {vendor}.")
DECLARE_MESSAGE(UploadedPackagesToVendor,
(msg::count, msg::elapsed, msg::vendor),
"",
"Uploaded {count} package(s) to {vendor} in {elapsed}")
DECLARE_MESSAGE(UploadingBinariesToVendor,
(msg::spec, msg::vendor, msg::path),
"",
Expand Down Expand Up @@ -2874,6 +2869,7 @@ DECLARE_MESSAGE(VSExaminedPaths, (), "", "The following paths were examined for
DECLARE_MESSAGE(VSNoInstances, (), "", "Could not locate a complete Visual Studio instance")
DECLARE_MESSAGE(WaitingForChildrenToExit, (), "", "Waiting for child processes to exit...")
DECLARE_MESSAGE(WaitingToTakeFilesystemLock, (msg::path), "", "waiting to take filesystem lock on {path}...")
DECLARE_MESSAGE(WaitUntilPackagesUploaded, (msg::count), "", "Wait until the remaining packages ({count}) are uploaded")
DECLARE_MESSAGE(WarningMessage, (), "", "warning: ")
DECLARE_MESSAGE(WarningMessageMustUsePrintWarning,
(msg::value),
Expand Down
28 changes: 28 additions & 0 deletions include/vcpkg/base/message_sinks.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include <vcpkg/base/messages.h>

#include <mutex>

namespace vcpkg
{

Expand Down Expand Up @@ -75,4 +77,30 @@ namespace vcpkg
CombiningSink(MessageSink& first, MessageSink& second) : m_first(first), m_second(second) { }
void print(Color c, StringView sv) override;
};

struct BGMessageSink final : MessageSink
{
BGMessageSink(MessageSink& out_sink) : out_sink(out_sink) { }
~BGMessageSink() { publish_directly_to_out_sink(); }
// must be called from producer
void print(Color c, StringView sv) override;
using MessageSink::print;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
using MessageSink::print;

There's no hiding going on here since it's an override.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but without it I get

[ 21%] Building CXX object CMakeFiles/vcpkglib.dir/src/vcpkg/commands.xdownload.cpp.o
/Users/leanderSchulten/git_projekte/vcpkg-tool/src/vcpkg/binarycaching.cpp:1785:35: error: no viable conversion from 'const decltype(::vcpkg::msg::detail::make_message_base(msg::count))' (aka 'const MessageT<vcpkg::msg::count_t>') to 'vcpkg::Color'
                bg_msg_sink.print(msgStoredBinariesToDestinations, msg::count = num_destinations);
                                  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/leanderSchulten/git_projekte/vcpkg-tool/include/vcpkg/base/message_sinks.h:98:26: note: passing argument to parameter 'c' here
        void print(Color c, StringView sv) override;        
                         ^
/Users/leanderSchulten/git_projekte/vcpkg-tool/src/vcpkg/binarycaching.cpp:1790:106: error: too few arguments to function call, expected 2, have 1
                        fmt::format(" ({}/{})", count_pushed, count_pushed + remaining_packages_to_push)));
                                                                                                         ^
/Users/leanderSchulten/git_projekte/vcpkg-tool/include/vcpkg/base/message_sinks.h:98:14: note: 'print' declared here
        void print(Color c, StringView sv) override;        
             ^


// must be called from consumer (synchronizer of out)
void print_published();

void publish_directly_to_out_sink();

private:
MessageSink& out_sink;

std::mutex m_published_lock;
std::vector<std::pair<Color, std::string>> m_published;

// buffers messages until newline is reached
// guarded by m_print_directly_lock
std::vector<std::pair<Color, std::string>> m_unpublished;
Comment on lines +100 to +102
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to add some form of API that lets whole lines be submitted to the sink at a time rather than needing the complexity of the publish/not published yet going on here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean somethink like a MessageSink that only allows the printing of complete lines by providing only *nl functions?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like that? Maybe? I think what this really argues is that we really need a semi-standardized 'document' error type @ras0219-msft has been asking for ages... we're almost done getting rid of ParseControlErrorInfo which means we will finally have a unified way of handling errors and can finally look at messing with that.

std::mutex m_print_directly_lock;
bool m_print_directly_to_out_sink = false;
};
}
2 changes: 2 additions & 0 deletions include/vcpkg/base/strings.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ namespace vcpkg::Strings

const char* find_first_of(StringView searched, StringView candidates);

[[nodiscard]] std::string::size_type find_last(StringView searched, char c);

[[nodiscard]] std::vector<StringView> find_all_enclosed(StringView input,
StringView left_delim,
StringView right_delim);
Expand Down
26 changes: 24 additions & 2 deletions include/vcpkg/binarycaching.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@
#include <vcpkg/base/fwd/message_sinks.h>

#include <vcpkg/fwd/binarycaching.h>
#include <vcpkg/fwd/build.h>
#include <vcpkg/fwd/dependencies.h>
#include <vcpkg/fwd/tools.h>
#include <vcpkg/fwd/vcpkgpaths.h>

#include <vcpkg/base/batch-queue.h>
#include <vcpkg/base/downloads.h>
#include <vcpkg/base/expected.h>
#include <vcpkg/base/message_sinks.h>
#include <vcpkg/base/path.h>

#include <vcpkg/archives.h>
Expand All @@ -18,6 +21,7 @@
#include <iterator>
#include <set>
#include <string>
#include <thread>
#include <unordered_map>
#include <vector>

Expand Down Expand Up @@ -196,23 +200,41 @@ namespace vcpkg

struct BinaryCache : ReadOnlyBinaryCache
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When adding threading functionality to the codebase that is not effectively 'do a single function but faster', I think there needs to be a discussion in a comment of 'this is how the threads and communication between them work'.

For instance:

// compression and upload of binary cache entries happens on a single 'background' thread, `m_push_thread`
// Thread safety is achieved within the binary cache providers by:
//   1. Only using one thread in the background for this work.
//   2. Forming a queue of work for that thread to consume in `m_actions_to_push`, which maintains its own thread safety
//   3. Sending any replies from the background thread through `m_bg_msg_sink`
//   4. Ensuring any supporting data, such as tool exes, is provided before the background thread is started.
//   5. Ensuring that work is not submitted to the background thread until the corresponding `packages` directory to upload is no longer being actively touched by the foreground thread.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does your approach here survive #1076 ? Hard links mean that we have a lot less certainty on the packages directory being 'hermetic'.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#1076 does not have an impact here. The files "copied" to the installed dir are not later changed by another package. Even if they are overwritten, the hard link in the packages folder would still link to the same original file.

Copy link
Contributor Author

@autoantwort autoantwort Nov 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has an impact on windows if #802 gets merged before this. Because when the packages folder gets compressed by 7z, the next feature gets tested and stuff gets removed from the installed dir and on windows you cant remove a hard link even if the linked file is only opened via another hard link -.-

PS: Not sure, but I noticed this behavior only on the windows dev drive, but maybe the normal filesystem was simply too slow so that this never happened

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was finally able to catch this situation that happens in combination of this PR with #802:
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly the catch seems to only happen with this specific rocksdb.lib file and error nearly only happens with lib files.

And in general it only happens on the dev drive and not on a normal NTFS drive. Strage 😕

{
static ExpectedL<BinaryCache> make(const VcpkgCmdArguments& args, const VcpkgPaths& paths, MessageSink& sink);
static ExpectedL<std::unique_ptr<BinaryCache>> make(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
MessageSink& sink);

BinaryCache(const Filesystem& fs);
BinaryCache(const BinaryCache&) = delete;
BinaryCache(BinaryCache&&) = default;
BinaryCache(BinaryCache&&) = delete;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree with this design change. BinaryCache itself already contains several unique_ptr-alikes, and intends to firewall that storage decision from its customers. If there are immovable bits the unique_ptr juggling should happen inside rather than outside.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment about 'BinaryCache is supposed to hide unique_ptr' should get fixed, which will also eliminate a lot of the changes in this PR attempting to adapt to that change.

How would you implement that? The function push_thread_main uses the members of the class, which gets moved away if you move the BinaryCache. So I guess using pimpl is the only solution here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have now put all data in an extra struct that is hold via a std::unique_ptr by the BinaryCache class.

~BinaryCache();

/// Called upon a successful build of `action` to store those contents in the binary cache.
void push_success(const InstallPlanAction& action);

void print_push_success_messages();
void wait_for_async_complete();

private:
BinaryCache(BinaryProviders&& providers, const Filesystem& fs);

const Filesystem& m_fs;
Optional<ZipTool> m_zip_tool;
bool m_needs_nuspec_data = false;
bool m_needs_zip_file = false;

struct ActionToPush
{
BinaryPackageWriteInfo request;
CleanPackages clean_after_push;
};

void push_thread_main();

BGMessageSink m_bg_msg_sink;
BGThreadBatchQueue<ActionToPush> m_actions_to_push;
std::atomic_int m_remaining_packages_to_push = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::atomic_int m_remaining_packages_to_push = 0;
std::atomic_size_t m_remaining_packages_to_push = 0;

I think this should be size_t because we effectively could have size_t packages.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This member existing at all is a smell to me. The number of items in the queue should be a part of the queue, not something tracked externally. Moreover, the queue already contains locks and stuff so I'm not sure why we need an atomic here.

std::thread m_push_thread;
};

ExpectedL<DownloadManagerConfig> parse_download_configuration(const Optional<std::string>& arg);
Expand Down
6 changes: 2 additions & 4 deletions locales/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1455,10 +1455,6 @@
"_UpdateBaselineUpdatedBaseline.comment": "example of {old_value}, {new_value} is '5507daa796359fe8d45418e694328e878ac2b82f' An example of {url} is https://github.com/microsoft/vcpkg.",
"UpgradeInManifest": "The upgrade command does not currently support manifest mode. Instead, modify your vcpkg.json and run install.",
"UpgradeRunWithNoDryRun": "If you are sure you want to rebuild the above packages, run this command with the --no-dry-run option.",
"UploadedBinaries": "Uploaded binaries to {count} {vendor}.",
"_UploadedBinaries.comment": "An example of {count} is 42. An example of {vendor} is Azure.",
"UploadedPackagesToVendor": "Uploaded {count} package(s) to {vendor} in {elapsed}",
"_UploadedPackagesToVendor.comment": "An example of {count} is 42. An example of {elapsed} is 3.532 min. An example of {vendor} is Azure.",
"UploadingBinariesToVendor": "Uploading binaries for '{spec}' to '{vendor}' source \"{path}\".",
"_UploadingBinariesToVendor.comment": "An example of {spec} is zlib:x64-windows. An example of {vendor} is Azure. An example of {path} is /foo/bar.",
"UploadingBinariesUsingVendor": "Uploading binaries for '{spec}' using '{vendor}' \"{path}\".",
Expand Down Expand Up @@ -1558,6 +1554,8 @@
"VersionTableHeader": "Version",
"VersionVerifiedOK": "OK: {version_spec} -> {commit_sha}",
"_VersionVerifiedOK.comment": "An example of {version_spec} is zlib:x64-windows@1.0.0. An example of {commit_sha} is 7cfad47ae9f68b183983090afd6337cd60fd4949.",
"WaitUntilPackagesUploaded": "Wait until the remaining packages ({count}) are uploaded",
"_WaitUntilPackagesUploaded.comment": "An example of {count} is 42.",
"WaitingForChildrenToExit": "Waiting for child processes to exit...",
"WaitingToTakeFilesystemLock": "waiting to take filesystem lock on {path}...",
"_WaitingToTakeFilesystemLock.comment": "An example of {path} is /foo/bar.",
Expand Down
8 changes: 8 additions & 0 deletions src/vcpkg-test/strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ TEST_CASE ("find_first_of", "[strings]")
REQUIRE(find_first_of("abcdefg", "gb") == std::string("bcdefg"));
}

TEST_CASE ("find_last", "[strings]")
{
using vcpkg::Strings::find_last;
REQUIRE(find_last("abcdefg", 'a') == 0);
REQUIRE(find_last("abcdefg", 'g') == 6);
REQUIRE(find_last("abcdefg", 'z') == std::string::npos);
}

TEST_CASE ("contains_any_ignoring_c_comments", "[strings]")
{
using vcpkg::Strings::contains_any_ignoring_c_comments;
Expand Down
71 changes: 71 additions & 0 deletions src/vcpkg/base/message_sinks.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <vcpkg/base/file_sink.h>
#include <vcpkg/base/message_sinks.h>
#include <vcpkg/base/strings.h>

namespace
{
Expand Down Expand Up @@ -58,4 +59,74 @@ namespace vcpkg
m_second.print(c, sv);
}

void BGMessageSink::print(Color c, StringView sv)
{
std::lock_guard<std::mutex> print_lk(m_print_directly_lock);
if (m_print_directly_to_out_sink)
{
out_sink.print(c, sv);
return;
}

auto pos = Strings::find_last(sv, '\n');
if (pos != std::string::npos)
{
{
std::lock_guard<std::mutex> lk(m_published_lock);
m_published.insert(m_published.end(),
std::make_move_iterator(m_unpublished.begin()),
std::make_move_iterator(m_unpublished.end()));
m_published.emplace_back(c, sv.substr(0, pos + 1));
}
m_unpublished.clear();
if (sv.size() > pos + 1)
{
m_unpublished.emplace_back(c, sv.substr(pos + 1));
}
}
else
{
m_unpublished.emplace_back(c, sv);
}
}

void BGMessageSink::print_published()
{
std::vector<std::pair<Color, std::string>> tmp;
for (;;)
{
{
std::lock_guard<std::mutex> lk(m_published_lock);
swap(tmp, m_published);
}

if (tmp.empty())
{
return;
}

for (auto&& m : tmp)
{
out_sink.print(m.first, m.second);
}

tmp.clear();
}
}

void BGMessageSink::publish_directly_to_out_sink()
{
std::lock_guard<std::mutex> print_lk(m_print_directly_lock);
std::lock_guard<std::mutex> lk(m_published_lock);
Comment on lines +119 to +120
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::lock_guard<std::mutex> print_lk(m_print_directly_lock);
std::lock_guard<std::mutex> lk(m_published_lock);
std::lock_guard<std::mutex, std::mutex> lk(m_print_directly_lock, m_published_lock);

if this survives

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you actually mean std::scoped_lock.


m_print_directly_to_out_sink = true;
for (auto& messages : {&m_published, &m_unpublished})
{
for (auto&& m : *messages)
{
out_sink.print(m.first, m.second);
autoantwort marked this conversation as resolved.
Show resolved Hide resolved
}
messages->clear();
}
}
}
6 changes: 6 additions & 0 deletions src/vcpkg/base/strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,12 @@ const char* Strings::find_first_of(StringView input, StringView chars)
return std::find_first_of(input.begin(), input.end(), chars.begin(), chars.end());
}

std::string::size_type Strings::find_last(StringView searched, char c)
{
auto iter = std::find(searched.rbegin(), searched.rend(), c);
return iter == searched.rend() ? std::string::npos : (&*iter - searched.begin());
}

std::vector<StringView> Strings::find_all_enclosed(StringView input, StringView left_delim, StringView right_delim)
{
auto it_left = input.begin();
Expand Down
Loading