Merge lp:~xavi-garcia-mena/keeper/task-state-manager into lp:keeper/devel
- task-state-manager
- Merge into devel
Status: | Needs review |
---|---|
Proposed branch: | lp:~xavi-garcia-mena/keeper/task-state-manager |
Merge into: | lp:keeper/devel |
Diff against target: |
1634 lines (+1003/-359) 15 files modified
include/helper/backup-helper.h (+4/-0) include/helper/helper.h (+4/-2) src/cli/main.cpp (+0/-1) src/helper/backup-helper.cpp (+41/-14) src/helper/helper.cpp (+23/-27) src/service/CMakeLists.txt (+3/-0) src/service/keeper-task-backup.cpp (+175/-0) src/service/keeper-task-backup.h (+46/-0) src/service/keeper-task.cpp (+176/-0) src/service/keeper-task.h (+73/-0) src/service/keeper.cpp (+16/-315) src/service/private/keeper-task_p.h (+54/-0) src/service/task-manager.cpp (+327/-0) src/service/task-manager.h (+60/-0) tests/unit/helper/fake-helper.h (+1/-0) |
To merge this branch: | bzr merge lp:~xavi-garcia-mena/keeper/task-state-manager |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
unity-api-1-bot | continuous-integration | Needs Fixing | |
Charles Kerr (community) | Approve | ||
Review via email: mp+303802@code.launchpad.net |
Commit message
Initial implementation of a task manager that holds the state and cleans keeper.cpp from having references to helpers.
Description of the change
Initial implementation of a task manager that holds the state and cleans keeper.cpp from having references to helpers.
Main class is TaskManager, that runs KeeperTask objects sequentially and stores the state of all of them.
A KeeperTask object basically holds the state of that task and the common members between different kinds of tasks. For example, the Helper is a protected member of KeeperTask, and the concrete tasks will be the ones to define if the helper is a backup or restore helper.
KeeperTaskBackup inherits from KeeperTask, represents a backup task and holds all the storage framework socket functionality.
Note: I've created a private/
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:96
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild:
https:/
Charles Kerr (charlesk) wrote : | # |
Mostly LGTM, a few comments and suggestions inline.
Main issue is I suspect I know what the problem is that's requiring the DATA_COMPLETE, you may want to talk to james about the shared_
Michi Henning (michihenning) wrote : | # |
I added a response to one of Charles's comments.
Charles Kerr (charlesk) wrote : | # |
Replied with more detail inline
Michi Henning (michihenning) wrote : | # |
Thanks for the comments Charles!
I'm a Qt newbie, so I might be getting this wrong. But I was under the impression that, if the QLocalSocket is destroyed, the signal connection is torn down too. In other words, you either get the signal and, if you do, the socket is still guaranteed to be there, or the socket was destroyed, in which case you don't get the signal.
Have I got this wrong?
At any rate, as long as you keep a copy of the socket shared_ptr around, you know that it can't magically disappear from underneath you. Isn't that sufficient to make sure that things are OK with respect to life cycle?
Xavi Garcia (xavi-garcia-mena) wrote : | # |
Thanks for the review, Charles, I left some comments inline.
I also found a bug in the state management while creating the new integration tests and I will fix them in this branch.
Regarding the QLocalSocket issue... I will change the code to reset the shared_ptr and when I get more information I will let you all know.
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:97
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:98
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Continuous integration, rev:99
https:/
Executed test runs:
FAILURE: https:/
FAILURE: https:/
Click here to trigger a rebuild:
https:/
Xavi Garcia (xavi-garcia-mena) wrote : | # |
Michi, Charles... I removed the "hack" and when we don't need the QLocalSocket I just drop the shared_ptr.... it works fine now. I updated the version of storage-framework this week, so that possibly fixed the issue I had.
Charles Kerr (charlesk) wrote : | # |
Michi,
Yes, I think you're misunderstanding. What I'm saying is because we're using `delete o' instead of `o.deleteLater()' in the QLocalSocket's shared_ptr, we're setting up a case where it can be destroyed in the middle of its bytesWritten signal.
1. keeper calls create_file(), gets an uploader
2. uploader's ctor creates a QLocalSocket smart ptr (socket refcount init to 1)
3. keeper holds onto the uploader (uploader refcount init to 1)
4. keeper calls uploader::socket(), keeps a ref (socket refcount inc to 2), subscribes to bytesWritten
(work happens)
5. keeper gets a socket:
two paths here:
6a. if keeper's got an error flag set on this task, eg error between the backup helper and keeper, we set the task as in error and reset state, including our socket smart_ptr (socket refcount dec to 1) and our uploader smart_ptr (uploader refcount dec to 0, socket refcount dec to 0) so we've called "delete QLocalSocket" in the middle of its bytesWritten callback
(less sure about this, branch, steps to trigger same bug here depend on how Qt signals work)
6b. if no error flag but we've written all we planned to, keeper calls finish_upload()
7b. UploaderImpl:
8b. disconnectFromS
9b. keeper says "we're done, clear the state", including our socket reference (socket refcount dec to 1) and our uploader (uploader refcount dec to 0, socket refcount dec to 0), so again we've called 'delete QLocalSocket" in the middle of its bytesWritten callback
On top of that, keeper has its own bug in branch b: it's letting the uploader refcount dec to 0 while still having a QFutureWatcher has a dangling reference to the now-destroyed uploader's QFuture.
unity-api-1-bot (unity-api-1-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
FAILURE: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Michi Henning (michihenning) wrote : | # |
> Michi,
>
> Yes, I think you're misunderstanding. What I'm saying is because we're using
> `delete o' instead of `o.deleteLater()' in the QLocalSocket's shared_ptr,
> we're setting up a case where it can be destroyed in the middle of its
> bytesWritten signal.
Ah, OK, thanks for the explanation, I get it now :-)
I've pushed a fix and added it to silo 60. The QLocalSocket shared pointers that are handed to the client now have a custom deleter that calls socket-
Unmerged revisions
Preview Diff
1 | === modified file 'include/helper/backup-helper.h' |
2 | --- include/helper/backup-helper.h 2016-08-21 23:43:33 +0000 |
3 | +++ include/helper/backup-helper.h 2016-08-30 14:16:37 +0000 |
4 | @@ -52,6 +52,10 @@ |
5 | void stop() override; |
6 | void on_helper_process_stopped() override; |
7 | int get_helper_socket() const; |
8 | + QString to_string(Helper::State state) const override; |
9 | + |
10 | +public Q_SLOTS: |
11 | + void on_storage_framework_finished(); |
12 | |
13 | private: |
14 | QScopedPointer<BackupHelperPrivate> const d_ptr; |
15 | |
16 | === modified file 'include/helper/helper.h' |
17 | --- include/helper/helper.h 2016-08-21 23:43:33 +0000 |
18 | +++ include/helper/helper.h 2016-08-30 14:16:37 +0000 |
19 | @@ -37,11 +37,13 @@ |
20 | Q_DISABLE_COPY(Helper) |
21 | |
22 | Q_ENUMS(State) |
23 | - enum class State {NOT_STARTED, STARTED, CANCELLED, FAILED, COMPLETE}; |
24 | + enum class State {NOT_STARTED, STARTED, CANCELLED, FAILED, DATA_COMPLETE, COMPLETE}; |
25 | |
26 | Q_PROPERTY(Helper::State state READ state NOTIFY state_changed) |
27 | State state() const __pure; |
28 | |
29 | + virtual QString to_string(Helper::State state) const; |
30 | + |
31 | // NB: range is [0.0 .. 1.0] |
32 | Q_PROPERTY(float percent_done READ percent_done NOTIFY percent_done_changed) |
33 | float percent_done() const __pure; |
34 | @@ -70,7 +72,7 @@ |
35 | Helper(QString const & appid, const clock_func& clock=default_clock, QObject *parent=nullptr); |
36 | void set_state(State); |
37 | void record_data_transferred(qint64 n_bytes); |
38 | - virtual void on_helper_process_stopped(); |
39 | + virtual void on_helper_process_stopped() = 0; |
40 | |
41 | private: |
42 | |
43 | |
44 | === modified file 'src/cli/main.cpp' |
45 | --- src/cli/main.cpp 2016-08-26 09:30:11 +0000 |
46 | +++ src/cli/main.cpp 2016-08-30 14:16:37 +0000 |
47 | @@ -75,7 +75,6 @@ |
48 | { |
49 | if (iter_values.value().toString() == "folder") |
50 | { |
51 | - // got it |
52 | qDebug() << "Adding uuid" << iter.key() << "with type:" << "folder"; |
53 | uuids << iter.key(); |
54 | } |
55 | |
56 | === modified file 'src/helper/backup-helper.cpp' |
57 | --- src/helper/backup-helper.cpp 2016-08-24 07:04:33 +0000 |
58 | +++ src/helper/backup-helper.cpp 2016-08-30 14:16:37 +0000 |
59 | @@ -51,11 +51,6 @@ |
60 | , helper_socket_(new QLocalSocket()) |
61 | , read_socket_(new QLocalSocket()) |
62 | , upload_buffer_{} |
63 | - , n_read_{} |
64 | - , n_uploaded_{} |
65 | - , read_error_{} |
66 | - , write_error_{} |
67 | - , cancelled_{} |
68 | { |
69 | // listen for inactivity |
70 | QObject::connect(timer_.data(), &QTimer::timeout, |
71 | @@ -139,6 +134,20 @@ |
72 | return int(helper_socket_->socketDescriptor()); |
73 | } |
74 | |
75 | + void on_storage_framework_finished() |
76 | + { |
77 | + qDebug() << "storage framework has finished for the current helper..."; |
78 | + storage_framework_socket_.reset(); |
79 | + check_for_done(); |
80 | + } |
81 | + |
82 | + QString to_string(Helper::State state) const |
83 | + { |
84 | + return state == Helper::State::STARTED |
85 | + ? QStringLiteral("saving") |
86 | + : q_ptr->Helper::to_string(state); |
87 | + } |
88 | + |
89 | private: |
90 | |
91 | void on_inactivity_detected() |
92 | @@ -158,8 +167,8 @@ |
93 | n_uploaded_ += n; |
94 | q_ptr->record_data_transferred(n); |
95 | qDebug("n_read %zu n_uploaded %zu (newly uploaded %zu)", size_t(n_read_), size_t(n_uploaded_), size_t(n)); |
96 | + process_more(); |
97 | check_for_done(); |
98 | - process_more(); |
99 | } |
100 | |
101 | void process_more() |
102 | @@ -218,8 +227,10 @@ |
103 | { |
104 | if (n_uploaded_ == q_ptr->expected_size()) |
105 | { |
106 | - qDebug() << "n_uploaded = " << n_uploaded_ << " expected = " << q_ptr->expected_size() << " --- COMPLETE"; |
107 | - q_ptr->set_state(Helper::State::COMPLETE); |
108 | + if (storage_framework_socket_) |
109 | + q_ptr->set_state(Helper::State::DATA_COMPLETE); |
110 | + else |
111 | + q_ptr->set_state(Helper::State::COMPLETE); |
112 | } |
113 | else if (read_error_ || write_error_ || (n_uploaded_ > q_ptr->expected_size())) |
114 | { |
115 | @@ -241,15 +252,15 @@ |
116 | BackupHelper * const q_ptr; |
117 | QScopedPointer<QTimer> timer_; |
118 | std::shared_ptr<QLocalSocket> storage_framework_socket_; |
119 | - std::shared_ptr<QMetaObject::Connection> storage_framework_socket_connection_; |
120 | QScopedPointer<QLocalSocket> helper_socket_; |
121 | QScopedPointer<QLocalSocket> read_socket_; |
122 | QByteArray upload_buffer_; |
123 | - qint64 n_read_; |
124 | - qint64 n_uploaded_; |
125 | - bool read_error_; |
126 | - bool write_error_; |
127 | - bool cancelled_; |
128 | + qint64 n_read_ = 0; |
129 | + qint64 n_uploaded_ = 0; |
130 | + bool read_error_ = false; |
131 | + bool write_error_ = false; |
132 | + bool cancelled_ = false; |
133 | + std::shared_ptr<QMetaObject::Connection> storage_framework_socket_connection_; |
134 | }; |
135 | |
136 | /*** |
137 | @@ -307,3 +318,19 @@ |
138 | |
139 | return d->get_helper_socket(); |
140 | } |
141 | + |
142 | +QString |
143 | +BackupHelper::to_string(Helper::State state) const |
144 | +{ |
145 | + Q_D(const BackupHelper); |
146 | + |
147 | + return d->to_string(state); |
148 | +} |
149 | + |
150 | +void |
151 | +BackupHelper::on_storage_framework_finished() |
152 | +{ |
153 | + Q_D(BackupHelper); |
154 | + |
155 | + return d->on_storage_framework_finished(); |
156 | +} |
157 | |
158 | === modified file 'src/helper/helper.cpp' |
159 | --- src/helper/helper.cpp 2016-08-21 23:43:33 +0000 |
160 | +++ src/helper/helper.cpp 2016-08-30 14:16:37 +0000 |
161 | @@ -166,7 +166,7 @@ |
162 | { |
163 | if (state_ != state) |
164 | { |
165 | - qDebug() << "changing state of helper" << static_cast<void*>(this) << "from" << toString(state_) << "to" << toString(state); |
166 | + qDebug() << "changing state of helper" << static_cast<void*>(this) << "from" << q_ptr->to_string(state_) << "to" << q_ptr->to_string(state); |
167 | state_ = state; |
168 | q_ptr->state_changed(state); |
169 | } |
170 | @@ -221,9 +221,21 @@ |
171 | ual_stop(); |
172 | } |
173 | |
174 | - void on_helper_process_stopped() |
175 | + QString to_string(Helper::State state) const |
176 | { |
177 | - q_ptr->set_state(Helper::State::COMPLETE); |
178 | + auto ret = QStringLiteral("bug"); |
179 | + |
180 | + switch (state) |
181 | + { |
182 | + case State::NOT_STARTED: ret = QStringLiteral("not-started"); break; |
183 | + case State::STARTED: ret = QStringLiteral("started"); break; |
184 | + case State::CANCELLED: ret = QStringLiteral("cancelled"); break; |
185 | + case State::FAILED: ret = QStringLiteral("failed"); break; |
186 | + case State::DATA_COMPLETE: ret = QStringLiteral("finishing"); break; |
187 | + case State::COMPLETE: ret = QStringLiteral("complete"); break; |
188 | + } |
189 | + |
190 | + return ret; |
191 | } |
192 | |
193 | private: |
194 | @@ -311,22 +323,6 @@ |
195 | } |
196 | } |
197 | |
198 | - QString toString(Helper::State state) |
199 | - { |
200 | - auto ret = QStringLiteral("bug"); |
201 | - |
202 | - switch (state) |
203 | - { |
204 | - case State::NOT_STARTED: ret = QStringLiteral("not-started"); break; |
205 | - case State::STARTED: ret = QStringLiteral("started"); break; |
206 | - case State::CANCELLED: ret = QStringLiteral("cancelled"); break; |
207 | - case State::FAILED: ret = QStringLiteral("failed"); break; |
208 | - case State::COMPLETE: ret = QStringLiteral("complete"); break; |
209 | - } |
210 | - |
211 | - return ret; |
212 | - } |
213 | - |
214 | Helper * const q_ptr; |
215 | QString appid_; |
216 | clock_func clock_; |
217 | @@ -360,6 +356,14 @@ |
218 | return d->state(); |
219 | } |
220 | |
221 | +QString |
222 | +Helper::to_string(Helper::State state) const |
223 | +{ |
224 | + Q_D(const Helper); |
225 | + |
226 | + return d->to_string(state); |
227 | +} |
228 | + |
229 | int |
230 | Helper::speed() const |
231 | { |
232 | @@ -438,11 +442,3 @@ |
233 | |
234 | d->stop(); |
235 | } |
236 | - |
237 | -void |
238 | -Helper::on_helper_process_stopped() |
239 | -{ |
240 | - Q_D(Helper); |
241 | - |
242 | - d->on_helper_process_stopped(); |
243 | -} |
244 | |
245 | === modified file 'src/service/CMakeLists.txt' |
246 | --- src/service/CMakeLists.txt 2016-08-12 06:08:22 +0000 |
247 | +++ src/service/CMakeLists.txt 2016-08-30 14:16:37 +0000 |
248 | @@ -12,6 +12,9 @@ |
249 | keeper-user.cpp |
250 | keeper-helper.cpp |
251 | restore-choices.cpp |
252 | + task-manager.cpp |
253 | + keeper-task.cpp |
254 | + keeper-task-backup.cpp |
255 | ) |
256 | add_library( |
257 | ${SERVICE_LIB} |
258 | |
259 | === added file 'src/service/keeper-task-backup.cpp' |
260 | --- src/service/keeper-task-backup.cpp 1970-01-01 00:00:00 +0000 |
261 | +++ src/service/keeper-task-backup.cpp 2016-08-30 14:16:37 +0000 |
262 | @@ -0,0 +1,175 @@ |
263 | +/* |
264 | + * Copyright (C) 2016 Canonical, Ltd. |
265 | + * |
266 | + * This program is free software: you can redistribute it and/or modify it |
267 | + * under the terms of the GNU General Public License version 3, as published |
268 | + * by the Free Software Foundation. |
269 | + * |
270 | + * This program is distributed in the hope that it will be useful, but |
271 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
272 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
273 | + * PURPOSE. See the GNU General Public License for more details. |
274 | + * |
275 | + * You should have received a copy of the GNU General Public License along |
276 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
277 | + * |
278 | + * Authors: |
279 | + * Xavi Garcia <xavi.garcia.mena@canoincal.com> |
280 | + * Charles Kerr <charles.kerr@canoincal.com> |
281 | + */ |
282 | +#include "app-const.h" // DEKKO_APP_ID |
283 | +#include "helper/backup-helper.h" |
284 | +#include "keeper-task-backup.h" |
285 | +#include "keeper-task.h" |
286 | +#include "private/keeper-task_p.h" |
287 | +#include "storage-framework/storage_framework_client.h" |
288 | + |
289 | +class KeeperTaskBackupPrivate : public KeeperTaskPrivate |
290 | +{ |
291 | + Q_DECLARE_PUBLIC(KeeperTaskBackup) |
292 | +public: |
293 | + KeeperTaskBackupPrivate(KeeperTask * keeper_task, |
294 | + KeeperTask::TaskData const & task_data, |
295 | + QSharedPointer<HelperRegistry> const & helper_registry, |
296 | + QSharedPointer<StorageFrameworkClient> const & storage) |
297 | + : KeeperTaskPrivate(keeper_task, task_data, helper_registry, storage) |
298 | + { |
299 | + storage_framework_socket_connection_ready_.reset( |
300 | + new QMetaObject::Connection( |
301 | + QObject::connect( |
302 | + storage_.data(), &StorageFrameworkClient::socketReady, |
303 | + std::bind(&KeeperTaskBackupPrivate::on_backup_socket_ready, this, std::placeholders::_1) |
304 | + ) |
305 | + ), |
306 | + [](QMetaObject::Connection* c){ |
307 | + QObject::disconnect(*c); |
308 | + } |
309 | + ); |
310 | + } |
311 | + |
312 | + ~KeeperTaskBackupPrivate() = default; |
313 | + |
314 | + QStringList get_helper_urls() const |
315 | + { |
316 | + return helper_registry_->get_backup_helper_urls(task_data_.metadata); |
317 | + } |
318 | + |
319 | + void init_helper() |
320 | + { |
321 | + qDebug() << "Initializing a backup helper"; |
322 | + helper_.reset(new BackupHelper(DEKKO_APP_ID)); |
323 | + qDebug() << "Helper " << static_cast<void*>(helper_.data()) << " was created"; |
324 | + |
325 | + auto backup_helper = qSharedPointerDynamicCast<BackupHelper>(helper_); |
326 | + if (backup_helper) |
327 | + { |
328 | + // listen for the storage framework to finish |
329 | + storage_framework_socket_connection_finished_.reset( |
330 | + new QMetaObject::Connection( |
331 | + QObject::connect( |
332 | + storage_.data(), &StorageFrameworkClient::finished, |
333 | + std::bind(&BackupHelper::on_storage_framework_finished, backup_helper.data()) |
334 | + ) |
335 | + ), |
336 | + [](QMetaObject::Connection* c){ |
337 | + QObject::disconnect(*c); |
338 | + } |
339 | + ); |
340 | + } |
341 | + } |
342 | + |
343 | + void on_backup_socket_ready(std::shared_ptr<QLocalSocket> const & sf_socket) |
344 | + { |
345 | + qDebug("calling helper.set_storage_framework_socket(socket=%d)", int(sf_socket->socketDescriptor())); |
346 | + qDebug() << "Helper is " << static_cast<void*>(helper_.data()); |
347 | + auto backup_helper = qSharedPointerDynamicCast<BackupHelper>(helper_); |
348 | + if (!backup_helper) |
349 | + { |
350 | + qWarning() << "Only backup tasks are allowed to ask for storage framework sockets"; |
351 | + helper_->stop(); |
352 | + return; |
353 | + } |
354 | + backup_helper->set_storage_framework_socket(sf_socket); |
355 | + Q_EMIT(q_ptr->task_socket_ready(backup_helper->get_helper_socket())); |
356 | + } |
357 | + |
358 | + void ask_for_storage_framework_socket(quint64 n_bytes) |
359 | + { |
360 | + qDebug() << "asking storage framework for a socket"; |
361 | + storage_->getNewFileForBackup(n_bytes); |
362 | + helper_->set_expected_size(n_bytes); |
363 | + } |
364 | + |
365 | + void on_helper_state_changed(Helper::State state) override |
366 | + { |
367 | + auto new_state = state; |
368 | + switch (state) |
369 | + { |
370 | + case Helper::State::NOT_STARTED: |
371 | + break; |
372 | + |
373 | + case Helper::State::STARTED: |
374 | + qDebug() << "Backup helper started"; |
375 | + break; |
376 | + |
377 | + case Helper::State::CANCELLED: |
378 | + qDebug() << "Backup helper cancelled... closing the socket."; |
379 | + storage_->finish(false); |
380 | + break; |
381 | + |
382 | + case Helper::State::FAILED: |
383 | + qDebug() << "Backup helper failed... closing the socket."; |
384 | + storage_->finish(false); |
385 | + break; |
386 | + |
387 | + case Helper::State::DATA_COMPLETE: |
388 | + task_data_.percent_done = 1; |
389 | + qDebug() << "Backup helper finished... closing the socket."; |
390 | + try |
391 | + { |
392 | + storage_->finish(true); |
393 | + } |
394 | + catch (std::exception & e) |
395 | + { |
396 | + qDebug() << "Failed finishing sf... setting the state to failed"; |
397 | + new_state = Helper::State::FAILED; |
398 | + } |
399 | + break; |
400 | + case Helper::State::COMPLETE: |
401 | + break; |
402 | + } |
403 | + KeeperTaskPrivate::on_helper_state_changed(new_state); |
404 | + } |
405 | + |
406 | +private: |
407 | + std::shared_ptr<QMetaObject::Connection> storage_framework_socket_connection_ready_; |
408 | + std::shared_ptr<QMetaObject::Connection> storage_framework_socket_connection_finished_; |
409 | +}; |
410 | + |
411 | +KeeperTaskBackup::KeeperTaskBackup(TaskData const & task_data, |
412 | + QSharedPointer<HelperRegistry> const & helper_registry, |
413 | + QSharedPointer<StorageFrameworkClient> const & storage, |
414 | + QObject *parent) |
415 | + : KeeperTask(*new KeeperTaskBackupPrivate(this, task_data, helper_registry, storage), parent) |
416 | +{ |
417 | +} |
418 | + |
419 | +KeeperTaskBackup::~KeeperTaskBackup() = default; |
420 | + |
421 | +QStringList KeeperTaskBackup::get_helper_urls() const |
422 | +{ |
423 | + Q_D(const KeeperTaskBackup); |
424 | + return d->get_helper_urls(); |
425 | +} |
426 | + |
427 | +void KeeperTaskBackup::init_helper() |
428 | +{ |
429 | + Q_D(KeeperTaskBackup); |
430 | + d->init_helper(); |
431 | +} |
432 | + |
433 | +void KeeperTaskBackup::ask_for_storage_framework_socket(quint64 n_bytes) |
434 | +{ |
435 | + Q_D(KeeperTaskBackup); |
436 | + d->ask_for_storage_framework_socket(n_bytes); |
437 | +} |
438 | |
439 | === added file 'src/service/keeper-task-backup.h' |
440 | --- src/service/keeper-task-backup.h 1970-01-01 00:00:00 +0000 |
441 | +++ src/service/keeper-task-backup.h 2016-08-30 14:16:37 +0000 |
442 | @@ -0,0 +1,46 @@ |
443 | +/* |
444 | + * Copyright (C) 2016 Canonical, Ltd. |
445 | + * |
446 | + * This program is free software: you can redistribute it and/or modify it |
447 | + * under the terms of the GNU General Public License version 3, as published |
448 | + * by the Free Software Foundation. |
449 | + * |
450 | + * This program is distributed in the hope that it will be useful, but |
451 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
452 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
453 | + * PURPOSE. See the GNU General Public License for more details. |
454 | + * |
455 | + * You should have received a copy of the GNU General Public License along |
456 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
457 | + * |
458 | + * Authors: |
459 | + * Xavi Garcia <xavi.garcia.mena@canoincal.com> |
460 | + * Charles Kerr <charles.kerr@canoincal.com> |
461 | + */ |
462 | +#pragma once |
463 | + |
464 | +#include "keeper-task.h" |
465 | + |
466 | +class KeeperTaskBackupPrivate; |
467 | + |
468 | +class KeeperTaskBackup : public KeeperTask |
469 | +{ |
470 | + Q_OBJECT |
471 | + Q_DECLARE_PRIVATE(KeeperTaskBackup) |
472 | +public: |
473 | + |
474 | + KeeperTaskBackup(TaskData const & task_data, |
475 | + QSharedPointer<HelperRegistry> const & helper_registry, |
476 | + QSharedPointer<StorageFrameworkClient> const & storage, |
477 | + QObject *parent = nullptr); |
478 | + virtual ~KeeperTaskBackup(); |
479 | + |
480 | + Q_DISABLE_COPY(KeeperTaskBackup) |
481 | + |
482 | + void ask_for_storage_framework_socket(quint64 n_bytes); |
483 | + |
484 | +protected: |
485 | + QStringList get_helper_urls() const override; |
486 | + void init_helper() override; |
487 | + |
488 | +}; |
489 | |
490 | === added file 'src/service/keeper-task.cpp' |
491 | --- src/service/keeper-task.cpp 1970-01-01 00:00:00 +0000 |
492 | +++ src/service/keeper-task.cpp 2016-08-30 14:16:37 +0000 |
493 | @@ -0,0 +1,176 @@ |
494 | +/* |
495 | + * Copyright (C) 2016 Canonical, Ltd. |
496 | + * |
497 | + * This program is free software: you can redistribute it and/or modify it |
498 | + * under the terms of the GNU General Public License version 3, as published |
499 | + * by the Free Software Foundation. |
500 | + * |
501 | + * This program is distributed in the hope that it will be useful, but |
502 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
503 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
504 | + * PURPOSE. See the GNU General Public License for more details. |
505 | + * |
506 | + * You should have received a copy of the GNU General Public License along |
507 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
508 | + * |
509 | + * Authors: |
510 | + * Xavi Garcia <xavi.garcia.mena@canoincal.com> |
511 | + * Charles Kerr <charles.kerr@canoincal.com> |
512 | + */ |
513 | +#include "app-const.h" // DEKKO_APP_ID |
514 | +#include "helper/metadata.h" |
515 | +#include "keeper-task.h" |
516 | + |
517 | +#include "private/keeper-task_p.h" |
518 | + |
519 | +KeeperTaskPrivate::KeeperTaskPrivate(KeeperTask * keeper_task, |
520 | + KeeperTask::TaskData const & task_data, |
521 | + QSharedPointer<HelperRegistry> const & helper_registry, |
522 | + QSharedPointer<StorageFrameworkClient> const & storage) |
523 | + : q_ptr(keeper_task) |
524 | + , task_data_(task_data) |
525 | + , helper_registry_(helper_registry) |
526 | + , storage_(storage) |
527 | +{ |
528 | +} |
529 | + |
530 | +KeeperTaskPrivate::~KeeperTaskPrivate() = default; |
531 | + |
532 | +bool KeeperTaskPrivate::start() |
533 | +{ |
534 | + // initialize the helper |
535 | + q_ptr->init_helper(); |
536 | + |
537 | + const auto urls = q_ptr->get_helper_urls(); |
538 | + if (urls.isEmpty()) |
539 | + { |
540 | + task_data_.action = helper_->to_string(Helper::State::FAILED); |
541 | + task_data_.error = "no helper information in registry"; |
542 | + qWarning() << "ERROR: uuid: " << task_data_.metadata.uuid() << " has no url"; |
543 | + calculate_and_notify_state(Helper::State::FAILED); |
544 | + return false; |
545 | + } |
546 | + |
547 | + // listen for helper state changes |
548 | + QObject::connect(helper_.data(), &Helper::state_changed, |
549 | + std::bind(&KeeperTaskPrivate::on_helper_state_changed, this, std::placeholders::_1) |
550 | + ); |
551 | + |
552 | + // listen for helper process changes |
553 | + QObject::connect(helper_.data(), &Helper::percent_done_changed, |
554 | + std::bind(&KeeperTaskPrivate::on_helper_percent_done_changed, this, std::placeholders::_1) |
555 | + ); |
556 | + |
557 | + helper_->start(urls); |
558 | + return true; |
559 | +} |
560 | + |
561 | +QVariantMap KeeperTaskPrivate::state() const |
562 | +{ |
563 | + return state_; |
564 | +} |
565 | + |
566 | +void KeeperTaskPrivate::set_current_task_action(QString const& action) |
567 | +{ |
568 | + task_data_.action = action; |
569 | + calculate_task_state(); |
570 | +} |
571 | + |
572 | +void KeeperTaskPrivate::on_helper_state_changed(Helper::State state) |
573 | +{ |
574 | + switch (state) |
575 | + { |
576 | + case Helper::State::NOT_STARTED: |
577 | + break; |
578 | + |
579 | + case Helper::State::STARTED: |
580 | + qDebug() << "Helper started"; |
581 | + break; |
582 | + |
583 | + case Helper::State::CANCELLED: |
584 | + qDebug() << "Helper cancelled... closing the socket."; |
585 | + break; |
586 | + |
587 | + case Helper::State::FAILED: |
588 | + qDebug() << "Helper failed... closing the socket."; |
589 | + break; |
590 | + |
591 | + case Helper::State::DATA_COMPLETE: |
592 | + task_data_.percent_done = 1; |
593 | + qDebug() << "Helper data complete.. closing the socket."; |
594 | + break; |
595 | + |
596 | + case Helper::State::COMPLETE: |
597 | + qDebug() << "Helper complete."; |
598 | + break; |
599 | + } |
600 | + set_current_task_action(helper_->to_string(state)); |
601 | + calculate_and_notify_state(state); |
602 | +} |
603 | + |
604 | +void KeeperTaskPrivate::on_helper_percent_done_changed(float /*percent_done*/) |
605 | +{ |
606 | + calculate_task_state(); |
607 | +} |
608 | + |
609 | +QVariantMap KeeperTaskPrivate::calculate_task_state() |
610 | +{ |
611 | + QVariantMap ret; |
612 | + |
613 | + auto const uuid = task_data_.metadata.uuid(); |
614 | + |
615 | + ret.insert(QStringLiteral("action"), task_data_.action); |
616 | + |
617 | + ret.insert(QStringLiteral("display-name"), task_data_.metadata.display_name()); |
618 | + |
619 | + // FIXME: assuming backup_helper_ for now... |
620 | + int32_t speed {}; |
621 | + speed = helper_->speed(); |
622 | + ret.insert(QStringLiteral("speed"), speed); |
623 | + |
624 | + task_data_.percent_done = helper_->percent_done(); |
625 | + ret.insert(QStringLiteral("percent-done"), double(task_data_.percent_done)); |
626 | + |
627 | + if (task_data_.action == "failed") |
628 | + ret.insert(QStringLiteral("error"), task_data_.error); |
629 | + |
630 | + ret.insert(QStringLiteral("uuid"), uuid); |
631 | + |
632 | + return ret; |
633 | +} |
634 | + |
635 | +void KeeperTaskPrivate::calculate_and_notify_state(Helper::State state) |
636 | +{ |
637 | + state_ = calculate_task_state(); |
638 | + Q_EMIT(q_ptr->task_state_changed(state)); |
639 | +} |
640 | + |
641 | +KeeperTask::KeeperTask(TaskData const & task_data, |
642 | + QSharedPointer<HelperRegistry> const & helper_registry, |
643 | + QSharedPointer<StorageFrameworkClient> const & storage, |
644 | + QObject *parent) |
645 | + : QObject(parent) |
646 | + , d_ptr( new KeeperTaskPrivate(this, task_data, helper_registry, storage)) |
647 | +{ |
648 | +} |
649 | + |
650 | +KeeperTask::KeeperTask(KeeperTaskPrivate & d, QObject *parent) |
651 | + : QObject(parent) |
652 | + , d_ptr(&d) |
653 | +{ |
654 | +} |
655 | + |
656 | + |
657 | +KeeperTask::~KeeperTask() = default; |
658 | + |
659 | +bool KeeperTask::start() |
660 | +{ |
661 | + Q_D(KeeperTask); |
662 | + return d->start(); |
663 | +} |
664 | + |
665 | +QVariantMap KeeperTask::state() const |
666 | +{ |
667 | + Q_D(const KeeperTask); |
668 | + return d->state(); |
669 | +} |
670 | |
671 | === added file 'src/service/keeper-task.h' |
672 | --- src/service/keeper-task.h 1970-01-01 00:00:00 +0000 |
673 | +++ src/service/keeper-task.h 2016-08-30 14:16:37 +0000 |
674 | @@ -0,0 +1,73 @@ |
675 | +/* |
676 | + * Copyright (C) 2016 Canonical, Ltd. |
677 | + * |
678 | + * This program is free software: you can redistribute it and/or modify it |
679 | + * under the terms of the GNU General Public License version 3, as published |
680 | + * by the Free Software Foundation. |
681 | + * |
682 | + * This program is distributed in the hope that it will be useful, but |
683 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
684 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
685 | + * PURPOSE. See the GNU General Public License for more details. |
686 | + * |
687 | + * You should have received a copy of the GNU General Public License along |
688 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
689 | + * |
690 | + * Authors: |
691 | + * Xavi Garcia <xavi.garcia.mena@canoincal.com> |
692 | + * Charles Kerr <charles.kerr@canoincal.com> |
693 | + */ |
694 | + |
695 | +#pragma once |
696 | + |
697 | +#include "helper/metadata.h" |
698 | +#include "helper/backup-helper.h" |
699 | +#include "helper/helper.h" |
700 | + |
701 | +#include <QObject> |
702 | +#include <QSharedPointer> |
703 | + |
704 | +class HelperRegistry; |
705 | +class KeeperTaskPrivate; |
706 | +class StorageFrameworkClient; |
707 | + |
708 | +class KeeperTask : public QObject |
709 | +{ |
710 | + Q_OBJECT |
711 | + Q_DECLARE_PRIVATE(KeeperTask) |
712 | +public: |
713 | + |
714 | + enum class TaskType { BACKUP, RESTORE }; |
715 | + |
716 | + struct TaskData |
717 | + { |
718 | + QString action; |
719 | + QString error; |
720 | + KeeperTask::TaskType type; |
721 | + Metadata metadata; |
722 | + float percent_done; |
723 | + }; |
724 | + |
725 | + KeeperTask(TaskData const & task_data, |
726 | + QSharedPointer<HelperRegistry> const & helper_registry, |
727 | + QSharedPointer<StorageFrameworkClient> const & storage, |
728 | + QObject *parent = nullptr); |
729 | + virtual ~KeeperTask(); |
730 | + |
731 | + Q_DISABLE_COPY(KeeperTask) |
732 | + |
733 | + bool start(); |
734 | + QVariantMap state() const; |
735 | + |
736 | + Q_SIGNALS: |
737 | + void task_state_changed(Helper::State state); |
738 | + void task_socket_ready(int socket_descriptor); |
739 | + |
740 | +protected: |
741 | + KeeperTask(KeeperTaskPrivate & d, QObject *parent = nullptr); |
742 | + virtual QStringList get_helper_urls() const = 0; |
743 | + virtual void init_helper() = 0; |
744 | + |
745 | +protected: |
746 | + QScopedPointer<KeeperTaskPrivate> const d_ptr; |
747 | +}; |
748 | |
749 | === modified file 'src/service/keeper.cpp' |
750 | --- src/service/keeper.cpp 2016-08-19 16:12:41 +0000 |
751 | +++ src/service/keeper.cpp 2016-08-30 14:16:37 +0000 |
752 | @@ -18,68 +18,34 @@ |
753 | * Charles Kerr <charles.kerr@canonical.com> |
754 | */ |
755 | |
756 | -#include "app-const.h" // DEKKO_APP_ID |
757 | -#include "helper/backup-helper.h" |
758 | #include "helper/metadata.h" |
759 | #include "service/metadata-provider.h" |
760 | #include "service/keeper.h" |
761 | #include "storage-framework/storage_framework_client.h" |
762 | -#include "util/dbus-utils.h" |
763 | +#include "task-manager.h" |
764 | |
765 | #include <QDebug> |
766 | #include <QDBusMessage> |
767 | #include <QDBusConnection> |
768 | #include <QSharedPointer> |
769 | -#include <QScopedPointer> |
770 | -#include <QVariant> |
771 | #include <QVector> |
772 | |
773 | -#include <uuid/uuid.h> |
774 | - |
775 | - |
776 | class KeeperPrivate |
777 | { |
778 | - enum class TaskType { BACKUP, RESTORE }; |
779 | - |
780 | - struct TaskData |
781 | - { |
782 | - QString action; |
783 | - QString error; |
784 | - TaskType type; |
785 | - Metadata metadata; |
786 | - float percent_done; |
787 | - }; |
788 | - |
789 | public: |
790 | - |
791 | - QScopedPointer<BackupHelper> backup_helper_; |
792 | - QScopedPointer<StorageFrameworkClient> storage_; |
793 | + QScopedPointer<TaskManager> task_manager_; |
794 | |
795 | KeeperPrivate(Keeper* keeper, |
796 | const QSharedPointer<HelperRegistry>& helper_registry, |
797 | const QSharedPointer<MetadataProvider>& backup_choices, |
798 | const QSharedPointer<MetadataProvider>& restore_choices) |
799 | - : backup_helper_(new BackupHelper(DEKKO_APP_ID)) |
800 | + : q_ptr(keeper) |
801 | , storage_(new StorageFrameworkClient()) |
802 | - , q_ptr(keeper) |
803 | , helper_registry_(helper_registry) |
804 | , backup_choices_(backup_choices) |
805 | , restore_choices_(restore_choices) |
806 | { |
807 | - // listen for backup helper state changes |
808 | - QObject::connect(backup_helper_.data(), &Helper::state_changed, |
809 | - std::bind(&KeeperPrivate::on_helper_state_changed, this, std::placeholders::_1) |
810 | - ); |
811 | - |
812 | - // listen for backup helper process changes |
813 | - QObject::connect(backup_helper_.data(), &Helper::percent_done_changed, |
814 | - std::bind(&KeeperPrivate::on_helper_percent_done_changed, this, std::placeholders::_1) |
815 | - ); |
816 | - |
817 | - // listen for the storage framework to finish |
818 | - QObject::connect(storage_.data(), &StorageFrameworkClient::finished, |
819 | - std::bind(&KeeperPrivate::on_storage_framework_finished, this) |
820 | - ); |
821 | + task_manager_.reset(new TaskManager(helper_registry, storage_, get_backup_choices(), get_restore_choices())); |
822 | } |
823 | |
824 | ~KeeperPrivate() =default; |
825 | @@ -88,42 +54,7 @@ |
826 | |
827 | void start_tasks(QStringList const& uuids) |
828 | { |
829 | - if (!remaining_tasks_.isEmpty()) |
830 | - { |
831 | - // FIXME: return a dbus error here |
832 | - qWarning() << "keeper is already active"; |
833 | - return; |
834 | - } |
835 | - |
836 | - // rebuild the state variables |
837 | - state_.clear(); |
838 | - task_data_.clear(); |
839 | - all_tasks_.clear(); |
840 | - current_task_.clear(); |
841 | - remaining_tasks_.clear(); |
842 | - for(auto const& uuid : uuids) |
843 | - { |
844 | - Metadata m; |
845 | - TaskType type; |
846 | - if (!find_task_metadata(uuid, m, type)) |
847 | - { |
848 | - // TODO Report error to user |
849 | - qCritical() << "uuid" << uuid << "not found; skipping"; |
850 | - continue; |
851 | - } |
852 | - |
853 | - all_tasks_ << uuid; |
854 | - remaining_tasks_ << uuid; |
855 | - |
856 | - auto& td = task_data_[uuid]; |
857 | - td.metadata = m; |
858 | - td.type = type; |
859 | - td.action = QStringLiteral("queued"); |
860 | - |
861 | - update_task_state(td); |
862 | - } |
863 | - |
864 | - start_next_task(); |
865 | + task_manager_->start_tasks(uuids); |
866 | } |
867 | |
868 | QVector<Metadata> get_backup_choices() const |
869 | @@ -144,27 +75,21 @@ |
870 | |
871 | QVariantDictMap get_state() const |
872 | { |
873 | - return state_; |
874 | + return task_manager_->get_state(); |
875 | } |
876 | |
877 | QDBusUnixFileDescriptor start_backup(QDBusConnection bus, const QDBusMessage& msg, quint64 n_bytes) |
878 | { |
879 | - qDebug("Helper::StartBackup(n_bytes=%zu)", size_t(n_bytes)); |
880 | + |
881 | + qDebug("Keeper::StartBackup(n_bytes=%zu)", size_t(n_bytes)); |
882 | |
883 | // the next time we get a socket from storage-framework, return it to our caller |
884 | auto tag = new int {}; |
885 | - auto on_socket_ready = [bus,msg,n_bytes,tag,this](std::shared_ptr<QLocalSocket> const& sf_socket) |
886 | + auto on_socket_ready = [bus,msg,n_bytes,tag,this](int backup_reply) |
887 | { |
888 | - if (sf_socket) |
889 | - { |
890 | - qDebug("calling helper.set_storage_framework_socket(n_bytes=%zu socket=%d)", |
891 | - size_t(n_bytes), |
892 | - int(sf_socket->socketDescriptor())); |
893 | - backup_helper_->set_expected_size(n_bytes); |
894 | - backup_helper_->set_storage_framework_socket(sf_socket); |
895 | - } |
896 | + qDebug("BackupManager returned socket %d", backup_reply); |
897 | auto reply = msg.createReply(); |
898 | - reply << QVariant::fromValue(QDBusUnixFileDescriptor(backup_helper_->get_helper_socket())); |
899 | + reply << QVariant::fromValue(QDBusUnixFileDescriptor(backup_reply)); |
900 | bus.send(reply); |
901 | |
902 | // one-shot client, so disconnect now |
903 | @@ -174,14 +99,14 @@ |
904 | // cppcheck-suppress deallocuse |
905 | *tag = remember_connection( |
906 | QObject::connect( |
907 | - storage_.data(), |
908 | - &StorageFrameworkClient::socketReady, |
909 | + task_manager_.data(), |
910 | + &TaskManager::socket_ready, |
911 | on_socket_ready |
912 | ) |
913 | ); |
914 | |
915 | - // ask storage framework for a new socket |
916 | - storage_->getNewFileForBackup(n_bytes); |
917 | + qDebug() << "Asking for an storage framework socket to the task manager"; |
918 | + task_manager_->ask_for_storage_framework_socket(n_bytes); |
919 | |
920 | // tell the caller that we'll be responding async |
921 | msg.setDelayedReply(true); |
922 | @@ -190,225 +115,6 @@ |
923 | |
924 | private: |
925 | |
926 | - void on_helper_state_changed(Helper::State state) |
927 | - { |
928 | - switch (state) |
929 | - { |
930 | - case Helper::State::NOT_STARTED: |
931 | - break; |
932 | - |
933 | - case Helper::State::STARTED: |
934 | - qDebug() << "Backup helper started"; |
935 | - break; |
936 | - |
937 | - case Helper::State::CANCELLED: |
938 | - set_current_task_action(QStringLiteral("cancelled")); |
939 | - qDebug() << "Backup helper cancelled... closing the socket."; |
940 | - storage_->finish(false); |
941 | - break; |
942 | - |
943 | - case Helper::State::FAILED: |
944 | - set_current_task_action(QStringLiteral("failed")); |
945 | - qDebug() << "Backup helper failed... closing the socket."; |
946 | - storage_->finish(false); |
947 | - break; |
948 | - |
949 | - case Helper::State::COMPLETE: |
950 | - task_data_[current_task_].percent_done = 1; |
951 | - set_current_task_action(QStringLiteral("complete")); |
952 | - qDebug() << "Backup helper finished... closing the socket."; |
953 | - try |
954 | - { |
955 | - storage_->finish(true); |
956 | - } |
957 | - catch (std::exception & e) |
958 | - { |
959 | - qDebug() << "Failed finishing sf... seting the state to failed"; |
960 | - set_current_task_action(QStringLiteral("failed")); |
961 | - } |
962 | - break; |
963 | - } |
964 | - } |
965 | - |
966 | - void on_helper_percent_done_changed(float /*percent_done*/) |
967 | - { |
968 | - update_task_state(current_task_); |
969 | - } |
970 | - |
971 | - void on_storage_framework_finished() |
972 | - { |
973 | - qDebug() << "storage framework has finished for the current task"; |
974 | - start_next_task(); |
975 | - } |
976 | - |
977 | - /*** |
978 | - **** Task Queueing |
979 | - ***/ |
980 | - |
981 | - void start_next_task() |
982 | - { |
983 | - bool started {false}; |
984 | - |
985 | - while (!started && !remaining_tasks_.isEmpty()) |
986 | - started = start_task(remaining_tasks_.takeFirst()); |
987 | - |
988 | - if (!started) |
989 | - clear_current_task(); |
990 | - } |
991 | - |
992 | - bool start_task(QString const& uuid) |
993 | - { |
994 | - if (!task_data_.contains(uuid)) |
995 | - { |
996 | - qCritical() << "no task data found for" << uuid; |
997 | - return false; |
998 | - } |
999 | - |
1000 | - auto& td = task_data_[uuid]; |
1001 | - if (td.type == TaskType::BACKUP) |
1002 | - { |
1003 | - qDebug() << "Task is a backup task"; |
1004 | - |
1005 | - const auto urls = helper_registry_->get_backup_helper_urls(td.metadata); |
1006 | - if (urls.isEmpty()) |
1007 | - { |
1008 | - td.action = "failed"; |
1009 | - td.error = "no helper information in registry"; |
1010 | - qWarning() << "ERROR: uuid: " << uuid << " has no url"; |
1011 | - return false; |
1012 | - } |
1013 | - |
1014 | - set_current_task(uuid); |
1015 | - set_current_task_action(QStringLiteral("saving")); |
1016 | - backup_helper_->start(urls); |
1017 | - return true; |
1018 | - } |
1019 | - else // RESTORE |
1020 | - { |
1021 | - set_current_task(uuid); |
1022 | - set_current_task_action(QStringLiteral("restoring")); |
1023 | - qWarning() << "restore not implemented yet"; |
1024 | - return false; |
1025 | - } |
1026 | - } |
1027 | - |
1028 | - /*** |
1029 | - **** State |
1030 | - ***/ |
1031 | - |
1032 | - void update_task_state(QString const& uuid) |
1033 | - { |
1034 | - auto it = task_data_.find(uuid); |
1035 | - if (it == task_data_.end()) |
1036 | - { |
1037 | - qCritical() << "no task data for" << uuid; |
1038 | - return; |
1039 | - } |
1040 | - |
1041 | - update_task_state(it.value()); |
1042 | - } |
1043 | - |
1044 | - void update_task_state(TaskData& td) |
1045 | - { |
1046 | - state_[td.metadata.uuid()] = calculate_task_state(td); |
1047 | - |
1048 | -#if 0 |
1049 | - // FIXME: we don't need this to work correctly for the sprint because Marcus is polling in a loop |
1050 | - // but we will need this in order for him to stop doing that |
1051 | - |
1052 | - // TODO: compare old and new and decide if it's worth emitting a PropertyChanged signal; |
1053 | - // eg don't contribute to dbus noise for minor speed fluctuations |
1054 | - |
1055 | - // TODO: this function is called inside a loop when initializing the state |
1056 | - // after start_tasks(), so also ensure we don't have a notify flood here |
1057 | - |
1058 | - DBusUtils::notifyPropertyChanged( |
1059 | - QDBusConnection::sessionBus(), |
1060 | - *q_ptr, |
1061 | - DBusTypes::KEEPER_USER_PATH, |
1062 | - DBusTypes::KEEPER_USER_INTERFACE, |
1063 | - QStringList(QStringLiteral("State")) |
1064 | - ); |
1065 | -#endif |
1066 | - } |
1067 | - |
1068 | - QVariantMap calculate_task_state(TaskData& td) const |
1069 | - { |
1070 | - QVariantMap ret; |
1071 | - |
1072 | - auto const uuid = td.metadata.uuid(); |
1073 | - bool const current = uuid == current_task_; |
1074 | - |
1075 | - ret.insert(QStringLiteral("action"), td.action); |
1076 | - |
1077 | - ret.insert(QStringLiteral("display-name"), td.metadata.display_name()); |
1078 | - |
1079 | - // FIXME: assuming backup_helper_ for now... |
1080 | - int32_t speed {}; |
1081 | - if (current) |
1082 | - speed = backup_helper_->speed(); |
1083 | - ret.insert(QStringLiteral("speed"), speed); |
1084 | - |
1085 | - if (current) |
1086 | - td.percent_done = backup_helper_->percent_done(); |
1087 | - ret.insert(QStringLiteral("percent-done"), double(td.percent_done)); |
1088 | - |
1089 | - if (td.action == "failed") |
1090 | - ret.insert(QStringLiteral("error"), td.error); |
1091 | - |
1092 | - ret.insert(QStringLiteral("uuid"), uuid); |
1093 | - |
1094 | - return ret; |
1095 | - } |
1096 | - |
1097 | - void set_current_task(QString const& uuid) |
1098 | - { |
1099 | - auto const prev = current_task_; |
1100 | - |
1101 | - current_task_ = uuid; |
1102 | - |
1103 | - if (!prev.isEmpty()) |
1104 | - update_task_state(prev); |
1105 | - |
1106 | - if (!uuid.isEmpty()) |
1107 | - update_task_state(uuid); |
1108 | - } |
1109 | - |
1110 | - void clear_current_task() |
1111 | - { |
1112 | - set_current_task(QString()); |
1113 | - } |
1114 | - |
1115 | - void set_current_task_action(QString const& action) |
1116 | - { |
1117 | - auto& td = task_data_[current_task_]; |
1118 | - td.action = action; |
1119 | - update_task_state(td); |
1120 | - } |
1121 | - |
1122 | - /*** |
1123 | - **** Misc |
1124 | - ***/ |
1125 | - |
1126 | - bool find_task_metadata(QString const& uuid, Metadata& setme_task, TaskType& setme_type) const |
1127 | - { |
1128 | - for (const auto& c : get_backup_choices()) { |
1129 | - if (c.uuid() == uuid) { |
1130 | - setme_task = c; |
1131 | - setme_type = TaskType::BACKUP; |
1132 | - return true; |
1133 | - } |
1134 | - } |
1135 | - for (const auto& c : get_restore_choices()) { |
1136 | - if (c.uuid() == uuid) { |
1137 | - setme_task = c; |
1138 | - setme_type = TaskType::RESTORE; |
1139 | - return true; |
1140 | - } |
1141 | - } |
1142 | - return false; |
1143 | - } |
1144 | - |
1145 | /*** |
1146 | **** |
1147 | ***/ |
1148 | @@ -437,18 +143,13 @@ |
1149 | ***/ |
1150 | |
1151 | Keeper * const q_ptr; |
1152 | + QSharedPointer<StorageFrameworkClient> storage_; |
1153 | QSharedPointer<HelperRegistry> helper_registry_; |
1154 | QSharedPointer<MetadataProvider> backup_choices_; |
1155 | QSharedPointer<MetadataProvider> restore_choices_; |
1156 | mutable QVector<Metadata> cached_backup_choices_; |
1157 | mutable QVector<Metadata> cached_restore_choices_; |
1158 | - QStringList all_tasks_; |
1159 | - QStringList remaining_tasks_; |
1160 | - QString current_task_; |
1161 | - QVariantDictMap state_; |
1162 | QMap<int,std::shared_ptr<QMetaObject::Connection>> connections_; |
1163 | - |
1164 | - mutable QMap<QString,TaskData> task_data_; |
1165 | }; |
1166 | |
1167 | |
1168 | |
1169 | === added directory 'src/service/private' |
1170 | === added file 'src/service/private/keeper-task_p.h' |
1171 | --- src/service/private/keeper-task_p.h 1970-01-01 00:00:00 +0000 |
1172 | +++ src/service/private/keeper-task_p.h 2016-08-30 14:16:37 +0000 |
1173 | @@ -0,0 +1,54 @@ |
1174 | +/* |
1175 | + * Copyright (C) 2016 Canonical, Ltd. |
1176 | + * |
1177 | + * This program is free software: you can redistribute it and/or modify it |
1178 | + * under the terms of the GNU General Public License version 3, as published |
1179 | + * by the Free Software Foundation. |
1180 | + * |
1181 | + * This program is distributed in the hope that it will be useful, but |
1182 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
1183 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1184 | + * PURPOSE. See the GNU General Public License for more details. |
1185 | + * |
1186 | + * You should have received a copy of the GNU General Public License along |
1187 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1188 | + * |
1189 | + * Authors: |
1190 | + * Xavi Garcia <xavi.garcia.mena@canoincal.com> |
1191 | + * Charles Kerr <charles.kerr@canoincal.com> |
1192 | + */ |
1193 | + |
1194 | +#pragma once |
1195 | +#include "../keeper-task.h" |
1196 | + |
1197 | +class KeeperTaskPrivate |
1198 | +{ |
1199 | + Q_DECLARE_PUBLIC(KeeperTask) |
1200 | +public: |
1201 | + KeeperTaskPrivate(KeeperTask * keeper_task, |
1202 | + KeeperTask::TaskData const & task_data, |
1203 | + QSharedPointer<HelperRegistry> const & helper_registry, |
1204 | + QSharedPointer<StorageFrameworkClient> const & storage); |
1205 | + |
1206 | + virtual ~KeeperTaskPrivate(); |
1207 | + |
1208 | + bool start(); |
1209 | + QVariantMap state() const; |
1210 | + void ask_for_storage_framework_socket(quint64 n_bytes); |
1211 | + |
1212 | +protected: |
1213 | + void set_current_task_action(QString const& action); |
1214 | + void on_helper_percent_done_changed(float percent_done); |
1215 | + QVariantMap calculate_task_state(); |
1216 | + void calculate_and_notify_state(Helper::State state); |
1217 | + void on_backup_socket_ready(std::shared_ptr<QLocalSocket> const & sf_socket); |
1218 | + |
1219 | + virtual void on_helper_state_changed(Helper::State state); |
1220 | + |
1221 | + KeeperTask * const q_ptr; |
1222 | + KeeperTask::TaskData task_data_; |
1223 | + QSharedPointer<HelperRegistry> helper_registry_; |
1224 | + QSharedPointer<StorageFrameworkClient> storage_; |
1225 | + QSharedPointer<Helper> helper_; |
1226 | + QVariantMap state_; |
1227 | +}; |
1228 | |
1229 | === added file 'src/service/task-manager.cpp' |
1230 | --- src/service/task-manager.cpp 1970-01-01 00:00:00 +0000 |
1231 | +++ src/service/task-manager.cpp 2016-08-30 14:16:37 +0000 |
1232 | @@ -0,0 +1,327 @@ |
1233 | +/* |
1234 | + * Copyright (C) 2016 Canonical, Ltd. |
1235 | + * |
1236 | + * This program is free software: you can redistribute it and/or modify it |
1237 | + * under the terms of the GNU General Public License version 3, as published |
1238 | + * by the Free Software Foundation. |
1239 | + * |
1240 | + * This program is distributed in the hope that it will be useful, but |
1241 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
1242 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1243 | + * PURPOSE. See the GNU General Public License for more details. |
1244 | + * |
1245 | + * You should have received a copy of the GNU General Public License along |
1246 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1247 | + * |
1248 | + * Authors: |
1249 | + * Xavi Garcia <xavi.garcia.mena@canoincal.com> |
1250 | + * Charles Kerr <charles.kerr@canoincal.com> |
1251 | + */ |
1252 | + |
1253 | +#include "helper/metadata.h" |
1254 | +#include "keeper-task-backup.h" |
1255 | +#include "storage-framework/storage_framework_client.h" |
1256 | +#include "task-manager.h" |
1257 | + |
1258 | +class TaskManagerPrivate |
1259 | +{ |
1260 | +public: |
1261 | + TaskManagerPrivate(TaskManager * manager, |
1262 | + QSharedPointer<HelperRegistry> const & helper_registry, |
1263 | + QSharedPointer<StorageFrameworkClient> const & storage, |
1264 | + QVector<Metadata> const & backup_metadata, |
1265 | + QVector<Metadata> const & restore_metadata) |
1266 | + : q_ptr(manager) |
1267 | + , helper_registry_(helper_registry) |
1268 | + , backup_metadata_(backup_metadata) |
1269 | + , restore_metadata_(restore_metadata) |
1270 | + , storage_(storage) |
1271 | + { |
1272 | + } |
1273 | + |
1274 | + ~TaskManagerPrivate() = default; |
1275 | + |
1276 | + /*** |
1277 | + **** Task Queueing public |
1278 | + ***/ |
1279 | + |
1280 | + void start_tasks(QStringList const & task_uuids) |
1281 | + { |
1282 | + if (!remaining_tasks_.isEmpty()) |
1283 | + { |
1284 | + // FIXME: return a dbus error here |
1285 | + qWarning() << "keeper is already active"; |
1286 | + return; |
1287 | + } |
1288 | + |
1289 | + // rebuild the state variables |
1290 | + state_.clear(); |
1291 | + task_data_.clear(); |
1292 | + current_task_.clear(); |
1293 | + remaining_tasks_.clear(); |
1294 | + |
1295 | + for(auto const& uuid : task_uuids) |
1296 | + { |
1297 | + Metadata m; |
1298 | + KeeperTask::TaskType type; |
1299 | + if (!find_task_metadata(uuid, m, type)) |
1300 | + { |
1301 | + // TODO Report error to user |
1302 | + qCritical() << "uuid" << uuid << "not found; skipping"; |
1303 | + continue; |
1304 | + } |
1305 | + |
1306 | + remaining_tasks_ << uuid; |
1307 | + |
1308 | + auto& td = task_data_[uuid]; |
1309 | + td.metadata = m; |
1310 | + td.type = type; |
1311 | + td.action = QStringLiteral("queued"); // TODO i18n |
1312 | + |
1313 | +// update_task_state(td); |
1314 | + } |
1315 | + |
1316 | + start_next_task(); |
1317 | + } |
1318 | + |
1319 | + /*** |
1320 | + *** State public |
1321 | + ***/ |
1322 | + |
1323 | + QVariantDictMap get_state() const |
1324 | + { |
1325 | + return state_; |
1326 | + } |
1327 | + |
1328 | + void on_helper_state_changed(Helper::State state) |
1329 | + { |
1330 | + qDebug() << "Task State changed"; |
1331 | + auto& td = task_data_[current_task_]; |
1332 | + update_task_state(td); |
1333 | + |
1334 | + switch (state) |
1335 | + { |
1336 | + case Helper::State::NOT_STARTED: |
1337 | + case Helper::State::STARTED: |
1338 | + case Helper::State::CANCELLED: |
1339 | + case Helper::State::FAILED: |
1340 | + break; |
1341 | + |
1342 | + case Helper::State::DATA_COMPLETE: |
1343 | + task_data_[current_task_].percent_done = 1; |
1344 | + break; |
1345 | + case Helper::State::COMPLETE: |
1346 | + qDebug() << "STARTING NEXT TASK ---------------------------------------"; |
1347 | + start_next_task(); |
1348 | + break; |
1349 | + } |
1350 | + } |
1351 | + |
1352 | + void ask_for_storage_framework_socket(quint64 n_bytes) |
1353 | + { |
1354 | + qDebug() << "Starting backup"; |
1355 | + if (task_) |
1356 | + { |
1357 | + auto backup_task_ = qSharedPointerDynamicCast<KeeperTaskBackup>(task_); |
1358 | + if (!backup_task_) |
1359 | + { |
1360 | + qWarning() << "Only backup tasks are allowed to ask for storage framework sockets"; |
1361 | + // TODO Mark this as an error at the current task and move to the next task |
1362 | + return; |
1363 | + } |
1364 | + backup_task_->ask_for_storage_framework_socket(n_bytes); |
1365 | + } |
1366 | + } |
1367 | +private: |
1368 | + /*** |
1369 | + **** Task Queueing |
1370 | + ***/ |
1371 | + |
1372 | + bool start_task(QString const& uuid) |
1373 | + { |
1374 | + if (!task_data_.contains(uuid)) |
1375 | + { |
1376 | + qCritical() << "no task data found for" << uuid; |
1377 | + return false; |
1378 | + } |
1379 | + |
1380 | + auto& td = task_data_[uuid]; |
1381 | + |
1382 | + qDebug() << "Creating task for uuid = " << uuid; |
1383 | + // initialize a new task |
1384 | + |
1385 | + task_.data()->disconnect(); |
1386 | + if (td.type == KeeperTask::TaskType::BACKUP) |
1387 | + { |
1388 | + task_.reset(new KeeperTaskBackup(td, helper_registry_, storage_)); |
1389 | + } |
1390 | + else |
1391 | + { |
1392 | + // TODO initialize a Restore task |
1393 | + } |
1394 | + |
1395 | + qDebug() << "task created: " << state_; |
1396 | + |
1397 | + set_current_task(uuid); |
1398 | + |
1399 | + QObject::connect(task_.data(), &KeeperTask::task_state_changed, |
1400 | + std::bind(&TaskManagerPrivate::on_helper_state_changed, this, std::placeholders::_1) |
1401 | + ); |
1402 | + |
1403 | + QObject::connect(task_.data(), &KeeperTask::task_socket_ready, |
1404 | + std::bind(&TaskManager::socket_ready, q_ptr, std::placeholders::_1) |
1405 | + ); |
1406 | + |
1407 | + |
1408 | + return task_->start(); |
1409 | + } |
1410 | + |
1411 | + void set_current_task(QString const& uuid) |
1412 | + { |
1413 | + auto const prev = current_task_; |
1414 | + |
1415 | + current_task_ = uuid; |
1416 | + |
1417 | + if (!uuid.isEmpty()) |
1418 | + update_task_state(uuid); |
1419 | + } |
1420 | + |
1421 | + void clear_current_task() |
1422 | + { |
1423 | + set_current_task(QString()); |
1424 | + } |
1425 | + |
1426 | + void start_next_task() |
1427 | + { |
1428 | + bool started {false}; |
1429 | + |
1430 | + while (!started && !remaining_tasks_.isEmpty()) |
1431 | + started = start_task(remaining_tasks_.takeFirst()); |
1432 | + |
1433 | + if (!started) |
1434 | + clear_current_task(); |
1435 | + } |
1436 | + |
1437 | + /*** |
1438 | + **** State |
1439 | + ***/ |
1440 | + |
1441 | + void update_task_state(QString const& uuid) |
1442 | + { |
1443 | + auto it = task_data_.find(uuid); |
1444 | + if (it == task_data_.end()) |
1445 | + { |
1446 | + qCritical() << "no task data for" << uuid; |
1447 | + return; |
1448 | + } |
1449 | + |
1450 | + update_task_state(it.value()); |
1451 | + } |
1452 | + |
1453 | + void update_task_state(KeeperTask::KeeperTask::TaskData& td) |
1454 | + { |
1455 | + state_[td.metadata.uuid()] = task_->state(); |
1456 | + |
1457 | +#if 0 |
1458 | + // FIXME: we don't need this to work correctly for the sprint because Marcus is polling in a loop |
1459 | + // but we will need this in order for him to stop doing that |
1460 | + |
1461 | + // TODO: compare old and new and decide if it's worth emitting a PropertyChanged signal; |
1462 | + // eg don't contribute to dbus noise for minor speed fluctuations |
1463 | + |
1464 | + // TODO: this function is called inside a loop when initializing the state |
1465 | + // after start_tasks(), so also ensure we don't have a notify flood here |
1466 | + |
1467 | + DBusUtils::notifyPropertyChanged( |
1468 | + QDBusConnection::sessionBus(), |
1469 | + *q_ptr, |
1470 | + DBusTypes::KEEPER_USER_PATH, |
1471 | + DBusTypes::KEEPER_USER_INTERFACE, |
1472 | + QStringList(QStringLiteral("State")) |
1473 | + ); |
1474 | +#endif |
1475 | + } |
1476 | + |
1477 | + void set_current_task_action(QString const& action) |
1478 | + { |
1479 | + auto& td = task_data_[current_task_]; |
1480 | + td.action = action; |
1481 | + update_task_state(td); |
1482 | + } |
1483 | + |
1484 | + /*** |
1485 | + **** Misc |
1486 | + ***/ |
1487 | + |
1488 | + bool find_task_metadata(QString const& uuid, Metadata& setme_task, KeeperTask::TaskType & type) const |
1489 | + { |
1490 | + for (const auto& c : backup_metadata_) |
1491 | + { |
1492 | + if (c.uuid() == uuid) { |
1493 | + setme_task = c; |
1494 | + type = KeeperTask::TaskType::BACKUP; |
1495 | + return true; |
1496 | + } |
1497 | + } |
1498 | + for (const auto& c : restore_metadata_) |
1499 | + { |
1500 | + if (c.uuid() == uuid) { |
1501 | + setme_task = c; |
1502 | + type = KeeperTask::TaskType::RESTORE; |
1503 | + return true; |
1504 | + } |
1505 | + } |
1506 | + return false; |
1507 | + } |
1508 | + |
1509 | + TaskManager * const q_ptr; |
1510 | + QSharedPointer<HelperRegistry> helper_registry_; |
1511 | + QVector<Metadata> backup_metadata_; |
1512 | + QVector<Metadata> restore_metadata_; |
1513 | + QSharedPointer<StorageFrameworkClient> storage_; |
1514 | + |
1515 | + QStringList remaining_tasks_; |
1516 | + QString current_task_; |
1517 | + |
1518 | + QVariantDictMap state_; |
1519 | + QSharedPointer<KeeperTask> task_; |
1520 | + |
1521 | + mutable QMap<QString,KeeperTask::TaskData> task_data_; |
1522 | +}; |
1523 | + |
1524 | +/*** |
1525 | +**** |
1526 | +***/ |
1527 | + |
1528 | +TaskManager::TaskManager(QSharedPointer<HelperRegistry> const & helper_registry, |
1529 | + QSharedPointer<StorageFrameworkClient> const & storage, |
1530 | + QVector<Metadata> const & backup_metadata, |
1531 | + QVector<Metadata> const & restore_metadata, |
1532 | + QObject *parent) |
1533 | + : QObject(parent) |
1534 | + , d_ptr(new TaskManagerPrivate(this, helper_registry, storage, backup_metadata, restore_metadata)) |
1535 | +{ |
1536 | +} |
1537 | + |
1538 | +TaskManager::~TaskManager() = default; |
1539 | + |
1540 | +void TaskManager::start_tasks(QStringList const & task_uuids) |
1541 | +{ |
1542 | + Q_D(TaskManager); |
1543 | + |
1544 | + d->start_tasks(task_uuids); |
1545 | +} |
1546 | + |
1547 | +QVariantDictMap TaskManager::get_state() const |
1548 | +{ |
1549 | + Q_D(const TaskManager); |
1550 | + |
1551 | + return d->get_state(); |
1552 | +} |
1553 | + |
1554 | +void TaskManager::ask_for_storage_framework_socket(quint64 n_bytes) |
1555 | +{ |
1556 | + Q_D(TaskManager); |
1557 | + |
1558 | + d->ask_for_storage_framework_socket(n_bytes); |
1559 | +} |
1560 | |
1561 | === added file 'src/service/task-manager.h' |
1562 | --- src/service/task-manager.h 1970-01-01 00:00:00 +0000 |
1563 | +++ src/service/task-manager.h 2016-08-30 14:16:37 +0000 |
1564 | @@ -0,0 +1,60 @@ |
1565 | +/* |
1566 | + * Copyright (C) 2016 Canonical, Ltd. |
1567 | + * |
1568 | + * This program is free software: you can redistribute it and/or modify it |
1569 | + * under the terms of the GNU General Public License version 3, as published |
1570 | + * by the Free Software Foundation. |
1571 | + * |
1572 | + * This program is distributed in the hope that it will be useful, but |
1573 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
1574 | + * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR |
1575 | + * PURPOSE. See the GNU General Public License for more details. |
1576 | + * |
1577 | + * You should have received a copy of the GNU General Public License along |
1578 | + * with this program. If not, see <http://www.gnu.org/licenses/>. |
1579 | + * |
1580 | + * Authors: |
1581 | + * Xavi Garcia <xavi.garcia.mena@canoincal.com> |
1582 | + * Charles Kerr <charles.kerr@canoincal.com> |
1583 | + */ |
1584 | + |
1585 | +#pragma once |
1586 | + |
1587 | +#include "helper/metadata.h" |
1588 | +#include "keeper-task.h" |
1589 | +#include "qdbus-stubs/dbus-types.h" |
1590 | + |
1591 | +#include <QObject> |
1592 | + |
1593 | +class HelperRegistry; |
1594 | +class TaskManagerPrivate; |
1595 | +class StorageFrameworkClient; |
1596 | + |
1597 | +class TaskManager : public QObject |
1598 | +{ |
1599 | + Q_OBJECT |
1600 | + Q_DECLARE_PRIVATE(TaskManager) |
1601 | +public: |
1602 | + |
1603 | + TaskManager(QSharedPointer<HelperRegistry> const & helper_registry, |
1604 | + QSharedPointer<StorageFrameworkClient> const & storage, |
1605 | + QVector<Metadata> const & backup_metadata, |
1606 | + QVector<Metadata> const & restore_metadata, |
1607 | + QObject *parent = nullptr); |
1608 | + |
1609 | + virtual ~TaskManager(); |
1610 | + |
1611 | + Q_DISABLE_COPY(TaskManager) |
1612 | + |
1613 | + void start_tasks(QStringList const & task_uuids); |
1614 | + |
1615 | + QVariantDictMap get_state() const; |
1616 | + |
1617 | + void ask_for_storage_framework_socket(quint64 n_bytes); |
1618 | + |
1619 | +Q_SIGNALS: |
1620 | + void socket_ready(int reply); |
1621 | + |
1622 | +private: |
1623 | + QScopedPointer<TaskManagerPrivate> const d_ptr; |
1624 | +}; |
1625 | |
1626 | === modified file 'tests/unit/helper/fake-helper.h' |
1627 | --- tests/unit/helper/fake-helper.h 2016-08-17 13:14:32 +0000 |
1628 | +++ tests/unit/helper/fake-helper.h 2016-08-30 14:16:37 +0000 |
1629 | @@ -33,4 +33,5 @@ |
1630 | |
1631 | void record_data_transferred(qint64 n) {Helper::record_data_transferred(n);} |
1632 | void set_expected_size(qint64 n) {Helper::set_expected_size(n);} |
1633 | + void on_helper_process_stopped() override {set_state(Helper::State::COMPLETE);}; |
1634 | }; |
Also, the toString method in the helper has been changed to to_string and it's virtual.
The reason why is because, for example, the backup helper may say that the started state means "saving" while the restore helper would say "restoring".
There is a default implementation with the default strings.