//===- OnDiskKeyValueDB.cpp -------------------------------------*- C++ -*-===// // // 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 implements OnDiskKeyValueDB, an ondisk key value database. /// /// The KeyValue database file is named `actions.` inside the CAS /// directory. The database stores a mapping between a fixed-sized key and a /// fixed-sized value, where the size of key and value can be configured when /// opening the database. /// // //===----------------------------------------------------------------------===// #include "llvm/CAS/OnDiskKeyValueDB.h" #include "OnDiskCommon.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Path.h" using namespace llvm; using namespace llvm::cas; using namespace llvm::cas::ondisk; static constexpr StringLiteral ActionCacheFile = "actions."; Expected> OnDiskKeyValueDB::put(ArrayRef Key, ArrayRef Value) { if (LLVM_UNLIKELY(Value.size() != ValueSize)) return createStringError(errc::invalid_argument, "expected value size of " + itostr(ValueSize) + ", got: " + itostr(Value.size())); assert(Value.size() == ValueSize); auto ActionP = Cache.insertLazy( Key, [&](FileOffset TentativeOffset, OnDiskTrieRawHashMap::ValueProxy TentativeValue) { assert(TentativeValue.Data.size() == ValueSize); llvm::copy(Value, TentativeValue.Data.data()); }); if (LLVM_UNLIKELY(!ActionP)) return ActionP.takeError(); return (*ActionP)->Data; } Expected>> OnDiskKeyValueDB::get(ArrayRef Key) { // Check the result cache. OnDiskTrieRawHashMap::ConstOnDiskPtr ActionP = Cache.find(Key); if (!ActionP) return std::nullopt; assert(isAddrAligned(Align(8), ActionP->Data.data())); return ActionP->Data; } Expected> OnDiskKeyValueDB::open(StringRef Path, StringRef HashName, unsigned KeySize, StringRef ValueName, size_t ValueSize) { if (std::error_code EC = sys::fs::create_directories(Path)) return createFileError(Path, EC); SmallString<256> CachePath(Path); sys::path::append(CachePath, ActionCacheFile + CASFormatVersion); constexpr uint64_t MB = 1024ull * 1024ull; constexpr uint64_t GB = 1024ull * 1024ull * 1024ull; uint64_t MaxFileSize = GB; auto CustomSize = getOverriddenMaxMappingSize(); if (!CustomSize) return CustomSize.takeError(); if (*CustomSize) MaxFileSize = **CustomSize; std::optional ActionCache; if (Error E = OnDiskTrieRawHashMap::create( CachePath, "llvm.actioncache[" + HashName + "->" + ValueName + "]", KeySize * 8, /*DataSize=*/ValueSize, MaxFileSize, /*MinFileSize=*/MB) .moveInto(ActionCache)) return std::move(E); return std::unique_ptr( new OnDiskKeyValueDB(ValueSize, std::move(*ActionCache))); } Error OnDiskKeyValueDB::validate(CheckValueT CheckValue) const { return Cache.validate( [&](FileOffset Offset, OnDiskTrieRawHashMap::ConstValueProxy Record) -> Error { auto formatError = [&](Twine Msg) { return createStringError( llvm::errc::illegal_byte_sequence, "bad cache value at 0x" + utohexstr((unsigned)Offset.get(), /*LowerCase=*/true) + ": " + Msg.str()); }; if (Record.Data.size() != ValueSize) return formatError("wrong cache value size"); if (!isAddrAligned(Align(8), Record.Data.data())) return formatError("wrong cache value alignment"); if (CheckValue) return CheckValue(Offset, Record.Data); return Error::success(); }); }