LeechCraft 0.6.70-16373-g319c272718
Modular cross-platform feature rich live environment.
Loading...
Searching...
No Matches
consistencychecker.cpp
Go to the documentation of this file.
1/**********************************************************************
2 * LeechCraft - modular cross-platform feature rich internet client.
3 * Copyright (C) 2006-2014 Georg Rudoy
4 *
5 * Distributed under the Boost Software License, Version 1.0.
6 * (See accompanying file LICENSE or copy at https://www.boost.org/LICENSE_1_0.txt)
7 **********************************************************************/
8
10#include <memory>
11#include <QFile>
12#include <QSqlDatabase>
13#include <QMessageBox>
14#include <QtConcurrentRun>
15#include <util/sll/visitor.h>
16#include <util/sys/paths.h>
18#include <util/util.h>
19#include "dumper.h"
20#include "util.h"
21
22namespace LC::Util
23{
25 {
26 const std::shared_ptr<ConsistencyChecker> Checker_;
27 public:
28 explicit FailedImpl (std::shared_ptr<ConsistencyChecker> checker)
29 : Checker_ {std::move (checker)}
30 {
31 }
32 private:
34 {
35 return Checker_->DumpReinit ();
36 }
37 };
38
39 ConsistencyChecker::ConsistencyChecker (QString dbPath, QString dialogContext, QObject *parent)
40 : QObject { parent }
41 , DBPath_ { std::move (dbPath) }
42 , DialogContext_ { std::move (dialogContext) }
43 {
44 }
45
46 std::shared_ptr<ConsistencyChecker> ConsistencyChecker::Create (QString dbPath, QString dialogContext)
47 {
48 return std::shared_ptr<ConsistencyChecker> { new ConsistencyChecker { std::move (dbPath), std::move (dialogContext) } };
49 }
50
52 {
53 return QtConcurrent::run ([pThis = shared_from_this ()] { return pThis->CheckDB (); });
54 }
55
56 ConsistencyChecker::CheckResult_t ConsistencyChecker::CheckDB ()
57 {
58 qDebug () << Q_FUNC_INFO
59 << "checking"
60 << DBPath_;
61 const auto& connName = Util::GenConnectionName ("ConsistencyChecker_" + DBPath_);
62
63 std::shared_ptr<QSqlDatabase> db
64 {
65 new QSqlDatabase { QSqlDatabase::addDatabase ("QSQLITE", connName) },
66 [connName] (QSqlDatabase *db)
67 {
68 delete db;
69 QSqlDatabase::removeDatabase (connName);
70 }
71 };
72
73 db->setDatabaseName (DBPath_);
74 if (!db->open ())
75 {
76 qWarning () << Q_FUNC_INFO
77 << "cannot open the DB, but that's not the kind of errors we're solving.";
78 return Succeeded {};
79 }
80
81 QSqlQuery pragma { *db };
82 static const QString checkQuery = qgetenv ("LC_THOROUGH_SQLITE_CHECK") == "1" ?
83 QStringLiteral ("PRAGMA integrity_check;") :
84 QStringLiteral ("PRAGMA quick_check;");
85 const auto isGood = pragma.exec (checkQuery) &&
86 pragma.next () &&
87 pragma.value (0) == "ok";
88 qDebug () << Q_FUNC_INFO
89 << "done checking"
90 << DBPath_
91 << "; result is:"
92 << isGood;
93 if (isGood)
94 return Succeeded {};
95 else
96 return std::make_shared<FailedImpl> (shared_from_this ());
97 }
98
99 QFuture<ConsistencyChecker::DumpResult_t> ConsistencyChecker::DumpReinit ()
100 {
101 QFutureInterface<DumpResult_t> iface;
102 iface.reportStarted ();
103
104 DumpReinitImpl (iface);
105
106 return iface.future ();
107 }
108
109 namespace
110 {
111 void ReportResult (QFutureInterface<ConsistencyChecker::DumpResult_t> iface,
113 {
114 iface.reportFinished (&result);
115 }
116 }
117
118 void ConsistencyChecker::DumpReinitImpl (QFutureInterface<DumpResult_t> iface)
119 {
120 const QFileInfo fi { DBPath_ };
121 const auto filesize = fi.size ();
122
123 while (true)
124 {
125 const auto available = GetSpaceInfo (DBPath_).Available_;
126
127 qDebug () << Q_FUNC_INFO
128 << "db size:" << filesize
129 << "free space:" << available;
130 if (available >= static_cast<quint64> (filesize))
131 break;
132
133 if (QMessageBox::question (nullptr,
134 DialogContext_,
135 tr ("Not enough available space on partition with file %1: "
136 "%2 while the restored file is expected to be around %3. "
137 "Please either free some disk space on this partition "
138 "and retry or cancel the restore process.")
139 .arg ("<em>" + DBPath_ + "</em>",
140 Util::MakePrettySize (available),
141 Util::MakePrettySize (filesize)),
142 QMessageBox::Retry | QMessageBox::Cancel) == QMessageBox::Cancel)
143 {
144 ReportResult (iface, DumpError { tr ("Not enough available disk space.") });
145 return;
146 }
147 }
148
149 const auto& newPath = DBPath_ + ".new";
150
151 while (true)
152 {
153 if (!QFile::exists (newPath))
154 break;
155
156 if (QMessageBox::question (nullptr,
157 DialogContext_,
158 tr ("%1 already exists. Please either remove the file manually "
159 "and retry or cancel the restore process.")
160 .arg ("<em>" + newPath + "</em>"),
161 QMessageBox::Retry | QMessageBox::Cancel) == QMessageBox::Cancel)
162 {
163 ReportResult (iface, DumpError { tr ("Backup file already exists.") });
164 return;
165 }
166 }
167
168 const auto dumper = new Dumper { DBPath_, newPath };
169
170 const auto managed = shared_from_this ();
171 Util::Sequence (nullptr, dumper->GetFuture ()) >>
172 [iface, newPath, managed] (const Dumper::Result_t& result)
173 {
174 Util::Visit (result,
175 [iface] (const Dumper::Error& error)
176 {
177 ReportResult (iface,
178 DumpError { tr ("Unable to restore the database.") + " " + error.What_ });
179 },
180 [iface, newPath, managed] (Dumper::Finished) { managed->HandleDumperFinished (iface, newPath); });
181 };
182 }
183
184 void ConsistencyChecker::HandleDumperFinished (QFutureInterface<DumpResult_t> iface, const QString& to)
185 {
186 const auto oldSize = QFileInfo { DBPath_ }.size ();
187 const auto newSize = QFileInfo { to }.size ();
188
189 const auto& backup = DBPath_ + ".bak";
190 while (!QFile::rename (DBPath_, backup))
191 QMessageBox::critical (nullptr,
192 DialogContext_,
193 tr ("Unable to backup %1 to %2. Please remove %2 and hit OK.")
194 .arg (DBPath_,
195 backup));
196
197 QFile::rename (to, DBPath_);
198
199 ReportResult (iface, DumpFinished { oldSize, newSize });
200 }
201}
QFuture< CheckResult_t > StartCheck()
std::variant< Succeeded, Failed > CheckResult_t
static std::shared_ptr< ConsistencyChecker > Create(QString dbPath, QString dialogContext)
std::variant< DumpFinished, DumpError > DumpResult_t
std::variant< Finished, Error > Result_t
Definition dumper.h:37
FailedImpl(std::shared_ptr< ConsistencyChecker > checker)
QString GenConnectionName(const QString &base)
Generates an unique thread-safe connection name.
Definition util.cpp:51
auto Visit(const Either< Left, Right > &either, Args &&... args)
Definition either.h:215
SpaceInfo GetSpaceInfo(const QString &path)
Returns the disk space info of the partition containing path.
Definition paths.cpp:154
QString MakePrettySize(qint64 sourcesize)
Makes a formatted size from number.
Definition util.cpp:53
STL namespace.
quint64 Available_
How much space is available to the current user.
Definition paths.h:202