Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions llvm/include/llvm/CAS/CASActionCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//===- llvm/CAS/CASActionCache.h --------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CAS_CASACTIONCACHE_H
#define LLVM_CAS_CASACTIONCACHE_H

#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CAS/CASCacheKey.h"
#include "llvm/CAS/CASReference.h"
#include "llvm/Support/Error.h"
#include <cstddef>

namespace llvm {
namespace cas {

class CASDB;

/// A cache from a key describing an action to the result of doing it.
///
/// Actions are expected to be pure (write-once, collision is an error).
class ActionCache {
protected:
virtual void anchor();

public:
/// Get a previously computed result for \p ActionKey.
Optional<ObjectRef> get(const CacheKey &ActionKey) const {
SmallVector<char, 32> Storage;
return getImpl(resolveKey(ActionKey));
}

/// Cache \p Result for the \p ActionKey computation.
Error put(const CacheKey &ActionKey, const ObjectRef &Result) {
SmallVector<char, 32> Storage;
return putImpl(resolveKey(ActionKey), Result);
}

/// Poison the cache for \p ActionKey.
Error poison(const CacheKey &ActionKey) {
SmallVector<char, 32> Storage;
return poisonImpl(resolveKey(ActionKey));
}

/// Get or compute a result for \p ActionKey. Equivalent to calling \a get()
/// (followed by \a compute() and \a put() on failure), but avoids calling \a
/// resolveKey() twice.
Expected<ObjectRef> getOrCompute(
const CacheKey &ActionKey,
function_ref<Expected<ObjectRef> ()> Compute);

CASDB &getCAS() const { return CAS; }

protected:
/// Convert \p ActionKey to internal key, using \p Storage if necessary for
/// storage. Default implementation uses CacheKey's string representation
/// directly.
virtual ArrayRef<uint8_t> resolveKey(const CacheKey &ActionKey,
SmallVectorImpl<char> &Storage) const;

virtual Optional<ObjectRef> getImpl(ArrayRef<uint8_t> ResolvedKey) const = 0;
virtual Error putImpl(ArrayRef<uint8_t> ResolvedKey, const ObjectRef &Result) = 0;
virtual Error poisonImpl(ArrayRef<uint8_t> ResolvedKey) = 0;

ActionCache(CASDB &CAS) : CAS(CAS) {}

private:
CASDB &CAS;
};

} // end namespace cas
} // end namespace llvm

#endif // LLVM_CAS_CASACTIONCACHE_H
78 changes: 78 additions & 0 deletions llvm/include/llvm/CAS/CASActionCaches.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//===- llvm/CAS/CASActionCaches.h -------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CAS_CASACTIONCACHES_H
#define LLVM_CAS_CASACTIONCACHES_H

#include "llvm/CAS/CASActionCache.h"
#include "llvm/CAS/CASID.h"

namespace llvm {
namespace cas {

/// Create an action cache in memory.
std::unique_ptr<ActionCache> createInMemoryActionCache(CASDB &CAS);

/// Abstract string-based map.
class AbstractStringMap {
public:
virtual Error put(StringRef Key, StringRef Value);

/// Return \c true on missing.
virtual bool get(StringRef Key, raw_ostream &ValueOS);
};

/// Adapts an abstract StringMap to an ActionCache, storing the result as the
/// ObjectID of the cache.
class StringMapActionCacheAdaptor : public ActionCache {
public:
ArrayRef<uint8_t> resolveKey(const CacheKey &ActionKey,
SmallVectorImpl<char> &Storage) const override;

/// Put mapping from \p ActionKey to \p Result. Calls \a CASDB::getObjectID()
/// and then \a putID(). Does not store the content of \p Result.
Error putImpl(ArrayRef<uint8_t> ActionKey, const ObjectRef &Result) override;

/// Put mapping from \p ActionKey to \p Result.
Optional<CASID> putID(ArrayRef<uint8_t> ActionKey, const CASID &Result);

/// Get mapped result for \a ActionKey. Calls \a getID() and then \a
/// CASDB::getReference().
Optional<ObjectRef> getImpl(ArrayRef<uint8_t> ActionKey) const override;

/// Get the ID for the result of \p ActionKey.
Optional<CASID> getID(ArrayRef<uint8_t> ActionKey) const;

AbstractStringMap &getMap() const { return Map; };

private:
AbstractStringMap &Map;
};

/// Adapts an abstract StringMap to an ActionCache, storing the result as the
/// ObjectID of the cache. This also caches the content of objects themselves.
class StringMapActionCacheAdaptorWithObjectStorage : public ActionCache {
public:
/// Put mapping from \p ActionKey to \p Result, also storing the transitive
/// content of \p Result in the map.
Error put(const CacheKey &ActionKey, const ObjectRef &Result) override;

/// Get mapped result for \a ActionKey. Stores the transitive content of the
/// result in the CAS as well.
Optional<ObjectRef> get(const CacheKey &ActionKey) const override;

AbstractStringMap &getMap() const { return UnderlyingAdaptor.getMap(); };

private:
StringMapActionCacheAdaptor UnderlyingAdaptor;
};

} // end namespace cas
} // end namespace llvm

#endif // LLVM_CAS_CASACTIONCACHES_H
101 changes: 101 additions & 0 deletions llvm/include/llvm/CAS/CASCacheKey.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//===- llvm/CAS/CASCacheKey.h -----------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CAS_CASCACHEKEY_H
#define LLVM_CAS_CASCACHEKEY_H

#include "llvm/ADT/Optional.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CAS/CASID.h"
#include "llvm/CAS/CASReference.h"
#include "llvm/CAS/TreeEntry.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h" // FIXME: Split out sys::fs::file_status.
#include <cstddef>

namespace llvm {
namespace cas {

/// A key for caching an operation. Use \a CacheKeyBuilder to create one.
///
/// The key optionally embeds an internal hash, along with a hash schema
/// identifier to catch misuses.
class CacheKey {
public:
StringRef getKey() const { return Key; }

/// Get an already computed hash of the key for \p Schema, if any.
Optional<ArrayRef<uint8_t>> getHashedKey(StringRef Schema) const {
if (Hashed && Hashed->Schema == Schema)
return arrayRefFromStringRef(Hashed->KeyHash);
return None;
}

/// Hash and return the key for \p Schema, or use the stored one if it
/// already exists.
ArrayRef<uint8_t> hashKey(
StringRef Schema,
function_ref<void (StringRef Key, SmallVectorImpl<uint8_t> &Hash)> Hasher) {
if (Optional<ArrayRef<uint8_t>> HashedKey = getHashedKey(Schema))
return HashedKey;

SmallVector<uint8_t> Hash;
Hasher(Key, Hasher);
HashedKey.emplace(HashedKeyT{toStringRef(Hash).str(), Schema.str()});
return arrayRefFromStringRef(HashedKey->Hash);
}

explicit CacheKey(const Twine &Key) : Key(Key.str()) {}

private:
struct HashedKeyT {
std::string Hash;
std::string Schema;
};

std::string Key;
Optional<HashedKeyT> HashedKey;
};

class CASDB;

/// A builder for a cache key.
class CacheKeyBuilder {
public:
CacheKeyBuilder &add(const Twine &Twine, Optional<StringRef> Name = None) {
if (Name)
Elements.push_back(Twine(*Name));
Elements.push_back(Twine);
}
CacheKeyBuilder &add(ObjectRef Object, Optional<StringRef> Name = None) {
if (Name)
Elements.push_back(Twine(*Name));
Elements.push_back(Object);
}
CacheKey build(CASDB &CAS);

explicit CacheKeyBuilder(Optional<StringRef> KeyName = None) {
if (KeyName)
Elements.push_back(Twine(*KeyName));
}

private:
struct CacheKeyElement {
Optional<std::string> Bytes;
Optional<ObjectRef> Object;
CacheKeyElement(const Twine &String) : Bytes(String.str()) {}
CacheKeyElement(const ObjectRef &Object) : Object(Object) {}
};
SmallVector<CacheKeyElement> Elements;
BumpPtrAllocator Alloc;
};

} // end namespace cas
} // end namespace llvm

#endif // LLVM_CAS_CASCACHEKEY_H
1 change: 0 additions & 1 deletion llvm/include/llvm/CAS/CASDB.h
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ class CASDB : public CASIDContext {
///
/// Errors if the object cannot be loaded.
virtual Expected<AnyObjectHandle> loadObject(ObjectRef Ref) = 0;

/// Load the object called \p ID.
///
/// Returns \c None if it's unknown in this CAS instance.
Expand Down
35 changes: 35 additions & 0 deletions llvm/lib/CAS/CASActionCache.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//===- CASActionCache.cpp ---------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm/CAS/CASActionCache.h"

using namespace llvm;
using namespace llvm::cas;

void CASActionCache::anchor() {}

ArrayRef<uint8_t> ActionCache::resolveKey(const CacheKey &ActionKey,
SmallVectorImpl<char> &Storage) const {
raw_svector_stream(Storage) << ActionKey;
return arrayRefFromStringRef(StringRef(Storage.begin(), Storage.size()));
}

Expected<ObjectRef> ActionCache::getOrCompute(
const CacheKey &ActionKey,
function_ref<Expected<ObjectRef> ()> Computation) {
SmallVector<char, 32> KeyStorage;
ArrayRef<uint8_t> ResolvedKey = resolveKey(ActionKey, KeyStorage);
if (Optional<ObjectRef> Result = getImpl(ResolvedKey))
return *Object;
Optional<ObjectRef> Result;
if (Error E = Computation().moveInto(Result))
return std::move(E);
if (Error E = putImpl(ResolvedKey, *Result))
return std::move(E);
return *Result;
}
Loading