forked from WiscADSL/MadFS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_gc.cpp
162 lines (130 loc) · 4.26 KB
/
test_gc.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#include <fcntl.h>
#include "common.h"
#include "gc.h"
#include "lib/lib.h"
#include "utils/logging.h"
const char* filepath = get_filepath();
using madfs::BLOCK_SIZE;
using madfs::NUM_INLINE_TX_ENTRY;
using madfs::NUM_TX_ENTRY_PER_BLOCK;
using madfs::debug::clear_timer;
using madfs::debug::print_file;
using madfs::utility::GarbageCollector;
struct BasicTestOpt {
int num_bytes_per_iter = BLOCK_SIZE;
int num_iter = NUM_INLINE_TX_ENTRY + NUM_TX_ENTRY_PER_BLOCK + 1;
bool print = false;
// if set, the offset will be random in [0, random_block_range * BLOCK_SIZE)
int random_block_range = 0;
};
void basic_test(BasicTestOpt opt) {
const auto& [num_bytes_per_iter, num_iter, print, random_block_range] = opt;
unlink(filepath);
int fd = open(filepath, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
auto src_buf = std::make_unique<char[]>(num_bytes_per_iter);
for (int i = 0; i < num_iter; ++i) {
ssize_t ret;
if (random_block_range) {
off_t offset = (rand() % random_block_range) * BLOCK_SIZE;
ret = pwrite(fd, src_buf.get(), num_bytes_per_iter, offset);
} else {
ret = pwrite(fd, src_buf.get(), num_bytes_per_iter, 0);
}
ASSERT(ret == num_bytes_per_iter);
}
fsync(fd);
auto file = madfs::get_file(fd);
auto file_size = file->blk_table.get_state_unsafe().file_size;
if (print) std::cerr << *file;
close(fd);
clear_timer();
{
GarbageCollector garbage_collector(filepath);
garbage_collector.do_gc();
if (print) std::cerr << *garbage_collector.get_file();
}
{
int new_fd = open(filepath, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
auto new_file = madfs::get_file(new_fd);
ASSERT(new_file->blk_table.get_state_unsafe().file_size == file_size);
close(new_fd);
}
}
/**
* Test the basic functionality of garbage collection.
*
* Launch a number of io threads to write to the file, and then run the gc
* thread while the io threads are in the background.
*/
void sync_test() {
unlink(filepath);
int fd = open(filepath, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
int num_io_threads = 4;
std::atomic<bool> gc_done = false;
std::vector<std::atomic<bool>> io_threads_done(num_io_threads);
std::vector<std::thread> io_threads;
for (int i = 0; i < num_io_threads; ++i) {
io_threads.emplace_back([&, i]() {
if (i != 0) {
// wait for the previous thread to finish
while (!io_threads_done[i - 1].load()) {
std::this_thread::yield();
}
}
int num_iter = i == 0
? NUM_INLINE_TX_ENTRY + NUM_TX_ENTRY_PER_BLOCK * 5 + 1
: NUM_TX_ENTRY_PER_BLOCK;
LOG_INFO("thread %d start", i);
char buf[BLOCK_SIZE]{};
for (int iter = 0; iter < num_iter; ++iter) {
auto ret = pwrite(fd, buf, BLOCK_SIZE, 0);
ASSERT(ret == BLOCK_SIZE);
}
fsync(fd);
LOG_INFO("thread %d finished writing", i);
// notify the next thread to start
io_threads_done[i] = true;
// keep running until the gc is done
while (!gc_done.load()) {
std::this_thread::yield();
}
LOG_INFO("thread %d exiting", i);
});
}
std::thread gc_thread([&]() {
while (!io_threads_done[num_io_threads - 1].load()) {
std::this_thread::yield();
}
LOG_INFO("gc start");
GarbageCollector garbage_collector(filepath);
std::cerr << garbage_collector.file;
std::cerr << garbage_collector.file->shm_mgr;
garbage_collector.do_gc();
std::cerr << garbage_collector.file;
LOG_INFO("gc finished");
gc_done = true;
});
gc_thread.join();
for (auto& t : io_threads) t.join();
close(fd);
{
GarbageCollector garbage_collector(filepath);
std::cerr << garbage_collector.file->shm_mgr;
garbage_collector.do_gc();
std::cerr << garbage_collector.file;
}
}
int main() {
srand(0); // NOLINT(cert-msc51-cpp)
// basic_test({1, 1'000'000});
// basic_test({BLOCK_SIZE * 64, 1'000'000});
basic_test({});
basic_test({.random_block_range = 1000});
if constexpr (!madfs::BuildOptions::use_pmemcheck) {
// the following tests are too slow for pmemcheck
basic_test({.num_bytes_per_iter = BLOCK_SIZE * 63});
basic_test({.num_bytes_per_iter = BLOCK_SIZE * 64});
basic_test({.num_bytes_per_iter = BLOCK_SIZE * 65});
}
sync_test();
}