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