brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.8 KiB · db8ce1d Raw
124 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 This file implements the common abstractions for CAS database file.10///11//===----------------------------------------------------------------------===//12 13#include "DatabaseFile.h"14 15using namespace llvm;16using namespace llvm::cas;17using namespace llvm::cas::ondisk;18 19Error ondisk::createTableConfigError(std::errc ErrC, StringRef Path,20                                     StringRef TableName, const Twine &Msg) {21  return createStringError(make_error_code(ErrC),22                           Path + "[" + TableName + "]: " + Msg);23}24 25Error ondisk::checkTable(StringRef Label, size_t Expected, size_t Observed,26                         StringRef Path, StringRef TrieName) {27  if (Expected == Observed)28    return Error::success();29  return createTableConfigError(std::errc::invalid_argument, Path, TrieName,30                                "mismatched " + Label +31                                    " (expected: " + Twine(Expected) +32                                    ", observed: " + Twine(Observed) + ")");33}34 35Expected<DatabaseFile>36DatabaseFile::create(const Twine &Path, uint64_t Capacity,37                     function_ref<Error(DatabaseFile &)> NewDBConstructor) {38  // Constructor for if the file doesn't exist.39  auto NewFileConstructor = [&](MappedFileRegionArena &Alloc) -> Error {40    if (Alloc.capacity() <41        sizeof(Header) + sizeof(MappedFileRegionArena::Header))42      return createTableConfigError(std::errc::argument_out_of_domain,43                                    Path.str(), "datafile",44                                    "Allocator too small for header");45    (void)new (Alloc.data()) Header{getMagic(), getVersion(), {0}};46    DatabaseFile DB(Alloc);47    return NewDBConstructor(DB);48  };49 50  // Get or create the file.51  MappedFileRegionArena Alloc;52  if (Error E = MappedFileRegionArena::create(Path, Capacity, sizeof(Header),53                                              NewFileConstructor)54                    .moveInto(Alloc))55    return std::move(E);56 57  return DatabaseFile::get(58      std::make_unique<MappedFileRegionArena>(std::move(Alloc)));59}60 61Error DatabaseFile::addTable(TableHandle Table) {62  assert(Table);63  assert(&Table.getRegion() == &getRegion());64  int64_t ExistingRootOffset = 0;65  const int64_t NewOffset =66      reinterpret_cast<const char *>(&Table.getHeader()) - getRegion().data();67  if (H->RootTableOffset.compare_exchange_strong(ExistingRootOffset, NewOffset))68    return Error::success();69 70  // Silently ignore attempts to set the root to itself.71  if (ExistingRootOffset == NewOffset)72    return Error::success();73 74  // Return an proper error message.75  TableHandle Root(getRegion(), ExistingRootOffset);76  if (Root.getName() == Table.getName())77    return createStringError(78        make_error_code(std::errc::not_supported),79        "collision with existing table of the same name '" + Table.getName() +80            "'");81 82  return createStringError(make_error_code(std::errc::not_supported),83                           "cannot add new table '" + Table.getName() +84                               "'"85                               " to existing root '" +86                               Root.getName() + "'");87}88 89std::optional<TableHandle> DatabaseFile::findTable(StringRef Name) {90  int64_t RootTableOffset = H->RootTableOffset.load();91  if (!RootTableOffset)92    return std::nullopt;93 94  TableHandle Root(getRegion(), RootTableOffset);95  if (Root.getName() == Name)96    return Root;97 98  return std::nullopt;99}100 101Error DatabaseFile::validate(MappedFileRegion &Region) {102  if (Region.size() < sizeof(Header))103    return createStringError(std::errc::invalid_argument,104                             "database: missing header");105 106  // Check the magic and version.107  auto *H = reinterpret_cast<Header *>(Region.data());108  if (H->Magic != getMagic())109    return createStringError(std::errc::invalid_argument,110                             "database: bad magic");111  if (H->Version != getVersion())112    return createStringError(std::errc::invalid_argument,113                             "database: wrong version");114 115  auto *MFH = reinterpret_cast<MappedFileRegionArena::Header *>(Region.data() +116                                                                sizeof(Header));117  // Check the bump-ptr, which should point past the header.118  if (MFH->BumpPtr.load() < (int64_t)sizeof(Header))119    return createStringError(std::errc::invalid_argument,120                             "database: corrupt bump-ptr");121 122  return Error::success();123}124