test/libcephfs: add cases for last dir testing.

Signed-off-by: Igor Fedotov <igor.fedotov@croit.io>
This commit is contained in:
Igor Fedotov 2023-01-23 13:59:41 +03:00
parent e178629962
commit 3e88c6b49a

View File

@ -16,6 +16,7 @@
#include "include/stat.h"
#include "include/ceph_assert.h"
#include "include/object.h"
#include "include/stringify.h"
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
@ -51,6 +52,10 @@ public:
ceph_shutdown(cmount);
}
int conf_get(const char *option, char *buf, size_t len) {
return ceph_conf_get(cmount, option, buf, len);
}
string make_file_path(const char* relpath) {
char path[PATH_MAX];
sprintf(path, "%s/%s", dir_path, relpath);
@ -143,7 +148,7 @@ public:
}
int for_each_readdir(const char* relpath,
std::function<bool(const dirent* dire)> fn)
std::function<bool(const dirent*, const struct ceph_statx*)> fn)
{
auto subdir_path = make_file_path(relpath);
struct ceph_dir_result* ls_dir;
@ -151,13 +156,28 @@ public:
if (r != 0) {
return r;
}
struct dirent* result;
while( nullptr != (result = ceph_readdir(cmount, ls_dir))) {
if (strcmp(result->d_name, ".") == 0 ||
strcmp(result->d_name, "..") == 0) {
while (1) {
struct dirent result;
struct ceph_statx stx;
r = ceph_readdirplus_r(
cmount, ls_dir, &result, &stx, CEPH_STATX_BASIC_STATS,
0,
NULL);
if (!r)
break;
if (r < 0) {
std::cerr << "ceph_readdirplus_r failed, error: "
<< r << std::endl;
return r;
}
if (strcmp(result.d_name, ".") == 0 ||
strcmp(result.d_name, "..") == 0) {
continue;
}
if (!fn(result)) {
if (!fn(&result, &stx)) {
r = -EINTR;
break;
}
@ -171,7 +191,7 @@ public:
vector<string> expected(expected0);
auto end = expected.end();
int r = for_each_readdir(relpath,
[&](const dirent* dire) {
[&](const dirent* dire, const struct ceph_statx* stx) {
std::string name(dire->d_name);
auto it = std::find(expected.begin(), end, name);
@ -276,13 +296,13 @@ public:
{
int r =
for_each_readdir(relpath0,
[&] (const dirent* dire) {
[&](const dirent* dire, const struct ceph_statx* stx) {
string relpath = concat_path(relpath0, dire->d_name);
if (dire->d_type == DT_REG) {
unlink(relpath.c_str());
} else if (dire->d_type == DT_DIR) {
if (S_ISDIR(stx->stx_mode)) {
purge_dir(relpath.c_str());
rmdir(relpath.c_str());
} else {
unlink(relpath.c_str());
}
return true;
});
@ -314,6 +334,11 @@ public:
void prepareSnapDiffLib1Cases();
void prepareSnapDiffLib2Cases();
void prepareSnapDiffLib3Cases();
void prepareHugeSnapDiff(const std::string& name_prefix_start,
const std::string& name_prefix_bulk,
const std::string& name_prefix_end,
size_t file_count,
bool bulk_diff);
};
// Helper function to verify readdir_snapdiff returns expected results
@ -609,6 +634,72 @@ void TestMount::prepareSnapDiffLib2Cases()
ASSERT_EQ(0, mksnap("snap3"));
}
/* The following method creates a folder with tons of file
updated between two snapshots
We're to test SnapDiff readdir API against that structure.
* where:
- xN denotes file 'x' version N.
- X denotes folder name
- * denotes no/removed file/folder
# snap1 snap2
* aaaaA1 | aaaaA1 |
* aaaaB1 | * |
* * | aaaaC2 |
* aaaaD1 | aaaaD2 |
# file<NNN>1 | file<NNN>2|
* fileZ1 | fileA1 |
* zzzzA1 | zzzzA1 |
* zzzzB1 | * |
* * | zzzzC2 |
* zzzzD1 | zzzzD2 |
*/
void TestMount::prepareHugeSnapDiff(const std::string& name_prefix_start,
const std::string& name_prefix_bulk,
const std::string& name_prefix_end,
size_t file_count,
bool bulk_diff)
{
//************ snap1 *************
std::string startA = name_prefix_start + "A";
std::string startB = name_prefix_start + "B";
std::string startC = name_prefix_start + "C";
std::string startD = name_prefix_start + "D";
std::string endA = name_prefix_end + "A";
std::string endB = name_prefix_end + "B";
std::string endC = name_prefix_end + "C";
std::string endD = name_prefix_end + "D";
ASSERT_LE(0, write_full(startA.c_str(), "hello world"));
ASSERT_LE(0, write_full(startB.c_str(), "hello world"));
ASSERT_LE(0, write_full(startD.c_str(), "hello world"));
for(size_t i = 0; i < file_count; i++) {
auto s = name_prefix_bulk + stringify(i);
ASSERT_LE(0, write_full(s.c_str(), "hello world"));
}
ASSERT_LE(0, write_full(endA.c_str(), "hello world"));
ASSERT_LE(0, write_full(endB.c_str(), "hello world"));
ASSERT_LE(0, write_full(endD.c_str(), "hello world"));
ASSERT_EQ(0, mksnap("snap1"));
ASSERT_LE(0, unlink(startB.c_str()));
ASSERT_LE(0, write_full(startC.c_str(), "hello world2"));
ASSERT_LE(0, write_full(startD.c_str(), "hello world2"));
if (bulk_diff) {
for(size_t i = 0; i < file_count; i++) {
auto s = std::string(name_prefix_bulk) + stringify(i);
ASSERT_LE(0, write_full(s.c_str(), "hello world2"));
}
}
ASSERT_LE(0, unlink(endB.c_str()));
ASSERT_LE(0, write_full(endC.c_str(), "hello world2"));
ASSERT_LE(0, write_full(endD.c_str(), "hello world2"));
ASSERT_EQ(0, mksnap("snap2"));
}
/*
* More versatile SnapDiff readdir API verification,
* includes 3 different snapshots and interleaving/repetitive calls to make sure
@ -1469,3 +1560,125 @@ TEST(LibCephFS, SnapDiffCases1_3)
test_mount.rmsnap("snap2");
test_mount.rmsnap("snap3");
}
/*
* SnapDiff readdir API testing for huge dir
* when delta is minor.
*/
TEST(LibCephFS, HugeSnapDiffSmallDelta)
{
TestMount test_mount;
long int file_count = 10000;
printf("Seeding %ld files...\n", file_count);
// Create simple directory tree with a couple of snapshots
// to test against.
string name_prefix_start = "aaaa";
string name_prefix_bulk = "file";
string name_prefix_end = "zzzz";
test_mount.prepareHugeSnapDiff(name_prefix_start,
name_prefix_bulk,
name_prefix_end,
file_count,
false);
uint64_t snapid1;
uint64_t snapid2;
// learn snapshot ids and do basic verification
ASSERT_EQ(0, test_mount.get_snapid("snap1", &snapid1));
ASSERT_EQ(0, test_mount.get_snapid("snap2", &snapid2));
ASSERT_GT(snapid1, 0);
ASSERT_GT(snapid2, 0);
ASSERT_GT(snapid2, snapid1);
std::cout << snapid1 << " vs. " << snapid2 << std::endl;
//
// Make sure snap1 vs. snap2 delta for the root is as expected
//
{
vector<pair<string, uint64_t>> expected;
expected.emplace_back(name_prefix_start + "B", snapid1);
expected.emplace_back(name_prefix_start + "C", snapid2);
expected.emplace_back(name_prefix_start + "D", snapid2);
expected.emplace_back(name_prefix_end + "B", snapid1);
expected.emplace_back(name_prefix_end + "C", snapid2);
expected.emplace_back(name_prefix_end + "D", snapid2);
test_mount.verify_snap_diff(expected, "", "snap1", "snap2");
}
std::cout << "------------- closing -------------" << std::endl;
ASSERT_EQ(0, test_mount.purge_dir(""));
ASSERT_EQ(0, test_mount.rmsnap("snap1"));
ASSERT_EQ(0, test_mount.rmsnap("snap2"));
}
/*
* SnapDiff readdir API testing for huge dir
* when delta is large
*/
TEST(LibCephFS, HugeSnapDiffLargeDelta)
{
TestMount test_mount;
// Calculate amount of files required to have multiple directory fragments
// using relevant config parameters.
// file_count = mds_bal_spli_size * mds_bal_fragment_fast_factor + 100
char buf[256];
int r = test_mount.conf_get("mds_bal_split_size", buf, sizeof(buf));
ASSERT_TRUE(r >= 0);
long int file_count = strtol(buf, nullptr, 10);
r = test_mount.conf_get("mds_bal_fragment_fast_factor ", buf, sizeof(buf));
ASSERT_TRUE(r >= 0);
double factor = strtod(buf, nullptr);
file_count *= factor;
file_count += 100;
printf("Seeding %ld files...\n", file_count);
// Create simple directory tree with a couple of snapshots
// to test against.
string name_prefix_start = "aaaa";
string name_prefix_bulk = "file";
string name_prefix_end = "zzzz";
test_mount.prepareHugeSnapDiff(name_prefix_start,
name_prefix_bulk,
name_prefix_end,
file_count,
true);
uint64_t snapid1;
uint64_t snapid2;
// learn snapshot ids and do basic verification
ASSERT_EQ(0, test_mount.get_snapid("snap1", &snapid1));
ASSERT_EQ(0, test_mount.get_snapid("snap2", &snapid2));
ASSERT_GT(snapid1, 0);
ASSERT_GT(snapid2, 0);
ASSERT_GT(snapid2, snapid1);
std::cout << snapid1 << " vs. " << snapid2 << std::endl;
//
// Make sure snap1 vs. snap2 delta for the root is as expected
//
{
vector<pair<string, uint64_t>> expected;
expected.emplace_back(name_prefix_start + "B", snapid1);
expected.emplace_back(name_prefix_start + "C", snapid2);
expected.emplace_back(name_prefix_start + "D", snapid2);
for (size_t i = 0; i < (size_t)file_count; i++) {
expected.emplace_back(name_prefix_bulk + stringify(i), snapid2);
}
expected.emplace_back(name_prefix_end + "B", snapid1);
expected.emplace_back(name_prefix_end + "C", snapid2);
expected.emplace_back(name_prefix_end + "D", snapid2);
test_mount.verify_snap_diff(expected, "", "snap1", "snap2");
}
std::cout << "------------- closing -------------" << std::endl;
ASSERT_EQ(0, test_mount.purge_dir(""));
ASSERT_EQ(0, test_mount.rmsnap("snap1"));
ASSERT_EQ(0, test_mount.rmsnap("snap2"));
}