Commit f9ad7359 authored by Max Kellermann's avatar Max Kellermann

lib/nfs/Manager: use boost::intrusive::map

Reduce overhead for storing the key twice, and more overhead while looking up the connection to remove it after a failure.
parent 952fe987
......@@ -22,12 +22,48 @@
#include "event/Loop.hxx"
#include "Log.hxx"
#include <string.h>
void
NfsManager::ManagedConnection::OnNfsConnectionError(Error &&error)
{
FormatError(error, "NFS error on %s:%s", GetServer(), GetExportName());
manager.connections.erase(Key(GetServer(), GetExportName()));
manager.connections.erase(manager.connections.iterator_to(*this));
delete this;
}
inline bool
NfsManager::Compare::operator()(const LookupKey a,
const ManagedConnection &b) const
{
int result = strcmp(a.server, b.GetServer());
if (result != 0)
return result < 0;
result = strcmp(a.export_name, b.GetExportName());
return result < 0;
}
inline bool
NfsManager::Compare::operator()(const ManagedConnection &a,
const LookupKey b) const
{
int result = strcmp(a.GetServer(), b.server);
if (result != 0)
return result < 0;
result = strcmp(a.GetExportName(), b.export_name);
return result < 0;
}
NfsManager::~NfsManager()
{
assert(loop.IsInside());
connections.clear_and_dispose([](ManagedConnection *c){
delete c;
});
}
NfsConnection &
......@@ -37,21 +73,15 @@ NfsManager::GetConnection(const char *server, const char *export_name)
assert(export_name != nullptr);
assert(loop.IsInside());
const std::string key = Key(server, export_name);
#if defined(__GNUC__) && !defined(__clang__) && !GCC_CHECK_VERSION(4,8)
/* std::map::emplace() not available; this hack uses the move
constructor */
auto e = connections.insert(std::make_pair(key,
ManagedConnection(*this, loop,
server,
export_name)));
#else
auto e = connections.emplace(std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(*this, loop,
server,
export_name));
#endif
return e.first->second;
Map::insert_commit_data hint;
auto result = connections.insert_check(LookupKey{server, export_name},
Compare(), hint);
if (result.second) {
auto c = new ManagedConnection(*this, loop,
server, export_name);
connections.insert_commit(*c, hint);
return *c;
} else {
return *result.first;
}
}
......@@ -24,15 +24,21 @@
#include "Connection.hxx"
#include "Compiler.h"
#include <string>
#include <map>
#include <boost/intrusive/set.hpp>
/**
* A manager for NFS connections. Handles multiple connections to
* multiple NFS servers.
*/
class NfsManager {
class ManagedConnection final : public NfsConnection {
struct LookupKey {
const char *server;
const char *export_name;
};
class ManagedConnection final
: public NfsConnection,
public boost::intrusive::set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>> {
NfsManager &manager;
public:
......@@ -42,39 +48,44 @@ class NfsManager {
:NfsConnection(_loop, _server, _export_name),
manager(_manager) {}
#if defined(__GNUC__) && !defined(__clang__) && !GCC_CHECK_VERSION(4,8)
/* needed due to lack of std::map::emplace() */
ManagedConnection(ManagedConnection &&other)
:NfsConnection(std::move(other)),
manager(other.manager) {}
#endif
protected:
/* virtual methods from NfsConnection */
void OnNfsConnectionError(Error &&error) override;
};
struct Compare {
gcc_pure
bool operator()(const LookupKey a,
const ManagedConnection &b) const;
gcc_pure
bool operator()(const ManagedConnection &a,
const LookupKey b) const;
};
EventLoop &loop;
/**
* Maps server+":"+export_name (see method Key()) to
* #ManagedConnection.
* Maps server and export_name to #ManagedConnection.
*/
std::map<std::string, ManagedConnection> connections;
typedef boost::intrusive::set<ManagedConnection,
boost::intrusive::compare<Compare>,
boost::intrusive::constant_time_size<false>> Map;
Map connections;
public:
NfsManager(EventLoop &_loop)
:loop(_loop) {}
/**
* Must be run from EventLoop's thread.
*/
~NfsManager();
gcc_pure
NfsConnection &GetConnection(const char *server,
const char *export_name);
private:
gcc_pure
static std::string Key(const char *server, const char *export_name) {
return std::string(server) + ':' + export_name;
}
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment