aboutsummaryrefslogtreecommitdiff
path: root/llvm/unittests/CAS/UnifiedOnDiskCacheTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/unittests/CAS/UnifiedOnDiskCacheTest.cpp')
-rw-r--r--llvm/unittests/CAS/UnifiedOnDiskCacheTest.cpp198
1 files changed, 198 insertions, 0 deletions
diff --git a/llvm/unittests/CAS/UnifiedOnDiskCacheTest.cpp b/llvm/unittests/CAS/UnifiedOnDiskCacheTest.cpp
new file mode 100644
index 0000000..09aebc2
--- /dev/null
+++ b/llvm/unittests/CAS/UnifiedOnDiskCacheTest.cpp
@@ -0,0 +1,198 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CAS/UnifiedOnDiskCache.h"
+#include "CASTestConfig.h"
+#include "OnDiskCommonUtils.h"
+#include "llvm/Testing/Support/Error.h"
+#include "llvm/Testing/Support/SupportHelpers.h"
+#include "gtest/gtest.h"
+
+using namespace llvm;
+using namespace llvm::cas;
+using namespace llvm::cas::ondisk;
+using namespace llvm::unittest::cas;
+
+/// Visits all the files of a directory recursively and returns the sum of their
+/// sizes.
+static Expected<size_t> countFileSizes(StringRef Path) {
+ size_t TotalSize = 0;
+ std::error_code EC;
+ for (sys::fs::directory_iterator DirI(Path, EC), DirE; !EC && DirI != DirE;
+ DirI.increment(EC)) {
+ if (DirI->type() == sys::fs::file_type::directory_file) {
+ Expected<size_t> Subsize = countFileSizes(DirI->path());
+ if (!Subsize)
+ return Subsize.takeError();
+ TotalSize += *Subsize;
+ continue;
+ }
+ ErrorOr<sys::fs::basic_file_status> Stat = DirI->status();
+ if (!Stat)
+ return createFileError(DirI->path(), Stat.getError());
+ TotalSize += Stat->getSize();
+ }
+ if (EC)
+ return createFileError(Path, EC);
+ return TotalSize;
+}
+
+TEST_F(OnDiskCASTest, UnifiedOnDiskCacheTest) {
+ unittest::TempDir Temp("ondisk-unified", /*Unique=*/true);
+ std::unique_ptr<UnifiedOnDiskCache> UniDB;
+
+ const uint64_t SizeLimit = 1024ull * 64;
+ auto reopenDB = [&]() {
+ UniDB.reset();
+ ASSERT_THAT_ERROR(UnifiedOnDiskCache::open(Temp.path(), SizeLimit, "blake3",
+ sizeof(HashType))
+ .moveInto(UniDB),
+ Succeeded());
+ };
+
+ reopenDB();
+
+ HashType RootHash;
+ HashType OtherHash;
+ HashType Key1Hash;
+ HashType Key2Hash;
+ {
+ OnDiskGraphDB &DB = UniDB->getGraphDB();
+ std::optional<ObjectID> ID1;
+ ASSERT_THAT_ERROR(store(DB, "1", {}).moveInto(ID1), Succeeded());
+ std::optional<ObjectID> ID2;
+ ASSERT_THAT_ERROR(store(DB, "2", {}).moveInto(ID2), Succeeded());
+ std::optional<ObjectID> IDRoot;
+ ASSERT_THAT_ERROR(store(DB, "root", {*ID1, *ID2}).moveInto(IDRoot),
+ Succeeded());
+ ArrayRef<uint8_t> Digest = DB.getDigest(*IDRoot);
+ ASSERT_EQ(Digest.size(), RootHash.size());
+ llvm::copy(Digest, RootHash.data());
+
+ std::optional<ObjectID> IDOther;
+ ASSERT_THAT_ERROR(store(DB, "other", {}).moveInto(IDOther), Succeeded());
+ Digest = DB.getDigest(*IDOther);
+ ASSERT_EQ(Digest.size(), OtherHash.size());
+ llvm::copy(Digest, OtherHash.data());
+
+ Key1Hash = digest("key1");
+ std::optional<ObjectID> Val;
+ ASSERT_THAT_ERROR(
+ cachePut(UniDB->getKeyValueDB(), Key1Hash, *IDRoot).moveInto(Val),
+ Succeeded());
+ EXPECT_EQ(IDRoot, Val);
+
+ Key2Hash = digest("key2");
+ std::optional<ObjectID> KeyID;
+ ASSERT_THAT_ERROR(DB.getReference(Key2Hash).moveInto(KeyID), Succeeded());
+ ASSERT_THAT_ERROR(cachePut(UniDB->getKeyValueDB(),
+ UniDB->getGraphDB().getDigest(*KeyID), *ID1)
+ .moveInto(Val),
+ Succeeded());
+ }
+
+ auto checkTree = [&](const HashType &Digest, StringRef ExpectedTree) {
+ OnDiskGraphDB &DB = UniDB->getGraphDB();
+ std::optional<ObjectID> ID;
+ ASSERT_THAT_ERROR(DB.getReference(Digest).moveInto(ID), Succeeded());
+ std::string PrintedTree;
+ raw_string_ostream OS(PrintedTree);
+ ASSERT_THAT_ERROR(printTree(DB, *ID, OS), Succeeded());
+ EXPECT_EQ(PrintedTree, ExpectedTree);
+ };
+ auto checkRootTree = [&]() {
+ return checkTree(RootHash, "root\n 1\n 2\n");
+ };
+
+ auto checkKey = [&](const HashType &Key, StringRef ExpectedData) {
+ OnDiskGraphDB &DB = UniDB->getGraphDB();
+ std::optional<ObjectID> Val;
+ ASSERT_THAT_ERROR(cacheGet(UniDB->getKeyValueDB(), Key).moveInto(Val),
+ Succeeded());
+
+ ASSERT_TRUE(Val.has_value());
+ std::optional<ondisk::ObjectHandle> Obj;
+ ASSERT_THAT_ERROR(DB.load(*Val).moveInto(Obj), Succeeded());
+ EXPECT_EQ(toStringRef(DB.getObjectData(*Obj)), ExpectedData);
+ };
+
+ checkRootTree();
+ checkTree(OtherHash, "other\n");
+ checkKey(Key1Hash, "root");
+ checkKey(Key2Hash, "1");
+
+ auto storeBigObject = [&](unsigned Index) {
+ SmallString<1000> Buf;
+ Buf.append(970, 'a');
+ raw_svector_ostream(Buf) << Index;
+ std::optional<ObjectID> ID;
+ ASSERT_THAT_ERROR(store(UniDB->getGraphDB(), Buf, {}).moveInto(ID),
+ Succeeded());
+ };
+
+ uint64_t PrevStoreSize = UniDB->getStorageSize();
+ unsigned Index = 0;
+ while (!UniDB->hasExceededSizeLimit()) {
+ storeBigObject(Index++);
+ }
+ EXPECT_GT(UniDB->getStorageSize(), PrevStoreSize);
+ UniDB->setSizeLimit(SizeLimit * 2);
+ EXPECT_FALSE(UniDB->hasExceededSizeLimit());
+ UniDB->setSizeLimit(SizeLimit);
+ EXPECT_TRUE(UniDB->hasExceededSizeLimit());
+
+ reopenDB();
+
+ EXPECT_FALSE(UniDB->hasExceededSizeLimit());
+ EXPECT_FALSE(UniDB->needsGarbageCollection());
+
+ checkRootTree();
+ checkKey(Key1Hash, "root");
+
+ while (!UniDB->hasExceededSizeLimit()) {
+ storeBigObject(Index++);
+ }
+ PrevStoreSize = UniDB->getStorageSize();
+ ASSERT_THAT_ERROR(UniDB->close(), Succeeded());
+ EXPECT_TRUE(UniDB->needsGarbageCollection());
+
+ reopenDB();
+ EXPECT_TRUE(UniDB->needsGarbageCollection());
+
+ std::optional<size_t> DirSizeBefore;
+ ASSERT_THAT_ERROR(countFileSizes(Temp.path()).moveInto(DirSizeBefore),
+ Succeeded());
+
+ ASSERT_THAT_ERROR(UnifiedOnDiskCache::collectGarbage(Temp.path()),
+ Succeeded());
+
+ std::optional<size_t> DirSizeAfter;
+ ASSERT_THAT_ERROR(countFileSizes(Temp.path()).moveInto(DirSizeAfter),
+ Succeeded());
+ EXPECT_LT(*DirSizeAfter, *DirSizeBefore);
+
+ reopenDB();
+ EXPECT_FALSE(UniDB->needsGarbageCollection());
+
+ checkRootTree();
+ checkKey(Key1Hash, "root");
+
+ EXPECT_LT(UniDB->getStorageSize(), PrevStoreSize);
+
+ // 'Other' tree and 'Key2' got garbage-collected.
+ {
+ OnDiskGraphDB &DB = UniDB->getGraphDB();
+ std::optional<ObjectID> ID;
+ ASSERT_THAT_ERROR(DB.getReference(OtherHash).moveInto(ID), Succeeded());
+ EXPECT_FALSE(DB.containsObject(*ID));
+ std::optional<ObjectID> Val;
+ ASSERT_THAT_ERROR(cacheGet(UniDB->getKeyValueDB(), Key2Hash).moveInto(Val),
+ Succeeded());
+ EXPECT_FALSE(Val.has_value());
+ }
+}