diff options
Diffstat (limited to 'llvm/lib/CAS/ActionCaches.cpp')
| -rw-r--r-- | llvm/lib/CAS/ActionCaches.cpp | 166 | 
1 files changed, 166 insertions, 0 deletions
diff --git a/llvm/lib/CAS/ActionCaches.cpp b/llvm/lib/CAS/ActionCaches.cpp index 571c5b3..003c850 100644 --- a/llvm/lib/CAS/ActionCaches.cpp +++ b/llvm/lib/CAS/ActionCaches.cpp @@ -13,7 +13,11 @@  #include "BuiltinCAS.h"  #include "llvm/ADT/TrieRawHashMap.h"  #include "llvm/CAS/ActionCache.h" +#include "llvm/CAS/OnDiskKeyValueDB.h" +#include "llvm/CAS/UnifiedOnDiskCache.h" +#include "llvm/Config/llvm-config.h"  #include "llvm/Support/BLAKE3.h" +#include "llvm/Support/Errc.h"  #define DEBUG_TYPE "cas-action-caches" @@ -47,12 +51,54 @@ public:    Expected<std::optional<CASID>> getImpl(ArrayRef<uint8_t> ActionKey,                                           bool CanBeDistributed) const final; +  Error validate() const final { +    return createStringError("InMemoryActionCache doesn't support validate()"); +  } +  private:    using DataT = CacheEntry<sizeof(HashType)>;    using InMemoryCacheT = ThreadSafeTrieRawHashMap<DataT, sizeof(HashType)>;    InMemoryCacheT Cache;  }; + +/// Builtin basic OnDiskActionCache that uses one underlying OnDiskKeyValueDB. +class OnDiskActionCache final : public ActionCache { +public: +  Error putImpl(ArrayRef<uint8_t> ActionKey, const CASID &Result, +                bool CanBeDistributed) final; +  Expected<std::optional<CASID>> getImpl(ArrayRef<uint8_t> ActionKey, +                                         bool CanBeDistributed) const final; + +  static Expected<std::unique_ptr<OnDiskActionCache>> create(StringRef Path); + +  Error validate() const final; + +private: +  static StringRef getHashName() { return "BLAKE3"; } + +  OnDiskActionCache(std::unique_ptr<ondisk::OnDiskKeyValueDB> DB); + +  std::unique_ptr<ondisk::OnDiskKeyValueDB> DB; +  using DataT = CacheEntry<sizeof(HashType)>; +}; + +/// Builtin unified ActionCache that wraps around UnifiedOnDiskCache to provide +/// access to its ActionCache. +class UnifiedOnDiskActionCache final : public ActionCache { +public: +  Error putImpl(ArrayRef<uint8_t> ActionKey, const CASID &Result, +                bool CanBeDistributed) final; +  Expected<std::optional<CASID>> getImpl(ArrayRef<uint8_t> ActionKey, +                                         bool CanBeDistributed) const final; + +  UnifiedOnDiskActionCache(std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB); + +  Error validate() const final; + +private: +  std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB; +};  } // end namespace  static Error createResultCachePoisonedError(ArrayRef<uint8_t> KeyHash, @@ -99,3 +145,123 @@ std::unique_ptr<ActionCache> createInMemoryActionCache() {  }  } // namespace llvm::cas + +OnDiskActionCache::OnDiskActionCache( +    std::unique_ptr<ondisk::OnDiskKeyValueDB> DB) +    : ActionCache(builtin::BuiltinCASContext::getDefaultContext()), +      DB(std::move(DB)) {} + +Expected<std::unique_ptr<OnDiskActionCache>> +OnDiskActionCache::create(StringRef AbsPath) { +  std::unique_ptr<ondisk::OnDiskKeyValueDB> DB; +  if (Error E = ondisk::OnDiskKeyValueDB::open(AbsPath, getHashName(), +                                               sizeof(HashType), getHashName(), +                                               sizeof(DataT)) +                    .moveInto(DB)) +    return std::move(E); +  return std::unique_ptr<OnDiskActionCache>( +      new OnDiskActionCache(std::move(DB))); +} + +Expected<std::optional<CASID>> +OnDiskActionCache::getImpl(ArrayRef<uint8_t> Key, +                           bool /*CanBeDistributed*/) const { +  std::optional<ArrayRef<char>> Val; +  if (Error E = DB->get(Key).moveInto(Val)) +    return std::move(E); +  if (!Val) +    return std::nullopt; +  return CASID::create(&getContext(), toStringRef(*Val)); +} + +Error OnDiskActionCache::putImpl(ArrayRef<uint8_t> Key, const CASID &Result, +                                 bool /*CanBeDistributed*/) { +  auto ResultHash = Result.getHash(); +  ArrayRef Expected((const char *)ResultHash.data(), ResultHash.size()); +  ArrayRef<char> Observed; +  if (Error E = DB->put(Key, Expected).moveInto(Observed)) +    return E; + +  if (Expected == Observed) +    return Error::success(); + +  return createResultCachePoisonedError( +      Key, getContext(), Result, +      ArrayRef((const uint8_t *)Observed.data(), Observed.size())); +} + +Error OnDiskActionCache::validate() const { +  // FIXME: without the matching CAS there is nothing we can check about the +  // cached values. The hash size is already validated by the DB validator. +  return DB->validate(nullptr); +} + +UnifiedOnDiskActionCache::UnifiedOnDiskActionCache( +    std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB) +    : ActionCache(builtin::BuiltinCASContext::getDefaultContext()), +      UniDB(std::move(UniDB)) {} + +Expected<std::optional<CASID>> +UnifiedOnDiskActionCache::getImpl(ArrayRef<uint8_t> Key, +                                  bool /*CanBeDistributed*/) const { +  std::optional<ArrayRef<char>> Val; +  if (Error E = UniDB->getKeyValueDB().get(Key).moveInto(Val)) +    return std::move(E); +  if (!Val) +    return std::nullopt; +  auto ID = ondisk::UnifiedOnDiskCache::getObjectIDFromValue(*Val); +  return CASID::create(&getContext(), +                       toStringRef(UniDB->getGraphDB().getDigest(ID))); +} + +Error UnifiedOnDiskActionCache::putImpl(ArrayRef<uint8_t> Key, +                                        const CASID &Result, +                                        bool /*CanBeDistributed*/) { +  auto Expected = UniDB->getGraphDB().getReference(Result.getHash()); +  if (LLVM_UNLIKELY(!Expected)) +    return Expected.takeError(); + +  auto Value = ondisk::UnifiedOnDiskCache::getValueFromObjectID(*Expected); +  std::optional<ArrayRef<char>> Observed; +  if (Error E = UniDB->getKeyValueDB().put(Key, Value).moveInto(Observed)) +    return E; + +  auto ObservedID = ondisk::UnifiedOnDiskCache::getObjectIDFromValue(*Observed); +  if (*Expected == ObservedID) +    return Error::success(); + +  return createResultCachePoisonedError( +      Key, getContext(), Result, UniDB->getGraphDB().getDigest(ObservedID)); +} + +Error UnifiedOnDiskActionCache::validate() const { +  auto ValidateRef = [](FileOffset Offset, ArrayRef<char> Value) -> Error { +    auto ID = ondisk::UnifiedOnDiskCache::getObjectIDFromValue(Value); +    auto formatError = [&](Twine Msg) { +      return createStringError( +          llvm::errc::illegal_byte_sequence, +          "bad record at 0x" + +              utohexstr((unsigned)Offset.get(), /*LowerCase=*/true) + ": " + +              Msg.str()); +    }; +    if (ID.getOpaqueData() == 0) +      return formatError("zero is not a valid ref"); +    return Error::success(); +  }; +  return UniDB->getKeyValueDB().validate(ValidateRef); +} + +Expected<std::unique_ptr<ActionCache>> +cas::createOnDiskActionCache(StringRef Path) { +#if LLVM_ENABLE_ONDISK_CAS +  return OnDiskActionCache::create(Path); +#else +  return createStringError(inconvertibleErrorCode(), "OnDiskCache is disabled"); +#endif +} + +std::unique_ptr<ActionCache> +cas::builtin::createActionCacheFromUnifiedOnDiskCache( +    std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB) { +  return std::make_unique<UnifiedOnDiskActionCache>(std::move(UniDB)); +}  | 
