]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
- work on dbus client
authorArvin Schnell <aschnell@suse.de>
Thu, 2 Aug 2012 12:42:37 +0000 (14:42 +0200)
committerArvin Schnell <aschnell@suse.de>
Thu, 2 Aug 2012 12:42:37 +0000 (14:42 +0200)
client/snapper.cc
server/Client.cc
server/Client.h
server/MetaSnapper.cc
server/MetaSnapper.h
server/snapperd.cc

index 57deaec346695856322a6aa28d1cfd868a48d4a6..6542a9500ffbe0d8059916e20d7aff80d328a924 100644 (file)
@@ -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);
index 523110a996f3ae034f98873470aa2095f2b91ffb..5567422af76b1d454b963d370c6f80d45b7bdb39 100644 (file)
@@ -24,6 +24,9 @@
 #include "MetaSnapper.h"
 
 
+Clients clients;
+
+
 template <typename ListType, typename Type>
 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<Comparison*>::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;
     }
 }
index 4563bc3b0b9a02d4c0f7e638650efcc5807f5cb6..10ccf53d1020276fe04dc8a9bbbfa9020b2a4e1e 100644 (file)
@@ -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<Comparison*> 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
index c4cfdfe20729607982cffe77d7bc4398d1c8d415..7a85193f5a71795e95051a26c436bf9bee76112e 100644 (file)
 #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<boost::mutex> lock(mutex);
+
+    return ++counter;
+}
+
+
+int
+RefCounter::dec_use_count()
+{
+    boost::lock_guard<boost::mutex> 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<boost::mutex> lock(mutex);
+
+    struct timespec tmp;
+    clock_gettime(CLOCK_MONOTONIC, &tmp);
+    last_used = tmp.tv_sec;
+}
+
+
+int
+RefCounter::use_count() const
+{
+    boost::lock_guard<boost::mutex> lock(mutex);
+
+    return counter;
+}
+
+
+int
+RefCounter::unused_for() const
+{
+    boost::lock_guard<boost::mutex> 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<ConfigInfo>::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);
 }
index 1d3a1996539e946c75f29fe9b1023b69cc2518b0..b73d1c302caf9fa7b2ff5f4691561f985ffc530b 100644 (file)
@@ -24,6 +24,8 @@
 #define SNAPPER_META_SNAPPER_H
 
 
+#include <boost/thread.hpp>
+
 #include <snapper/Snapper.h>
 #include <snapper/Snapshot.h>
 #include <snapper/Comparison.h>
@@ -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
index 65d14d419a6b4ca230d1c4245ebe5075aa90f204..643e0547f7445f95e960230652d95d6c6e8d822a 100644 (file)
@@ -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<boost::shared_mutex> 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<boost::shared_mutex> 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<Undo>::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<boost::shared_mutex> 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;
 }