Imported Upstream version 1.5.1

This commit is contained in:
Mario Fetka
2020-09-22 02:25:22 +02:00
commit 434d6067d9
2103 changed files with 928962 additions and 0 deletions

View File

@@ -0,0 +1,131 @@
/*
* Copyright (c) 2012 by Matthias Noack, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#ifndef CPP_TEST_COMMON_DROP_RULES_H_
#define CPP_TEST_COMMON_DROP_RULES_H_
namespace xtreemfs {
namespace rpc {
/** This interface is used for arbitrary implementations of drop rules
* for RPC requests processed by TestRPCServer.
*/
class DropRule {
public:
/** This method is called for every received process */
virtual bool DropRequest(uint32_t proc_id) = 0;
/** This method is used to determine whether or not a rule can be deleted */
virtual bool IsPointless() const = 0;
/** Helper predicate function for std::algorithm */
static bool IsPointlessPred(const DropRule* rule) {
return rule->IsPointless();
}
virtual ~DropRule() {};
};
/** This rule skips m requests before dropping n requests. Afterwards, the rule
* becomes pointless. The proc_id is not checked.
*/
class SkipMDropNRule : public DropRule {
public:
SkipMDropNRule(size_t skip, size_t drop) : skip_count_(skip), drop_count_(drop) {}
virtual bool DropRequest(uint32_t proc_id) {
if (skip_count_ == 0 && drop_count_ > 0) {
--drop_count_;
return true;
} else if (skip_count_ > 0) {
--skip_count_;
}
return false;
// or just:
// return skip_count_-- > 0 ? ++skip_count_ : drop_count_-- > 0 ? true : ++drop_count_;
}
virtual bool IsPointless() const {
return (drop_count_ == 0) && (skip_count_ == 0);
}
private:
size_t skip_count_;
size_t drop_count_;
};
/** This rule is used in combination with another rule which will be only
* called when the proc_id passed to DropRequest matches the one passed
* to the ctor.
*/
class ProcIDFilterRule : public DropRule {
public:
/** Construct a proc_id filtered rule from an existing rule.
* The ownership of rule's pointee is transfered to the created instance.
*/
ProcIDFilterRule(uint32_t proc_id, DropRule* rule)
: proc_id_(proc_id), rule_(rule) {}
virtual bool DropRequest(uint32_t proc_id) {
return proc_id == proc_id_ ? rule_->DropRequest(proc_id) : false;
}
virtual bool IsPointless() const {
return rule_->IsPointless();
}
private:
uint32_t proc_id_;
boost::scoped_ptr<DropRule> rule_;
};
/** This rule drops n requests without checking the proc_id. */
class DropNRule : public DropRule {
public:
DropNRule(size_t count) : count_(count) {}
virtual bool DropRequest(uint32_t proc_id) {
if (count_ > 0) {
--count_;
return true;
} else {
return false;
}
}
virtual bool IsPointless() const {
return count_ == 0;
}
private:
size_t count_;
};
/** This rule drops all rules with a certain proc_id. This rule will never
* become pointless.
*/
class DropByProcIDRule : public DropRule {
public:
DropByProcIDRule(uint32_t proc_id)
: proc_id_(proc_id) {}
virtual bool DropRequest(uint32_t proc_id) {
return proc_id_ == proc_id;
}
virtual bool IsPointless() const {
return false;
}
private:
size_t proc_id_;
};
} // namespace rpc
} // namespace xtreemfs
#endif

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#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 "util/logging.h"
using namespace std;
using namespace xtreemfs::rpc;
using namespace xtreemfs::util;
namespace xtreemfs {
TestEnvironment::TestEnvironment()
: options(), user_credentials() {
user_credentials.set_username("ClientTest");
user_credentials.add_groups("ClientTest");
dir.reset(new TestRPCServerDIR());
mrc.reset(new TestRPCServerMRC());
osds.push_back(new TestRPCServerOSD());
volume_name_ = "test";
}
TestEnvironment::~TestEnvironment() {
for (size_t i = 0; i < osds.size(); i++) {
delete osds[i];
}
}
void TestEnvironment::AddOSDs(int num_of_osds) {
for (int i = 1; i < num_of_osds; i++) {
osds.push_back(new TestRPCServerOSD());
}
}
bool TestEnvironment::Start() {
if (!dir->Start()) {
return false;
}
if (Logging::log->loggingActive(LEVEL_INFO)) {
Logging::log->getLog(LEVEL_INFO)
<< "DIR running at: " << dir->GetAddress() << endl;
}
if (!mrc->Start()) {
return false;
}
if (Logging::log->loggingActive(LEVEL_INFO)) {
Logging::log->getLog(LEVEL_INFO)
<< "MRC running at: " << mrc->GetAddress() << endl;
}
dir->RegisterVolume(volume_name_, mrc->GetAddress());
for (size_t i = 0; i < osds.size(); i++) {
if (!osds[i]->Start()) {
return false;
}
if (Logging::log->loggingActive(LEVEL_INFO)) {
Logging::log->getLog(LEVEL_INFO)
<< "OSD running at: " << osds[i]->GetAddress() << endl;
}
mrc->RegisterOSD(osds[i]->GetAddress());
}
// TODO(mberlin): Register OSDs at MRC.
// If the DIR server address was not explicitly overridden, set it to the
// started test DIR server.
if (options.service_addresses.empty()) {
options.service_addresses.Add(dir->GetAddress());
}
client.reset(Client::CreateClient(
options.service_addresses,
user_credentials,
NULL, // No SSL options.
options));
// Start the client (a connection to the DIR service will be setup).
client->Start();
return true;
}
void TestEnvironment::Stop() {
if (client.get()) {
client->Shutdown();
}
if (dir.get()) {
dir->Stop();
}
if (mrc.get()) {
mrc->Stop();
}
for (size_t i = 0; i < osds.size(); i++) {
osds[i]->Stop();
}
}
} // namespace xtreemfs

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#ifndef CPP_TEST_COMMON_TEST_ENVIRONMENT_H_
#define CPP_TEST_COMMON_TEST_ENVIRONMENT_H_
#include <boost/scoped_ptr.hpp>
#include <string>
#include <vector>
#include "libxtreemfs/options.h"
#include "pbrpc/RPC.pb.h" // xtreemfs::pbrpc::UserCredentials
namespace xtreemfs {
namespace rpc {
class TestRPCServerMRC;
class TestRPCServerDIR;
class TestRPCServerOSD;
} // namespace rpc
class Client;
/** Aggregator class which bundles Client and TestRPCServer objects to
* run unit tests.
*
* Modify options accordingly before executing Start() to influence
* the client.
*/
class TestEnvironment {
public:
explicit TestEnvironment();
~TestEnvironment();
bool Start();
void Stop();
/** Add num_of_osds additional OSDs before executing Start(). */
void AddOSDs(int num_of_osds);
boost::scoped_ptr<Client> client;
Options options;
xtreemfs::pbrpc::UserCredentials user_credentials;
/** Volume name under which the MRC will be registered. */
std::string volume_name_;
boost::scoped_ptr<xtreemfs::rpc::TestRPCServerDIR> dir;
boost::scoped_ptr<xtreemfs::rpc::TestRPCServerMRC> mrc;
std::vector<xtreemfs::rpc::TestRPCServerOSD*> osds;
};
} // namespace xtreemfs
#endif // CPP_TEST_COMMON_TEST_ENVIRONMENT_H_

View File

@@ -0,0 +1,590 @@
/*
* Copyright (c) 2011-2012 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#ifndef CPP_TEST_COMMON_TEST_RPC_SERVER_H_
#define CPP_TEST_COMMON_TEST_RPC_SERVER_H_
#include <stdint.h>
#ifndef WIN32
#include <csignal>
#include <pthread.h>
#endif // !WIN32
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/scoped_array.hpp>
#include <boost/smart_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include "include/Common.pb.h"
#include "pbrpc/RPC.pb.h"
#include "rpc/record_marker.h"
#include "util/logging.h"
#include "xtreemfs/DIR.pb.h"
#include "xtreemfs/get_request_message.h"
#include "drop_rules.h"
namespace xtreemfs {
namespace rpc {
/** Base class which allows to implement a test XtreemFS server.
*
* Implementations have to set interface_id_ accordingly and add
* implemented operations to operations_.
*/
template <class Derived> class TestRPCServer {
public:
TestRPCServer()
: interface_id_(0),
drop_connection_(false) {}
virtual ~TestRPCServer() {}
/** Starts the RPC Server at free, random port. False if not successful. */
bool Start() {
using boost::asio::ip::tcp;
using xtreemfs::util::Logging;
xtreemfs::util::initialize_logger(xtreemfs::util::LEVEL_WARN);
if (interface_id_ == 0) {
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
<< "You forgot to set interface_id_ in"
" your TestRPCServer implementation."<< std::endl;
return false;
}
if (operations_.size() == 0) {
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
<< "You have not registered any implemented operations." << std::endl;
return false;
}
try {
tcp::endpoint localhost(
boost::asio::ip::address::from_string("127.0.0.1"), 0);
acceptor_.reset(
new tcp::acceptor(io_service, localhost));
daemon_.reset(new boost::thread(boost::bind(&TestRPCServer<Derived>::Run,
this)));
} catch (const std::exception& e) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
<< "Failed to start the server: " << e.what() << std::endl;
}
return false;
}
return true;
}
/** Stops the server again. */
void Stop() {
using xtreemfs::util::Logging;
// Stop running Session() threads.
std::map< boost::thread::id,
boost::shared_ptr<boost::thread> > active_sessions_copy;
{
boost::mutex::scoped_lock lock(active_sessions_mutex_);
active_sessions_copy = active_sessions_;
// Close active sessions.
for (std::map< boost::thread::id,
boost::shared_ptr<boost::asio::ip::tcp::socket> >::iterator iter
= active_sessions_socks_.begin();
iter != active_sessions_socks_.end();
iter++) {
iter->second->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
}
}
// Wait for all closed sessions to exit.
for (std::map< boost::thread::id,
boost::shared_ptr<boost::thread> >::iterator iter
= active_sessions_copy.begin();
iter != active_sessions_copy.end();
iter++) {
iter->second->join();
}
{
boost::mutex::scoped_lock lock(active_sessions_mutex_);
if (active_sessions_.size() > 0) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
<< "There are open sessions left ("
<< active_sessions_.size() << ")" << std::endl;
}
}
}
{
boost::mutex::scoped_lock lock(drop_rules_mutex_);
for (std::list<DropRule*>::iterator it = drop_rules_.begin();
it != drop_rules_.end();
++it) {
delete *it;
}
drop_rules_.clear();
}
// Unfortunately, boost::asio does not allow to abort synchronous operations
// See: https://svn.boost.org/trac/boost/ticket/2832
// Randomly acceptor_->close(ec); succeeds, but not guaranteed. Even things
// like shutdown(acceptor_->native(), SHUT_RDWR); did not work.
// During debugging in Eclipse, I noticed that the daemon_ thread exits from
// the blocking acceptor_->accept() if it was interrupted by the debugger.
// Therefore, we call a no-op signal handler in the thread now and accept()
// becomes unblocked, effectively allowing to stop the daemon_ thread.
if (daemon_.get()) {
daemon_->interrupt();
// Ignore errors.
boost::system::error_code ec;
acceptor_->close(ec);
if (!daemon_->timed_join(boost::posix_time::milliseconds(10))) {
#ifdef WIN32
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
<< "Failed to stop the server, daemon thread won't unblock. "
"Abort manually with Ctrl + C." << std::endl;
#else
pthread_kill(daemon_->native_handle(), SIGUSR2);
daemon_->join();
#endif
}
}
}
/** Returns the address of the service in the format "ip-address:port". */
std::string GetAddress() {
return acceptor_->local_endpoint().address().to_string() + ":"
+ boost::lexical_cast<std::string>(acceptor_->local_endpoint().port());
}
/** Add a DropRule, ownership is transferred to the callee. */
void AddDropRule(DropRule* rule) {
boost::mutex::scoped_lock lock(drop_rules_mutex_);
drop_rules_.push_back(rule);
RemovePointlessDropRules(lock);
}
/** The connection will be shut down once after this call. */
void DropConnection() {
boost::mutex::scoped_lock lock(drop_connection_mutex_);
drop_connection_ = true;
}
protected:
/** Function pointer an implemented server operation. */
typedef google::protobuf::Message* (Derived::*Operation)(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
struct Op {
Op() {}
Op(Derived* server, Operation op)
: server(server), op(op) {}
/** Pointer to the implementation of TestRPCServer. */
Derived* server;
/** Function pointer to the implemented operation. */
Operation op;
};
/** Interface ID of the implemented XtreemFS service. */
uint32_t interface_id_;
/** Implementations have to register implemented operations with the
* corresponding proc_id here. */
std::map<uint32_t, Op> operations_;
private:
/** Delete old rules, should be called from a locked context */
void RemovePointlessDropRules(const boost::mutex::scoped_lock& lock) {
std::remove_if(drop_rules_.begin(), drop_rules_.end(), &DropRule::IsPointlessPred);
}
/** Returns true if the request shall be dropped. */
bool CheckIfRequestShallBeDropped(uint32_t proc_id) {
using xtreemfs::util::Logging;
boost::mutex::scoped_lock lock(drop_rules_mutex_);
bool drop_request = false;
// NOTE: all drop rules must be asked even if drop_request is already
// true. This is important for counting rules or other side effects.
for (std::list<DropRule*>::iterator it = drop_rules_.begin();
it != drop_rules_.end();
++it) {
drop_request = drop_request || (*it)->DropRequest(proc_id);
}
if (drop_request) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
<< "Dropping request (proc_id = " << proc_id << ")" << std::endl;
}
}
return drop_request;
}
static void DummySignalHandler(int signal) {
// See comment at TestRPCServer::Stop() why this is needed.
}
/** Processes the "request" and returns a response.
*
* @remarks Ownership of return value is transferred to caller.
*/
google::protobuf::Message* ExecuteOperation(
uint32_t proc_id,
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
typename std::map<uint32_t, Op>::iterator iter
= operations_.find(proc_id);
if (iter == operations_.end()) {
return NULL;
}
Op& entry = iter->second;
return (entry.server->*(entry.op))
(auth, user_credentials, request, data, data_len,
response_data, response_data_len);
}
/** Daemon function which accepts new connections. */
void Run() {
using boost::asio::ip::tcp;
using xtreemfs::util::Logging;
#ifndef WIN32
signal(SIGUSR2, DummySignalHandler);
#endif
for (;;) {
if (boost::this_thread::interruption_requested()) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
<< "Received interrupt, aborting server listener." << std::endl;
}
break;
}
boost::shared_ptr<tcp::socket> sock(new tcp::socket(io_service));
try {
acceptor_->accept(*sock);
{
boost::mutex::scoped_lock lock(drop_connection_mutex_);
if (drop_connection_) {
drop_connection_ = false;
sock->shutdown(tcp::socket::shutdown_both);
continue;
}
}
boost::shared_ptr<boost::thread> new_thread(new boost::thread(
boost::bind(&TestRPCServer<Derived>::Session, this, sock)));
{
boost::mutex::scoped_lock lock(active_sessions_mutex_);
active_sessions_[new_thread->get_id()] = new_thread;
active_sessions_socks_[new_thread->get_id()] = sock;
}
} catch (const boost::system::system_error&) {
break;
}
}
}
/** Connection handler. */
void Session(boost::shared_ptr<boost::asio::ip::tcp::socket> sock) {
using xtreemfs::util::Logging;
try {
std::string remote_address =
sock->remote_endpoint().address().to_string() + ":"
+ boost::lexical_cast<std::string>(sock->remote_endpoint().port());
boost::scoped_array<char> record_marker_buffer(
new char[xtreemfs::rpc::RecordMarker::get_size()]);
boost::scoped_array<char> header_buffer;
boost::scoped_array<char> message_buffer;
boost::scoped_array<char> data_buffer;
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
<< "New client connection from: " << remote_address << std::endl;
}
for (;;) {
if (boost::this_thread::interruption_requested()) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
<< "Received interrupt, aborting test server connection to: "
<< remote_address << std::endl;
}
break;
}
size_t length = 0;
boost::scoped_ptr<xtreemfs::rpc::RecordMarker> request_rm;
try {
// Read record marker.
length = boost::asio::read(
*sock,
boost::asio::buffer(record_marker_buffer.get(),
xtreemfs::rpc::RecordMarker::get_size()));
if (length < xtreemfs::rpc::RecordMarker::get_size()) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
<< "Read invalid record marker from: "
<< remote_address << std::endl;
}
break;
}
request_rm.reset(
new xtreemfs::rpc::RecordMarker(record_marker_buffer.get()));
// Read header, message and data.
std::vector<boost::asio::mutable_buffer> bufs;
header_buffer.reset(new char[request_rm->header_len()]);
bufs.push_back(
boost::asio::buffer(reinterpret_cast<void*>(header_buffer.get()),
request_rm->header_len()));
if (request_rm->message_len() > 0) {
message_buffer.reset(new char[request_rm->message_len()]);
bufs.push_back(
boost::asio::buffer(
reinterpret_cast<void*>(message_buffer.get()),
request_rm->message_len()));
} else {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
<< "Received a request with an empty message from: "
<< remote_address << std::endl;
}
break;
}
if (request_rm->data_len() > 0) {
data_buffer.reset(new char[request_rm->data_len()]);
bufs.push_back(
boost::asio::buffer(reinterpret_cast<void*>(data_buffer.get()),
request_rm->data_len()));
} else {
data_buffer.reset(NULL);
}
length = boost::asio::read(*sock, bufs);
if (length != (request_rm->header_len()
+ request_rm->message_len()
+ request_rm->data_len())) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
<< "Failed to read a complete request from: "
<< remote_address << std::endl;
}
break;
}
} catch (const boost::system::error_code& error) {
if (error == boost::asio::error::eof) {
break; // Connection closed cleanly by peer.
} else {
throw;
}
}
// Parse header and message.
xtreemfs::pbrpc::RPCHeader request_rpc_header;
if (!request_rpc_header.ParseFromArray(
reinterpret_cast<void*>(header_buffer.get()),
request_rm->header_len())) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
<< "Failed to parse request header received from: "
<< remote_address << std::endl;
}
break;
}
uint32_t interface_id
= request_rpc_header.request_header().interface_id();
uint32_t proc_id = request_rpc_header.request_header().proc_id();
if (interface_id != interface_id_) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
<< "Received a message which was not intended for this service"
" with interface id: " << interface_id_ << " (Message from"
" = " << remote_address
<< " (interface id = " << interface_id << ", proc id = "
<< proc_id << ")" << std::endl;
}
break;
}
boost::scoped_ptr<google::protobuf::Message> request_message(
xtreemfs::pbrpc::GetMessageForProcID(interface_id, proc_id));
if (!request_message.get()) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
<< "Failed to find a suitable request message type for message"
" received from: " << remote_address << " (interface id = "
<< interface_id
<< ", proc id = " << proc_id << ")" << std::endl;
}
break;
}
if (!request_message->ParseFromArray(
reinterpret_cast<void*>(message_buffer.get()),
request_rm->message_len())) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
<< "Failed to parse request message received from: "
<< remote_address << std::endl;
break;
}
}
// Check if the request should be dropped.
if (CheckIfRequestShallBeDropped(proc_id)) {
continue;
}
// Process request.
boost::scoped_array<char> response_data;
uint32_t response_data_len = 0;
boost::scoped_ptr<google::protobuf::Message> response_message(
ExecuteOperation(proc_id,
request_rpc_header.request_header().auth_data(),
request_rpc_header.request_header().user_creds(),
*request_message,
data_buffer.get(),
request_rm->data_len(),
&response_data,
&response_data_len));
if (!response_message.get()) {
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
<< "No response was generated. Operation with proc id = "
<< proc_id << " is probably not implemented? (interface_id = "
<< interface_id_ << ")" << std::endl;
break;
}
if (!response_message->IsInitialized()) {
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
<< "Response message is not valid."
" Not all required fields have been initialized: "
<< response_message->InitializationErrorString() << std::endl;
break;
}
// Send response.
xtreemfs::pbrpc::RPCHeader response_header(request_rpc_header);
xtreemfs::rpc::RecordMarker response_rm(
response_header.ByteSize(),
response_message->ByteSize(),
response_data_len);
size_t response_bytes_size = xtreemfs::rpc::RecordMarker::get_size()
+ response_rm.header_len()
+ response_rm.message_len()
+ response_rm.data_len();
boost::scoped_array<char> response_bytes(new char[response_bytes_size]);
char* response = response_bytes.get();
response_rm.serialize(response);
response += xtreemfs::rpc::RecordMarker::get_size();
response_header.CheckInitialized();
if (!response_header.SerializeToArray(response, response_rm.header_len())) {
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
<< "Failed to serialize header" << std::endl;
break;
}
response += response_rm.header_len();
response_message->CheckInitialized();
if (!response_message->SerializeToArray(response, response_rm.message_len())) {
Logging::log->getLog(xtreemfs::util::LEVEL_ERROR)
<< "Failed to serialize message" << std::endl;
break;
}
response += response_rm.message_len();
if (response_data.get() != NULL) {
memcpy(response, response_data.get(), response_data_len);
}
std::vector<boost::asio::mutable_buffer> write_bufs;
write_bufs.push_back(
boost::asio::buffer(reinterpret_cast<void*>(response_bytes.get()),
response_bytes_size));
boost::asio::write(*sock, write_bufs);
}
} catch (const boost::system::system_error& e) {
if (e.code() != boost::asio::error::eof) {
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_WARN)) {
Logging::log->getLog(xtreemfs::util::LEVEL_WARN)
<< "Exception in thread: " << e.what() << std::endl;
}
}
}
{
boost::mutex::scoped_lock lock(active_sessions_mutex_);
active_sessions_.erase(boost::this_thread::get_id());
active_sessions_socks_.erase(boost::this_thread::get_id());
}
}
/** Guards access to active_sessions_ and active_sessions_socks_. */
boost::mutex active_sessions_mutex_;
/** Active client connections (thread id -> thread). */
std::map< boost::thread::id,
boost::shared_ptr<boost::thread> > active_sessions_;
/** Socket of active client connections. Needed to cleanly shut them down. */
std::map< boost::thread::id,
boost::shared_ptr<boost::asio::ip::tcp::socket> >
active_sessions_socks_;
/** Thread which listens on the server socket and accepts new connections. */
boost::scoped_ptr<boost::thread> daemon_;
boost::asio::io_service io_service;
boost::scoped_ptr<boost::asio::ip::tcp::acceptor> acceptor_;
/** Drop rules for incoming requests. */
std::list<DropRule*> drop_rules_;
/** Guards access drop_rules_. */
boost::mutex drop_rules_mutex_;
/** Used to drop the next connection. */
bool drop_connection_;
/** Guards access drop_connection_. */
boost::mutex drop_connection_mutex_;
};
} // namespace rpc
} // namespace xtreemfs
#endif // CPP_TEST_COMMON_TEST_RPC_SERVER_H_

View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#include "common/test_rpc_server_dir.h"
#include "libxtreemfs/pbrpc_url.h"
#include "xtreemfs/DIR.pb.h"
#include "xtreemfs/DIRServiceConstants.h"
using namespace std;
using namespace xtreemfs::pbrpc;
namespace xtreemfs {
namespace rpc {
TestRPCServerDIR::TestRPCServerDIR() {
interface_id_ = INTERFACE_ID_DIR;
// Register available operations.
operations_[PROC_ID_XTREEMFS_SERVICE_GET_BY_NAME]
= Op(this, &TestRPCServerDIR::GetServiceByNameOperation);
operations_[PROC_ID_XTREEMFS_SERVICE_GET_BY_UUID]
= Op(this, &TestRPCServerDIR::GetServiceByUUIDOperation);
operations_[PROC_ID_XTREEMFS_ADDRESS_MAPPINGS_GET]
= Op(this, &TestRPCServerDIR::GetAddressMappingOperation);
}
void TestRPCServerDIR::RegisterVolume(const std::string& volume_name,
const std::string& mrc_uuid) {
boost::mutex::scoped_lock lock(mutex_);
known_volumes_[volume_name] = mrc_uuid;
}
google::protobuf::Message* TestRPCServerDIR::GetServiceByNameOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
const serviceGetByNameRequest* rq
= reinterpret_cast<const serviceGetByNameRequest*>(&request);
string mrc_uuid;
{
boost::mutex::scoped_lock lock(mutex_);
map<string, string>::iterator iter = known_volumes_.find(rq->name());
if (iter != known_volumes_.end()) {
mrc_uuid = iter->second;
}
}
ServiceSet* response = new ServiceSet();
if (!mrc_uuid.empty()) {
Service* new_entry = response->add_services();
new_entry->set_type(SERVICE_TYPE_VOLUME);
new_entry->set_uuid(mrc_uuid);
new_entry->set_version(0);
new_entry->set_name(rq->name());
new_entry->set_last_updated_s(0);
KeyValuePair* new_data = new_entry->mutable_data()->add_data();
new_data->set_key("mrc");
new_data->set_value(mrc_uuid);
}
return response;
}
google::protobuf::Message* TestRPCServerDIR::GetServiceByUUIDOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
const serviceGetByUUIDRequest* rq
= reinterpret_cast<const serviceGetByUUIDRequest*>(&request);
string mrc_uuid = rq->name();
string name;
{
boost::mutex::scoped_lock lock(mutex_);
map<string, string>::iterator iter;
for (iter = known_volumes_.begin(); iter != known_volumes_.end(); ++iter) {
if (iter->second == mrc_uuid) {
name = iter->first;
mrc_uuid = iter->second;
break;
}
}
}
ServiceSet* response = new ServiceSet();
if (!name.empty()) {
Service* new_entry = response->add_services();
new_entry->set_type(SERVICE_TYPE_VOLUME);
new_entry->set_uuid(mrc_uuid);
new_entry->set_version(0);
new_entry->set_name(name);
new_entry->set_last_updated_s(0);
KeyValuePair* new_data = new_entry->mutable_data()->add_data();
new_data->set_key("mrc");
new_data->set_value(mrc_uuid);
}
return response;
}
google::protobuf::Message* TestRPCServerDIR::GetAddressMappingOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
const addressMappingGetRequest* rq
= reinterpret_cast<const addressMappingGetRequest*>(&request);
AddressMappingSet* response = new AddressMappingSet();
AddressMapping* mapping = response->add_mappings();
size_t uuid_split_pos = rq->uuid().find_last_of(":");
mapping->set_uuid(rq->uuid());
mapping->set_version(0);
mapping->set_protocol(PBRPCURL::GetSchemePBRPC());
mapping->set_address(rq->uuid().substr(0, uuid_split_pos));
mapping->set_port(atoi(rq->uuid().substr(uuid_split_pos+1).c_str()));
mapping->set_match_network("*");
mapping->set_ttl_s(3600);
mapping->set_uri("");
return response;
}
} // namespace rpc
} // namespace xtreemfs

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2014-2014 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#ifndef CPP_TEST_COMMON_TEST_RPC_SERVER_DIR_CPP_
#define CPP_TEST_COMMON_TEST_RPC_SERVER_DIR_CPP_
#include "common/test_rpc_server.h"
#include <boost/thread/mutex.hpp>
#include <map>
#include <string>
namespace google {
namespace protobuf {
class Message;
} // namespace protobuf
} // namespace google
namespace xtreemfs {
namespace rpc {
class TestRPCServerDIR : public TestRPCServer<TestRPCServerDIR> {
public:
TestRPCServerDIR();
void RegisterVolume(const std::string& volume_name,
const std::string& mrc_uuid);
protected:
/** Mock-up version returns the given UUID (hostname:port) as address. */
virtual google::protobuf::Message* GetAddressMappingOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
private:
google::protobuf::Message* GetServiceByNameOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
google::protobuf::Message* GetServiceByUUIDOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
/** Guards access to known_volumes_. */
boost::mutex mutex_;
std::map<std::string, std::string> known_volumes_;
};
} // namespace rpc
} // namespace xtreemfs
#endif // CPP_TEST_COMMON_TEST_RPC_SERVER_DIR_CPP_

View File

@@ -0,0 +1,146 @@
/*
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#include "common/test_rpc_server_mrc.h"
#include "xtreemfs/MRC.pb.h"
#include "xtreemfs/MRCServiceConstants.h"
#include <ctime>
using namespace std;
using namespace xtreemfs::pbrpc;
namespace xtreemfs {
namespace rpc {
TestRPCServerMRC::TestRPCServerMRC() : file_size_(1024 * 1024) {
interface_id_ = INTERFACE_ID_MRC;
// Register available operations.
operations_[PROC_ID_OPEN] = Op(this, &TestRPCServerMRC::OpenOperation);
operations_[PROC_ID_XTREEMFS_RENEW_CAPABILITY] =
Op(this, &TestRPCServerMRC::RenewCapabilityOperation);
operations_[PROC_ID_XTREEMFS_UPDATE_FILE_SIZE] =
Op(this, &TestRPCServerMRC::UpdateFileSizeOperation);
operations_[PROC_ID_FTRUNCATE] =
Op(this, &TestRPCServerMRC::FTruncate);
}
google::protobuf::Message* TestRPCServerMRC::OpenOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
const openRequest* rq = reinterpret_cast<const openRequest*>(&request);
openResponse* response = new openResponse();
XCap* xcap = response->mutable_creds()->mutable_xcap();
xcap->set_access_mode(rq->flags());
xcap->set_client_identity("client_identity");
xcap->set_expire_time_s(3600);
xcap->set_expire_timeout_s(static_cast<uint32_t>(time(0)) + 3600);
xcap->set_file_id(rq->volume_name() + ":0");
xcap->set_replicate_on_close(false);
xcap->set_server_signature("signature");
xcap->set_snap_config(SNAP_CONFIG_SNAPS_DISABLED);
xcap->set_snap_timestamp(0);
xcap->set_truncate_epoch(0);
XLocSet* xlocset = response->mutable_creds()->mutable_xlocs();
xlocset->set_read_only_file_size(file_size_);
xlocset->set_replica_update_policy(""); // "" = REPL_UPDATE_PC_NONE;
xlocset->set_version(0);
xlocset->add_replicas();
Replica* replica = xlocset->mutable_replicas(0);
replica->set_replication_flags(0);
for (std::vector<std::string>::iterator it = osd_uuids_.begin();
it != osd_uuids_.end();
++it) {
replica->add_osd_uuids(*it);
}
replica->mutable_striping_policy()->set_type(STRIPING_POLICY_RAID0);
replica->mutable_striping_policy()->set_stripe_size(128);
replica->mutable_striping_policy()->set_width(1);
response->set_timestamp_s(static_cast<uint32_t>(time(0)));
return response;
}
google::protobuf::Message* TestRPCServerMRC::RenewCapabilityOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
const XCap* rq = reinterpret_cast<const XCap*>(&request);
XCap* response = new XCap(*rq);
response->set_expire_time_s(time(0) + 3600);
response->set_expire_timeout_s(3600);
return response;
}
google::protobuf::Message* TestRPCServerMRC::UpdateFileSizeOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
//const xtreemfs_update_file_sizeRequest* rq =
// reinterpret_cast<const xtreemfs_update_file_sizeRequest*>(&request);
timestampResponse* response = new timestampResponse();
response->set_timestamp_s(static_cast<uint32_t>(time(0)));
return response;
}
google::protobuf::Message* TestRPCServerMRC::FTruncate(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
const XCap* rq = reinterpret_cast<const XCap*>(&request);
XCap* response = new XCap(*rq);
response->set_expire_time_s(time(0) + 3600);
response->set_expire_timeout_s(3600);
return response;
}
void TestRPCServerMRC::SetFileSize(uint64_t size) {
boost::mutex::scoped_lock lock(mutex_);
file_size_ = size;
}
void TestRPCServerMRC::RegisterOSD(std::string uuid) {
boost::mutex::scoped_lock lock(mutex_);
osd_uuids_.push_back(uuid);
}
} // namespace rpc
} // namespace xtreemfs

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#ifndef CPP_TEST_COMMON_TEST_RPC_SERVER_MRC_CPP_
#define CPP_TEST_COMMON_TEST_RPC_SERVER_MRC_CPP_
#include "common/test_rpc_server.h"
#include <stdint.h>
#include <boost/thread/mutex.hpp>
namespace google {
namespace protobuf {
class Message;
} // namespace protobuf
} // namespace google
namespace xtreemfs {
namespace rpc {
class TestRPCServerMRC : public TestRPCServer<TestRPCServerMRC> {
public:
TestRPCServerMRC();
void SetFileSize(uint64_t size);
void RegisterOSD(std::string uuid);
private:
google::protobuf::Message* OpenOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
google::protobuf::Message* UpdateFileSizeOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
google::protobuf::Message* RenewCapabilityOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
google::protobuf::Message* FTruncate(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
/** Mutex used to protect all member variables from concurrent access. */
boost::mutex mutex_;
/** Default file size reported by the MRC for every file requested. */
uint64_t file_size_;
std::vector<std::string> osd_uuids_;
};
} // namespace rpc
} // namespace xtreemfs
#endif // CPP_TEST_COMMON_TEST_RPC_SERVER_MRC_CPP_

View File

@@ -0,0 +1,146 @@
/*
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#include "common/test_rpc_server_osd.h"
#include "util/logging.h"
#include "xtreemfs/OSD.pb.h"
#include "xtreemfs/OSDServiceConstants.h"
using namespace std;
using namespace xtreemfs::pbrpc;
using xtreemfs::util::Logging;
namespace xtreemfs {
namespace rpc {
const int kMaxFileSize = 10 * 1024 * 1024;
TestRPCServerOSD::TestRPCServerOSD() : file_size_(0) {
interface_id_ = INTERFACE_ID_OSD;
// Register available operations.
operations_[PROC_ID_TRUNCATE]
= Op(this, &TestRPCServerOSD::TruncateOperation);
operations_[PROC_ID_WRITE]
= Op(this, &TestRPCServerOSD::WriteOperation);
operations_[PROC_ID_READ]
= Op(this, &TestRPCServerOSD::ReadOperation);
data_.reset(new char[kMaxFileSize]);
}
const std::vector<WriteEntry> TestRPCServerOSD::GetReceivedWrites() const {
boost::mutex::scoped_lock lock(mutex_);
return received_writes_;
}
google::protobuf::Message* TestRPCServerOSD::TruncateOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
boost::mutex::scoped_lock lock(mutex_);
const truncateRequest* rq
= static_cast<const truncateRequest*>(&request);
file_size_ = rq->new_file_size();
assert(file_size_ <= kMaxFileSize);
OSDWriteResponse* response = new OSDWriteResponse();
response->set_size_in_bytes(rq->new_file_size());
response->set_truncate_epoch(0);
return response;
}
google::protobuf::Message* TestRPCServerOSD::ReadOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
boost::mutex::scoped_lock lock(mutex_);
const readRequest* rq
= static_cast<const readRequest*>(&request);
const int64_t object_size =
rq->file_credentials().xlocs().replicas(0).
striping_policy().stripe_size() * 1024;
const int64_t offset = rq->object_number() * object_size +
rq->offset();
const int64_t bytes_to_read =
std::min(static_cast<int64_t>(rq->length()), file_size_ - offset);
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
<< "Received read: object_number: " << rq->object_number()
<< ", offset: " << offset
<< ", read length: " << rq->length()
<< ", object_size: " << object_size
<< ", file_size: " << file_size_
<< ", sending: " << bytes_to_read << " bytes"
<< std::endl;
}
if (bytes_to_read > 0) {
response_data->reset(new char[bytes_to_read]);
*response_data_len = bytes_to_read;
memcpy(response_data->get(), &data_[offset], bytes_to_read);
}
ObjectData* response = new ObjectData();
response->set_zero_padding(0);
response->set_invalid_checksum_on_osd(false);
response->set_checksum(0);
return response;
}
google::protobuf::Message* TestRPCServerOSD::WriteOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len) {
boost::mutex::scoped_lock lock(mutex_);
const writeRequest* rq
= static_cast<const writeRequest*>(&request);
received_writes_.push_back(
WriteEntry(rq->object_number(), rq->offset(), data_len));
if (Logging::log->loggingActive(xtreemfs::util::LEVEL_DEBUG)) {
Logging::log->getLog(xtreemfs::util::LEVEL_DEBUG)
<< "Received write: object_number: " << rq->object_number()
<< ", offset: " << rq->offset()
<< ", data_len: " << data_len << std::endl;
}
const uint64_t object_size =
rq->file_credentials().xlocs().replicas(0).
striping_policy().stripe_size() * 1024;
const uint64_t offset = rq->object_number() * object_size + rq->offset();
file_size_ = offset + data_len;
assert(file_size_ <= kMaxFileSize);
memcpy(&data_[offset], data, data_len);
OSDWriteResponse* response = new OSDWriteResponse();
response->set_size_in_bytes(file_size_);
response->set_truncate_epoch(0);
return response;
}
} // namespace rpc
} // namespace xtreemfs

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2012 by Michael Berlin, Zuse Institute Berlin
*
* Licensed under the BSD License, see LICENSE file for details.
*
*/
#ifndef CPP_TEST_COMMON_TEST_RPC_SERVER_OSD_CPP_
#define CPP_TEST_COMMON_TEST_RPC_SERVER_OSD_CPP_
#include "common/test_rpc_server.h"
#include <stdint.h>
#include <boost/thread/mutex.hpp>
#include <vector>
namespace google {
namespace protobuf {
class Message;
} // namespace protobuf
} // namespace google
namespace xtreemfs {
namespace rpc {
class WriteEntry {
public:
WriteEntry()
: object_number_(0), offset_(0), data_len_(0) { }
WriteEntry(uint64_t objectNumber, uint32_t offset, uint32_t data_len)
: object_number_(objectNumber), offset_(offset), data_len_(data_len) { }
bool operator==(const WriteEntry& other) const {
return (other.object_number_ == this->object_number_)
&& (other.offset_ == this->offset_)
&& (other.data_len_ == this->data_len_);
}
uint64_t object_number_;
uint32_t offset_;
uint32_t data_len_;
};
class TestRPCServerOSD : public TestRPCServer<TestRPCServerOSD> {
public:
TestRPCServerOSD();
const std::vector<WriteEntry> GetReceivedWrites() const;
private:
google::protobuf::Message* TruncateOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
google::protobuf::Message* ReadOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
google::protobuf::Message* WriteOperation(
const pbrpc::Auth& auth,
const pbrpc::UserCredentials& user_credentials,
const google::protobuf::Message& request,
const char* data,
uint32_t data_len,
boost::scoped_array<char>* response_data,
uint32_t* response_data_len);
/** Mutex used to protect all member variables from concurrent access. */
mutable boost::mutex mutex_;
/** A single file size is remembered between requests. */
int64_t file_size_;
/** The file data. */
boost::scoped_array<char> data_;
/** A list of received write requests that can be used to check against an
* expected result.
*/
std::vector<WriteEntry> received_writes_;
};
} // namespace rpc
} // namespace xtreemfs
#endif // CPP_TEST_COMMON_TEST_RPC_SERVER_OSD_CPP_