//===----------------------------------------------------------------------===// // // 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 // //===----------------------------------------------------------------------===// // /// \file /// This file declares the common interface for a DatabaseFile that is used to /// implement OnDiskCAS. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_CAS_DATABASEFILE_H #define LLVM_LIB_CAS_DATABASEFILE_H #include "llvm/ADT/StringRef.h" #include "llvm/CAS/MappedFileRegionArena.h" #include "llvm/Support/Error.h" namespace llvm::cas::ondisk { using MappedFileRegion = MappedFileRegionArena::RegionT; /// Generic handle for a table. /// /// Generic table header layout: /// - 2-bytes: TableKind /// - 2-bytes: TableNameSize /// - 4-bytes: TableNameRelOffset (relative to header) class TableHandle { public: enum class TableKind : uint16_t { TrieRawHashMap = 1, DataAllocator = 2, }; struct Header { TableKind Kind; uint16_t NameSize; int32_t NameRelOffset; ///< Relative to Header. }; explicit operator bool() const { return H; } const Header &getHeader() const { return *H; } MappedFileRegion &getRegion() const { return *Region; } template static void check() { static_assert( std::is_same::value, "T::GenericHeader should be of type TableHandle::Header"); static_assert(offsetof(typename T::Header, GenericHeader) == 0, "T::GenericHeader must be the head of T::Header"); } template bool is() const { return T::Kind == H->Kind; } template T dyn_cast() const { check(); if (is()) return T(*Region, *reinterpret_cast(H)); return T(); } template T cast() const { assert(is()); return dyn_cast(); } StringRef getName() const { auto *Begin = reinterpret_cast(H) + H->NameRelOffset; return StringRef(Begin, H->NameSize); } TableHandle() = default; TableHandle(MappedFileRegion &Region, Header &H) : Region(&Region), H(&H) {} TableHandle(MappedFileRegion &Region, intptr_t HeaderOffset) : TableHandle(Region, *reinterpret_cast
(Region.data() + HeaderOffset)) { } private: MappedFileRegion *Region = nullptr; Header *H = nullptr; }; /// Encapsulate a database file, which: /// - Sets/checks magic. /// - Sets/checks version. /// - Points at an arbitrary root table. /// - Sets up a MappedFileRegionArena for allocation. /// /// Top-level layout: /// - 4-bytes: Magic /// - 4-bytes: Version /// - 8-bytes: RootTableOffset (16-bits: Kind; 48-bits: Offset) /// - 8-bytes: BumpPtr from MappedFileRegionArena class DatabaseFile { public: static constexpr uint32_t getMagic() { return 0xDA7ABA53UL; } static constexpr uint32_t getVersion() { return 1UL; } struct Header { uint32_t Magic; uint32_t Version; std::atomic RootTableOffset; }; const Header &getHeader() { return *H; } MappedFileRegionArena &getAlloc() { return Alloc; } MappedFileRegion &getRegion() { return Alloc.getRegion(); } /// Add a table. This is currently not thread safe and should be called inside /// NewDBConstructor. Error addTable(TableHandle Table); /// Find a table. May return null. std::optional findTable(StringRef Name); /// Create the DatabaseFile at Path with Capacity. static Expected create(const Twine &Path, uint64_t Capacity, function_ref NewDBConstructor); size_t size() const { return Alloc.size(); } private: static Expected get(std::unique_ptr Alloc) { if (Error E = validate(Alloc->getRegion())) return std::move(E); return DatabaseFile(std::move(Alloc)); } static Error validate(MappedFileRegion &Region); DatabaseFile(MappedFileRegionArena &Alloc) : H(reinterpret_cast
(Alloc.data())), Alloc(Alloc) {} DatabaseFile(std::unique_ptr Alloc) : DatabaseFile(*Alloc) { OwnedAlloc = std::move(Alloc); } Header *H = nullptr; MappedFileRegionArena &Alloc; std::unique_ptr OwnedAlloc; }; Error createTableConfigError(std::errc ErrC, StringRef Path, StringRef TableName, const Twine &Msg); Error checkTable(StringRef Label, size_t Expected, size_t Observed, StringRef Path, StringRef TrieName); } // namespace llvm::cas::ondisk #endif