154 lines · c
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/// \file10/// This file declares the common interface for a DatabaseFile that is used to11/// implement OnDiskCAS.12//13//===----------------------------------------------------------------------===//14 15#ifndef LLVM_LIB_CAS_DATABASEFILE_H16#define LLVM_LIB_CAS_DATABASEFILE_H17 18#include "llvm/ADT/StringRef.h"19#include "llvm/CAS/MappedFileRegionArena.h"20#include "llvm/Support/Error.h"21 22namespace llvm::cas::ondisk {23 24using MappedFileRegion = MappedFileRegionArena::RegionT;25 26/// Generic handle for a table.27///28/// Generic table header layout:29/// - 2-bytes: TableKind30/// - 2-bytes: TableNameSize31/// - 4-bytes: TableNameRelOffset (relative to header)32class TableHandle {33public:34 enum class TableKind : uint16_t {35 TrieRawHashMap = 1,36 DataAllocator = 2,37 };38 struct Header {39 TableKind Kind;40 uint16_t NameSize;41 int32_t NameRelOffset; ///< Relative to Header.42 };43 44 explicit operator bool() const { return H; }45 const Header &getHeader() const { return *H; }46 MappedFileRegion &getRegion() const { return *Region; }47 48 template <class T> static void check() {49 static_assert(50 std::is_same<decltype(T::Header::GenericHeader), Header>::value,51 "T::GenericHeader should be of type TableHandle::Header");52 static_assert(offsetof(typename T::Header, GenericHeader) == 0,53 "T::GenericHeader must be the head of T::Header");54 }55 template <class T> bool is() const { return T::Kind == H->Kind; }56 template <class T> T dyn_cast() const {57 check<T>();58 if (is<T>())59 return T(*Region, *reinterpret_cast<typename T::Header *>(H));60 return T();61 }62 template <class T> T cast() const {63 assert(is<T>());64 return dyn_cast<T>();65 }66 67 StringRef getName() const {68 auto *Begin = reinterpret_cast<const char *>(H) + H->NameRelOffset;69 return StringRef(Begin, H->NameSize);70 }71 72 TableHandle() = default;73 TableHandle(MappedFileRegion &Region, Header &H) : Region(&Region), H(&H) {}74 TableHandle(MappedFileRegion &Region, intptr_t HeaderOffset)75 : TableHandle(Region,76 *reinterpret_cast<Header *>(Region.data() + HeaderOffset)) {77 }78 79private:80 MappedFileRegion *Region = nullptr;81 Header *H = nullptr;82};83 84/// Encapsulate a database file, which:85/// - Sets/checks magic.86/// - Sets/checks version.87/// - Points at an arbitrary root table.88/// - Sets up a MappedFileRegionArena for allocation.89///90/// Top-level layout:91/// - 4-bytes: Magic92/// - 4-bytes: Version93/// - 8-bytes: RootTableOffset (16-bits: Kind; 48-bits: Offset)94/// - 8-bytes: BumpPtr from MappedFileRegionArena95class DatabaseFile {96public:97 static constexpr uint32_t getMagic() { return 0xDA7ABA53UL; }98 static constexpr uint32_t getVersion() { return 1UL; }99 struct Header {100 uint32_t Magic;101 uint32_t Version;102 std::atomic<int64_t> RootTableOffset;103 };104 105 const Header &getHeader() { return *H; }106 MappedFileRegionArena &getAlloc() { return Alloc; }107 MappedFileRegion &getRegion() { return Alloc.getRegion(); }108 109 /// Add a table. This is currently not thread safe and should be called inside110 /// NewDBConstructor.111 Error addTable(TableHandle Table);112 113 /// Find a table. May return null.114 std::optional<TableHandle> findTable(StringRef Name);115 116 /// Create the DatabaseFile at Path with Capacity.117 static Expected<DatabaseFile>118 create(const Twine &Path, uint64_t Capacity,119 function_ref<Error(DatabaseFile &)> NewDBConstructor);120 121 size_t size() const { return Alloc.size(); }122 123private:124 static Expected<DatabaseFile>125 get(std::unique_ptr<MappedFileRegionArena> Alloc) {126 if (Error E = validate(Alloc->getRegion()))127 return std::move(E);128 return DatabaseFile(std::move(Alloc));129 }130 131 static Error validate(MappedFileRegion &Region);132 133 DatabaseFile(MappedFileRegionArena &Alloc)134 : H(reinterpret_cast<Header *>(Alloc.data())), Alloc(Alloc) {}135 DatabaseFile(std::unique_ptr<MappedFileRegionArena> Alloc)136 : DatabaseFile(*Alloc) {137 OwnedAlloc = std::move(Alloc);138 }139 140 Header *H = nullptr;141 MappedFileRegionArena &Alloc;142 std::unique_ptr<MappedFileRegionArena> OwnedAlloc;143};144 145Error createTableConfigError(std::errc ErrC, StringRef Path,146 StringRef TableName, const Twine &Msg);147 148Error checkTable(StringRef Label, size_t Expected, size_t Observed,149 StringRef Path, StringRef TrieName);150 151} // namespace llvm::cas::ondisk152 153#endif154