Skip to content

Commit bc126e8

Browse files
committed
add basic tests for btree LL and VI
1 parent dc15b70 commit bc126e8

9 files changed

+499
-237
lines changed

source/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ endif()
6868
# clang-tidy
6969
# ---------------------------------------------------------------------------
7070

71-
# clang-tidy
71+
# # clang-tidy
7272
# add_custom_target(run-clang-tidy
7373
# COMMAND clang-tidy -p=${CMAKE_BINARY_DIR} --config-file=${CMAKE_SOURCE_DIR}/.clang-tidy ${LEANSTORE_SRC}
7474
# COMMENT "Running Clang-Tidy"

source/utils/Files.cpp

+37-36
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22

33
#include "Exceptions.hpp"
44
#include "Units.hpp"
5-
// -------------------------------------------------------------------------------------
6-
// -------------------------------------------------------------------------------------
5+
76
#include <fcntl.h>
87
#include <sys/stat.h>
98
#include <unistd.h>
@@ -13,17 +12,16 @@
1312
#include <cmath>
1413
#include <sstream>
1514
#include <thread>
16-
// -------------------------------------------------------------------------------------
15+
1716
using namespace std;
18-
// -------------------------------------------------------------------------------------
17+
1918
namespace leanstore {
2019
namespace utils {
21-
// -------------------------------------------------------------------------------------
20+
21+
// WARNING: this only works with 4 byte types
2222
template <class T>
23-
bool createTestFileImpl(
24-
const string& file_name, uint64_t count,
25-
function<T(int)> factory) // WARNING: this only works with 4 byte types
26-
{
23+
bool createTestFileImpl(const string& file_name, uint64_t count,
24+
function<T(int)> factory) {
2725
// Open file
2826
ofstream of(file_name, ios::binary);
2927
if (!of.is_open() || !of.good())
@@ -46,7 +44,7 @@ bool createTestFileImpl(
4644
of.close();
4745
return of.good();
4846
}
49-
// -------------------------------------------------------------------------------------
47+
5048
template <class T>
5149
bool foreachInFileImpl(const string& file_name, function<void(T)> callback) {
5250
// Open file
@@ -64,20 +62,20 @@ bool foreachInFileImpl(const string& file_name, function<void(T)> callback) {
6462
}
6563
return true;
6664
}
67-
// -------------------------------------------------------------------------------------
65+
6866
bool CreateTestFile(const string& file_name, uint64_t count,
6967
function<int32_t(int32_t)> factory) {
7068
return createTestFileImpl<int32_t>(file_name, count, factory);
7169
}
72-
// -------------------------------------------------------------------------------------
70+
7371
bool ForeachInFile(const string& file_name, function<void(uint32_t)> callback) {
7472
return foreachInFileImpl<uint32_t>(file_name, callback);
7573
}
76-
// -------------------------------------------------------------------------------------
74+
7775
bool CreateDirectory(const string& directory_name) {
7876
return mkdir(directory_name.c_str(), 0666) == 0;
7977
}
80-
// -------------------------------------------------------------------------------------
78+
8179
bool CreateFile(const string& file_name, const uint64_t bytes) {
8280
int file_fd = open(file_name.c_str(), O_CREAT | O_WRONLY, 0666);
8381
if (file_fd < 0) {
@@ -94,7 +92,7 @@ bool CreateFile(const string& file_name, const uint64_t bytes) {
9492

9593
return true;
9694
}
97-
// -------------------------------------------------------------------------------------
95+
9896
bool CreateFile(const string& file_name, const string& content) {
9997
int file_fd = open(file_name.c_str(), O_CREAT | O_TRUNC | O_WRONLY, 0666);
10098
if (file_fd < 0) {
@@ -104,9 +102,11 @@ bool CreateFile(const string& file_name, const string& content) {
104102
size_t written_bytes = write(file_fd, content.data(), content.size());
105103
return written_bytes == content.size();
106104
}
107-
// -------------------------------------------------------------------------------------
108-
void DeleteFile(const std::string& file_name) { remove(file_name.c_str()); }
109-
// -------------------------------------------------------------------------------------
105+
106+
void DeleteFile(const std::string& file_name) {
107+
remove(file_name.c_str());
108+
}
109+
110110
uint64_t GetFileLength(const string& file_name) {
111111
int fileFD = open(file_name.c_str(), O_RDWR);
112112
if (fileFD < 0) {
@@ -124,45 +124,45 @@ uint64_t GetFileLength(const string& file_name) {
124124
close(fileFD);
125125
return st.st_size;
126126
}
127-
// -------------------------------------------------------------------------------------
127+
128128
bool fileExists(const string& file_name) {
129129
struct stat buffer;
130130
bool exists = (stat(file_name.c_str(), &buffer) == 0);
131131
return exists && (buffer.st_mode & S_IFREG);
132132
}
133-
// -------------------------------------------------------------------------------------
133+
134134
bool directoryExists(const string& file_name) {
135135
struct stat buffer;
136136
bool exists = (stat(file_name.c_str(), &buffer) == 0);
137137
return exists && (buffer.st_mode & S_IFDIR);
138138
}
139-
// -------------------------------------------------------------------------------------
139+
140140
bool pathExists(const string& file_name) {
141141
struct stat buffer;
142142
bool exists = (stat(file_name.c_str(), &buffer) == 0);
143143
return exists;
144144
}
145-
// -------------------------------------------------------------------------------------
145+
146146
string LoadFileToMemory(const string& file_name) {
147147
uint64_t length = GetFileLength(file_name);
148148
string data(length, 'a');
149149
ifstream in(file_name);
150150
in.read(&data[0], length);
151151
return data;
152152
}
153-
// -------------------------------------------------------------------------------------
153+
154154
namespace {
155-
// -------------------------------------------------------------------------------------
155+
156156
uint64_t applyPrecision(uint64_t input, uint32_t precision) {
157157
uint32_t digits = log10(input) + 1;
158158
if (digits <= precision)
159159
return input;
160160
uint32_t invalidDigits = pow(10, digits - precision);
161161
return (uint64_t)((double)input / invalidDigits + .5f) * invalidDigits;
162162
}
163-
// -------------------------------------------------------------------------------------
163+
164164
} // namespace
165-
// -------------------------------------------------------------------------------------
165+
166166
string FormatTime(chrono::nanoseconds ns, uint32_t precision) {
167167
ostringstream os;
168168

@@ -184,7 +184,7 @@ string FormatTime(chrono::nanoseconds ns, uint32_t precision) {
184184

185185
return os.str();
186186
}
187-
// -------------------------------------------------------------------------------------
187+
188188
void PinThread(int socket) {
189189
#ifdef __linux__
190190
// Doesn't work on OS X right now
@@ -202,7 +202,7 @@ void PinThread(int socket) {
202202
#endif
203203
(void)socket;
204204
}
205-
// -------------------------------------------------------------------------------------
205+
206206
void RunMultithreaded(uint32_t thread_count, function<void(uint32_t)> foo) {
207207
atomic<bool> start(false);
208208
vector<unique_ptr<thread>> threads(thread_count);
@@ -218,7 +218,7 @@ void RunMultithreaded(uint32_t thread_count, function<void(uint32_t)> foo) {
218218
iter->join();
219219
}
220220
}
221-
// -------------------------------------------------------------------------------------
221+
222222
uint8_t* AlignedAlloc(uint64_t alignment, uint64_t size) {
223223
void* result = nullptr;
224224
int error = posix_memalign(&result, alignment, size);
@@ -227,8 +227,9 @@ uint8_t* AlignedAlloc(uint64_t alignment, uint64_t size) {
227227
}
228228
return reinterpret_cast<uint8_t*>(result);
229229
}
230-
// -------------------------------------------------------------------------------------
230+
231231
namespace {
232+
232233
array<char, 16> NUM_TO_HEX{{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
233234
'a', 'b', 'c', 'd', 'e', 'f'}};
234235
uint8_t HexToNum(char c) {
@@ -240,8 +241,9 @@ uint8_t HexToNum(char c) {
240241
}
241242
UNREACHABLE();
242243
}
244+
243245
} // namespace
244-
// -------------------------------------------------------------------------------------
246+
245247
const string DataToHex(const uint8_t* data, uint32_t len, bool spaces) {
246248
string result;
247249
for (uint32_t i = 0; i < len; i++) {
@@ -252,11 +254,11 @@ const string DataToHex(const uint8_t* data, uint32_t len, bool spaces) {
252254
}
253255
return result;
254256
}
255-
// -------------------------------------------------------------------------------------
257+
256258
const string StringToHex(const string& str, bool spaces) {
257259
return DataToHex((const uint8_t*)str.data(), str.size(), spaces);
258260
}
259-
// -------------------------------------------------------------------------------------
261+
260262
const vector<uint8_t> HexToData(const string& str, bool spaces) {
261263
assert(spaces || str.size() % 2 == 0);
262264

@@ -269,7 +271,7 @@ const vector<uint8_t> HexToData(const string& str, bool spaces) {
269271

270272
return result;
271273
}
272-
// -------------------------------------------------------------------------------------
274+
273275
const string HexToString(const string& str, bool spaces) {
274276
assert(spaces || str.size() % 2 == 0);
275277

@@ -282,7 +284,6 @@ const string HexToString(const string& str, bool spaces) {
282284

283285
return result;
284286
}
285-
// -------------------------------------------------------------------------------------
287+
286288
} // namespace utils
287289
} // namespace leanstore
288-
// -------------------------------------------------------------------------------------

tests/BTreeLLTest.cpp

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
#include "LeanStore.hpp"
2+
#include "storage/buffer-manager/BufferFrame.hpp"
3+
#include "storage/buffer-manager/BufferManager.hpp"
4+
#include "utils/DebugFlags.hpp"
5+
#include "utils/Defer.hpp"
6+
#include "utils/RandomGenerator.hpp"
7+
8+
#include <gtest/gtest.h>
9+
10+
#include <filesystem>
11+
12+
namespace leanstore {
13+
14+
class BTreeLLTest : public ::testing::Test {
15+
protected:
16+
std::unique_ptr<LeanStore> mLeanStore;
17+
18+
BTreeLLTest() {
19+
FLAGS_vi = true;
20+
FLAGS_enable_print_btree_stats_on_exit = true;
21+
FLAGS_wal = true;
22+
FLAGS_bulk_insert = false;
23+
}
24+
25+
~BTreeLLTest() = default;
26+
};
27+
28+
TEST_F(BTreeLLTest, BTreeLLCreate) {
29+
FLAGS_data_dir = "/tmp/BTreeLLTest/BTreeLLCreate";
30+
std::filesystem::path dir_path = FLAGS_data_dir;
31+
std::filesystem::remove_all(dir_path);
32+
std::filesystem::create_directories(dir_path);
33+
34+
FLAGS_worker_threads = 2;
35+
FLAGS_recover = false;
36+
mLeanStore = std::make_unique<leanstore::LeanStore>();
37+
storage::btree::BTreeLL* btree;
38+
storage::btree::BTreeLL* another;
39+
40+
// create leanstore btree for table records
41+
auto btreeName = "testTree1";
42+
auto btreeConfig = leanstore::storage::btree::BTreeGeneric::Config{
43+
.mEnableWal = FLAGS_wal,
44+
.mUseBulkInsert = FLAGS_bulk_insert,
45+
};
46+
47+
cr::CRManager::sInstance->scheduleJobSync(0, [&]() {
48+
EXPECT_TRUE(mLeanStore->RegisterBTreeLL(btreeName, btreeConfig, &btree));
49+
EXPECT_NE(btree, nullptr);
50+
});
51+
52+
// create btree with same should fail in the same worker
53+
cr::CRManager::sInstance->scheduleJobSync(0, [&]() {
54+
EXPECT_FALSE(mLeanStore->RegisterBTreeLL(btreeName, btreeConfig, &another));
55+
EXPECT_EQ(another, nullptr);
56+
});
57+
58+
// create btree with same should also fail in other workers
59+
cr::CRManager::sInstance->scheduleJobSync(1, [&]() {
60+
EXPECT_FALSE(mLeanStore->RegisterBTreeLL(btreeName, btreeConfig, &another));
61+
EXPECT_EQ(another, nullptr);
62+
});
63+
64+
// create btree with another different name should success
65+
btreeName = "testTree2";
66+
cr::CRManager::sInstance->scheduleJobSync(0, [&]() {
67+
EXPECT_TRUE(mLeanStore->RegisterBTreeLL(btreeName, btreeConfig, &another));
68+
EXPECT_NE(btree, nullptr);
69+
});
70+
}
71+
72+
TEST_F(BTreeLLTest, BTreeLLInsertAndLookup) {
73+
FLAGS_data_dir = "/tmp/BTreeLLTest/BTreeLLInsertAndLookup";
74+
std::filesystem::path dir_path = FLAGS_data_dir;
75+
std::filesystem::remove_all(dir_path);
76+
std::filesystem::create_directories(dir_path);
77+
FLAGS_worker_threads = 2;
78+
FLAGS_recover = false;
79+
mLeanStore = std::make_unique<leanstore::LeanStore>();
80+
storage::btree::BTreeLL* btree;
81+
82+
// prepare key-value pairs to insert
83+
size_t numKVs(10);
84+
std::vector<std::tuple<std::string, std::string>> kvToTest;
85+
for (size_t i = 0; i < numKVs; ++i) {
86+
std::string key("key_btree_LL_xxxxxxxxxxxx_" + std::to_string(i));
87+
std::string val("VAL_BTREE_LL_YYYYYYYYYYYY_" + std::to_string(i));
88+
kvToTest.push_back(std::make_tuple(key, val));
89+
}
90+
91+
// create leanstore btree for table records
92+
auto btreeName = "testTree1";
93+
auto btreeConfig = leanstore::storage::btree::BTreeGeneric::Config{
94+
.mEnableWal = FLAGS_wal,
95+
.mUseBulkInsert = FLAGS_bulk_insert,
96+
};
97+
cr::CRManager::sInstance->scheduleJobSync(0, [&]() {
98+
EXPECT_TRUE(mLeanStore->RegisterBTreeLL(btreeName, btreeConfig, &btree));
99+
EXPECT_NE(btree, nullptr);
100+
101+
// insert some values
102+
for (size_t i = 0; i < numKVs; ++i) {
103+
const auto& [key, val] = kvToTest[i];
104+
EXPECT_EQ(btree->insert(Slice((const u8*)key.data(), key.size()),
105+
Slice((const u8*)val.data(), val.size())),
106+
OP_RESULT::OK);
107+
}
108+
});
109+
110+
// query on the created btree in the same worker
111+
cr::CRManager::sInstance->scheduleJobSync(0, [&]() {
112+
std::string copiedValue;
113+
auto copyValueOut = [&](Slice val) {
114+
copiedValue = std::string((const char*)val.data(), val.size());
115+
};
116+
for (size_t i = 0; i < numKVs; ++i) {
117+
const auto& [key, expectedVal] = kvToTest[i];
118+
EXPECT_EQ(
119+
btree->Lookup(Slice((const u8*)key.data(), key.size()), copyValueOut),
120+
OP_RESULT::OK);
121+
EXPECT_EQ(copiedValue, expectedVal);
122+
}
123+
});
124+
125+
// query on the created btree in another worker
126+
cr::CRManager::sInstance->scheduleJobSync(1, [&]() {
127+
std::string copiedValue;
128+
auto copyValueOut = [&](Slice val) {
129+
copiedValue = std::string((const char*)val.data(), val.size());
130+
};
131+
for (size_t i = 0; i < numKVs; ++i) {
132+
const auto& [key, expectedVal] = kvToTest[i];
133+
EXPECT_EQ(
134+
btree->Lookup(Slice((const u8*)key.data(), key.size()), copyValueOut),
135+
OP_RESULT::OK);
136+
EXPECT_EQ(copiedValue, expectedVal);
137+
}
138+
});
139+
}
140+
141+
} // namespace leanstore

0 commit comments

Comments
 (0)