llvm-project/llvm/lib/CAS/ObjectStore.cpp
Steven Wu 6032ff6c81
[CAS] Fix a bug in CAS storeFromOpenFileImpl (#153315)
Fix a bug in upstreamed CAS implemenation due to copy/paste error. The
missing coverage will be covered by future upstreamed tests.
2025-08-12 23:25:14 +00:00

163 lines
5.1 KiB
C++

//===- ObjectStore.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/ObjectStore.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include <optional>
using namespace llvm;
using namespace llvm::cas;
void CASContext::anchor() {}
void ObjectStore::anchor() {}
LLVM_DUMP_METHOD void CASID::dump() const { print(dbgs()); }
LLVM_DUMP_METHOD void ObjectRef::dump() const { print(dbgs()); }
LLVM_DUMP_METHOD void ObjectHandle::dump() const { print(dbgs()); }
std::string CASID::toString() const {
std::string S;
raw_string_ostream(S) << *this;
return S;
}
static void printReferenceBase(raw_ostream &OS, StringRef Kind,
uint64_t InternalRef, std::optional<CASID> ID) {
OS << Kind << "=" << InternalRef;
if (ID)
OS << "[" << *ID << "]";
}
void ReferenceBase::print(raw_ostream &OS, const ObjectHandle &This) const {
assert(this == &This);
printReferenceBase(OS, "object-handle", InternalRef, std::nullopt);
}
void ReferenceBase::print(raw_ostream &OS, const ObjectRef &This) const {
assert(this == &This);
std::optional<CASID> ID;
#if LLVM_ENABLE_ABI_BREAKING_CHECKS
if (CAS)
ID = CAS->getID(This);
#endif
printReferenceBase(OS, "object-ref", InternalRef, ID);
}
Expected<ObjectHandle> ObjectStore::load(ObjectRef Ref) {
std::optional<ObjectHandle> Handle;
if (Error E = loadIfExists(Ref).moveInto(Handle))
return std::move(E);
if (!Handle)
return createStringError(errc::invalid_argument,
"missing object '" + getID(Ref).toString() + "'");
return *Handle;
}
std::unique_ptr<MemoryBuffer>
ObjectStore::getMemoryBuffer(ObjectHandle Node, StringRef Name,
bool RequiresNullTerminator) {
return MemoryBuffer::getMemBuffer(
toStringRef(getData(Node, RequiresNullTerminator)), Name,
RequiresNullTerminator);
}
void ObjectStore::readRefs(ObjectHandle Node,
SmallVectorImpl<ObjectRef> &Refs) const {
consumeError(forEachRef(Node, [&Refs](ObjectRef Ref) -> Error {
Refs.push_back(Ref);
return Error::success();
}));
}
Expected<ObjectProxy> ObjectStore::getProxy(const CASID &ID) {
std::optional<ObjectRef> Ref = getReference(ID);
if (!Ref)
return createUnknownObjectError(ID);
return getProxy(*Ref);
}
Expected<ObjectProxy> ObjectStore::getProxy(ObjectRef Ref) {
std::optional<ObjectHandle> H;
if (Error E = load(Ref).moveInto(H))
return std::move(E);
return ObjectProxy::load(*this, Ref, *H);
}
Expected<std::optional<ObjectProxy>>
ObjectStore::getProxyIfExists(ObjectRef Ref) {
std::optional<ObjectHandle> H;
if (Error E = loadIfExists(Ref).moveInto(H))
return std::move(E);
if (!H)
return std::nullopt;
return ObjectProxy::load(*this, Ref, *H);
}
Error ObjectStore::createUnknownObjectError(const CASID &ID) {
return createStringError(std::make_error_code(std::errc::invalid_argument),
"unknown object '" + ID.toString() + "'");
}
Expected<ObjectProxy> ObjectStore::createProxy(ArrayRef<ObjectRef> Refs,
StringRef Data) {
Expected<ObjectRef> Ref = store(Refs, arrayRefFromStringRef<char>(Data));
if (!Ref)
return Ref.takeError();
return getProxy(*Ref);
}
Expected<ObjectRef>
ObjectStore::storeFromOpenFileImpl(sys::fs::file_t FD,
std::optional<sys::fs::file_status> Status) {
// TODO: For the on-disk CAS implementation use cloning to store it as a
// standalone file if the file-system supports it and the file is large.
uint64_t Size = Status ? Status->getSize() : -1;
auto Buffer = MemoryBuffer::getOpenFile(FD, /*Filename=*/"", Size);
if (!Buffer)
return errorCodeToError(Buffer.getError());
return store({}, arrayRefFromStringRef<char>((*Buffer)->getBuffer()));
}
Error ObjectStore::validateTree(ObjectRef Root) {
SmallDenseSet<ObjectRef> ValidatedRefs;
SmallVector<ObjectRef, 16> RefsToValidate;
RefsToValidate.push_back(Root);
while (!RefsToValidate.empty()) {
ObjectRef Ref = RefsToValidate.pop_back_val();
auto [I, Inserted] = ValidatedRefs.insert(Ref);
if (!Inserted)
continue; // already validated.
if (Error E = validate(getID(Ref)))
return E;
Expected<ObjectHandle> Obj = load(Ref);
if (!Obj)
return Obj.takeError();
if (Error E = forEachRef(*Obj, [&RefsToValidate](ObjectRef R) -> Error {
RefsToValidate.push_back(R);
return Error::success();
}))
return E;
}
return Error::success();
}
std::unique_ptr<MemoryBuffer>
ObjectProxy::getMemoryBuffer(StringRef Name,
bool RequiresNullTerminator) const {
return CAS->getMemoryBuffer(H, Name, RequiresNullTerminator);
}