Imported Upstream version 1.5.1
This commit is contained in:
131
cpp/test/common/drop_rules.h
Normal file
131
cpp/test/common/drop_rules.h
Normal 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
|
||||
108
cpp/test/common/test_environment.cpp
Normal file
108
cpp/test/common/test_environment.cpp
Normal 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
|
||||
59
cpp/test/common/test_environment.h
Normal file
59
cpp/test/common/test_environment.h
Normal 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_
|
||||
590
cpp/test/common/test_rpc_server.h
Normal file
590
cpp/test/common/test_rpc_server.h
Normal 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_
|
||||
144
cpp/test/common/test_rpc_server_dir.cpp
Normal file
144
cpp/test/common/test_rpc_server_dir.cpp
Normal 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
|
||||
72
cpp/test/common/test_rpc_server_dir.h
Normal file
72
cpp/test/common/test_rpc_server_dir.h
Normal 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_
|
||||
146
cpp/test/common/test_rpc_server_mrc.cpp
Normal file
146
cpp/test/common/test_rpc_server_mrc.cpp
Normal 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
|
||||
82
cpp/test/common/test_rpc_server_mrc.h
Normal file
82
cpp/test/common/test_rpc_server_mrc.h
Normal 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_
|
||||
146
cpp/test/common/test_rpc_server_osd.cpp
Normal file
146
cpp/test/common/test_rpc_server_osd.cpp
Normal 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
|
||||
97
cpp/test/common/test_rpc_server_osd.h
Normal file
97
cpp/test/common/test_rpc_server_osd.h
Normal 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_
|
||||
Reference in New Issue
Block a user