llvm-project/llvm/lib/CAS/BuiltinCAS.cpp
Steven Wu 6747ea050d
[CAS] Add UnifiedOnDiskCache and OnDiskCAS (#114103)
Add a new abstraction layer UnifiedOnDiskCache that adds new functions
of disk space management and data validation that builds on top of
OnDiskGraphDB and OnDiskKeyValueDB.

Build upon UnifiedOnDiskCache, it is OnDiskCAS that implements
ObjectStore and ActionCache interface for LLVM tools to interact with
CAS storage.
2025-11-03 09:50:28 -08:00

107 lines
3.6 KiB
C++

//===- BuiltinCAS.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 "BuiltinCAS.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/CAS/BuiltinObjectHasher.h"
#include "llvm/CAS/UnifiedOnDiskCache.h"
#include "llvm/Support/Process.h"
using namespace llvm;
using namespace llvm::cas;
using namespace llvm::cas::builtin;
static StringRef getCASIDPrefix() { return "llvmcas://"; }
void BuiltinCASContext::anchor() {}
Expected<HashType> BuiltinCASContext::parseID(StringRef Reference) {
if (!Reference.consume_front(getCASIDPrefix()))
return createStringError(std::make_error_code(std::errc::invalid_argument),
"invalid cas-id '" + Reference + "'");
// FIXME: Allow shortened references?
if (Reference.size() != 2 * sizeof(HashType))
return createStringError(std::make_error_code(std::errc::invalid_argument),
"wrong size for cas-id hash '" + Reference + "'");
std::string Binary;
if (!tryGetFromHex(Reference, Binary))
return createStringError(std::make_error_code(std::errc::invalid_argument),
"invalid hash in cas-id '" + Reference + "'");
assert(Binary.size() == sizeof(HashType));
HashType Digest;
llvm::copy(Binary, Digest.data());
return Digest;
}
Expected<CASID> BuiltinCAS::parseID(StringRef Reference) {
Expected<HashType> Digest = BuiltinCASContext::parseID(Reference);
if (!Digest)
return Digest.takeError();
return CASID::create(&getContext(), toStringRef(*Digest));
}
void BuiltinCASContext::printID(ArrayRef<uint8_t> Digest, raw_ostream &OS) {
SmallString<64> Hash;
toHex(Digest, /*LowerCase=*/true, Hash);
OS << getCASIDPrefix() << Hash;
}
void BuiltinCASContext::printIDImpl(raw_ostream &OS, const CASID &ID) const {
BuiltinCASContext::printID(ID.getHash(), OS);
}
const BuiltinCASContext &BuiltinCASContext::getDefaultContext() {
static BuiltinCASContext DefaultContext;
return DefaultContext;
}
Expected<ObjectRef> BuiltinCAS::store(ArrayRef<ObjectRef> Refs,
ArrayRef<char> Data) {
return storeImpl(BuiltinObjectHasher<HasherT>::hashObject(*this, Refs, Data),
Refs, Data);
}
Error BuiltinCAS::validateObject(const CASID &ID) {
auto Ref = getReference(ID);
if (!Ref)
return createUnknownObjectError(ID);
auto Handle = load(*Ref);
if (!Handle)
return Handle.takeError();
auto Proxy = ObjectProxy::load(*this, *Ref, *Handle);
SmallVector<ObjectRef> Refs;
if (auto E = Proxy.forEachReference([&](ObjectRef Ref) -> Error {
Refs.push_back(Ref);
return Error::success();
}))
return E;
ArrayRef<char> Data(Proxy.getData().data(), Proxy.getData().size());
auto Hash = BuiltinObjectHasher<HasherT>::hashObject(*this, Refs, Data);
if (!ID.getHash().equals(Hash))
return createCorruptObjectError(ID);
return Error::success();
}
Expected<std::unique_ptr<ondisk::UnifiedOnDiskCache>>
cas::builtin::createBuiltinUnifiedOnDiskCache(StringRef Path) {
#if LLVM_ENABLE_ONDISK_CAS
return ondisk::UnifiedOnDiskCache::open(Path, /*SizeLimit=*/std::nullopt,
BuiltinCASContext::getHashName(),
sizeof(HashType));
#else
return createStringError(inconvertibleErrorCode(), "OnDiskCache is disabled");
#endif
}