summaryrefslogtreecommitdiff
path: root/src/buildtool/execution_api/local/local_ac.hpp
blob: f319940a8bf2326354f29e1c636ffca73977c700 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#ifndef INCLUDED_SRC_BUILDTOOL_EXECUTION_API_LOCAL_LOCAL_AC_HPP
#define INCLUDED_SRC_BUILDTOOL_EXECUTION_API_LOCAL_LOCAL_AC_HPP

#include "gsl-lite/gsl-lite.hpp"
#include "src/buildtool/common/bazel_types.hpp"
#include "src/buildtool/execution_api/common/execution_common.hpp"
#include "src/buildtool/execution_api/local/config.hpp"
#include "src/buildtool/execution_api/local/file_storage.hpp"
#include "src/buildtool/execution_api/local/local_cas.hpp"
#include "src/buildtool/file_system/file_system_manager.hpp"
#include "src/buildtool/logging/logger.hpp"

class LocalAC {
  public:
    explicit LocalAC(gsl::not_null<LocalCAS<ObjectType::File>*> cas) noexcept
        : cas_{std::move(cas)} {};

    LocalAC(gsl::not_null<LocalCAS<ObjectType::File>*> cas,
            std::filesystem::path cache_root) noexcept
        : cas_{std::move(cas)}, cache_root_{std::move(cache_root)} {}

    LocalAC(LocalAC const&) = delete;
    LocalAC(LocalAC&&) = delete;
    auto operator=(LocalAC const&) -> LocalAC& = delete;
    auto operator=(LocalAC &&) -> LocalAC& = delete;
    ~LocalAC() noexcept = default;

    [[nodiscard]] auto StoreResult(
        bazel_re::Digest const& action_id,
        bazel_re::ActionResult const& result) const noexcept -> bool {
        auto bytes = result.SerializeAsString();
        auto digest = cas_->StoreBlobFromBytes(bytes);
        return (digest and file_store_.AddFromBytes(
                               action_id.hash(), digest->SerializeAsString()));
    }

    [[nodiscard]] auto CachedResult(bazel_re::Digest const& action_id)
        const noexcept -> std::optional<bazel_re::ActionResult> {
        auto entry_path = file_store_.GetPath(action_id.hash());
        bazel_re::Digest digest{};
        auto const entry =
            FileSystemManager::ReadFile(entry_path, ObjectType::File);
        if (not entry.has_value()) {
            logger_.Emit(LogLevel::Debug,
                         "Cache miss, entry not found {}",
                         entry_path.string());
            return std::nullopt;
        }
        if (not digest.ParseFromString(*entry)) {
            logger_.Emit(LogLevel::Warning,
                         "Parsing cache entry failed failed for action {}",
                         action_id.hash());
            return std::nullopt;
        }
        auto src_path = cas_->BlobPath(digest);
        bazel_re::ActionResult result{};
        if (src_path) {
            auto const bytes = FileSystemManager::ReadFile(*src_path);
            if (bytes.has_value() and result.ParseFromString(*bytes)) {
                return result;
            }
        }
        logger_.Emit(LogLevel::Warning,
                     "Parsing action result failed for action {}",
                     action_id.hash());
        return std::nullopt;
    }

  private:
    // The action cache stores the results of failed actions. For those to be
    // overwritable by subsequent runs we need to choose the store mode "last
    // wins" for the underlying file storage.
    static constexpr auto kStoreMode = StoreMode::LastWins;

    Logger logger_{"LocalAC"};
    gsl::not_null<LocalCAS<ObjectType::File>*> cas_;
    std::filesystem::path const cache_root_{
        LocalExecutionConfig::GetCacheDir()};
    FileStorage<ObjectType::File, kStoreMode> file_store_{cache_root_ / "ac"};
};

#endif  // INCLUDED_SRC_BUILDTOOL_EXECUTION_API_LOCAL_LOCAL_AC_HPP