blob: e8d72c9faef44ded25011decf638cb5dbe61ccfb [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// 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 "BuiltinCAS.h"
#include "llvm/CAS/BuiltinCASContext.h"
#include "llvm/CAS/BuiltinObjectHasher.h"
#include "llvm/CAS/OnDiskGraphDB.h"
#include "llvm/CAS/UnifiedOnDiskCache.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
using namespace llvm;
using namespace llvm::cas;
using namespace llvm::cas::builtin;
namespace {
class OnDiskCAS : public BuiltinCAS {
public:
Expected<ObjectRef> storeImpl(ArrayRef<uint8_t> ComputedHash,
ArrayRef<ObjectRef> Refs,
ArrayRef<char> Data) final;
Expected<std::optional<ObjectHandle>> loadIfExists(ObjectRef Ref) final;
CASID getID(ObjectRef Ref) const final;
std::optional<ObjectRef> getReference(const CASID &ID) const final;
Expected<bool> isMaterialized(ObjectRef Ref) const final;
ArrayRef<char> getDataConst(ObjectHandle Node) const final;
void print(raw_ostream &OS) const final;
Error validate(bool CheckHash) const final;
static Expected<std::unique_ptr<OnDiskCAS>> open(StringRef Path);
OnDiskCAS(std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB)
: UnifiedDB(std::move(UniDB)), DB(&UnifiedDB->getGraphDB()) {}
private:
ObjectHandle convertHandle(ondisk::ObjectHandle Node) const {
return makeObjectHandle(Node.getOpaqueData());
}
ondisk::ObjectHandle convertHandle(ObjectHandle Node) const {
return ondisk::ObjectHandle(Node.getInternalRef(*this));
}
ObjectRef convertRef(ondisk::ObjectID Ref) const {
return makeObjectRef(Ref.getOpaqueData());
}
ondisk::ObjectID convertRef(ObjectRef Ref) const {
return ondisk::ObjectID::fromOpaqueData(Ref.getInternalRef(*this));
}
size_t getNumRefs(ObjectHandle Node) const final {
auto RefsRange = DB->getObjectRefs(convertHandle(Node));
return llvm::size(RefsRange);
}
ObjectRef readRef(ObjectHandle Node, size_t I) const final {
auto RefsRange = DB->getObjectRefs(convertHandle(Node));
return convertRef(RefsRange.begin()[I]);
}
Error forEachRef(ObjectHandle Node,
function_ref<Error(ObjectRef)> Callback) const final;
Error setSizeLimit(std::optional<uint64_t> SizeLimit) final;
Expected<std::optional<uint64_t>> getStorageSize() const final;
Error pruneStorageData() final;
OnDiskCAS(std::unique_ptr<ondisk::OnDiskGraphDB> GraphDB)
: OwnedDB(std::move(GraphDB)), DB(OwnedDB.get()) {}
std::unique_ptr<ondisk::OnDiskGraphDB> OwnedDB;
std::shared_ptr<ondisk::UnifiedOnDiskCache> UnifiedDB;
ondisk::OnDiskGraphDB *DB;
};
} // end anonymous namespace
void OnDiskCAS::print(raw_ostream &OS) const { DB->print(OS); }
Error OnDiskCAS::validate(bool CheckHash) const {
auto Hasher = [](ArrayRef<ArrayRef<uint8_t>> Refs, ArrayRef<char> Data,
SmallVectorImpl<uint8_t> &Result) {
auto Hash = BuiltinObjectHasher<llvm::cas::builtin::HasherT>::hashObject(
Refs, Data);
Result.assign(Hash.begin(), Hash.end());
};
if (auto E = DB->validate(CheckHash, Hasher))
return E;
return Error::success();
}
CASID OnDiskCAS::getID(ObjectRef Ref) const {
ArrayRef<uint8_t> Hash = DB->getDigest(convertRef(Ref));
return CASID::create(&getContext(), toStringRef(Hash));
}
std::optional<ObjectRef> OnDiskCAS::getReference(const CASID &ID) const {
std::optional<ondisk::ObjectID> ObjID =
DB->getExistingReference(ID.getHash());
if (!ObjID)
return std::nullopt;
return convertRef(*ObjID);
}
Expected<bool> OnDiskCAS::isMaterialized(ObjectRef ExternalRef) const {
return DB->isMaterialized(convertRef(ExternalRef));
}
ArrayRef<char> OnDiskCAS::getDataConst(ObjectHandle Node) const {
return DB->getObjectData(convertHandle(Node));
}
Expected<std::optional<ObjectHandle>>
OnDiskCAS::loadIfExists(ObjectRef ExternalRef) {
Expected<std::optional<ondisk::ObjectHandle>> ObjHnd =
DB->load(convertRef(ExternalRef));
if (!ObjHnd)
return ObjHnd.takeError();
if (!*ObjHnd)
return std::nullopt;
return convertHandle(**ObjHnd);
}
Expected<ObjectRef> OnDiskCAS::storeImpl(ArrayRef<uint8_t> ComputedHash,
ArrayRef<ObjectRef> Refs,
ArrayRef<char> Data) {
SmallVector<ondisk::ObjectID, 64> IDs;
IDs.reserve(Refs.size());
for (ObjectRef Ref : Refs) {
IDs.push_back(convertRef(Ref));
}
auto StoredID = DB->getReference(ComputedHash);
if (LLVM_UNLIKELY(!StoredID))
return StoredID.takeError();
if (Error E = DB->store(*StoredID, IDs, Data))
return std::move(E);
return convertRef(*StoredID);
}
Error OnDiskCAS::forEachRef(ObjectHandle Node,
function_ref<Error(ObjectRef)> Callback) const {
auto RefsRange = DB->getObjectRefs(convertHandle(Node));
for (ondisk::ObjectID Ref : RefsRange) {
if (Error E = Callback(convertRef(Ref)))
return E;
}
return Error::success();
}
Error OnDiskCAS::setSizeLimit(std::optional<uint64_t> SizeLimit) {
UnifiedDB->setSizeLimit(SizeLimit);
return Error::success();
}
Expected<std::optional<uint64_t>> OnDiskCAS::getStorageSize() const {
return UnifiedDB->getStorageSize();
}
Error OnDiskCAS::pruneStorageData() { return UnifiedDB->collectGarbage(); }
Expected<std::unique_ptr<OnDiskCAS>> OnDiskCAS::open(StringRef AbsPath) {
Expected<std::unique_ptr<ondisk::OnDiskGraphDB>> DB =
ondisk::OnDiskGraphDB::open(AbsPath, BuiltinCASContext::getHashName(),
sizeof(HashType));
if (!DB)
return DB.takeError();
return std::unique_ptr<OnDiskCAS>(new OnDiskCAS(std::move(*DB)));
}
bool cas::isOnDiskCASEnabled() {
#if LLVM_ENABLE_ONDISK_CAS
return true;
#else
return false;
#endif
}
Expected<std::unique_ptr<ObjectStore>> cas::createOnDiskCAS(const Twine &Path) {
#if LLVM_ENABLE_ONDISK_CAS
// FIXME: An absolute path isn't really good enough. Should open a directory
// and use openat() for files underneath.
SmallString<256> AbsPath;
Path.toVector(AbsPath);
sys::fs::make_absolute(AbsPath);
return OnDiskCAS::open(AbsPath);
#else
return createStringError(inconvertibleErrorCode(), "OnDiskCAS is disabled");
#endif /* LLVM_ENABLE_ONDISK_CAS */
}
std::unique_ptr<ObjectStore>
cas::builtin::createObjectStoreFromUnifiedOnDiskCache(
std::shared_ptr<ondisk::UnifiedOnDiskCache> UniDB) {
return std::make_unique<OnDiskCAS>(std::move(UniDB));
}