From: Arvin Schnell Date: Thu, 2 Aug 2012 12:42:37 +0000 (+0200) Subject: - work on dbus client X-Git-Tag: v0.1.3~178 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e69c69dc5c5f181887abeaada94a7d994b7045e2;p=thirdparty%2Fsnapper.git - work on dbus client --- diff --git a/client/snapper.cc b/client/snapper.cc index 57deaec3..6542a950 100644 --- a/client/snapper.cc +++ b/client/snapper.cc @@ -1197,6 +1197,10 @@ main(int argc, char** argv) cerr << _("Invalid userdata.") << endl; else if (name == "error.illegal_snapshot") cerr << _("Illegal Snapshot.") << endl; + else if (name == "error.config_locked") + cerr << _("Config is locked.") << endl; + else if (name == "error.config_in_use") + cerr << _("Config is in use.") << endl; else cerr << _("Failure") << " (" << name << ")." << endl; exit(EXIT_FAILURE); diff --git a/server/Client.cc b/server/Client.cc index 523110a9..5567422a 100644 --- a/server/Client.cc +++ b/server/Client.cc @@ -24,6 +24,9 @@ #include "MetaSnapper.h" +Clients clients; + + template bool contains(const ListType& l, const Type& value) { @@ -40,11 +43,18 @@ Client::Client(const string& name) Client::~Client() { thread.interrupt(); - thread.join(); for (list::iterator it = comparisons.begin(); it != comparisons.end(); ++it) { + const Snapper* s = (*it)->getSnapper(); + + for (MetaSnappers::iterator it2 = meta_snappers.begin(); it2 != meta_snappers.end(); ++it2) + { + if (it2->is_equal(s)) + it2->dec_use_count(); + } + delete *it; } } diff --git a/server/Client.h b/server/Client.h index 4563bc3b..10ccf53d 100644 --- a/server/Client.h +++ b/server/Client.h @@ -101,7 +101,7 @@ public: void remove_lock(const string& config_name); bool has_lock(const string& config_name) const; - string name; + const string name; list comparisons; @@ -124,6 +124,8 @@ public: void add_task(DBus::Connection& conn, DBus::Message& msg); +private: + void worker(); }; @@ -158,4 +160,7 @@ private: }; +extern Clients clients; + + #endif diff --git a/server/MetaSnapper.cc b/server/MetaSnapper.cc index c4cfdfe2..7a85193f 100644 --- a/server/MetaSnapper.cc +++ b/server/MetaSnapper.cc @@ -30,6 +30,80 @@ #include "MetaSnapper.h" +MetaSnappers meta_snappers; + + +RefCounter::RefCounter() + : counter(0) +{ + struct timespec tmp; + clock_gettime(CLOCK_MONOTONIC, &tmp); + last_used = tmp.tv_sec; +} + + +int +RefCounter::inc_use_count() +{ + boost::lock_guard lock(mutex); + + return ++counter; +} + + +int +RefCounter::dec_use_count() +{ + boost::lock_guard lock(mutex); + + assert(counter > 0); + + if (--counter == 0) + { + struct timespec tmp; + clock_gettime(CLOCK_MONOTONIC, &tmp); + last_used = tmp.tv_sec; + } + + return counter; +} + + +void +RefCounter::update_use_time() +{ + boost::lock_guard lock(mutex); + + struct timespec tmp; + clock_gettime(CLOCK_MONOTONIC, &tmp); + last_used = tmp.tv_sec; +} + + +int +RefCounter::use_count() const +{ + boost::lock_guard lock(mutex); + + return counter; +} + + +int +RefCounter::unused_for() const +{ + boost::lock_guard lock(mutex); + + if (counter != 0) + return 0; + + struct timespec tmp; + clock_gettime(CLOCK_MONOTONIC, &tmp); + + return tmp.tv_sec - last_used; +} + + bool get_user_uid(const char* username, uid_t& uid) { @@ -135,10 +209,20 @@ MetaSnapper::getSnapper() if (!snapper) snapper = new Snapper(config_info.config_name); + update_use_time(); + return snapper; } +void +MetaSnapper::unload() +{ + delete snapper; + snapper = 0; +} + + MetaSnappers::MetaSnappers() { } @@ -156,8 +240,7 @@ MetaSnappers::init() for (list::const_iterator it = config_infos.begin(); it != config_infos.end(); ++it) { - MetaSnapper meta_snapper(*it); - entries.push_back(meta_snapper); + entries.emplace_back(*it); } } @@ -169,7 +252,7 @@ MetaSnappers::find(const string& config_name) if (it->configName() == config_name) return it; - throw; + throw UnknownConfig(); } @@ -182,19 +265,14 @@ MetaSnappers::createConfig(const string& config_name, const string& subvolume, Snapper::createConfig(config_name, subvolume, fstype, template_name); ConfigInfo config_info = Snapper::getConfig(config_name); - MetaSnapper meta_snapper(config_info); - entries.push_back(meta_snapper); + entries.emplace_back(config_info); } void -MetaSnappers::deleteConfig(const string& config_name) +MetaSnappers::deleteConfig(iterator it) { - iterator it = find(config_name); - if (it == end()) - throw; - - Snapper::deleteConfig(config_name); + Snapper::deleteConfig(it->configName()); entries.erase(it); } diff --git a/server/MetaSnapper.h b/server/MetaSnapper.h index 1d3a1996..b73d1c30 100644 --- a/server/MetaSnapper.h +++ b/server/MetaSnapper.h @@ -24,6 +24,8 @@ #define SNAPPER_META_SNAPPER_H +#include + #include #include #include @@ -33,7 +35,54 @@ using namespace std; using namespace snapper; -class MetaSnapper +class RefCounter : boost::noncopyable +{ +public: + + RefCounter(); + + int inc_use_count(); + int dec_use_count(); + void update_use_time(); + + int use_count() const; + int unused_for() const; + +private: + + mutable boost::mutex mutex; + + int counter; + + time_t last_used; + +}; + + +class RefHolder +{ +public: + + RefHolder(RefCounter& ref) : ref(ref) + { ref.inc_use_count(); } + ~RefHolder() + { ref.dec_use_count(); } + +private: + + RefCounter& ref; + +}; + + +struct UnknownConfig : public std::exception +{ + explicit UnknownConfig() throw() {} + virtual const char* what() const throw() { return "unknown config"; } +}; + + +class MetaSnapper : public RefCounter { public: @@ -48,7 +97,9 @@ public: Snapper* getSnapper(); - bool snapper_loaded() const { return snapper != NULL; } + bool is_equal(const Snapper* s) { return snapper && snapper == s; } + bool is_loaded() const { return snapper; } + void unload(); private: @@ -82,7 +133,7 @@ public: void createConfig(const string& config_name, const string& subvolume, const string& fstype, const string& template_name); - void deleteConfig(const string& config_name); + void deleteConfig(iterator); private: @@ -91,4 +142,7 @@ private: }; +extern MetaSnappers meta_snappers; + + #endif diff --git a/server/snapperd.cc b/server/snapperd.cc index 65d14d41..643e0547 100644 --- a/server/snapperd.cc +++ b/server/snapperd.cc @@ -55,9 +55,6 @@ using namespace snapper; #define INTERFACE "org.opensuse.Snapper" -Clients clients; -MetaSnappers meta_snappers; - boost::shared_mutex big_mutex; @@ -248,13 +245,6 @@ Client::introspect(DBus::Connection& conn, DBus::Message& msg) } -struct UnknownConfig : public std::exception -{ - explicit UnknownConfig() throw() {} - virtual const char* what() const throw() { return "unknown config"; } -}; - - struct Permissions : public std::exception { explicit Permissions() throw() {} @@ -299,7 +289,7 @@ check_lock(DBus::Connection& conn, DBus::Message& msg, const string& config_name { for (Clients::const_iterator it = clients.begin(); it != clients.end(); ++it) { - if (it->name == msg.get_sender()) + if (it->zombie || it->name == msg.get_sender()) continue; if (it->has_lock(config_name)) @@ -308,6 +298,21 @@ check_lock(DBus::Connection& conn, DBus::Message& msg, const string& config_name } +struct InUse : public std::exception +{ + explicit InUse() throw() {} + virtual const char* what() const throw() { return "in use"; } +}; + + +void +check_in_use(const MetaSnapper& meta_snapper) +{ + if (meta_snapper.use_count() != 0) + throw InUse(); +} + + void Client::signal_config_created(DBus::Connection& conn, const string& config_name) { @@ -442,9 +447,13 @@ Client::delete_config(DBus::Connection& conn, DBus::Message& msg) boost::unique_lock lock(big_mutex); + MetaSnappers::iterator it = meta_snappers.find(config_name); + check_permission(conn, msg); + check_lock(conn, msg, config_name); + check_in_use(*it); - meta_snappers.deleteConfig(config_name); + meta_snappers.deleteConfig(it); DBus::MessageMethodReturn reply(msg); @@ -730,11 +739,11 @@ Client::delete_snapshots(DBus::Connection& conn, DBus::Message& msg) boost::unique_lock lock(big_mutex); - check_lock(conn, msg, config_name); - MetaSnappers::iterator it = meta_snappers.find(config_name); check_permission(conn, msg, *it); + check_lock(conn, msg, config_name); + check_in_use(*it); Snapper* snapper = it->getSnapper(); @@ -839,6 +848,8 @@ Client::create_comparison(DBus::Connection& conn, DBus::Message& msg) Snapshots::const_iterator snapshot1 = snapshots.find(num1); Snapshots::const_iterator snapshot2 = snapshots.find(num2); + RefHolder ref_holder(*it); + lock.unlock(); Comparison* comparison = new Comparison(snapper, snapshot1, snapshot2); @@ -847,6 +858,8 @@ Client::create_comparison(DBus::Connection& conn, DBus::Message& msg) comparisons.push_back(comparison); + it->inc_use_count(); + DBus::MessageMethodReturn reply(msg); conn.send(reply); @@ -975,10 +988,8 @@ Client::set_undo(DBus::Connection& conn, DBus::Message& msg) for (list::const_iterator it2 = undos.begin(); it2 != undos.end(); ++it2) { Files::iterator it3 = files.find(it2->filename); - if (it3 == files.end()) - throw; - - it3->setUndo(it2->undo); + if (it3 != files.end()) + it3->setUndo(it2->undo); } DBus::MessageMethodReturn reply(msg); @@ -1106,13 +1117,13 @@ Client::debug(DBus::Connection& conn, DBus::Message& msg) std::ostringstream s; s << " name:'" << it->name << "'"; if (&*it == this) - s << " myself"; + s << ", myself"; if (it->zombie) - s << " zombie"; + s << ", zombie"; if (!it->locks.empty()) - s << " locks:'" << boost::join(it->locks, ",") << "'"; + s << ", locks '" << boost::join(it->locks, " ") << "'"; if (!it->comparisons.empty()) - s << " comparisons:" << it->comparisons.size(); + s << ", comparisons " << it->comparisons.size(); hoho << s.str(); } @@ -1121,8 +1132,14 @@ Client::debug(DBus::Connection& conn, DBus::Message& msg) { std::ostringstream s; s << " name:'" << it->configName() << "'"; - if (it->snapper_loaded()) - s << " (loaded)"; + if (it->is_loaded()) + { + s << ", loaded"; + if (it->use_count() == 0) + s << ", unused for " << it->unused_for() << "s"; + else + s << ", use count " << it->use_count(); + } hoho << s.str(); } @@ -1216,6 +1233,11 @@ Client::dispatch(DBus::Connection& conn, DBus::Message& msg) DBus::MessageError reply(msg, "error.config_locked", DBUS_ERROR_FAILED); conn.send(reply); } + catch (const InUse& e) + { + DBus::MessageError reply(msg, "error.config_in_use", DBUS_ERROR_FAILED); + conn.send(reply); + } catch (const NoComparison& e) { DBus::MessageError reply(msg, "error.no_comparisons", DBUS_ERROR_FAILED); @@ -1340,16 +1362,17 @@ MyMainLoop::client_disconnected(const string& name) void MyMainLoop::periodic() { - y2deb("periodic"); - boost::unique_lock lock(big_mutex); clients.remove_zombies(); if (clients.empty()) - { - y2deb("no clients left"); set_idle_timeout(30); + + for (MetaSnappers::iterator it = meta_snappers.begin(); it != meta_snappers.end(); ++it) + { + if (it->is_loaded() && it->unused_for() > 10) + it->unload(); } } @@ -1362,6 +1385,10 @@ MyMainLoop::periodic_timeout() if (clients.has_zombies()) return 1000; + for (MetaSnappers::const_iterator it = meta_snappers.begin(); it != meta_snappers.end(); ++it) + if (it->is_loaded() && it->use_count() == 0) + return 1000; + return -1; }