xtreemfs/cpp/test/libxtreemfs/async_write_handler_test.cpp
2020-09-22 02:25:22 +02:00

250 lines
7.6 KiB
C++

/*
* Copyright (c) 2012 by Matthias Noack, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#include <gtest/gtest.h>
#include <algorithm>
#include <vector>
#include "common/test_environment.h"
#include "common/test_rpc_server_dir.h"
#include "common/test_rpc_server_mrc.h"
#include "common/test_rpc_server_osd.h"
#include "libxtreemfs/client.h"
#include "libxtreemfs/file_handle.h"
#include "libxtreemfs/options.h"
#include "libxtreemfs/volume.h"
#include "libxtreemfs/xtreemfs_exception.h"
#include "rpc/client.h"
#include "xtreemfs/OSDServiceConstants.h"
using namespace std;
using namespace xtreemfs::pbrpc;
using namespace xtreemfs::util;
namespace xtreemfs {
namespace rpc {
class AsyncWriteHandlerTest : public ::testing::Test {
protected:
static const int kBlockSize = 1024 * 128;
virtual void SetUp() {
initialize_logger(LEVEL_WARN);
test_env.options.connect_timeout_s = 3;
test_env.options.request_timeout_s = 3;
test_env.options.retry_delay_s = 3;
test_env.options.enable_async_writes = true;
test_env.options.async_writes_max_request_size_kb = 128;
test_env.options.async_writes_max_requests = 8;
test_env.options.periodic_xcap_renewal_interval_s = 2;
ASSERT_TRUE(test_env.Start());
// Open a volume
volume = test_env.client->OpenVolume(
test_env.volume_name_,
NULL, // No SSL options.
test_env.options);
// Open a file.
file = volume->OpenFile(
test_env.user_credentials,
"/test_file",
static_cast<xtreemfs::pbrpc::SYSTEM_V_FCNTL>(
xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_CREAT |
xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_TRUNC |
xtreemfs::pbrpc::SYSTEM_V_FCNTL_H_O_RDWR));
}
virtual void TearDown() {
//volume->Close();
test_env.Stop();
}
TestEnvironment test_env;
Volume* volume;
FileHandle* file;
};
/** A normal async write with nothing special */
TEST_F(AsyncWriteHandlerTest, NormalWrite) {
size_t blocks = 5;
size_t buffer_size = kBlockSize * blocks;
boost::scoped_array<char> write_buf(new char[buffer_size]());
vector<WriteEntry> expected(blocks);
for (size_t i = 0; i < blocks; ++i) {
expected[i] = WriteEntry(i, 0, kBlockSize);
}
ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0));
ASSERT_NO_THROW(file->Flush());
EXPECT_TRUE(equal(expected.begin(),
expected.end(),
test_env.osds[0]->GetReceivedWrites().end() - blocks));
ASSERT_NO_THROW(file->Close());
}
/** Let the first write request fail. The write should be retried and finally
* succeed. */
TEST_F(AsyncWriteHandlerTest, FirstWriteFail) {
size_t blocks = 5;
size_t buffer_size = kBlockSize * blocks;
boost::scoped_array<char> write_buf(new char[buffer_size]());
vector<WriteEntry> expected_tail(blocks);
for (size_t i = 0; i < blocks; ++i) {
expected_tail[i] = WriteEntry(i, 0, kBlockSize);
}
test_env.osds[0]->AddDropRule(
new ProcIDFilterRule(xtreemfs::pbrpc::PROC_ID_WRITE, new DropNRule(1)));
ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0));
ASSERT_NO_THROW(file->Flush());
EXPECT_TRUE(equal(expected_tail.begin(), expected_tail.end(),
test_env.osds[0]->GetReceivedWrites().end() - expected_tail.size()));
ASSERT_NO_THROW(file->Close());
}
/** Let the last write request fail. The write should be retried and finally
* succeed. */
TEST_F(AsyncWriteHandlerTest, LastWriteFail) {
size_t blocks = 5;
size_t buffer_size = kBlockSize * blocks;
boost::scoped_array<char> write_buf(new char[buffer_size]());
vector<WriteEntry> expected_front(blocks - 1);
vector<WriteEntry> expected_tail(1);
for (size_t i = 0; i < blocks - 1; ++i) {
expected_front[i] = WriteEntry(i, 0, kBlockSize);
}
expected_tail[0] = WriteEntry(blocks - 1, 0, kBlockSize);
test_env.osds[0]->AddDropRule(
new ProcIDFilterRule(xtreemfs::pbrpc::PROC_ID_WRITE,
new SkipMDropNRule(blocks - 1, 1)));
ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0));
ASSERT_NO_THROW(file->Flush());
EXPECT_TRUE(equal(expected_front.begin(),
expected_front.end(),
test_env.osds[0]->GetReceivedWrites().begin()));
EXPECT_TRUE(equal(expected_tail.begin(),
expected_tail.end(),
test_env.osds[0]->GetReceivedWrites().end() -
expected_tail.size()));
ASSERT_NO_THROW(file->Close());
}
/** Let the intermediate write request fail. The write should be retried and
* finally succeed. */
TEST_F(AsyncWriteHandlerTest, IntermediateWriteFail) {
size_t blocks = 5;
size_t buffer_size = kBlockSize * blocks;
size_t middle = blocks / 2;
boost::scoped_array<char> write_buf(new char[buffer_size]());
vector<WriteEntry> expected_front(middle);
vector<WriteEntry> expected_tail(blocks - middle);
for (size_t i = 0; i < middle; ++i) {
expected_front[i] = WriteEntry(i, 0, kBlockSize);
}
for (size_t i = middle; i < blocks; ++i) {
expected_tail[i - middle] = WriteEntry(i, 0, kBlockSize);
}
test_env.osds[0]->AddDropRule(
new ProcIDFilterRule(xtreemfs::pbrpc::PROC_ID_WRITE,
new SkipMDropNRule(middle, 1)));
ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0));
ASSERT_NO_THROW(file->Flush());
EXPECT_TRUE(equal(expected_front.begin(),
expected_front.end(),
test_env.osds[0]->GetReceivedWrites().begin()));
EXPECT_TRUE(equal(expected_tail.begin(),
expected_tail.end(),
test_env.osds[0]->GetReceivedWrites().end() -
expected_tail.size()));
ASSERT_NO_THROW(file->Close());
}
/** Let the all writes request fail. The write should be retried and finally
* succeed. */
TEST_F(AsyncWriteHandlerTest, AllWritesFail) {
size_t blocks = 5;
size_t buffer_size = kBlockSize * blocks;
boost::scoped_array<char> write_buf(new char[buffer_size]());
vector<WriteEntry> expected_tail(blocks);
for (size_t i = 0; i < blocks; ++i) {
expected_tail[i] = WriteEntry(i, 0, kBlockSize);
}
test_env.osds[0]->AddDropRule(
new ProcIDFilterRule(xtreemfs::pbrpc::PROC_ID_WRITE,
new DropNRule(blocks)));
ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0));
ASSERT_NO_THROW(file->Flush());
EXPECT_TRUE(equal(expected_tail.begin(),
expected_tail.end(),
test_env.osds[0]->GetReceivedWrites().end() -
expected_tail.size()));
ASSERT_NO_THROW(file->Close());
}
/** Let the first write request fail when there are more writes than
* writeahead allows. The write should be retried and finally succeed. */
TEST_F(AsyncWriteHandlerTest, FirstWriteFailLong) {
size_t blocks = 2 * test_env.options.async_writes_max_requests;
size_t buffer_size = kBlockSize * blocks;
boost::scoped_array<char> write_buf(new char[buffer_size]());
vector<WriteEntry> expected_tail(blocks);
for (size_t i = 0; i < blocks; ++i) {
expected_tail[i] = WriteEntry(i, 0, kBlockSize);
}
test_env.osds[0]->AddDropRule(
new ProcIDFilterRule(xtreemfs::pbrpc::PROC_ID_WRITE, new DropNRule(1)));
ASSERT_NO_THROW(file->Write(write_buf.get(), buffer_size, 0));
ASSERT_NO_THROW(file->Flush());
EXPECT_TRUE(equal(expected_tail.begin(),
expected_tail.end(),
test_env.osds[0]->GetReceivedWrites().end() -
expected_tail.size()));
ASSERT_NO_THROW(file->Close());
}
/** TODO(mno): Maybe let all future requests fail to test the retry count. */
} // namespace rpc
} // namespace xtreemfs