diff options
author | Max Kellermann <max@duempel.org> | 2014-10-01 20:26:38 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2014-10-01 20:49:40 +0200 |
commit | f9ad73598ba08ce26f236eae2691a5c60a6e807d (patch) | |
tree | e3c1a427119b3697be97d93298a26c1c16bad6f0 | |
parent | 952fe987967b805046da95e9bcc424bba7fa397b (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.cxx | 66 | ||||
-rw-r--r-- | src/lib/nfs/Manager.hxx | 49 |
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 |