--- /dev/null
+/*
+ * Copyright (c) 2012 Novell, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <snapper/Log.h>
+
+#include "Background.h"
+
+
+Backgrounds backgrounds;
+
+
+Backgrounds::Backgrounds()
+{
+}
+
+
+Backgrounds::~Backgrounds()
+{
+ thread.interrupt();
+ thread.join();
+}
+
+
+void
+Backgrounds::add_task(MetaSnapper* meta_snapper, Snapshots::const_iterator snapshot1,
+ Snapshots::const_iterator snapshot2)
+{
+ if (thread.get_id() == boost::thread::id())
+ thread = boost::thread(boost::bind(&Backgrounds::worker, this));
+
+ boost::unique_lock<boost::mutex> lock(mutex);
+ tasks.push_back(Task(meta_snapper, snapshot1, snapshot2));
+ meta_snapper->inc_use_count();
+ lock.unlock();
+
+ condition.notify_one();
+}
+
+
+enum {
+ IOPRIO_CLASS_NONE,
+ IOPRIO_CLASS_RT,
+ IOPRIO_CLASS_BE,
+ IOPRIO_CLASS_IDLE,
+};
+
+enum {
+ IOPRIO_WHO_PROCESS = 1,
+ IOPRIO_WHO_PGRP,
+ IOPRIO_WHO_USER,
+};
+
+#define IOPRIO_CLASS_SHIFT (13)
+#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
+
+#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
+#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
+#define IOPRIO_PRIO_VALUE(ioclass, data) (((ioclass) << IOPRIO_CLASS_SHIFT) | data)
+
+
+void
+Backgrounds::worker()
+{
+ pid_t tid = syscall(SYS_gettid);
+
+ int priority = 20;
+ if (setpriority(PRIO_PROCESS, tid, priority) != 0)
+ {
+ y2war("failed to set priority errno:" << errno);
+ }
+
+ int ioclass = IOPRIO_CLASS_IDLE;
+ int data = 0;
+ if (syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, tid, IOPRIO_PRIO_VALUE(ioclass, data)) != 0)
+ {
+ y2war("failed to set io-priority errno:" << errno);
+ }
+
+ try
+ {
+ while (true)
+ {
+ boost::unique_lock<boost::mutex> lock(mutex);
+ while (tasks.empty())
+ condition.wait(lock);
+ Task task = tasks.front();
+ lock.unlock();
+
+ Snapper* snapper = task.meta_snapper->getSnapper();
+ Comparison comparison(snapper, task.snapshot1, task.snapshot2);
+ task.meta_snapper->dec_use_count();
+
+ lock.lock();
+ tasks.pop_front();
+ lock.unlock();
+ }
+ }
+ catch (const boost::thread_interrupted&)
+ {
+ y2deb("worker interrupted");
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2012 Novell, Inc.
+ *
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, contact Novell, Inc.
+ *
+ * To contact Novell about this file by physical or electronic mail, you may
+ * find current contact information at www.novell.com.
+ */
+
+
+#ifndef SNAPPER_BACKGROUND_H
+#define SNAPPER_BACKGROUND_H
+
+
+#include <boost/thread.hpp>
+
+#include <snapper/Comparison.h>
+
+#include "MetaSnapper.h"
+
+
+using namespace std;
+using namespace snapper;
+
+
+class Backgrounds : private boost::noncopyable
+{
+
+public:
+
+ Backgrounds();
+ ~Backgrounds();
+
+ struct Task
+ {
+ Task(MetaSnapper* meta_snapper, Snapshots::const_iterator snapshot1,
+ Snapshots::const_iterator snapshot2)
+ : meta_snapper(meta_snapper), snapshot1(snapshot1), snapshot2(snapshot2) {}
+
+ MetaSnapper* meta_snapper;
+ Snapshots::const_iterator snapshot1;
+ Snapshots::const_iterator snapshot2;
+ };
+
+ typedef list<Task>::const_iterator const_iterator;
+
+ const_iterator begin() const { return tasks.begin(); }
+
+ const_iterator end() const { return tasks.end(); }
+
+ bool empty() const { return tasks.empty(); }
+
+ void add_task(MetaSnapper* meta_snapper, Snapshots::const_iterator snapshot1,
+ Snapshots::const_iterator snapshot2);
+
+private:
+
+ void worker();
+
+ boost::condition_variable condition;
+ boost::mutex mutex;
+ boost::thread thread;
+ list<Task> tasks;
+
+};
+
+
+extern Backgrounds backgrounds;
+
+
+#endif
#include "Types.h"
#include "Client.h"
#include "MetaSnapper.h"
+#include "Background.h"
boost::shared_mutex big_mutex;
snap2->setUserdata(userdata);
snap2->flushInfo();
- // snapper->startBackgroundComparsion(snap1, snap2); // TODO
+ map<string, string>::const_iterator pos = it->config_info.raw.find("BACKGROUND_COMPARISON");
+ if (pos == it->config_info.raw.end() || pos->second == "yes")
+ backgrounds.add_task(&(*it), snap1, snap2);
DBus::MessageMethodReturn reply(msg);
hoho << s.str();
}
+ hoho << "backgrounds:";
+ for (Backgrounds::const_iterator it = backgrounds.begin(); it != backgrounds.end(); ++it)
+ {
+ std::ostringstream s;
+ s << " name:'" << it->meta_snapper->configName() << "'";
+ hoho << s.str();
+ }
+
hoho << "meta-snappers:";
for (MetaSnappers::const_iterator it = meta_snappers.begin(); it != meta_snappers.end(); ++it)
{
while (true)
{
boost::unique_lock<boost::mutex> lock(mutex);
-
while (tasks.empty())
condition.wait(lock);
-
Task task = tasks.front();
tasks.pop();
-
lock.unlock();
dispatch(task.conn, task.msg);
snapperd.cc \
Client.cc Client.h \
MetaSnapper.cc MetaSnapper.h \
+ Background.cc Background.h \
Types.cc Types.h
snapperd_LDADD = ../snapper/libsnapper.la ../dbus/libdbus.la \
#include "MetaSnapper.h"
#include "Client.h"
+#include "Background.h"
#include "Types.h"
clients.remove_zombies();
- if (clients.empty())
+ if (clients.empty() && backgrounds.empty())
set_idle_timeout(idle_time);
for (MetaSnappers::iterator it = meta_snappers.begin(); it != meta_snappers.end(); ++it)
if (clients.has_zombies())
return 1000;
+ if (!backgrounds.empty())
+ 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;
# Makefile.am for snapper/snapper
#
-AM_CXXFLAGS = -D_FILE_OFFSET_BITS=64 -DLIBDIR=\"$(libdir)\"
+AM_CXXFLAGS = -D_FILE_OFFSET_BITS=64
INCLUDES = -I/usr/include/libxml2
}
- // Directory that contains the per snapshot directory with info files.
- // For btrfs e.g. "/.snapshots" or "/home/.snapshots".
- // For ext4 e.g. "/.snapshots-info" or "/home/.snapshots-info".
- string
- Snapper::infosDir() const
- {
- return filesystem->infosDir();
- }
-
-
SDir
Snapper::openSubvolumeDir() const
{
}
- void
- Snapper::startBackgroundComparsion(Snapshots::const_iterator snapshot1,
- Snapshots::const_iterator snapshot2)
- {
- if (snapshot1 == snapshots.end() || snapshot1->isCurrent())
- throw IllegalSnapshotException();
-
- if (snapshot2 == snapshots.end() || snapshot2->isCurrent())
- throw IllegalSnapshotException();
-
- bool background_comparison = true;
- config->getValue("BACKGROUND_COMPARISON", background_comparison);
- if (!background_comparison)
- return;
-
- y2mil("num1:" << snapshot1->getNum() << " num2:" << snapshot2->getNum());
-
- if (!snapshot1->isCurrent())
- snapshot1->mountFilesystemSnapshot();
- if (!snapshot2->isCurrent())
- snapshot2->mountFilesystemSnapshot();
-
- bool invert = snapshot1->getNum() > snapshot2->getNum();
-
- if (invert)
- swap(snapshot1, snapshot2);
-
- string dir1 = snapshot1->snapshotDir();
- string dir2 = snapshot2->snapshotDir();
-
- string output = snapshot2->infoDir() + "/filelist-" + decString(snapshot1->getNum()) +
- ".txt";
-
- SystemCmd(NICEBIN " -n 19 " IONICEBIN " -c 3 " COMPAREDIRSBIN " " + quote(dir1) + " " +
- quote(dir2) + " " + quote(output));
- }
-
-
ConfigInfo
Snapper::getConfig(const string& config_name)
{
string configName() const { return config_name; }
string subvolumeDir() const;
- string infosDir() const;
#ifndef SWIG
SDir openSubvolumeDir() const;
void deleteSnapshot(Snapshots::iterator snapshot);
- void startBackgroundComparsion(Snapshots::const_iterator snapshot1,
- Snapshots::const_iterator snapshot2);
-
const vector<string>& getIgnorePatterns() const { return ignore_patterns; }
static ConfigInfo getConfig(const string& config_name);
#define CHSNAPBIN "/sbin/chsnap"
-#define COMPAREDIRSBIN LIBDIR "/snapper/bin/compare-dirs"
-
-#define NICEBIN "/usr/bin/nice"
-#define IONICEBIN "/usr/bin/ionice"
-
#define CPBIN "/bin/cp"
#define TOUCHBIN "/usr/bin/touch"
#define RMBIN "/bin/rm"
}
- // Directory where the info file is saved. Obviously not available for
- // current.
- // For btrfs e.g. "/.snapshots/1" or "/home/.snapshots/1".
- // For ext4 e.g. "/.snapshots-info/1" or "/home/.snapshots-info/1".
- string
- Snapshot::infoDir() const
- {
- if (isCurrent())
- throw IllegalSnapshotException();
-
- return snapper->infosDir() + "/" + decString(num);
- }
-
-
// Directory containing the actual content of the snapshot.
// For btrfs e.g. "/" or "/home" for current and "/.snapshots/1/snapshot"
// or "/home/.snapshots/1/snapshot" otherwise.
void flushInfo();
- string infoDir() const;
string snapshotDir() const;
#ifndef SWIG