diff options
author | Oliver Reiche <oliver.reiche@huawei.com> | 2022-06-13 13:30:13 +0200 |
---|---|---|
committer | Oliver Reiche <oliver.reiche@huawei.com> | 2022-06-13 15:55:41 +0200 |
commit | a1c2e003f921cc4a04c5845ed18d75546a96fd88 (patch) | |
tree | 8c4682d797c0ede6bc2d156b931f6e3282fa68f4 /src | |
parent | 27c3ec0bcab188a43c50ba4be0632ab8410bb677 (diff) | |
download | justbuild-a1c2e003f921cc4a04c5845ed18d75546a96fd88.tar.gz |
TargetCache: Initial implementation
Diffstat (limited to 'src')
-rw-r--r-- | src/buildtool/build_engine/target_map/TARGETS | 16 | ||||
-rw-r--r-- | src/buildtool/build_engine/target_map/target_cache.cpp | 115 | ||||
-rw-r--r-- | src/buildtool/build_engine/target_map/target_cache.hpp | 111 | ||||
-rw-r--r-- | src/buildtool/execution_api/local/config.hpp | 6 |
4 files changed, 248 insertions, 0 deletions
diff --git a/src/buildtool/build_engine/target_map/TARGETS b/src/buildtool/build_engine/target_map/TARGETS index 3854039c..a4704623 100644 --- a/src/buildtool/build_engine/target_map/TARGETS +++ b/src/buildtool/build_engine/target_map/TARGETS @@ -35,6 +35,7 @@ , "deps": [ "configured_target" , "result_map" + , ["src/buildtool/common", "common"] , ["src/buildtool/build_engine/analysed_target", "target"] , ["src/buildtool/build_engine/base_maps", "entity_name"] , ["src/buildtool/build_engine/base_maps", "field_reader"] @@ -57,4 +58,19 @@ , "deps": ["target_map"] , "stage": ["src", "buildtool", "build_engine", "target_map"] } +, "target_cache": + { "type": ["@", "rules", "CC", "library"] + , "name": ["target_cache"] + , "hdrs": ["target_cache.hpp"] + , "srcs": ["target_cache.cpp"] + , "deps": + [ ["src/buildtool/build_engine/analysed_target", "target"] + , ["src/buildtool/build_engine/base_maps", "entity_name"] + , ["src/buildtool/execution_api/local", "local"] + , ["src/buildtool/execution_api/remote", "config"] + , ["src/buildtool/file_system", "file_root"] + , ["src/buildtool/logging", "logging"] + ] + , "stage": ["src", "buildtool", "build_engine", "target_map"] + } } diff --git a/src/buildtool/build_engine/target_map/target_cache.cpp b/src/buildtool/build_engine/target_map/target_cache.cpp new file mode 100644 index 00000000..aca14363 --- /dev/null +++ b/src/buildtool/build_engine/target_map/target_cache.cpp @@ -0,0 +1,115 @@ +#include "src/buildtool/build_engine/target_map/target_cache.hpp" + +#include "src/buildtool/common/repository_config.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/execution_api/remote/config.hpp" +#include "src/buildtool/file_system/file_system_manager.hpp" +#include "src/buildtool/logging/logger.hpp" + +auto TargetCache::Key::Create(BuildMaps::Base::EntityName const& target, + Configuration const& effective_config) noexcept + -> std::optional<TargetCache::Key> { + static auto const& repos = RepositoryConfig::Instance(); + try { + if (auto repo_key = + repos.RepositoryKey(target.GetNamedTarget().repository)) { + // target's repository is content-fixed, we can compute a cache key + auto target_desc = nlohmann::json{ + {{"repo_key", *repo_key}, + {"target_name", target.ToString()}, + {"effective_config", effective_config.ToString()}}}; + static auto const& cas = LocalCAS<ObjectType::File>::Instance(); + if (auto target_key = cas.StoreBlobFromBytes(target_desc.dump(2))) { + return Key{ + {ArtifactDigest{std::move(*target_key)}, ObjectType::File}}; + } + } + } catch (std::exception const& ex) { + Logger::Log(LogLevel::Error, + "Creating target cache key failed with:\n{}", + ex.what()); + } + return std::nullopt; +} + +auto TargetCache::Entry::FromTarget( + AnalysedTargetPtr const& target, + std::unordered_map<ArtifactDescription, Artifact::ObjectInfo> const& + replacements) noexcept -> std::optional<TargetCache::Entry> { + auto result = TargetResult{ + target->Artifacts(), target->Provides(), target->RunFiles()}; + if (auto desc = result.ReplaceNonKnownAndToJson(replacements)) { + return Entry{*desc}; + } + return std::nullopt; +} + +auto TargetCache::Entry::ToResult() const -> std::optional<TargetResult> { + return TargetResult::FromJson(desc_); +} + +auto TargetCache::Store(Key const& key, Entry const& value) const noexcept + -> bool { + if (auto digest = CAS().StoreBlobFromBytes(value.ToJson().dump(2))) { + auto data = Artifact::ObjectInfo{ArtifactDigest{std::move(*digest)}, + ObjectType::File} + .ToString(); + logger_.Emit(LogLevel::Debug, + "Adding entry for key {} as {}", + key.Id().ToString(), + data); + return file_store_.AddFromBytes(key.Id().digest.hash(), data); + } + return false; +} + +auto TargetCache::Read(Key const& key) const noexcept + -> std::optional<std::pair<Entry, Artifact::ObjectInfo>> { + auto entry_path = file_store_.GetPath(key.Id().digest.hash()); + 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 (auto info = Artifact::ObjectInfo::FromString(*entry)) { + if (auto path = CAS().BlobPath(info->digest)) { + if (auto value = FileSystemManager::ReadFile(*path)) { + try { + return std::make_pair(Entry{nlohmann::json::parse(*value)}, + std::move(*info)); + } catch (std::exception const& ex) { + logger_.Emit(LogLevel::Warning, + "Parsing entry for key {} failed with:\n{}", + key.Id().ToString(), + ex.what()); + } + } + } + } + logger_.Emit(LogLevel::Warning, + "Reading entry for key {} failed", + key.Id().ToString()); + return std::nullopt; +} + +auto TargetCache::ComputeCacheDir() -> std::filesystem::path { + return LocalExecutionConfig::TargetCacheDir() / ExecutionBackendId(); +} + +auto TargetCache::ExecutionBackendId() -> std::string { + auto address = RemoteExecutionConfig::RemoteAddress(); + auto properties = RemoteExecutionConfig::PlatformProperties(); + auto backend_desc = nlohmann::json{ + {"remote_address", + address ? nlohmann::json{fmt::format( + "{}:{}", address->host, address->port)} + : nlohmann::json{}}, + {"platform_properties", + properties}}.dump(2); + return CAS().StoreBlobFromBytes(backend_desc).value().hash(); +} diff --git a/src/buildtool/build_engine/target_map/target_cache.hpp b/src/buildtool/build_engine/target_map/target_cache.hpp new file mode 100644 index 00000000..eb31b831 --- /dev/null +++ b/src/buildtool/build_engine/target_map/target_cache.hpp @@ -0,0 +1,111 @@ +#ifndef INCLUDED_SRC_BUILDTOOL_BUILD_ENGINE_TARGET_MAP_TARGET_CACHE_HPP +#define INCLUDED_SRC_BUILDTOOL_BUILD_ENGINE_TARGET_MAP_TARGET_CACHE_HPP + +#include <unordered_map> + +#include <nlohmann/json.hpp> + +#include "src/buildtool/build_engine/analysed_target/analysed_target.hpp" +#include "src/buildtool/build_engine/base_maps/entity_name.hpp" +#include "src/buildtool/common/artifact.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 TargetCache { + public: + // Key for target cache. Created from target name and effective config. + class Key { + public: + [[nodiscard]] static auto Create( + BuildMaps::Base::EntityName const& target, + Configuration const& effective_config) noexcept + -> std::optional<Key>; + + [[nodiscard]] auto Id() const& -> Artifact::ObjectInfo const& { + return id_; + } + [[nodiscard]] auto Id() && -> Artifact::ObjectInfo { + return std::move(id_); + } + [[nodiscard]] auto operator==(Key const& other) const -> bool { + return this->Id() == other.Id(); + } + + private: + explicit Key(Artifact::ObjectInfo id) : id_{std::move(id)} {} + Artifact::ObjectInfo id_; + }; + + // Entry for target cache. Created from target, contains TargetResult. + class Entry { + friend class TargetCache; + + public: + // Create the entry from target with replacement artifacts/infos. + // Replacement artifacts must replace all non-known artifacts by known. + [[nodiscard]] static auto FromTarget( + AnalysedTargetPtr const& target, + std::unordered_map<ArtifactDescription, Artifact::ObjectInfo> const& + replacements) noexcept -> std::optional<Entry>; + + // Obtain TargetResult from cache entry. + [[nodiscard]] auto ToResult() const -> std::optional<TargetResult>; + + private: + nlohmann::json desc_; + + explicit Entry(nlohmann::json desc) : desc_{std::move(desc)} {} + [[nodiscard]] auto ToJson() const& -> nlohmann::json const& { + return desc_; + } + [[nodiscard]] auto ToJson() && -> nlohmann::json { + return std::move(desc_); + } + }; + + TargetCache() = default; + TargetCache(TargetCache const&) = delete; + TargetCache(TargetCache&&) = delete; + auto operator=(TargetCache const&) -> TargetCache& = delete; + auto operator=(TargetCache&&) -> TargetCache& = delete; + ~TargetCache() noexcept = default; + + [[nodiscard]] static auto Instance() -> TargetCache& { + static TargetCache instance; + return instance; + } + + // Store new key entry pair in the target cache. + [[nodiscard]] auto Store(Key const& key, Entry const& value) const noexcept + -> bool; + + // Read existing entry and object info for given key from the target cache. + [[nodiscard]] auto Read(Key const& key) const noexcept + -> std::optional<std::pair<Entry, Artifact::ObjectInfo>>; + + private: + Logger logger_{"TargetCache"}; + FileStorage<ObjectType::File, + StoreMode::LastWins, + /*kSetEpochTime=*/false> + file_store_{ComputeCacheDir()}; + + [[nodiscard]] static auto CAS() noexcept -> LocalCAS<ObjectType::File>& { + return LocalCAS<ObjectType::File>::Instance(); + } + [[nodiscard]] static auto ComputeCacheDir() -> std::filesystem::path; + [[nodiscard]] static auto ExecutionBackendId() -> std::string; +}; + +namespace std { +template <> +struct hash<TargetCache::Key> { + [[nodiscard]] auto operator()(TargetCache::Key const& k) const { + return std::hash<Artifact::ObjectInfo>{}(k.Id()); + } +}; +} // namespace std + +#endif // INCLUDED_SRC_BUILDTOOL_BUILD_ENGINE_TARGET_MAP_TARGET_CACHE_HPP diff --git a/src/buildtool/execution_api/local/config.hpp b/src/buildtool/execution_api/local/config.hpp index 2dc4466b..5ce8b9ef 100644 --- a/src/buildtool/execution_api/local/config.hpp +++ b/src/buildtool/execution_api/local/config.hpp @@ -123,6 +123,12 @@ class LocalExecutionConfig { return CacheRoot() / "ac"; } + /// \brief Target cache directory + [[nodiscard]] static auto TargetCacheDir() noexcept + -> std::filesystem::path { + return CacheRoot() / "tc"; + } + [[nodiscard]] static auto GetLauncher() noexcept -> std::vector<std::string> { return Data().launcher; |