summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Kellermann <max@duempel.org>2014-10-01 20:26:38 +0200
committerMax Kellermann <max@duempel.org>2014-10-01 20:49:40 +0200
commitf9ad73598ba08ce26f236eae2691a5c60a6e807d (patch)
treee3c1a427119b3697be97d93298a26c1c16bad6f0
parent952fe987967b805046da95e9bcc424bba7fa397b (diff)
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.
-rw-r--r--src/lib/nfs/Manager.cxx66
-rw-r--r--src/lib/nfs/Manager.hxx49
2 files changed, 78 insertions, 37 deletions
diff --git a/src/lib/nfs/Manager.cxx b/src/lib/nfs/Manager.cxx
index 5c236552c..c5aecf48d 100644
--- a/src/lib/nfs/Manager.cxx
+++ b/src/lib/nfs/Manager.cxx
@@ -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;
+ }
}
diff --git a/src/lib/nfs/Manager.hxx b/src/lib/nfs/Manager.hxx
index 0e2c998fe..612b01f9c 100644
--- a/src/lib/nfs/Manager.hxx
+++ b/src/lib/nfs/Manager.hxx
@@ -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