LLVM 22.0.0git
ActionCaches.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file This file implements the underlying ActionCache implementations.
10///
11//===----------------------------------------------------------------------===//
12
13#include "BuiltinCAS.h"
18#include "llvm/Config/llvm-config.h"
19#include "llvm/Support/BLAKE3.h"
20#include "llvm/Support/Errc.h"
21
22#define DEBUG_TYPE "cas-action-caches"
23
24using namespace llvm;
25using namespace llvm::cas;
26
27namespace {
28
29using HasherT = BLAKE3;
30using HashType = decltype(HasherT::hash(std::declval<ArrayRef<uint8_t> &>()));
31
32template <size_t Size> class CacheEntry {
33public:
34 CacheEntry() = default;
35 CacheEntry(ArrayRef<uint8_t> Hash) { llvm::copy(Hash, Value.data()); }
36 CacheEntry(const CacheEntry &Entry) { llvm::copy(Entry.Value, Value.data()); }
37 ArrayRef<uint8_t> getValue() const { return Value; }
38
39private:
40 std::array<uint8_t, Size> Value;
41};
42
43/// Builtin InMemory ActionCache that stores the mapping in memory.
44class InMemoryActionCache final : public ActionCache {
45public:
46 InMemoryActionCache()
48
49 Error putImpl(ArrayRef<uint8_t> ActionKey, const CASID &Result,
50 bool CanBeDistributed) final;
52 bool CanBeDistributed) const final;
53
54 Error validate() const final {
55 return createStringError("InMemoryActionCache doesn't support validate()");
56 }
57
58private:
59 using DataT = CacheEntry<sizeof(HashType)>;
60 using InMemoryCacheT = ThreadSafeTrieRawHashMap<DataT, sizeof(HashType)>;
61
62 InMemoryCacheT Cache;
63};
64
65/// Builtin basic OnDiskActionCache that uses one underlying OnDiskKeyValueDB.
66class OnDiskActionCache final : public ActionCache {
67public:
68 Error putImpl(ArrayRef<uint8_t> ActionKey, const CASID &Result,
69 bool CanBeDistributed) final;
71 bool CanBeDistributed) const final;
72
74
75 Error validate() const final;
76
77private:
78 static StringRef getHashName() { return "BLAKE3"; }
79
80 OnDiskActionCache(std::unique_ptr<ondisk::OnDiskKeyValueDB> DB);
81
82 std::unique_ptr<ondisk::OnDiskKeyValueDB> DB;
83 using DataT = CacheEntry<sizeof(HashType)>;
84};
85
86/// Builtin unified ActionCache that wraps around UnifiedOnDiskCache to provide
87/// access to its ActionCache.
88class UnifiedOnDiskActionCache final : public ActionCache {
89public:
90 Error putImpl(ArrayRef<uint8_t> ActionKey, const CASID &Result,
91 bool CanBeDistributed) final;
93 bool CanBeDistributed) const final;
94
95 UnifiedOnDiskActionCache(std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB);
96
97 Error validate() const final;
98
99private:
100 std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB;
101};
102} // end namespace
103
105 const CASContext &Context,
106 CASID Output,
107 ArrayRef<uint8_t> ExistingOutput) {
108 std::string Existing =
109 CASID::create(&Context, toStringRef(ExistingOutput)).toString();
111 toHex(KeyHash, /*LowerCase=*/true, Key);
112 return createStringError(std::make_error_code(std::errc::invalid_argument),
113 "cache poisoned for '" + Key + "' (new='" +
114 Output.toString() + "' vs. existing '" +
115 Existing + "')");
116}
117
119InMemoryActionCache::getImpl(ArrayRef<uint8_t> Key,
120 bool /*CanBeDistributed*/) const {
121 auto Result = Cache.find(Key);
122 if (!Result)
123 return std::nullopt;
124 return CASID::create(&getContext(), toStringRef(Result->Data.getValue()));
125}
126
127Error InMemoryActionCache::putImpl(ArrayRef<uint8_t> Key, const CASID &Result,
128 bool /*CanBeDistributed*/) {
129 DataT Expected(Result.getHash());
130 const InMemoryCacheT::value_type &Cached = *Cache.insertLazy(
131 Key, [&](auto ValueConstructor) { ValueConstructor.emplace(Expected); });
132
133 const DataT &Observed = Cached.Data;
134 if (Expected.getValue() == Observed.getValue())
135 return Error::success();
136
138 Observed.getValue());
139}
140
141namespace llvm::cas {
142
143std::unique_ptr<ActionCache> createInMemoryActionCache() {
144 return std::make_unique<InMemoryActionCache>();
145}
146
147} // namespace llvm::cas
148
149OnDiskActionCache::OnDiskActionCache(
150 std::unique_ptr<ondisk::OnDiskKeyValueDB> DB)
151 : ActionCache(builtin::BuiltinCASContext::getDefaultContext()),
152 DB(std::move(DB)) {}
153
155OnDiskActionCache::create(StringRef AbsPath) {
156 std::unique_ptr<ondisk::OnDiskKeyValueDB> DB;
157 if (Error E = ondisk::OnDiskKeyValueDB::open(AbsPath, getHashName(),
158 sizeof(HashType), getHashName(),
159 sizeof(DataT))
160 .moveInto(DB))
161 return std::move(E);
162 return std::unique_ptr<OnDiskActionCache>(
163 new OnDiskActionCache(std::move(DB)));
164}
165
167OnDiskActionCache::getImpl(ArrayRef<uint8_t> Key,
168 bool /*CanBeDistributed*/) const {
169 std::optional<ArrayRef<char>> Val;
170 if (Error E = DB->get(Key).moveInto(Val))
171 return std::move(E);
172 if (!Val)
173 return std::nullopt;
174 return CASID::create(&getContext(), toStringRef(*Val));
175}
176
177Error OnDiskActionCache::putImpl(ArrayRef<uint8_t> Key, const CASID &Result,
178 bool /*CanBeDistributed*/) {
179 auto ResultHash = Result.getHash();
180 ArrayRef Expected((const char *)ResultHash.data(), ResultHash.size());
181 ArrayRef<char> Observed;
182 if (Error E = DB->put(Key, Expected).moveInto(Observed))
183 return E;
184
185 if (Expected == Observed)
186 return Error::success();
187
189 Key, getContext(), Result,
190 ArrayRef((const uint8_t *)Observed.data(), Observed.size()));
191}
192
193Error OnDiskActionCache::validate() const {
194 // FIXME: without the matching CAS there is nothing we can check about the
195 // cached values. The hash size is already validated by the DB validator.
196 return DB->validate(nullptr);
197}
198
199UnifiedOnDiskActionCache::UnifiedOnDiskActionCache(
200 std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB)
201 : ActionCache(builtin::BuiltinCASContext::getDefaultContext()),
202 UniDB(std::move(UniDB)) {}
203
205UnifiedOnDiskActionCache::getImpl(ArrayRef<uint8_t> Key,
206 bool /*CanBeDistributed*/) const {
207 std::optional<ArrayRef<char>> Val;
208 if (Error E = UniDB->getKeyValueDB().get(Key).moveInto(Val))
209 return std::move(E);
210 if (!Val)
211 return std::nullopt;
213 return CASID::create(&getContext(),
214 toStringRef(UniDB->getGraphDB().getDigest(ID)));
215}
216
217Error UnifiedOnDiskActionCache::putImpl(ArrayRef<uint8_t> Key,
218 const CASID &Result,
219 bool /*CanBeDistributed*/) {
220 auto Expected = UniDB->getGraphDB().getReference(Result.getHash());
222 return Expected.takeError();
223
225 std::optional<ArrayRef<char>> Observed;
226 if (Error E = UniDB->getKeyValueDB().put(Key, Value).moveInto(Observed))
227 return E;
228
229 auto ObservedID = ondisk::UnifiedOnDiskCache::getObjectIDFromValue(*Observed);
230 if (*Expected == ObservedID)
231 return Error::success();
232
234 Key, getContext(), Result, UniDB->getGraphDB().getDigest(ObservedID));
235}
236
237Error UnifiedOnDiskActionCache::validate() const {
238 auto ValidateRef = [](FileOffset Offset, ArrayRef<char> Value) -> Error {
240 auto formatError = [&](Twine Msg) {
241 return createStringError(
243 "bad record at 0x" +
244 utohexstr((unsigned)Offset.get(), /*LowerCase=*/true) + ": " +
245 Msg.str());
246 };
247 if (ID.getOpaqueData() == 0)
248 return formatError("zero is not a valid ref");
249 return Error::success();
250 };
251 return UniDB->getKeyValueDB().validate(ValidateRef);
252}
253
256#if LLVM_ENABLE_ONDISK_CAS
257 return OnDiskActionCache::create(Path);
258#else
259 return createStringError(inconvertibleErrorCode(), "OnDiskCache is disabled");
260#endif
261}
262
263std::unique_ptr<ActionCache>
265 std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB) {
266 return std::make_unique<UnifiedOnDiskActionCache>(std::move(UniDB));
267}
This file contains the declaration of the ActionCache class, which is the base class for ActionCache ...
static Error createResultCachePoisonedError(ArrayRef< uint8_t > KeyHash, const CASContext &Context, CASID Output, ArrayRef< uint8_t > ExistingOutput)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define LLVM_UNLIKELY(EXPR)
Definition Compiler.h:336
This declares OnDiskKeyValueDB, a key value storage database of fixed size key and value.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:41
size_t size() const
size - Get the array size.
Definition ArrayRef.h:143
const T * data() const
Definition ArrayRef.h:140
A class that wraps the BLAKE3 algorithm.
Definition BLAKE3.h:38
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
Lock-free thread-safe hash-mapped trie.
pointer find(ArrayRef< uint8_t > Hash)
pointer insertLazy(const_pointer Hint, ArrayRef< uint8_t > Hash, function_ref< void(LazyValueConstructor)> OnConstruct)
Insert with a hint.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
LLVM Value Representation.
Definition Value.h:75
A cache from a key (that describes an action) to the result of performing that action.
Definition ActionCache.h:49
Context for CAS identifiers.
Definition CASID.h:28
Unique identifier for a CAS object.
Definition CASID.h:58
std::string toString() const
Return a printable string for CASID.
static CASID create(const CASContext *Context, StringRef Hash)
Create CASID from CASContext and raw hash bytes.
Definition CASID.h:116
static const BuiltinCASContext & getDefaultContext()
static Expected< std::unique_ptr< OnDiskKeyValueDB > > open(StringRef Path, StringRef HashName, unsigned KeySize, StringRef ValueName, size_t ValueSize, UnifiedOnDiskCache *UnifiedCache=nullptr)
Open the on-disk store from a directory.
static ValueBytes getValueFromObjectID(ObjectID ID)
static ObjectID getObjectIDFromValue(ArrayRef< char > Value)
Helper function to convert the value stored in KeyValueDB and ObjectID.
LLVM_ABI sandboxir::Value * getValue(llvm::Value *V) const
Definition Context.cpp:629
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
std::unique_ptr< ActionCache > createActionCacheFromUnifiedOnDiskCache(std::shared_ptr< ondisk::UnifiedOnDiskCache > UniDB)
Expected< std::unique_ptr< ActionCache > > createOnDiskActionCache(StringRef Path)
Create an action cache on disk.
std::unique_ptr< ActionCache > createInMemoryActionCache()
Create an action cache in memory.
Context & getContext() const
Definition BasicBlock.h:99
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:477
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:98
std::string utohexstr(uint64_t X, bool LowerCase=false, unsigned Width=0)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1305
@ illegal_byte_sequence
Definition Errc.h:52
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt copy(R &&Range, OutputIt Out)
Definition STLExtras.h:1835
void toHex(ArrayRef< uint8_t > Input, bool LowerCase, SmallVectorImpl< char > &Output)
Convert buffer Input to its hexadecimal representation. The returned string is double the size of Inp...
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1867
StringRef toStringRef(bool B)
Construct a string ref from a boolean.
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:867