Skip to content

Commit 7929022

Browse files
committed
feat(binary-cache): Add write-back support to binary cache
1 parent 6081c15 commit 7929022

File tree

8 files changed

+640
-294
lines changed

8 files changed

+640
-294
lines changed

azure-pipelines/end-to-end-tests-dir/binary-caching.ps1

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,27 @@ Require-FileExists "$installRoot/$Triplet/include/hello-1.h"
4747
Require-FileExists "$buildtreesRoot/vcpkg-hello-world-1/src"
4848
Require-FileNotExists "$buildtreesRoot/detect_compiler"
4949

50+
# Test write back to files archive
51+
Remove-Item -Recurse -Force $installRoot
52+
Remove-Item -Recurse -Force $buildtreesRoot
53+
Run-Vcpkg -TestArgs ($commonArgs + @("install","vcpkg-hello-world-1", "vcpkg-cmake", "vcpkg-cmake-config", "--x-binarysource=clear;files,$ArchiveRoot;files,$ArchiveRootSecondary,write;files,$ArchiveRootUnused,read"))
54+
Throw-IfFailed
55+
Require-FileExists "$installRoot/$Triplet/include/hello-1.h"
56+
Require-FileNotExists "$buildtreesRoot/vcpkg-hello-world-1/src"
57+
if ((Get-ChildItem $ArchiveRootSecondary -Filter '*.zip' | Measure-Object).Count -ne 4) {
58+
throw "In '$CurrentTest': did not write back exactly 4 packages to the secondary archive"
59+
}
60+
if ((Get-ChildItem $ArchiveRootUnused -Filter '*.zip' | Measure-Object).Count -ne 0) {
61+
throw "In '$CurrentTest': some packages were written to the unused archive"
62+
}
63+
64+
# Test restore from secondary archive
65+
Remove-Item -Recurse -Force $installRoot
66+
Run-Vcpkg -TestArgs ($commonArgs + @("install","vcpkg-hello-world-1", "vcpkg-cmake", "vcpkg-cmake-config", "--x-binarysource=clear;files,$ArchiveRootSecondary,read"))
67+
Throw-IfFailed
68+
Require-FileExists "$installRoot/$Triplet/include/hello-1.h"
69+
Require-FileNotExists "$buildtreesRoot/vcpkg-hello-world-1/src"
70+
5071
if(-Not $IsLinux -and -Not $IsMacOS) {
5172
# Test restoring from nuget
5273
Remove-Item -Recurse -Force $installRoot
@@ -78,8 +99,8 @@ if(-Not $IsLinux -and -Not $IsMacOS) {
7899
Require-FileExists "$installRoot/$Triplet/include/hello-2.h"
79100
Require-FileNotExists "$buildtreesRoot/vcpkg-hello-world-1/src"
80101
Require-FileExists "$buildtreesRoot/vcpkg-hello-world-2/src"
81-
if ((Get-ChildItem $NuGetRoot -Filter '*.nupkg' | Measure-Object).Count -ne 1) {
82-
throw "In '$CurrentTest': did not create exactly 1 NuGet package"
102+
if ((Get-ChildItem $NuGetRoot -Filter '*.nupkg' | Measure-Object).Count -ne 4) {
103+
throw "In '$CurrentTest': did not create exactly 4 NuGet packages"
83104
}
84105

85106
# Test export

azure-pipelines/end-to-end-tests-prelude.ps1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ $packagesRoot = Join-Path $TestingRoot 'packages'
55
$NuGetRoot = Join-Path $TestingRoot 'nuget'
66
$NuGetRoot2 = Join-Path $TestingRoot 'nuget2'
77
$ArchiveRoot = Join-Path $TestingRoot 'archives'
8+
$ArchiveRootSecondary = Join-Path $TestingRoot 'archives-secondary'
9+
$ArchiveRootUnused = Join-Path $TestingRoot 'archives-unused'
810
$VersionFilesRoot = Join-Path $TestingRoot 'version-test'
911
$directoryArgs = @(
1012
"--x-buildtrees-root=$buildtreesRoot",

include/vcpkg/base/util.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,19 @@ namespace vcpkg::Util
4444

4545
return false;
4646
}
47+
template<class Vec, class Filter>
48+
std::vector<ElementT<Vec>> filtered_copy(const Vec& container, const Filter&& filter)
49+
{
50+
std::vector<ElementT<Vec>> ret;
51+
for (auto&& item : container)
52+
{
53+
if (filter(item))
54+
{
55+
ret.push_back(item);
56+
}
57+
}
58+
return ret;
59+
}
4760
template<class Vec, class Key>
4861
bool contains(const Vec& container, const Key& item)
4962
{

include/vcpkg/binarycaching.h

Lines changed: 69 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,26 @@
2525

2626
namespace vcpkg
2727
{
28+
/// Unique identifier for a provider
29+
using ProviderId = size_t;
30+
2831
struct CacheStatus
2932
{
33+
using ReaderProviders = std::vector<const IReadBinaryProvider*>;
34+
3035
bool should_attempt_precheck(const IReadBinaryProvider* sender) const noexcept;
3136
bool should_attempt_restore(const IReadBinaryProvider* sender) const noexcept;
37+
bool should_attempt_write_back(ProviderId provider_id) const noexcept;
3238

3339
bool is_unavailable(const IReadBinaryProvider* sender) const noexcept;
3440
const IReadBinaryProvider* get_available_provider() const noexcept;
41+
ReaderProviders& get_unavailable_providers() noexcept;
3542
bool is_restored() const noexcept;
3643

3744
void mark_unavailable(const IReadBinaryProvider* sender);
3845
void mark_available(const IReadBinaryProvider* sender) noexcept;
3946
void mark_restored() noexcept;
47+
void mark_written_back(ProviderId provider_id) noexcept;
4048

4149
private:
4250
CacheStatusState m_status = CacheStatusState::unknown;
@@ -75,10 +83,13 @@ namespace vcpkg
7583

7684
/// Called upon a successful build of `action` to store those contents in the binary cache.
7785
/// returns the number of successful uploads
78-
virtual size_t push_success(const BinaryPackageWriteInfo& request, MessageSink& msg_sink) = 0;
86+
virtual size_t push_success(const BinaryPackageWriteInfo& request,
87+
MessageSink& msg_sink,
88+
CacheStatus& cache_status) = 0;
7989

8090
virtual bool needs_nuspec_data() const = 0;
8191
virtual bool needs_zip_file() const = 0;
92+
virtual std::vector<ProviderId> get_provider_ids() const = 0;
8293
};
8394

8495
struct IReadBinaryProvider
@@ -93,6 +104,10 @@ namespace vcpkg
93104
/// Prerequisites: actions[i].package_abi(), out_status.size() == actions.size()
94105
virtual void fetch(View<const InstallPlanAction*> actions, Span<RestoreResult> out_status) const = 0;
95106

107+
/// Flag to indicate if the provider supports an efficient check to see if a certain set of packages are
108+
/// available. If not, packages will assumed to be present & will always be fetched.
109+
virtual bool can_precheck() const = 0;
110+
96111
/// Checks whether the `actions` are present in the cache, without restoring them.
97112
///
98113
/// Used by CI to determine missing packages. For each `i`, out_status[i] should be set to
@@ -103,6 +118,11 @@ namespace vcpkg
103118

104119
virtual LocalizedString restored_message(size_t count,
105120
std::chrono::high_resolution_clock::duration elapsed) const = 0;
121+
122+
/// Unique identifier for this provider.
123+
///
124+
/// Used by the cache to exclude cache providers during the write-back phase.
125+
virtual ProviderId id() const = 0;
106126
};
107127

108128
struct UrlTemplate
@@ -114,44 +134,62 @@ namespace vcpkg
114134
std::string instantiate_variables(const BinaryPackageReadInfo& info) const;
115135
};
116136

137+
struct GithubActionsInfo
138+
{
139+
};
140+
117141
struct NuGetRepoInfo
118142
{
119143
std::string repo;
120144
std::string branch;
121145
std::string commit;
122146
};
123147

148+
enum class CacheType
149+
{
150+
Read,
151+
Write,
152+
ReadWrite
153+
};
154+
155+
template<typename T>
156+
struct CacheProvider
157+
{
158+
ProviderId id;
159+
T source;
160+
CacheType cache_type;
161+
162+
[[nodiscard]] constexpr bool is_read() const noexcept
163+
{
164+
return cache_type == CacheType::Read || cache_type == CacheType::ReadWrite;
165+
}
166+
167+
[[nodiscard]] constexpr bool is_write() const noexcept
168+
{
169+
return cache_type == CacheType::Write || cache_type == CacheType::ReadWrite;
170+
}
171+
};
172+
173+
template<typename T>
174+
using ProviderList = std::vector<CacheProvider<T>>;
175+
124176
struct BinaryConfigParserState
125177
{
178+
ProviderId provider_count = 0;
126179
bool nuget_interactive = false;
127180
std::set<StringLiteral> binary_cache_providers;
128181

129182
std::string nugettimeout = "100";
130183

131-
std::vector<Path> archives_to_read;
132-
std::vector<Path> archives_to_write;
133-
134-
std::vector<UrlTemplate> url_templates_to_get;
135-
std::vector<UrlTemplate> url_templates_to_put;
136-
137-
std::vector<std::string> gcs_read_prefixes;
138-
std::vector<std::string> gcs_write_prefixes;
139-
140-
std::vector<std::string> aws_read_prefixes;
141-
std::vector<std::string> aws_write_prefixes;
184+
ProviderList<Path> archives;
185+
ProviderList<UrlTemplate> url_templates;
186+
ProviderList<std::string> gcs_prefixes;
187+
ProviderList<std::string> aws_prefixes;
142188
bool aws_no_sign_request = false;
143-
144-
std::vector<std::string> cos_read_prefixes;
145-
std::vector<std::string> cos_write_prefixes;
146-
147-
bool gha_write = false;
148-
bool gha_read = false;
149-
150-
std::vector<std::string> sources_to_read;
151-
std::vector<std::string> sources_to_write;
152-
153-
std::vector<Path> configs_to_read;
154-
std::vector<Path> configs_to_write;
189+
ProviderList<std::string> cos_prefixes;
190+
Optional<CacheProvider<GithubActionsInfo>> gha;
191+
ProviderList<std::string> sources;
192+
ProviderList<Path> configs;
155193

156194
std::vector<std::string> secrets;
157195

@@ -173,6 +211,8 @@ namespace vcpkg
173211
NuGetRepoInfo nuget_repo;
174212
};
175213

214+
[[nodiscard]] bool HasWriteOnlyProviders(const BinaryProviders& providers);
215+
176216
struct ReadOnlyBinaryCache
177217
{
178218
ReadOnlyBinaryCache() = default;
@@ -182,7 +222,7 @@ namespace vcpkg
182222
/// executing `actions`.
183223
void fetch(View<InstallPlanAction> actions);
184224

185-
bool is_restored(const InstallPlanAction& ipa) const;
225+
Optional<CacheStatus> cache_status(const InstallPlanAction& ipa) const;
186226

187227
/// Checks whether the `actions` are present in the cache, without restoring them. Used by CI to determine
188228
/// missing packages.
@@ -192,6 +232,10 @@ namespace vcpkg
192232
protected:
193233
BinaryProviders m_config;
194234

235+
/// Flag to indicate that at least one provider is write-only. This implies that the write-back phase should
236+
/// always take place for every Cache item.
237+
bool m_has_write_only_providers;
238+
195239
std::unordered_map<std::string, CacheStatus> m_status;
196240
};
197241

src/vcpkg-test/binarycaching.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ struct KnowNothingBinaryProvider : IReadBinaryProvider
2323
CHECK(out_status[idx] == RestoreResult::unavailable);
2424
}
2525
}
26+
27+
bool can_precheck() const override { return true; }
28+
2629
void precheck(View<const InstallPlanAction*> actions, Span<CacheAvailability> out_status) const override
2730
{
2831
REQUIRE(actions.size() == out_status.size());
@@ -36,6 +39,8 @@ struct KnowNothingBinaryProvider : IReadBinaryProvider
3639
{
3740
return LocalizedString::from_raw("Nothing");
3841
}
42+
43+
ProviderId id() const override { return 1; }
3944
};
4045

4146
TEST_CASE ("CacheStatus operations", "[BinaryCache]")

0 commit comments

Comments
 (0)