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 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
#include "btree_dir.h"
#include "crypto.h"
#include "myutils.h"
#include "test_common.h"
#include <catch.hpp>
#include <algorithm>
#include <limits>
#include <random>
#include <string>
#include <unordered_set>
#include <vector>
#include <cryptopp/rng.h>
static void test(securefs::BtreeDirectory& dir,
securefs::Directory& reference,
unsigned rounds,
double prob_get,
double prob_add,
double prob_del,
unsigned sequence) THREAD_ANNOTATION_REQUIRES(dir)
THREAD_ANNOTATION_REQUIRES(reference)
{
(void)sequence; // May be used later
bool is_prob_valid = (prob_get >= 0 && prob_add >= 0 && prob_del >= 0
&& prob_get + prob_add + prob_del <= 1.0);
REQUIRE(is_prob_valid);
std::uniform_real_distribution<> prob_dist(0, 1);
std::uniform_int_distribution<int> name_dist(0, 65535);
std::vector<std::string> filenames, filenames_prime;
securefs::Directory::callback inserter
= [&](const std::string& name, const securefs::id_type&, int) -> bool
{
filenames.push_back(name);
return true;
};
securefs::Directory::callback inserter_prime
= [&](const std::string& name, const securefs::id_type&, int) -> bool
{
filenames_prime.push_back(name);
return true;
};
dir.iterate_over_entries(inserter);
reference.iterate_over_entries(inserter_prime);
std::sort(filenames.begin(), filenames.end());
std::sort(filenames_prime.begin(), filenames_prime.end());
bool equal_filenames = (filenames == filenames_prime);
REQUIRE(equal_filenames);
securefs::id_type id, id_prime;
int type, type_prime;
for (unsigned i = 0; i < rounds; ++i)
{
auto p = prob_dist(get_random_number_engine());
if (p < prob_get)
{
filenames.clear();
dir.iterate_over_entries(inserter);
for (const std::string& n : filenames)
{
bool got = dir.get_entry(n, id, type);
bool got_prime = reference.get_entry(n, id_prime, type_prime);
REQUIRE(got == got_prime);
bool id_equal = (id == id_prime);
REQUIRE(id_equal);
REQUIRE(type == type_prime);
}
}
else if (p < prob_get + prob_add)
{
auto name = securefs::strprintf("%12d", name_dist(get_random_number_engine()));
securefs::generate_random(id.data(), id.size());
type = S_IFREG;
bool added = dir.add_entry(name, id, type);
bool added_prime = reference.add_entry(name, id, type);
REQUIRE(added == added_prime);
filenames.push_back(std::move(name));
}
else if (p < prob_get + prob_add + prob_del)
{
if (filenames.empty())
continue;
std::uniform_int_distribution<size_t> index_dist(0, filenames.size() - 1);
size_t idx = index_dist(get_random_number_engine());
bool removed = dir.remove_entry(filenames[idx], id, type);
bool removed_prime = reference.remove_entry(filenames[idx], id_prime, type_prime);
REQUIRE(removed == removed_prime);
filenames.erase(filenames.begin() + idx);
}
else
{
REQUIRE(dir.validate_free_list());
REQUIRE(dir.validate_btree_structure());
}
}
}
static void test_btree_dir(unsigned max_padding_size)
{
const size_t NUM_ENTRIES = 1000;
securefs::key_type key(0x3e);
securefs::id_type null_id{};
securefs::OSService service("tmp");
auto tmp1 = service.temp_name("btree", "1");
auto tmp2 = service.temp_name("btree", "2");
auto tmp3 = service.temp_name("btree", "3");
auto tmp4 = service.temp_name("btree", "4");
int flags = O_RDWR | O_EXCL | O_CREAT;
{
securefs::BtreeDirectory dir(service.open_file_stream(tmp1, flags, 0644),
service.open_file_stream(tmp2, flags, 0644),
key,
null_id,
true,
8000,
12,
max_padding_size,
false);
securefs::SimpleDirectory ref_dir(service.open_file_stream(tmp3, flags, 0644),
service.open_file_stream(tmp4, flags, 0644),
key,
null_id,
true,
8000,
12,
max_padding_size,
false);
securefs::DoubleFileLockGuard dflg(dir, ref_dir);
test(dir, ref_dir, 1000, 0.3, 0.5, 0.1, 1);
test(dir, ref_dir, 1000, 0.3, 0.1, 0.5, 2);
test(dir, ref_dir, 1000, 0.3, 0.3, 0.3, 3);
dir.flush();
ref_dir.flush();
}
{
// Test if the data persists on the disk
securefs::BtreeDirectory dir(service.open_file_stream(tmp1, O_RDWR, 0),
service.open_file_stream(tmp2, O_RDWR, 0),
key,
null_id,
true,
8000,
12,
max_padding_size,
false);
securefs::SimpleDirectory ref_dir(service.open_file_stream(tmp3, O_RDWR, 0),
service.open_file_stream(tmp4, O_RDWR, 0),
key,
null_id,
true,
8000,
12,
max_padding_size,
false);
securefs::DoubleFileLockGuard dflg(dir, ref_dir);
test(dir, ref_dir, 1000, 0.3, 0.3, 0.3, 4);
dir.flush();
ref_dir.flush();
}
}
TEST_CASE("Test BtreeDirectory")
{
test_btree_dir(0);
test_btree_dir(128);
}
|