|
| 1 | +//===- llvm/CAS/ActionCache.h -----------------------------------*- C++ -*-===// |
| 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 | +#ifndef LLVM_CAS_CASACTIONCACHE_H |
| 10 | +#define LLVM_CAS_CASACTIONCACHE_H |
| 11 | + |
| 12 | +#include "llvm/ADT/FunctionExtras.h" |
| 13 | +#include "llvm/ADT/StringRef.h" |
| 14 | +#include "llvm/CAS/CASID.h" |
| 15 | +#include "llvm/CAS/CASReference.h" |
| 16 | +#include "llvm/Support/Error.h" |
| 17 | +#include <future> |
| 18 | + |
| 19 | +namespace llvm::cas { |
| 20 | + |
| 21 | +class ObjectStore; |
| 22 | +class CASID; |
| 23 | +class ObjectProxy; |
| 24 | + |
| 25 | +/// A key for caching an operation. |
| 26 | +/// It is implemented as a bag of bytes and provides a convenient constructor |
| 27 | +/// for CAS types. |
| 28 | +class CacheKey { |
| 29 | +public: |
| 30 | + StringRef getKey() const { return Key; } |
| 31 | + |
| 32 | + // TODO: Support CacheKey other than a CASID but rather any array of bytes. |
| 33 | + // To do that, ActionCache need to be able to rehash the key into the index, |
| 34 | + // which then `getOrCompute` method can be used to avoid multiple calls to |
| 35 | + // has function. |
| 36 | + CacheKey(const CASID &ID); |
| 37 | + CacheKey(const ObjectProxy &Proxy); |
| 38 | + CacheKey(const ObjectStore &CAS, const ObjectRef &Ref); |
| 39 | + |
| 40 | +private: |
| 41 | + std::string Key; |
| 42 | +}; |
| 43 | + |
| 44 | +using AsyncCASIDValue = AsyncValue<CASID>; |
| 45 | + |
| 46 | +/// This is used to workaround the issue of MSVC needing default-constructible |
| 47 | +/// types for \c std::promise/future. |
| 48 | +struct AsyncErrorValue { |
| 49 | + Error take() { return std::move(Value); } |
| 50 | + |
| 51 | + AsyncErrorValue() : Value(Error::success()) {} |
| 52 | + AsyncErrorValue(Error &&E) : Value(std::move(E)) {} |
| 53 | + |
| 54 | +private: |
| 55 | + Error Value; |
| 56 | +}; |
| 57 | + |
| 58 | +/// A cache from a key describing an action to the result of doing it. |
| 59 | +/// |
| 60 | +/// Actions are expected to be pure (collision is an error). |
| 61 | +class ActionCache { |
| 62 | + virtual void anchor(); |
| 63 | + |
| 64 | +public: |
| 65 | + /// Get a previously computed result for \p ActionKey. |
| 66 | + /// |
| 67 | + /// \param Globally if true it is a hint to the underlying implementation that |
| 68 | + /// the lookup is profitable to be done on a distributed caching level, not |
| 69 | + /// just locally. The implementation is free to ignore this flag. |
| 70 | + Expected<std::optional<CASID>> get(const CacheKey &ActionKey, |
| 71 | + bool Globally = false) const { |
| 72 | + return getImpl(arrayRefFromStringRef(ActionKey.getKey()), Globally); |
| 73 | + } |
| 74 | + |
| 75 | + /// Asynchronous version of \c get. |
| 76 | + std::future<AsyncCASIDValue> getFuture(const CacheKey &ActionKey, |
| 77 | + bool Globally = false) const; |
| 78 | + |
| 79 | + /// Asynchronous version of \c get. |
| 80 | + void getAsync( |
| 81 | + const CacheKey &ActionKey, bool Globally, |
| 82 | + unique_function<void(Expected<std::optional<CASID>>)> Callback) const { |
| 83 | + return getImplAsync(arrayRefFromStringRef(ActionKey.getKey()), Globally, |
| 84 | + std::move(Callback)); |
| 85 | + } |
| 86 | + |
| 87 | + /// Cache \p Result for the \p ActionKey computation. |
| 88 | + /// |
| 89 | + /// \param Globally if true it is a hint to the underlying implementation that |
| 90 | + /// the association is profitable to be done on a distributed caching level, |
| 91 | + /// not just locally. The implementation is free to ignore this flag. |
| 92 | + Error put(const CacheKey &ActionKey, const CASID &Result, |
| 93 | + bool Globally = false) { |
| 94 | + assert(Result.getContext().getHashSchemaIdentifier() == |
| 95 | + getContext().getHashSchemaIdentifier() && |
| 96 | + "Hash schema mismatch"); |
| 97 | + return putImpl(arrayRefFromStringRef(ActionKey.getKey()), Result, Globally); |
| 98 | + } |
| 99 | + |
| 100 | + /// Asynchronous version of \c put. |
| 101 | + std::future<AsyncErrorValue> putFuture(const CacheKey &ActionKey, |
| 102 | + const CASID &Result, |
| 103 | + bool Globally = false); |
| 104 | + |
| 105 | + /// Asynchronous version of \c put. |
| 106 | + void putAsync(const CacheKey &ActionKey, const CASID &Result, bool Globally, |
| 107 | + unique_function<void(Error)> Callback) { |
| 108 | + assert(Result.getContext().getHashSchemaIdentifier() == |
| 109 | + getContext().getHashSchemaIdentifier() && |
| 110 | + "Hash schema mismatch"); |
| 111 | + return putImplAsync(arrayRefFromStringRef(ActionKey.getKey()), Result, |
| 112 | + Globally, std::move(Callback)); |
| 113 | + } |
| 114 | + |
| 115 | + virtual ~ActionCache() = default; |
| 116 | + |
| 117 | +protected: |
| 118 | + virtual Expected<std::optional<CASID>> getImpl(ArrayRef<uint8_t> ResolvedKey, |
| 119 | + bool Globally) const = 0; |
| 120 | + virtual void getImplAsync( |
| 121 | + ArrayRef<uint8_t> ResolvedKey, bool Globally, |
| 122 | + unique_function<void(Expected<std::optional<CASID>>)> Callback) const; |
| 123 | + |
| 124 | + virtual Error putImpl(ArrayRef<uint8_t> ResolvedKey, const CASID &Result, |
| 125 | + bool Globally) = 0; |
| 126 | + virtual void putImplAsync(ArrayRef<uint8_t> ResolvedKey, const CASID &Result, |
| 127 | + bool Globally, |
| 128 | + unique_function<void(Error)> Callback); |
| 129 | + |
| 130 | + ActionCache(const CASContext &Context) : Context(Context) {} |
| 131 | + |
| 132 | + const CASContext &getContext() const { return Context; } |
| 133 | + |
| 134 | +private: |
| 135 | + const CASContext &Context; |
| 136 | +}; |
| 137 | + |
| 138 | +/// Create an action cache in memory. |
| 139 | +std::unique_ptr<ActionCache> createInMemoryActionCache(); |
| 140 | + |
| 141 | +/// Get a reasonable default on-disk path for a persistent ActionCache for the |
| 142 | +/// current user. |
| 143 | +std::string getDefaultOnDiskActionCachePath(); |
| 144 | + |
| 145 | +/// Create an action cache on disk. |
| 146 | +Expected<std::unique_ptr<ActionCache>> createOnDiskActionCache(StringRef Path); |
| 147 | +} // end namespace llvm::cas |
| 148 | + |
| 149 | +#endif // LLVM_CAS_CASACTIONCACHE_H |
0 commit comments