brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.1 KiB · 9c68bc4 Raw
237 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8///9/// \file Implements OnDiskDataAllocator.10///11//===----------------------------------------------------------------------===//12 13#include "llvm/CAS/OnDiskDataAllocator.h"14#include "DatabaseFile.h"15#include "llvm/Config/llvm-config.h"16 17using namespace llvm;18using namespace llvm::cas;19using namespace llvm::cas::ondisk;20 21#if LLVM_ENABLE_ONDISK_CAS22 23//===----------------------------------------------------------------------===//24// DataAllocator data structures.25//===----------------------------------------------------------------------===//26 27namespace {28/// DataAllocator table layout:29/// - [8-bytes: Generic table header]30/// - 8-bytes: AllocatorOffset (reserved for implementing free lists)31/// - 8-bytes: Size for user data header32/// - <user data buffer>33///34/// Record layout:35/// - <data>36class DataAllocatorHandle {37public:38  static constexpr TableHandle::TableKind Kind =39      TableHandle::TableKind::DataAllocator;40 41  struct Header {42    TableHandle::Header GenericHeader;43    std::atomic<int64_t> AllocatorOffset;44    const uint64_t UserHeaderSize;45  };46 47  operator TableHandle() const {48    if (!H)49      return TableHandle();50    return TableHandle(*Region, H->GenericHeader);51  }52 53  Expected<MutableArrayRef<char>> allocate(MappedFileRegionArena &Alloc,54                                           size_t DataSize) {55    assert(&Alloc.getRegion() == Region);56    auto Ptr = Alloc.allocate(DataSize);57    if (LLVM_UNLIKELY(!Ptr))58      return Ptr.takeError();59    return MutableArrayRef(*Ptr, DataSize);60  }61 62  explicit operator bool() const { return H; }63  const Header &getHeader() const { return *H; }64  MappedFileRegion &getRegion() const { return *Region; }65 66  MutableArrayRef<uint8_t> getUserHeader() {67    return MutableArrayRef(reinterpret_cast<uint8_t *>(H + 1),68                           H->UserHeaderSize);69  }70 71  static Expected<DataAllocatorHandle>72  create(MappedFileRegionArena &Alloc, StringRef Name, uint32_t UserHeaderSize);73 74  DataAllocatorHandle() = default;75  DataAllocatorHandle(MappedFileRegion &Region, Header &H)76      : Region(&Region), H(&H) {}77  DataAllocatorHandle(MappedFileRegion &Region, intptr_t HeaderOffset)78      : DataAllocatorHandle(79            Region, *reinterpret_cast<Header *>(Region.data() + HeaderOffset)) {80  }81 82private:83  MappedFileRegion *Region = nullptr;84  Header *H = nullptr;85};86 87} // end anonymous namespace88 89struct OnDiskDataAllocator::ImplType {90  DatabaseFile File;91  DataAllocatorHandle Store;92};93 94Expected<DataAllocatorHandle>95DataAllocatorHandle::create(MappedFileRegionArena &Alloc, StringRef Name,96                            uint32_t UserHeaderSize) {97  // Allocate.98  auto Offset =99      Alloc.allocateOffset(sizeof(Header) + UserHeaderSize + Name.size() + 1);100  if (LLVM_UNLIKELY(!Offset))101    return Offset.takeError();102 103  // Construct the header and the name.104  assert(Name.size() <= UINT16_MAX && "Expected smaller table name");105  auto *H = new (Alloc.getRegion().data() + *Offset)106      Header{{TableHandle::TableKind::DataAllocator,107              static_cast<uint16_t>(Name.size()),108              static_cast<int32_t>(sizeof(Header) + UserHeaderSize)},109             /*AllocatorOffset=*/{0},110             /*UserHeaderSize=*/UserHeaderSize};111  // Memset UserHeader.112  char *UserHeader = reinterpret_cast<char *>(H + 1);113  memset(UserHeader, 0, UserHeaderSize);114  // Write database file name (null-terminated).115  char *NameStorage = UserHeader + UserHeaderSize;116  llvm::copy(Name, NameStorage);117  NameStorage[Name.size()] = 0;118  return DataAllocatorHandle(Alloc.getRegion(), *H);119}120 121Expected<OnDiskDataAllocator> OnDiskDataAllocator::create(122    const Twine &PathTwine, const Twine &TableNameTwine, uint64_t MaxFileSize,123    std::optional<uint64_t> NewFileInitialSize, uint32_t UserHeaderSize,124    function_ref<void(void *)> UserHeaderInit) {125  assert(!UserHeaderSize || UserHeaderInit);126  SmallString<128> PathStorage;127  StringRef Path = PathTwine.toStringRef(PathStorage);128  SmallString<128> TableNameStorage;129  StringRef TableName = TableNameTwine.toStringRef(TableNameStorage);130 131  // Constructor for if the file doesn't exist.132  auto NewDBConstructor = [&](DatabaseFile &DB) -> Error {133    auto Store =134        DataAllocatorHandle::create(DB.getAlloc(), TableName, UserHeaderSize);135    if (LLVM_UNLIKELY(!Store))136      return Store.takeError();137 138    if (auto E = DB.addTable(*Store))139      return E;140 141    if (UserHeaderSize)142      UserHeaderInit(Store->getUserHeader().data());143    return Error::success();144  };145 146  // Get or create the file.147  Expected<DatabaseFile> File =148      DatabaseFile::create(Path, MaxFileSize, NewDBConstructor);149  if (!File)150    return File.takeError();151 152  // Find the table and validate it.153  std::optional<TableHandle> Table = File->findTable(TableName);154  if (!Table)155    return createTableConfigError(std::errc::argument_out_of_domain, Path,156                                  TableName, "table not found");157  if (Error E = checkTable("table kind", (size_t)DataAllocatorHandle::Kind,158                           (size_t)Table->getHeader().Kind, Path, TableName))159    return std::move(E);160  auto Store = Table->cast<DataAllocatorHandle>();161  assert(Store && "Already checked the kind");162 163  // Success.164  OnDiskDataAllocator::ImplType Impl{DatabaseFile(std::move(*File)), Store};165  return OnDiskDataAllocator(std::make_unique<ImplType>(std::move(Impl)));166}167 168Expected<OnDiskDataAllocator::OnDiskPtr>169OnDiskDataAllocator::allocate(size_t Size) {170  auto Data = Impl->Store.allocate(Impl->File.getAlloc(), Size);171  if (LLVM_UNLIKELY(!Data))172    return Data.takeError();173 174  return OnDiskPtr(FileOffset(Data->data() - Impl->Store.getRegion().data()),175                   *Data);176}177 178Expected<ArrayRef<char>> OnDiskDataAllocator::get(FileOffset Offset,179                                                  size_t Size) const {180  assert(Offset);181  assert(Impl);182  if (Offset.get() + Size >= Impl->File.getAlloc().size())183    return createStringError(make_error_code(std::errc::protocol_error),184                             "requested size too large in allocator");185  return ArrayRef<char>{Impl->File.getRegion().data() + Offset.get(), Size};186}187 188MutableArrayRef<uint8_t> OnDiskDataAllocator::getUserHeader() const {189  return Impl->Store.getUserHeader();190}191 192size_t OnDiskDataAllocator::size() const { return Impl->File.size(); }193size_t OnDiskDataAllocator::capacity() const {194  return Impl->File.getRegion().size();195}196 197OnDiskDataAllocator::OnDiskDataAllocator(std::unique_ptr<ImplType> Impl)198    : Impl(std::move(Impl)) {}199 200#else // !LLVM_ENABLE_ONDISK_CAS201 202struct OnDiskDataAllocator::ImplType {};203 204Expected<OnDiskDataAllocator> OnDiskDataAllocator::create(205    const Twine &Path, const Twine &TableName, uint64_t MaxFileSize,206    std::optional<uint64_t> NewFileInitialSize, uint32_t UserHeaderSize,207    function_ref<void(void *)> UserHeaderInit) {208  return createStringError(make_error_code(std::errc::not_supported),209                           "OnDiskDataAllocator is not supported");210}211 212Expected<OnDiskDataAllocator::OnDiskPtr>213OnDiskDataAllocator::allocate(size_t Size) {214  return createStringError(make_error_code(std::errc::not_supported),215                           "OnDiskDataAllocator is not supported");216}217 218Expected<ArrayRef<char>> OnDiskDataAllocator::get(FileOffset Offset,219                                                  size_t Size) const {220  return createStringError(make_error_code(std::errc::not_supported),221                           "OnDiskDataAllocator is not supported");222}223 224MutableArrayRef<uint8_t> OnDiskDataAllocator::getUserHeader() const {225  return {};226}227 228size_t OnDiskDataAllocator::size() const { return 0; }229size_t OnDiskDataAllocator::capacity() const { return 0; }230 231#endif // LLVM_ENABLE_ONDISK_CAS232 233OnDiskDataAllocator::OnDiskDataAllocator(OnDiskDataAllocator &&RHS) = default;234OnDiskDataAllocator &235OnDiskDataAllocator::operator=(OnDiskDataAllocator &&RHS) = default;236OnDiskDataAllocator::~OnDiskDataAllocator() = default;237