125 lines · cpp
1//===- OnDiskKeyValueDB.cpp -------------------------------------*- C++ -*-===//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 implements OnDiskKeyValueDB, an ondisk key value database.11///12/// The KeyValue database file is named `actions.<version>` inside the CAS13/// directory. The database stores a mapping between a fixed-sized key and a14/// fixed-sized value, where the size of key and value can be configured when15/// opening the database.16///17//18//===----------------------------------------------------------------------===//19 20#include "llvm/CAS/OnDiskKeyValueDB.h"21#include "OnDiskCommon.h"22#include "llvm/ADT/StringExtras.h"23#include "llvm/CAS/UnifiedOnDiskCache.h"24#include "llvm/Support/Alignment.h"25#include "llvm/Support/Compiler.h"26#include "llvm/Support/Errc.h"27#include "llvm/Support/Path.h"28 29using namespace llvm;30using namespace llvm::cas;31using namespace llvm::cas::ondisk;32 33static constexpr StringLiteral ActionCacheFile = "actions.";34 35Expected<ArrayRef<char>> OnDiskKeyValueDB::put(ArrayRef<uint8_t> Key,36 ArrayRef<char> Value) {37 if (LLVM_UNLIKELY(Value.size() != ValueSize))38 return createStringError(errc::invalid_argument,39 "expected value size of " + itostr(ValueSize) +40 ", got: " + itostr(Value.size()));41 assert(Value.size() == ValueSize);42 auto ActionP = Cache.insertLazy(43 Key, [&](FileOffset TentativeOffset,44 OnDiskTrieRawHashMap::ValueProxy TentativeValue) {45 assert(TentativeValue.Data.size() == ValueSize);46 llvm::copy(Value, TentativeValue.Data.data());47 });48 if (LLVM_UNLIKELY(!ActionP))49 return ActionP.takeError();50 return (*ActionP)->Data;51}52 53Expected<std::optional<ArrayRef<char>>>54OnDiskKeyValueDB::get(ArrayRef<uint8_t> Key) {55 // Check the result cache.56 OnDiskTrieRawHashMap::ConstOnDiskPtr ActionP = Cache.find(Key);57 if (ActionP) {58 assert(isAddrAligned(Align(8), ActionP->Data.data()));59 return ActionP->Data;60 }61 if (!UnifiedCache || !UnifiedCache->UpstreamKVDB)62 return std::nullopt;63 64 // Try to fault in from upstream.65 return UnifiedCache->faultInFromUpstreamKV(Key);66}67 68Expected<std::unique_ptr<OnDiskKeyValueDB>>69OnDiskKeyValueDB::open(StringRef Path, StringRef HashName, unsigned KeySize,70 StringRef ValueName, size_t ValueSize,71 UnifiedOnDiskCache *Cache) {72 if (std::error_code EC = sys::fs::create_directories(Path))73 return createFileError(Path, EC);74 75 SmallString<256> CachePath(Path);76 sys::path::append(CachePath, ActionCacheFile + CASFormatVersion);77 constexpr uint64_t MB = 1024ull * 1024ull;78 constexpr uint64_t GB = 1024ull * 1024ull * 1024ull;79 80 uint64_t MaxFileSize = GB;81 auto CustomSize = getOverriddenMaxMappingSize();82 if (!CustomSize)83 return CustomSize.takeError();84 if (*CustomSize)85 MaxFileSize = **CustomSize;86 87 std::optional<OnDiskTrieRawHashMap> ActionCache;88 if (Error E = OnDiskTrieRawHashMap::create(89 CachePath,90 "llvm.actioncache[" + HashName + "->" + ValueName + "]",91 KeySize * 8,92 /*DataSize=*/ValueSize, MaxFileSize, /*MinFileSize=*/MB)93 .moveInto(ActionCache))94 return std::move(E);95 96 return std::unique_ptr<OnDiskKeyValueDB>(97 new OnDiskKeyValueDB(ValueSize, std::move(*ActionCache), Cache));98}99 100Error OnDiskKeyValueDB::validate(CheckValueT CheckValue) const {101 if (UnifiedCache && UnifiedCache->UpstreamKVDB) {102 if (auto E = UnifiedCache->UpstreamKVDB->validate(CheckValue))103 return E;104 }105 return Cache.validate(106 [&](FileOffset Offset,107 OnDiskTrieRawHashMap::ConstValueProxy Record) -> Error {108 auto formatError = [&](Twine Msg) {109 return createStringError(110 llvm::errc::illegal_byte_sequence,111 "bad cache value at 0x" +112 utohexstr((unsigned)Offset.get(), /*LowerCase=*/true) + ": " +113 Msg.str());114 };115 116 if (Record.Data.size() != ValueSize)117 return formatError("wrong cache value size");118 if (!isAddrAligned(Align(8), Record.Data.data()))119 return formatError("wrong cache value alignment");120 if (CheckValue)121 return CheckValue(Offset, Record.Data);122 return Error::success();123 });124}125