##// END OF EJS Templates
Add thread protection on AbortDownload process
perrinel -
r423:3698da027722
parent child
Show More
@@ -1,87 +1,120
1 1 #include "Network/NetworkController.h"
2 2
3 3 #include <QMutex>
4 4 #include <QNetworkAccessManager>
5 5 #include <QNetworkReply>
6 6 #include <QNetworkRequest>
7 #include <QReadWriteLock>
7 8 #include <QThread>
8 9
9 10 #include <unordered_map>
10 11
11 12 Q_LOGGING_CATEGORY(LOG_NetworkController, "NetworkController")
12 13
13 14 struct NetworkController::NetworkControllerPrivate {
14 15 explicit NetworkControllerPrivate(NetworkController *parent) : m_WorkingMutex{} {}
15 16 QMutex m_WorkingMutex;
16 17
18 QReadWriteLock m_Lock;
17 19 std::unordered_map<QNetworkReply *, QUuid> m_NetworkReplyToVariableId;
18 20 std::unique_ptr<QNetworkAccessManager> m_AccessManager{nullptr};
21
22 void lockRead() { m_Lock.lockForRead(); }
23 void lockWrite() { m_Lock.lockForWrite(); }
24 void unlock() { m_Lock.unlock(); }
19 25 };
20 26
21 27 NetworkController::NetworkController(QObject *parent)
22 28 : QObject(parent), impl{spimpl::make_unique_impl<NetworkControllerPrivate>(this)}
23 29 {
24 30 }
25 31
26 32 void NetworkController::onProcessRequested(const QNetworkRequest &request, QUuid identifier,
27 33 std::function<void(QNetworkReply *, QUuid)> callback)
28 34 {
29 qCInfo(LOG_NetworkController()) << tr("NetworkController registered")
30 << QThread::currentThread();
31 35 auto reply = impl->m_AccessManager->get(request);
36 qCDebug(LOG_NetworkController()) << tr("NetworkController registered")
37 << QThread::currentThread() << reply;
32 38
33 39 // Store the couple reply id
40 impl->lockWrite();
34 41 impl->m_NetworkReplyToVariableId[reply] = identifier;
42 impl->unlock();
35 43
36 44 auto onReplyFinished = [reply, this, identifier, callback]() {
37 45
38 qCInfo(LOG_NetworkController()) << tr("NetworkController onReplyFinished")
39 << QThread::currentThread();
46 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished")
47 << QThread::currentThread() << reply;
48 impl->lockRead();
40 49 auto it = impl->m_NetworkReplyToVariableId.find(reply);
50 impl->unlock();
41 51 if (it != impl->m_NetworkReplyToVariableId.cend()) {
52 impl->lockWrite();
53 impl->m_NetworkReplyToVariableId.erase(reply);
54 impl->unlock();
55 // Deletes reply
42 56 callback(reply, identifier);
57 reply->deleteLater();
58
59 emit this->replyDownloadProgress(identifier, 0);
43 60 }
61
62 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyFinished END")
63 << QThread::currentThread() << reply;
44 64 };
45 65
46 66 auto onReplyProgress = [reply, this](qint64 bytesRead, qint64 totalBytes) {
47 67
48 68 double progress = (bytesRead * 100.0) / totalBytes;
69 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress") << progress
70 << QThread::currentThread() << reply;
71 impl->lockRead();
49 72 auto it = impl->m_NetworkReplyToVariableId.find(reply);
73 impl->unlock();
50 74 if (it != impl->m_NetworkReplyToVariableId.cend()) {
51 75 emit this->replyDownloadProgress(it->second, progress);
52 76 }
77 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyProgress END")
78 << QThread::currentThread() << reply;
53 79 };
54 80
55 81
56 82 connect(reply, &QNetworkReply::finished, this, onReplyFinished);
57 83 connect(reply, &QNetworkReply::downloadProgress, this, onReplyProgress);
58 84 }
59 85
60 86 void NetworkController::initialize()
61 87 {
62 88 qCDebug(LOG_NetworkController()) << tr("NetworkController init") << QThread::currentThread();
63 89 impl->m_WorkingMutex.lock();
64 90 impl->m_AccessManager = std::make_unique<QNetworkAccessManager>();
65 91 qCDebug(LOG_NetworkController()) << tr("NetworkController init END");
66 92 }
67 93
68 94 void NetworkController::finalize()
69 95 {
70 96 impl->m_WorkingMutex.unlock();
71 97 }
72 98
73 99 void NetworkController::onReplyCanceled(QUuid identifier)
74 100 {
75 101 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
102 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled")
103 << QThread::currentThread();
104
76 105
106 impl->lockRead();
77 107 auto end = impl->m_NetworkReplyToVariableId.cend();
78 108 auto it = std::find_if(impl->m_NetworkReplyToVariableId.cbegin(), end, findReply);
109 impl->unlock();
79 110 if (it != end) {
80 111 it->first->abort();
81 112 }
113 qCDebug(LOG_NetworkController()) << tr("NetworkController onReplyCanceled END")
114 << QThread::currentThread();
82 115 }
83 116
84 117 void NetworkController::waitForFinish()
85 118 {
86 119 QMutexLocker locker{&impl->m_WorkingMutex};
87 120 }
@@ -1,238 +1,238
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableCacheController.h>
3 3 #include <Variable/VariableController.h>
4 4 #include <Variable/VariableModel.h>
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Data/IDataProvider.h>
8 8 #include <Data/IDataSeries.h>
9 9 #include <Time/TimeController.h>
10 10
11 11 #include <QDateTime>
12 12 #include <QMutex>
13 13 #include <QThread>
14 14 #include <QUuid>
15 15 #include <QtCore/QItemSelectionModel>
16 16
17 17 #include <unordered_map>
18 18
19 19 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
20 20
21 21 struct VariableController::VariableControllerPrivate {
22 22 explicit VariableControllerPrivate(VariableController *parent)
23 23 : m_WorkingMutex{},
24 24 m_VariableModel{new VariableModel{parent}},
25 25 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
26 26 m_VariableCacheController{std::make_unique<VariableCacheController>()}
27 27 {
28 28 }
29 29
30 30 QMutex m_WorkingMutex;
31 31 /// Variable model. The VariableController has the ownership
32 32 VariableModel *m_VariableModel;
33 33 QItemSelectionModel *m_VariableSelectionModel;
34 34
35 35
36 36 TimeController *m_TimeController{nullptr};
37 37 std::unique_ptr<VariableCacheController> m_VariableCacheController;
38 38
39 39 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
40 40 m_VariableToProviderMap;
41 41 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
42 42 };
43 43
44 44 VariableController::VariableController(QObject *parent)
45 45 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
46 46 {
47 47 qCDebug(LOG_VariableController()) << tr("VariableController construction")
48 48 << QThread::currentThread();
49 49
50 50 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
51 51 &VariableController::onAbortProgressRequested);
52 52 }
53 53
54 54 VariableController::~VariableController()
55 55 {
56 56 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
57 57 << QThread::currentThread();
58 58 this->waitForFinish();
59 59 }
60 60
61 61 VariableModel *VariableController::variableModel() noexcept
62 62 {
63 63 return impl->m_VariableModel;
64 64 }
65 65
66 66 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
67 67 {
68 68 return impl->m_VariableSelectionModel;
69 69 }
70 70
71 71 void VariableController::setTimeController(TimeController *timeController) noexcept
72 72 {
73 73 impl->m_TimeController = timeController;
74 74 }
75 75
76 76 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
77 77 {
78 78 if (!variable) {
79 79 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
80 80 return;
81 81 }
82 82
83 83 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
84 84 // make some treatments before the deletion
85 85 emit variableAboutToBeDeleted(variable);
86 86
87 87 // Deletes identifier
88 88 impl->m_VariableToIdentifierMap.erase(variable);
89 89
90 90 // Deletes provider
91 91 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
92 92 qCDebug(LOG_VariableController())
93 93 << tr("Number of providers deleted for variable %1: %2")
94 94 .arg(variable->name(), QString::number(nbProvidersDeleted));
95 95
96 96 // Clears cache
97 97 impl->m_VariableCacheController->clear(variable);
98 98
99 99 // Deletes from model
100 100 impl->m_VariableModel->deleteVariable(variable);
101 101 }
102 102
103 103 void VariableController::deleteVariables(
104 104 const QVector<std::shared_ptr<Variable> > &variables) noexcept
105 105 {
106 106 for (auto variable : qAsConst(variables)) {
107 107 deleteVariable(variable);
108 108 }
109 109 }
110 110
111 111 void VariableController::abortProgress(std::shared_ptr<Variable> variable)
112 112 {
113 113 }
114 114
115 115 void VariableController::createVariable(const QString &name, const QVariantHash &metadata,
116 116 std::shared_ptr<IDataProvider> provider) noexcept
117 117 {
118 118
119 119 if (!impl->m_TimeController) {
120 120 qCCritical(LOG_VariableController())
121 121 << tr("Impossible to create variable: The time controller is null");
122 122 return;
123 123 }
124 124
125 125 auto dateTime = impl->m_TimeController->dateTime();
126 126
127 127 if (auto newVariable = impl->m_VariableModel->createVariable(name, dateTime, metadata)) {
128 128 auto identifier = QUuid::createUuid();
129 129
130 130 // store the provider
131 131 impl->m_VariableToProviderMap[newVariable] = provider;
132 132 impl->m_VariableToIdentifierMap[newVariable] = identifier;
133 133
134 134 auto addDateTimeAcquired = [ this, varW = std::weak_ptr<Variable>{newVariable} ](
135 135 QUuid identifier, auto dataSeriesAcquired, auto dateTimeToPutInCache)
136 136 {
137 137 if (auto variable = varW.lock()) {
138 138 auto varIdentifier = impl->m_VariableToIdentifierMap.at(variable);
139 139 if (varIdentifier == identifier) {
140 140 impl->m_VariableCacheController->addDateTime(variable, dateTimeToPutInCache);
141 141 variable->setDataSeries(dataSeriesAcquired);
142 142 }
143 143 }
144 144 };
145 145
146 146 connect(provider.get(), &IDataProvider::dataProvided, addDateTimeAcquired);
147 147 this->onRequestDataLoading(newVariable, dateTime);
148 148 }
149 149 }
150 150
151 151 void VariableController::onDateTimeOnSelection(const SqpDateTime &dateTime)
152 152 {
153 153 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
154 154 << QThread::currentThread()->objectName();
155 155 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
156 156
157 157 for (const auto &selectedRow : qAsConst(selectedRows)) {
158 158 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
159 159 selectedVariable->setDateTime(dateTime);
160 160 this->onRequestDataLoading(selectedVariable, dateTime);
161 161 }
162 162 }
163 163 }
164 164
165 165 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
166 166 {
167 167 auto findReply = [identifier](const auto &entry) { return identifier == entry.second; };
168 168
169 169 auto end = impl->m_VariableToIdentifierMap.cend();
170 170 auto it = std::find_if(impl->m_VariableToIdentifierMap.cbegin(), end, findReply);
171 171 if (it != end) {
172 172 impl->m_VariableModel->setDataProgress(it->first, progress);
173 173 }
174 174 }
175 175
176 176 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
177 177 {
178 178 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAbortProgressRequested"
179 179 << QThread::currentThread()->objectName();
180 180
181 auto it = impl->m_VariableToIdentifier.find(variable);
182 if (it != impl->m_VariableToIdentifier.cend()) {
181 auto it = impl->m_VariableToIdentifierMap.find(variable);
182 if (it != impl->m_VariableToIdentifierMap.cend()) {
183 183 impl->m_VariableToProviderMap.at(variable)->requestDataAborting(it->second);
184 184 }
185 185 else {
186 186 qCWarning(LOG_VariableController())
187 187 << tr("Aborting progression of inexistant variable detected !!!")
188 188 << QThread::currentThread()->objectName();
189 189 }
190 190 }
191 191
192 192
193 193 void VariableController::onRequestDataLoading(std::shared_ptr<Variable> variable,
194 194 const SqpDateTime &dateTime)
195 195 {
196 196 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
197 197 << QThread::currentThread()->objectName();
198 198 // we want to load data of the variable for the dateTime.
199 199 // First we check if the cache contains some of them.
200 200 // For the other, we ask the provider to give them.
201 201 if (variable) {
202 202
203 203 auto dateTimeListNotInCache
204 204 = impl->m_VariableCacheController->provideNotInCacheDateTimeList(variable, dateTime);
205 205
206 206 if (!dateTimeListNotInCache.empty()) {
207 207 // Ask the provider for each data on the dateTimeListNotInCache
208 208 auto identifier = impl->m_VariableToIdentifierMap.at(variable);
209 209 impl->m_VariableToProviderMap.at(variable)->requestDataLoading(
210 210 identifier,
211 211 DataProviderParameters{std::move(dateTimeListNotInCache), variable->metadata()});
212 212 }
213 213 else {
214 214 emit variable->updated();
215 215 }
216 216 }
217 217 else {
218 218 qCCritical(LOG_VariableController()) << tr("Impossible to load data of a variable null");
219 219 }
220 220 }
221 221
222 222
223 223 void VariableController::initialize()
224 224 {
225 225 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
226 226 impl->m_WorkingMutex.lock();
227 227 qCDebug(LOG_VariableController()) << tr("VariableController init END");
228 228 }
229 229
230 230 void VariableController::finalize()
231 231 {
232 232 impl->m_WorkingMutex.unlock();
233 233 }
234 234
235 235 void VariableController::waitForFinish()
236 236 {
237 237 QMutexLocker locker{&impl->m_WorkingMutex};
238 238 }
General Comments 0
You need to be logged in to leave comments. Login now