Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
WIP: CAS: Start adding an ActionCache
  • Loading branch information
dexonsmith committed May 13, 2022
commit 0e648b8f68a3d9ee73032809f1589a793da7bad7
78 changes: 78 additions & 0 deletions llvm/include/llvm/CAS/CASActionCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//===- 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/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 {

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.
virtual Optional<ObjectRef> get(const CacheKey &ActionKey) const = 0;

/// Cache \p Result for the \p ActionKey computation.
virtual Error put(const CacheKey &ActionKey, const ObjectRef &Result) = 0;

/// Poison the cache for \p ActionKey.
virtual Error poison(const CacheKey &ActionKey) = 0;

/// Get or compute a result for \p ActionKey. The default implementation
/// calls \a get(), and if not found calls \p Compute and \a put().
///
/// Overrides should match this basic pattern, but is free to optimize or
/// audit. For example, it might share an internal lookup of \p ActionKey
/// between \a get() and \a put(). Or, it might probabilistically call \p
/// Compute even after \a get() returns a result, calling \a poision() on a
/// mismatch.
virtual Expected<ObjectRef> getOrCompute(
const CacheKey &ActionKey,
function_ref<Expected<ObjectRef> ()> Compute);
};

/// Abstract string-based map.
class AbstractStringMap {
virtual Error store(StringRef Key, StringRef Value);
virtual Error poison(StringRef Key);
virtual Error get(StringRef Key, SmallVectorImpl<char> &Value);
};

/// Adapts an abstract StringMap to an ActionCache, storing the result as the
/// ObjectID of the cache.
class StringMapActionCacheAdaptor : public ActionCache {
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 StringMapActionCacheAdaptorWithStorage : public StringMapActionCacheAdaptor {
};


} // namespace cas
} // namespace llvm

#endif // LLVM_CAS_CASACTIONCACHE_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
27 changes: 27 additions & 0 deletions llvm/lib/CAS/CASActionCache.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===- 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() {}

virtual Expected<ObjectRef> CASActionCache::getOrCompute(
const CacheKey &ActionKey,
function_ref<Expected<ObjectRef> ()> Computation) {
if (Optional<ObjectRef> Result = get(ActionKey))
return *Object;
Optional<ObjectRef> Result;
if (Error E = Computation().moveInto(Result))
return std::move(E);
if (Error E = put(ActionKey, *Result))
return std::move(E);
return *Result;
}