summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver Reiche <oliver.reiche@huawei.com>2024-06-27 17:12:06 +0200
committerOliver Reiche <oliver.reiche@huawei.com>2024-06-28 10:48:05 +0200
commit2e954a436b7c990e12eb98de9a6a9ba995dd9429 (patch)
treea215cf9b4fb8fe5e479ee7aa507f137b670bc660
parent67cab970091d5b23c07890deb29018c7eeb4edbc (diff)
downloadjustbuild-2e954a436b7c990e12eb98de9a6a9ba995dd9429.tar.gz
Use (un)expected for CAS access
-rw-r--r--src/buildtool/execution_api/execution_service/cas_utils.cpp19
-rw-r--r--src/buildtool/storage/TARGETS1
-rw-r--r--src/buildtool/storage/compactifier.cpp10
-rw-r--r--src/buildtool/storage/large_object_cas.hpp8
-rw-r--r--src/buildtool/storage/large_object_cas.tpp56
-rw-r--r--src/buildtool/storage/local_cas.hpp17
-rw-r--r--src/buildtool/storage/local_cas.tpp43
-rw-r--r--test/buildtool/storage/large_object_cas.test.cpp86
8 files changed, 107 insertions, 133 deletions
diff --git a/src/buildtool/execution_api/execution_service/cas_utils.cpp b/src/buildtool/execution_api/execution_service/cas_utils.cpp
index 8ab7b131..7dee7dc7 100644
--- a/src/buildtool/execution_api/execution_service/cas_utils.cpp
+++ b/src/buildtool/execution_api/execution_service/cas_utils.cpp
@@ -93,14 +93,11 @@ auto CASUtils::SplitBlobFastCDC(bazel_re::Digest const& blob_digest,
: storage.CAS().SplitBlob(blob_digest);
// Process result:
- if (auto* result = std::get_if<std::vector<bazel_re::Digest>>(&split)) {
- return std::move(*result);
+ if (split) {
+ return *std::move(split);
}
// Process errors
- if (auto* error = std::get_if<LargeObjectError>(&split)) {
- return ToGrpc(std::move(*error));
- }
- return grpc::Status{grpc::StatusCode::INTERNAL, "an unknown error"};
+ return ToGrpc(std::move(split).error());
}
auto CASUtils::SpliceBlob(bazel_re::Digest const& blob_digest,
@@ -114,12 +111,8 @@ auto CASUtils::SpliceBlob(bazel_re::Digest const& blob_digest,
: storage.CAS().SpliceBlob(blob_digest, chunk_digests, false);
// Process result:
- if (auto* result = std::get_if<bazel_re::Digest>(&splice)) {
- return std::move(*result);
+ if (splice) {
+ return *std::move(splice);
}
- // Process errors
- if (auto* error = std::get_if<LargeObjectError>(&splice)) {
- return ToGrpc(std::move(*error));
- }
- return grpc::Status{grpc::StatusCode::INTERNAL, "an unknown error"};
+ return ToGrpc(std::move(splice).error());
}
diff --git a/src/buildtool/storage/TARGETS b/src/buildtool/storage/TARGETS
index c9551874..ec395ec5 100644
--- a/src/buildtool/storage/TARGETS
+++ b/src/buildtool/storage/TARGETS
@@ -54,6 +54,7 @@
, ["src/buildtool/build_engine/expression", "expression"]
, ["src/utils/cpp", "file_locking"]
, ["src/utils/cpp", "gsl"]
+ , ["src/utils/cpp", "expected"]
, ["@", "gsl", "", "gsl"]
, ["@", "json", "", "json"]
, ["@", "fmt", "", "fmt"]
diff --git a/src/buildtool/storage/compactifier.cpp b/src/buildtool/storage/compactifier.cpp
index c8d65e8e..e9997efb 100644
--- a/src/buildtool/storage/compactifier.cpp
+++ b/src/buildtool/storage/compactifier.cpp
@@ -19,7 +19,6 @@
#include <filesystem>
#include <functional>
#include <optional>
-#include <variant>
#include <vector>
#include "src/buildtool/common/bazel_types.hpp"
@@ -283,21 +282,18 @@ template <ObjectType kType>
// Split the entry:
auto split_result = IsTreeObject(kType) ? task.cas.SplitTree(*digest)
: task.cas.SplitBlob(*digest);
- auto* parts = std::get_if<std::vector<bazel_re::Digest>>(&split_result);
- if (parts == nullptr) {
- auto* error = std::get_if<LargeObjectError>(&split_result);
- auto const error_message = error ? std::move(*error).Message() : "";
+ if (not split_result) {
task.Log(LogLevel::Error,
"Failed to split {}\nDigest: {}\nMessage: {}",
path.string(),
digest->hash(),
- error_message);
+ std::move(split_result).error().Message());
return false;
}
// If the file cannot actually be split (the threshold is too low), the
// file must not be deleted.
- if (parts->size() < 2) {
+ if (split_result->size() < 2) {
task.Log(LogLevel::Debug,
"{} cannot be compactified. The compactification "
"threshold is too low.",
diff --git a/src/buildtool/storage/large_object_cas.hpp b/src/buildtool/storage/large_object_cas.hpp
index cb81d8b5..6f287379 100644
--- a/src/buildtool/storage/large_object_cas.hpp
+++ b/src/buildtool/storage/large_object_cas.hpp
@@ -19,13 +19,13 @@
#include <optional>
#include <string>
#include <utility>
-#include <variant>
#include <vector>
#include "src/buildtool/common/bazel_types.hpp"
#include "src/buildtool/file_system/file_storage.hpp"
#include "src/buildtool/file_system/object_type.hpp"
#include "src/buildtool/storage/config.hpp"
+#include "src/utils/cpp/expected.hpp"
#include "src/utils/cpp/tmp_dir.hpp"
template <bool>
@@ -124,7 +124,7 @@ class LargeObjectCAS final {
/// \return A set of chunks the resulting object is composed of
/// or an error on failure.
[[nodiscard]] auto Split(bazel_re::Digest const& digest) const noexcept
- -> std::variant<LargeObjectError, std::vector<bazel_re::Digest>>;
+ -> expected<std::vector<bazel_re::Digest>, LargeObjectError>;
/// \brief Splice an object based on the reconstruction rules from the
/// storage. This method doesn't check whether the result of splicing is
@@ -133,7 +133,7 @@ class LargeObjectCAS final {
/// \return A temporary directory that contains a single file
/// "result" on success or an error on failure.
[[nodiscard]] auto TrySplice(bazel_re::Digest const& digest) const noexcept
- -> std::variant<LargeObjectError, LargeObject>;
+ -> expected<LargeObject, LargeObjectError>;
/// \brief Splice an object from parts. This method doesn't check whether
/// the result of splicing is already in the CAS.
@@ -143,7 +143,7 @@ class LargeObjectCAS final {
/// "result" on success or an error on failure.
[[nodiscard]] auto Splice(bazel_re::Digest const& digest,
std::vector<bazel_re::Digest> const& parts)
- const noexcept -> std::variant<LargeObjectError, LargeObject>;
+ const noexcept -> expected<LargeObject, LargeObjectError>;
/// \brief Uplink large entry from this generation to latest LocalCAS
/// generation. For the large entry it's parts get promoted first and then
diff --git a/src/buildtool/storage/large_object_cas.tpp b/src/buildtool/storage/large_object_cas.tpp
index db2f46a9..d216c8e8 100644
--- a/src/buildtool/storage/large_object_cas.tpp
+++ b/src/buildtool/storage/large_object_cas.tpp
@@ -119,7 +119,7 @@ auto LargeObjectCAS<kDoGlobalUplink, kType>::WriteEntry(
template <bool kDoGlobalUplink, ObjectType kType>
auto LargeObjectCAS<kDoGlobalUplink, kType>::Split(
bazel_re::Digest const& digest) const noexcept
- -> std::variant<LargeObjectError, std::vector<bazel_re::Digest>> {
+ -> expected<std::vector<bazel_re::Digest>, LargeObjectError> {
if (auto large_entry = ReadEntry(digest)) {
return std::move(*large_entry);
}
@@ -138,17 +138,17 @@ auto LargeObjectCAS<kDoGlobalUplink, kType>::Split(
}
if (not file_path) {
- return LargeObjectError{
- LargeObjectErrorCode::FileNotFound,
- fmt::format("could not find {}", digest.hash())};
+ return unexpected{
+ LargeObjectError{LargeObjectErrorCode::FileNotFound,
+ fmt::format("could not find {}", digest.hash())}};
}
// Split file into chunks:
FileChunker chunker{*file_path};
if (not chunker.IsOpen()) {
- return LargeObjectError{
- LargeObjectErrorCode::Internal,
- fmt::format("could not split {}", digest.hash())};
+ return unexpected{
+ LargeObjectError{LargeObjectErrorCode::Internal,
+ fmt::format("could not split {}", digest.hash())}};
}
std::vector<bazel_re::Digest> parts;
@@ -156,19 +156,19 @@ auto LargeObjectCAS<kDoGlobalUplink, kType>::Split(
while (auto chunk = chunker.NextChunk()) {
auto part = local_cas_.StoreBlob(*chunk, /*is_executable=*/false);
if (not part) {
- return LargeObjectError{LargeObjectErrorCode::Internal,
- "could not store a part."};
+ return unexpected{LargeObjectError{
+ LargeObjectErrorCode::Internal, "could not store a part."}};
}
parts.push_back(std::move(*part));
}
} catch (...) {
- return LargeObjectError{LargeObjectErrorCode::Internal,
- "an unknown error occured."};
+ return unexpected{LargeObjectError{LargeObjectErrorCode::Internal,
+ "an unknown error occured."}};
}
if (not chunker.Finished()) {
- return LargeObjectError{
- LargeObjectErrorCode::Internal,
- fmt::format("could not split {}", digest.hash())};
+ return unexpected{
+ LargeObjectError{LargeObjectErrorCode::Internal,
+ fmt::format("could not split {}", digest.hash())}};
}
std::ignore = WriteEntry(digest, parts);
@@ -178,12 +178,12 @@ auto LargeObjectCAS<kDoGlobalUplink, kType>::Split(
template <bool kDoGlobalUplink, ObjectType kType>
auto LargeObjectCAS<kDoGlobalUplink, kType>::TrySplice(
bazel_re::Digest const& digest) const noexcept
- -> std::variant<LargeObjectError, LargeObject> {
+ -> expected<LargeObject, LargeObjectError> {
auto parts = ReadEntry(digest);
if (not parts) {
- return LargeObjectError{
+ return unexpected{LargeObjectError{
LargeObjectErrorCode::FileNotFound,
- fmt::format("could not find large entry for {}", digest.hash())};
+ fmt::format("could not find large entry for {}", digest.hash())}};
}
return Splice(digest, *parts);
}
@@ -192,14 +192,14 @@ template <bool kDoGlobalUplink, ObjectType kType>
auto LargeObjectCAS<kDoGlobalUplink, kType>::Splice(
bazel_re::Digest const& digest,
std::vector<bazel_re::Digest> const& parts) const noexcept
- -> std::variant<LargeObjectError, LargeObject> {
+ -> expected<LargeObject, LargeObjectError> {
// Create temporary space for splicing:
LargeObject large_object;
if (not large_object.IsValid()) {
- return LargeObjectError{
+ return unexpected{LargeObjectError{
LargeObjectErrorCode::Internal,
fmt::format("could not create a temporary space for {}",
- digest.hash())};
+ digest.hash())}};
}
// Splice the object from parts
@@ -208,32 +208,32 @@ auto LargeObjectCAS<kDoGlobalUplink, kType>::Splice(
for (auto const& part : parts) {
auto part_path = local_cas_.BlobPath(part, /*is_executable=*/false);
if (not part_path) {
- return LargeObjectError{
+ return unexpected{LargeObjectError{
LargeObjectErrorCode::FileNotFound,
- fmt::format("could not find the part {}", part.hash())};
+ fmt::format("could not find the part {}", part.hash())}};
}
auto part_content = FileSystemManager::ReadFile(*part_path);
if (not part_content) {
- return LargeObjectError{
+ return unexpected{LargeObjectError{
LargeObjectErrorCode::Internal,
fmt::format("could not read the part content {}",
- part.hash())};
+ part.hash())}};
}
if (stream.good()) {
stream << *part_content;
}
else {
- return LargeObjectError{
+ return unexpected{LargeObjectError{
LargeObjectErrorCode::Internal,
- fmt::format("could not splice {}", digest.hash())};
+ fmt::format("could not splice {}", digest.hash())}};
}
}
stream.close();
} catch (...) {
- return LargeObjectError{LargeObjectErrorCode::Internal,
- "an unknown error occured"};
+ return unexpected{LargeObjectError{LargeObjectErrorCode::Internal,
+ "an unknown error occured"}};
}
return large_object;
}
diff --git a/src/buildtool/storage/local_cas.hpp b/src/buildtool/storage/local_cas.hpp
index 9309ef5d..b29c870b 100644
--- a/src/buildtool/storage/local_cas.hpp
+++ b/src/buildtool/storage/local_cas.hpp
@@ -18,7 +18,6 @@
#include <filesystem>
#include <optional>
#include <unordered_set>
-#include <variant>
#include <vector>
#include "gsl/gsl"
@@ -26,6 +25,7 @@
#include "src/buildtool/file_system/object_cas.hpp"
#include "src/buildtool/storage/garbage_collector.hpp"
#include "src/buildtool/storage/large_object_cas.hpp"
+#include "src/utils/cpp/expected.hpp"
/// \brief The local (logical) CAS for storing blobs and trees.
/// Blobs can be stored/queried as executable or non-executable. Trees might be
@@ -145,7 +145,7 @@ class LocalCAS {
/// \returns Digests of the parts of the large object or an
/// error code on failure.
[[nodiscard]] auto SplitBlob(bazel_re::Digest const& digest) const noexcept
- -> std::variant<LargeObjectError, std::vector<bazel_re::Digest>> {
+ -> expected<std::vector<bazel_re::Digest>, LargeObjectError> {
return cas_file_large_.Split(digest);
}
@@ -158,7 +158,7 @@ class LocalCAS {
[[nodiscard]] auto SpliceBlob(bazel_re::Digest const& digest,
std::vector<bazel_re::Digest> const& parts,
bool is_executable) const noexcept
- -> std::variant<LargeObjectError, bazel_re::Digest> {
+ -> expected<bazel_re::Digest, LargeObjectError> {
return is_executable ? Splice<ObjectType::Executable>(digest, parts)
: Splice<ObjectType::File>(digest, parts);
}
@@ -176,7 +176,7 @@ class LocalCAS {
/// \returns Digests of the parts of the large object or an
/// error code on failure.
[[nodiscard]] auto SplitTree(bazel_re::Digest const& digest) const noexcept
- -> std::variant<LargeObjectError, std::vector<bazel_re::Digest>> {
+ -> expected<std::vector<bazel_re::Digest>, LargeObjectError> {
return cas_tree_large_.Split(digest);
}
@@ -187,7 +187,7 @@ class LocalCAS {
/// failure.
[[nodiscard]] auto SpliceTree(bazel_re::Digest const& digest,
std::vector<bazel_re::Digest> const& parts)
- const noexcept -> std::variant<LargeObjectError, bazel_re::Digest> {
+ const noexcept -> expected<bazel_re::Digest, LargeObjectError> {
return Splice<ObjectType::Tree>(digest, parts);
}
@@ -315,7 +315,7 @@ class LocalCAS {
template <ObjectType kType>
[[nodiscard]] auto Splice(bazel_re::Digest const& digest,
std::vector<bazel_re::Digest> const& parts)
- const noexcept -> std::variant<LargeObjectError, bazel_re::Digest>;
+ const noexcept -> expected<bazel_re::Digest, LargeObjectError>;
};
#ifndef BOOTSTRAP_BUILD_TOOL
@@ -334,8 +334,9 @@ template <ObjectType kType>
auto LocalCAS<kDoGlobalUplink>::Splice(
bazel_re::Digest const& digest,
std::vector<bazel_re::Digest> const& parts) const noexcept
- -> std::variant<LargeObjectError, bazel_re::Digest> {
- return LargeObjectError{LargeObjectErrorCode::Internal, "not allowed"};
+ -> expected<bazel_re::Digest, LargeObjectError> {
+ return unexpected{
+ LargeObjectError{LargeObjectErrorCode::Internal, "not allowed"}};
}
#endif
diff --git a/src/buildtool/storage/local_cas.tpp b/src/buildtool/storage/local_cas.tpp
index e03d3062..e0cb3883 100644
--- a/src/buildtool/storage/local_cas.tpp
+++ b/src/buildtool/storage/local_cas.tpp
@@ -284,9 +284,8 @@ requires(kIsLocalGeneration) auto LocalCAS<kDoGlobalUplink>::TrySplice(
-> std::optional<LargeObject> {
auto spliced = IsTreeObject(kType) ? cas_tree_large_.TrySplice(digest)
: cas_file_large_.TrySplice(digest);
- auto* large = std::get_if<LargeObject>(&spliced);
- return large and large->IsValid() ? std::optional{std::move(*large)}
- : std::nullopt;
+ return spliced and spliced->IsValid() ? std::optional{std::move(*spliced)}
+ : std::nullopt;
}
template <bool kDoGlobalUplink>
@@ -343,7 +342,7 @@ template <ObjectType kType>
auto LocalCAS<kDoGlobalUplink>::Splice(
bazel_re::Digest const& digest,
std::vector<bazel_re::Digest> const& parts) const noexcept
- -> std::variant<LargeObjectError, bazel_re::Digest> {
+ -> expected<bazel_re::Digest, LargeObjectError> {
static constexpr bool kIsTree = IsTreeObject(kType);
static constexpr bool kIsExec = IsExecutableObject(kType);
@@ -353,39 +352,32 @@ auto LocalCAS<kDoGlobalUplink>::Splice(
}
// Splice the result from parts:
- std::optional<LargeObject> large_object;
auto splice_result = kIsTree ? cas_tree_large_.Splice(digest, parts)
: cas_file_large_.Splice(digest, parts);
- if (auto* result = std::get_if<LargeObject>(&splice_result)) {
- large_object = *result;
- }
- else if (auto* error = std::get_if<LargeObjectError>(&splice_result)) {
- return std::move(*error);
- }
- else {
- return LargeObjectError{
- LargeObjectErrorCode::Internal,
- fmt::format("could not splice {}", digest.hash())};
+ if (not splice_result) {
+ return unexpected{std::move(splice_result).error()};
}
+ auto const& large_object = *splice_result;
+
// Check digest consistency:
// Using Store{Tree, Blob} to calculate the resulting hash and later
// decide whether the result is valid is unreasonable, because these
// methods can refer to a file that existed before. The direct hash
// calculation is done instead.
- auto const file_path = large_object->GetPath();
+ auto const& file_path = large_object.GetPath();
auto spliced_digest = ObjectCAS<kType>::CreateDigest(file_path);
if (not spliced_digest) {
- return LargeObjectError{LargeObjectErrorCode::Internal,
- "could not calculate digest"};
+ return unexpected{LargeObjectError{LargeObjectErrorCode::Internal,
+ "could not calculate digest"}};
}
if (not detail::CheckDigestConsistency(*spliced_digest, digest)) {
- return LargeObjectError{
+ return unexpected{LargeObjectError{
LargeObjectErrorCode::InvalidResult,
fmt::format("actual result {} differs from the expected one {}",
spliced_digest->hash(),
- digest.hash())};
+ digest.hash())}};
}
// Check tree invariants:
@@ -394,12 +386,12 @@ auto LocalCAS<kDoGlobalUplink>::Splice(
// Read tree entries:
auto const tree_data = FileSystemManager::ReadFile(file_path);
if (not tree_data) {
- return LargeObjectError{
+ return unexpected{LargeObjectError{
LargeObjectErrorCode::Internal,
- fmt::format("could not read tree {}", digest.hash())};
+ fmt::format("could not read tree {}", digest.hash())}};
}
if (auto error = CheckTreeInvariant(digest, *tree_data)) {
- return std::move(*error);
+ return unexpected{std::move(*error)};
}
}
}
@@ -410,8 +402,9 @@ auto LocalCAS<kDoGlobalUplink>::Splice(
if (stored_digest) {
return std::move(*stored_digest);
}
- return LargeObjectError{LargeObjectErrorCode::Internal,
- fmt::format("could not splice {}", digest.hash())};
+ return unexpected{
+ LargeObjectError{LargeObjectErrorCode::Internal,
+ fmt::format("could not splice {}", digest.hash())}};
}
#endif // INCLUDED_SRC_BUILDTOOL_STORAGE_LOCAL_CAS_TPP
diff --git a/test/buildtool/storage/large_object_cas.test.cpp b/test/buildtool/storage/large_object_cas.test.cpp
index 0a62932a..dae2a29a 100644
--- a/test/buildtool/storage/large_object_cas.test.cpp
+++ b/test/buildtool/storage/large_object_cas.test.cpp
@@ -116,12 +116,11 @@ TEST_CASE_METHOD(HermeticLocalTestFixture,
// Split must be successful:
auto split_pack = large_cas.Split(digest);
- auto* parts = std::get_if<std::vector<bazel_re::Digest>>(&split_pack);
- REQUIRE(parts);
+ REQUIRE(split_pack);
// The result must contain one blob digest:
- CHECK(parts->size() == 1);
- CHECK_FALSE(NativeSupport::IsTree(parts->front().hash()));
+ CHECK(split_pack->size() == 1);
+ CHECK_FALSE(NativeSupport::IsTree(split_pack->front().hash()));
}
// Test splitting of a large object. The split must be successful and the entry
@@ -148,9 +147,8 @@ static void TestLarge() noexcept {
// Split the large object:
auto pack_1 = kIsTree ? cas.SplitTree(digest) : cas.SplitBlob(digest);
- auto* split = std::get_if<std::vector<bazel_re::Digest>>(&pack_1);
- CHECK(split);
- CHECK(split->size() > 1);
+ CHECK(pack_1);
+ CHECK(pack_1->size() > 1);
CHECK(FileSystemManager::RemoveFile(path));
CHECK_FALSE(FileSystemManager::IsFile(path));
@@ -159,9 +157,8 @@ static void TestLarge() noexcept {
// Check the second call loads the entry from the large CAS:
auto pack_2 =
kIsTree ? cas.SplitTree(digest) : cas.SplitBlob(digest);
- auto* split_2 = std::get_if<std::vector<bazel_re::Digest>>(&pack_2);
- CHECK(split_2);
- CHECK(split_2->size() == split->size());
+ CHECK(pack_2);
+ CHECK(pack_2->size() == pack_1->size());
// There must be no spliced file:
CHECK_FALSE(FileSystemManager::IsFile(path));
@@ -198,9 +195,8 @@ static void TestLarge() noexcept {
auto pack_3 = kIsTree
? Storage::Generation(0).CAS().SplitTree(digest)
: Storage::Generation(0).CAS().SplitBlob(digest);
- auto* split_3 = std::get_if<std::vector<bazel_re::Digest>>(&pack_3);
- REQUIRE(split_3);
- CHECK(split_3->size() == split->size());
+ REQUIRE(pack_3);
+ CHECK(pack_3->size() == pack_1->size());
// Check there are no spliced results in all generations:
for (std::size_t i = 0; i < StorageConfig::NumGenerations(); ++i) {
@@ -238,10 +234,9 @@ static void TestSmall() noexcept {
// Split the small object:
auto pack_1 = kIsTree ? cas.SplitTree(digest) : cas.SplitBlob(digest);
- auto* split = std::get_if<std::vector<bazel_re::Digest>>(&pack_1);
- CHECK(split);
- CHECK(split->size() == 1);
- CHECK_FALSE(NativeSupport::IsTree(split->front().hash()));
+ CHECK(pack_1);
+ CHECK(pack_1->size() == 1);
+ CHECK_FALSE(NativeSupport::IsTree(pack_1->front().hash()));
// Test that there is no large entry in the storage:
// To ensure there is no split of the initial object, it is removed:
@@ -251,16 +246,15 @@ static void TestSmall() noexcept {
// The part of a small executable is the same file but without the
// execution permission. It must be deleted too.
if constexpr (kIsExec) {
- auto part_path = cas.BlobPath(split->front(), false);
+ auto part_path = cas.BlobPath(pack_1->front(), false);
CHECK(part_path);
CHECK(FileSystemManager::RemoveFile(*part_path));
}
// Split must not find the large entry:
auto pack_2 = kIsTree ? cas.SplitTree(digest) : cas.SplitBlob(digest);
- auto* error_2 = std::get_if<LargeObjectError>(&pack_2);
- CHECK(error_2);
- CHECK(error_2->Code() == LargeObjectErrorCode::FileNotFound);
+ CHECK_FALSE(pack_2);
+ CHECK(pack_2.error().Code() == LargeObjectErrorCode::FileNotFound);
// There must be no spliced file:
CHECK_FALSE(FileSystemManager::IsFile(path));
@@ -296,9 +290,8 @@ static void TestEmpty() noexcept {
// Split the empty object:
auto pack_1 = kIsTree ? cas.SplitTree(digest) : cas.SplitBlob(digest);
- auto* split = std::get_if<std::vector<bazel_re::Digest>>(&pack_1);
- CHECK(split);
- CHECK(split->empty());
+ CHECK(pack_1);
+ CHECK(pack_1->empty());
// Test that there is no large entry in the storage:
// To ensure there is no split of the initial object, it is removed:
@@ -307,9 +300,8 @@ static void TestEmpty() noexcept {
// Split must not find the large entry:
auto pack_2 = kIsTree ? cas.SplitTree(digest) : cas.SplitBlob(digest);
- auto* error_2 = std::get_if<LargeObjectError>(&pack_2);
- CHECK(error_2);
- CHECK(error_2->Code() == LargeObjectErrorCode::FileNotFound);
+ CHECK_FALSE(pack_2);
+ CHECK(pack_2.error().Code() == LargeObjectErrorCode::FileNotFound);
// There must be no spliced file:
CHECK_FALSE(FileSystemManager::IsFile(path));
@@ -347,15 +339,14 @@ static void TestExternal() noexcept {
// Split the object:
auto pack_1 = kIsTree ? cas.SplitTree(digest) : cas.SplitBlob(digest);
- auto* split = std::get_if<std::vector<bazel_re::Digest>>(&pack_1);
- CHECK(split);
- CHECK(split->size() > 1);
+ CHECK(pack_1);
+ CHECK(pack_1->size() > 1);
// External source is emulated by moving the large entry to an older
// generation and promoting the parts of the entry to the youngest
// generation:
REQUIRE(GarbageCollector::TriggerGarbageCollection());
- for (auto const& part : *split) {
+ for (auto const& part : *pack_1) {
static constexpr bool is_executable = false;
REQUIRE(cas.BlobPath(part, is_executable));
}
@@ -373,8 +364,8 @@ static void TestExternal() noexcept {
// Reconstruct the result from parts:
std::ignore = kIsTree
- ? youngest.SpliceTree(digest, *split)
- : youngest.SpliceBlob(digest, *split, kIsExec);
+ ? youngest.SpliceTree(digest, *pack_1)
+ : youngest.SpliceBlob(digest, *pack_1, kIsExec);
CHECK(FileSystemManager::IsFile(path));
}
@@ -400,11 +391,10 @@ static void TestExternal() noexcept {
// Invalidation is simulated by reconstructing the small_digest
// object from the parts of the initial object:
auto splice =
- kIsTree ? youngest.SpliceTree(small_digest, *split)
- : youngest.SpliceBlob(small_digest, *split, kIsExec);
- auto* error = std::get_if<LargeObjectError>(&splice);
- REQUIRE(error);
- CHECK(error->Code() == LargeObjectErrorCode::InvalidResult);
+ kIsTree ? youngest.SpliceTree(small_digest, *pack_1)
+ : youngest.SpliceBlob(small_digest, *pack_1, kIsExec);
+ REQUIRE_FALSE(splice);
+ CHECK(splice.error().Code() == LargeObjectErrorCode::InvalidResult);
// The initial entry must not be affected:
REQUIRE(FileSystemManager::IsFile(path));
@@ -413,10 +403,10 @@ static void TestExternal() noexcept {
if constexpr (kIsTree) {
SECTION("Tree invariants check fails") {
// Check splice fails due to the tree invariants check.
- auto splice = youngest.SpliceTree(digest, *split);
- auto* error = std::get_if<LargeObjectError>(&splice);
- REQUIRE(error);
- CHECK(error->Code() == LargeObjectErrorCode::InvalidTree);
+ auto splice = youngest.SpliceTree(digest, *pack_1);
+ REQUIRE_FALSE(splice);
+ CHECK(splice.error().Code() ==
+ LargeObjectErrorCode::InvalidTree);
}
}
}
@@ -444,7 +434,7 @@ static void TestCompactification() {
REQUIRE(object);
auto& [digest, path] = *object;
auto result = kIsTree ? cas.SplitTree(digest) : cas.SplitBlob(digest);
- REQUIRE(std::get_if<std::vector<bazel_re::Digest>>(&result) != nullptr);
+ REQUIRE(result);
// For trees the size must be increased to exceed the internal
// compactification threshold:
@@ -575,13 +565,13 @@ TEST_CASE_METHOD(HermeticLocalTestFixture,
// Split large entries:
auto split_nested_tree = cas.SplitTree(*nested_tree_digest);
- REQUIRE(std::get_if<std::vector<bazel_re::Digest>>(&split_nested_tree));
+ REQUIRE(split_nested_tree);
auto split_nested_blob = cas.SplitBlob(*nested_blob_digest);
- REQUIRE(std::get_if<std::vector<bazel_re::Digest>>(&split_nested_blob));
+ REQUIRE(split_nested_blob);
auto split_large_tree = cas.SplitTree(*large_tree_digest);
- REQUIRE(std::get_if<std::vector<bazel_re::Digest>>(&split_large_tree));
+ REQUIRE(split_large_tree);
// Remove the spliced results:
REQUIRE(FileSystemManager::RemoveFile(*nested_tree_path));
@@ -607,10 +597,10 @@ TEST_CASE_METHOD(HermeticLocalTestFixture,
// However, they might be reconstructed on request because there entries are
// in the latest generation:
auto split_nested_tree_2 = latest_cas.SplitTree(*nested_tree_digest);
- REQUIRE_FALSE(std::get_if<LargeObjectError>(&split_nested_tree_2));
+ REQUIRE(split_nested_tree_2);
auto split_nested_blob_2 = latest_cas.SplitBlob(*nested_blob_digest);
- REQUIRE_FALSE(std::get_if<LargeObjectError>(&split_nested_blob_2));
+ REQUIRE(split_nested_blob_2);
// Check there are no spliced results in old generations:
for (std::size_t i = 1; i < StorageConfig::NumGenerations(); ++i) {