##// END OF EJS Templates
Implementation of varRequestId aborting to permit to cancel a request...
perrinel -
r826:7fcfa38ae909
parent child
Show More
@@ -1,416 +1,415
1 1 #include "Variable/VariableAcquisitionWorker.h"
2 2
3 3 #include "Variable/Variable.h"
4 4
5 5 #include <Data/AcquisitionRequest.h>
6 6 #include <Data/SqpRange.h>
7 7
8 8 #include <unordered_map>
9 9 #include <utility>
10 10
11 11 #include <QMutex>
12 12 #include <QReadWriteLock>
13 13 #include <QThread>
14 14
15 15 #include <cmath>
16 16
17 17 Q_LOGGING_CATEGORY(LOG_VariableAcquisitionWorker, "VariableAcquisitionWorker")
18 18
19 19 struct VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate {
20 20
21 21 explicit VariableAcquisitionWorkerPrivate(VariableAcquisitionWorker *parent)
22 22 : m_Lock{QReadWriteLock::Recursive}, q{parent}
23 23 {
24 24 }
25 25
26 26 void lockRead() { m_Lock.lockForRead(); }
27 27 void lockWrite() { m_Lock.lockForWrite(); }
28 28 void unlock() { m_Lock.unlock(); }
29 29
30 30 void removeVariableRequest(QUuid vIdentifier);
31 31
32 32 /// Remove the current request and execute the next one if exist
33 33 void updateToNextRequest(QUuid vIdentifier);
34 34
35 35 /// Remove and/or abort all AcqRequest in link with varRequestId
36 36 void cancelVarRequest(QUuid varRequestId);
37 37 void removeAcqRequest(QUuid acqRequestId);
38 38
39 39 QMutex m_WorkingMutex;
40 40 QReadWriteLock m_Lock;
41 41
42 42 std::map<QUuid, QVector<AcquisitionDataPacket> > m_AcqIdentifierToAcqDataPacketVectorMap;
43 43 std::map<QUuid, AcquisitionRequest> m_AcqIdentifierToAcqRequestMap;
44 44 std::map<QUuid, std::pair<QUuid, QUuid> > m_VIdentifierToCurrrentAcqIdNextIdPairMap;
45 45 VariableAcquisitionWorker *q;
46 46 };
47 47
48 48
49 49 VariableAcquisitionWorker::VariableAcquisitionWorker(QObject *parent)
50 50 : QObject{parent}, impl{spimpl::make_unique_impl<VariableAcquisitionWorkerPrivate>(this)}
51 51 {
52 52 }
53 53
54 54 VariableAcquisitionWorker::~VariableAcquisitionWorker()
55 55 {
56 56 qCInfo(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker destruction")
57 57 << QThread::currentThread();
58 58 this->waitForFinish();
59 59 }
60 60
61 61
62 62 QUuid VariableAcquisitionWorker::pushVariableRequest(QUuid varRequestId, QUuid vIdentifier,
63 63 SqpRange rangeRequested,
64 64 SqpRange cacheRangeRequested,
65 65 DataProviderParameters parameters,
66 66 std::shared_ptr<IDataProvider> provider)
67 67 {
68 68 qCDebug(LOG_VariableAcquisitionWorker())
69 69 << tr("TORM VariableAcquisitionWorker::pushVariableRequest ") << cacheRangeRequested;
70 70 auto varRequestIdCanceled = QUuid();
71 71
72 72 // Request creation
73 73 auto acqRequest = AcquisitionRequest{};
74 74 qCDebug(LOG_VariableAcquisitionWorker()) << tr("PushVariableRequest ") << vIdentifier
75 75 << varRequestId;
76 76 acqRequest.m_VarRequestId = varRequestId;
77 77 acqRequest.m_vIdentifier = vIdentifier;
78 78 acqRequest.m_DataProviderParameters = parameters;
79 79 acqRequest.m_RangeRequested = rangeRequested;
80 80 acqRequest.m_CacheRangeRequested = cacheRangeRequested;
81 81 acqRequest.m_Size = parameters.m_Times.size();
82 82 acqRequest.m_Provider = provider;
83 83
84 84
85 85 // Register request
86 86 impl->lockWrite();
87 87 impl->m_AcqIdentifierToAcqRequestMap.insert(
88 88 std::make_pair(acqRequest.m_AcqIdentifier, acqRequest));
89 89
90 90 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
91 91 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
92 92 // A current request already exists, we can replace the next one
93 93 auto oldAcqId = it->second.second;
94 94 auto acqIdentifierToAcqRequestMapIt = impl->m_AcqIdentifierToAcqRequestMap.find(oldAcqId);
95 95 if (acqIdentifierToAcqRequestMapIt != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
96 96 auto oldAcqRequest = acqIdentifierToAcqRequestMapIt->second;
97 97 varRequestIdCanceled = oldAcqRequest.m_VarRequestId;
98 98 }
99 99
100 100 it->second.second = acqRequest.m_AcqIdentifier;
101 101 impl->unlock();
102 102
103 103 // remove old acqIdentifier from the worker
104 104 impl->cancelVarRequest(varRequestIdCanceled);
105 // impl->m_AcqIdentifierToAcqRequestMap.erase(oldAcqId);
106 105 }
107 106 else {
108 107 // First request for the variable, it must be stored and executed
109 108 impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.insert(
110 109 std::make_pair(vIdentifier, std::make_pair(acqRequest.m_AcqIdentifier, QUuid())));
111 110 impl->unlock();
112 111
113 112 QMetaObject::invokeMethod(this, "onExecuteRequest", Qt::QueuedConnection,
114 113 Q_ARG(QUuid, acqRequest.m_AcqIdentifier));
115 114 }
116 115
117 116 return varRequestIdCanceled;
118 117 }
119 118
120 119 void VariableAcquisitionWorker::abortProgressRequested(QUuid vIdentifier)
121 120 {
122 121 impl->lockRead();
123 122
124 123 auto it = impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
125 124 if (it != impl->m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
126 125 auto currentAcqId = it->second.first;
127 126
128 127 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(currentAcqId);
129 128 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
130 129 auto request = it->second;
131 130 impl->unlock();
132 131
133 132 // Remove the current request from the worker
134 133 impl->updateToNextRequest(vIdentifier);
135 134
136 135 // notify the request aborting to the provider
137 136 request.m_Provider->requestDataAborting(currentAcqId);
138 137 }
139 138 else {
140 139 impl->unlock();
141 140 qCWarning(LOG_VariableAcquisitionWorker())
142 141 << tr("Impossible to abort an unknown acquisition request") << currentAcqId;
143 142 }
144 143 }
145 144 else {
146 145 impl->unlock();
147 146 }
148 147 }
149 148
150 149 void VariableAcquisitionWorker::onVariableRetrieveDataInProgress(QUuid acqIdentifier,
151 150 double progress)
152 151 {
153 152 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableRetrieveDataInProgress ")
154 153 << acqIdentifier << progress;
155 154 impl->lockRead();
156 155 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
157 156 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
158 157 auto currentPartSize = (aIdToARit->second.m_Size != 0) ? 100 / aIdToARit->second.m_Size : 0;
159 158
160 159 auto currentPartProgress
161 160 = std::isnan(progress) ? 0.0 : (progress * currentPartSize) / 100.0;
162 161 auto currentAlreadyProgress = aIdToARit->second.m_Progression * currentPartSize;
163 162
164 163 auto finalProgression = currentAlreadyProgress + currentPartProgress;
165 164 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, finalProgression);
166 165 qCDebug(LOG_VariableAcquisitionWorker())
167 166 << tr("TORM: onVariableRetrieveDataInProgress ")
168 167 << QThread::currentThread()->objectName() << aIdToARit->second.m_vIdentifier
169 168 << currentPartSize << currentAlreadyProgress << currentPartProgress << finalProgression;
170 169 if (finalProgression == 100.0) {
171 170 emit variableRequestInProgress(aIdToARit->second.m_vIdentifier, 0.0);
172 171 }
173 172 }
174 173 impl->unlock();
175 174 }
176 175
177 176 void VariableAcquisitionWorker::onVariableAcquisitionFailed(QUuid acqIdentifier)
178 177 {
179 178 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
180 179 << QThread::currentThread();
181 180 impl->lockRead();
182 181 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
183 182 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
184 183 auto request = it->second;
185 184 impl->unlock();
186 185 qCInfo(LOG_VariableAcquisitionWorker()) << tr("onVariableAcquisitionFailed")
187 186 << acqIdentifier << request.m_vIdentifier
188 187 << QThread::currentThread();
189 188 emit variableCanceledRequested(request.m_vIdentifier);
190 189 }
191 190 else {
192 191 impl->unlock();
193 192 // TODO log no acqIdentifier recognized
194 193 }
195 194 }
196 195
197 196 void VariableAcquisitionWorker::onVariableDataAcquired(QUuid acqIdentifier,
198 197 std::shared_ptr<IDataSeries> dataSeries,
199 198 SqpRange dataRangeAcquired)
200 199 {
201 200 qCDebug(LOG_VariableAcquisitionWorker()) << tr("TORM: onVariableDataAcquired on range ")
202 201 << acqIdentifier << dataRangeAcquired;
203 202 impl->lockWrite();
204 203 auto aIdToARit = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
205 204 if (aIdToARit != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
206 205 // Store the result
207 206 auto dataPacket = AcquisitionDataPacket{};
208 207 dataPacket.m_Range = dataRangeAcquired;
209 208 dataPacket.m_DateSeries = dataSeries;
210 209
211 210 auto aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
212 211 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
213 212 // A current request result already exists, we can update it
214 213 aIdToADPVit->second.push_back(dataPacket);
215 214 }
216 215 else {
217 216 // First request result for the variable, it must be stored
218 217 impl->m_AcqIdentifierToAcqDataPacketVectorMap.insert(
219 218 std::make_pair(acqIdentifier, QVector<AcquisitionDataPacket>() << dataPacket));
220 219 }
221 220
222 221
223 222 // Decrement the counter of the request
224 223 auto &acqRequest = aIdToARit->second;
225 224 acqRequest.m_Progression = acqRequest.m_Progression + 1;
226 225
227 226 // if the counter is 0, we can return data then run the next request if it exists and
228 227 // removed the finished request
229 228 if (acqRequest.m_Size == acqRequest.m_Progression) {
230 229 auto varId = acqRequest.m_vIdentifier;
231 230 auto rangeRequested = acqRequest.m_RangeRequested;
232 231 auto cacheRangeRequested = acqRequest.m_CacheRangeRequested;
233 232 // Return the data
234 233 aIdToADPVit = impl->m_AcqIdentifierToAcqDataPacketVectorMap.find(acqIdentifier);
235 234 if (aIdToADPVit != impl->m_AcqIdentifierToAcqDataPacketVectorMap.cend()) {
236 235 emit dataProvided(varId, rangeRequested, cacheRangeRequested, aIdToADPVit->second);
237 236 }
238 237 impl->unlock();
239 238
240 239 // Update to the next request
241 240 impl->updateToNextRequest(acqRequest.m_vIdentifier);
242 241 }
243 242 else {
244 243 impl->unlock();
245 244 }
246 245 }
247 246 else {
248 247 impl->unlock();
249 248 qCWarning(LOG_VariableAcquisitionWorker())
250 249 << tr("Impossible to retrieve AcquisitionRequest for the incoming data.");
251 250 }
252 251 }
253 252
254 253 void VariableAcquisitionWorker::onExecuteRequest(QUuid acqIdentifier)
255 254 {
256 255 qCDebug(LOG_VariableAcquisitionWorker()) << tr("onExecuteRequest") << QThread::currentThread();
257 256 impl->lockRead();
258 257 auto it = impl->m_AcqIdentifierToAcqRequestMap.find(acqIdentifier);
259 258 if (it != impl->m_AcqIdentifierToAcqRequestMap.cend()) {
260 259 auto request = it->second;
261 260 impl->unlock();
262 261 emit variableRequestInProgress(request.m_vIdentifier, 0.1);
263 262 request.m_Provider->requestDataLoading(acqIdentifier, request.m_DataProviderParameters);
264 263 }
265 264 else {
266 265 impl->unlock();
267 266 // TODO log no acqIdentifier recognized
268 267 }
269 268 }
270 269
271 270 void VariableAcquisitionWorker::initialize()
272 271 {
273 272 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init")
274 273 << QThread::currentThread();
275 274 impl->m_WorkingMutex.lock();
276 275 qCDebug(LOG_VariableAcquisitionWorker()) << tr("VariableAcquisitionWorker init END");
277 276 }
278 277
279 278 void VariableAcquisitionWorker::finalize()
280 279 {
281 280 impl->m_WorkingMutex.unlock();
282 281 }
283 282
284 283 void VariableAcquisitionWorker::waitForFinish()
285 284 {
286 285 QMutexLocker locker{&impl->m_WorkingMutex};
287 286 }
288 287
289 288 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeVariableRequest(
290 289 QUuid vIdentifier)
291 290 {
292 291 lockWrite();
293 292 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
294 293
295 294 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
296 295 // A current request already exists, we can replace the next one
297 296
298 297 m_AcqIdentifierToAcqRequestMap.erase(it->second.first);
299 298 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.first);
300 299
301 300 m_AcqIdentifierToAcqRequestMap.erase(it->second.second);
302 301 m_AcqIdentifierToAcqDataPacketVectorMap.erase(it->second.second);
303 302 }
304 303 m_VIdentifierToCurrrentAcqIdNextIdPairMap.erase(vIdentifier);
305 304 unlock();
306 305 }
307 306
308 307 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::updateToNextRequest(
309 308 QUuid vIdentifier)
310 309 {
311 310 lockRead();
312 311 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
313 312 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
314 313 if (it->second.second.isNull()) {
315 314 unlock();
316 315 // There is no next request, we can remove the variable request
317 316 removeVariableRequest(vIdentifier);
318 317 }
319 318 else {
320 319 auto acqIdentifierToRemove = it->second.first;
321 320 // Move the next request to the current request
322 321 auto nextRequestId = it->second.second;
323 322 it->second.first = nextRequestId;
324 323 it->second.second = QUuid();
325 324 unlock();
326 325 // Remove AcquisitionRequest and results;
327 326 lockWrite();
328 327 m_AcqIdentifierToAcqRequestMap.erase(acqIdentifierToRemove);
329 328 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqIdentifierToRemove);
330 329 unlock();
331 330 // Execute the current request
332 331 QMetaObject::invokeMethod(q, "onExecuteRequest", Qt::QueuedConnection,
333 332 Q_ARG(QUuid, nextRequestId));
334 333 }
335 334 }
336 335 else {
337 336 unlock();
338 337 qCCritical(LOG_VariableAcquisitionWorker())
339 338 << tr("Impossible to execute the acquisition on an unfound variable ");
340 339 }
341 340 }
342 341
343 342 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::cancelVarRequest(
344 343 QUuid varRequestId)
345 344 {
346 345 qCDebug(LOG_VariableAcquisitionWorker())
347 346 << "VariableAcquisitionWorkerPrivate::cancelVarRequest 0";
348 347 lockRead();
349 348 // get all AcqIdentifier in link with varRequestId
350 349 QVector<QUuid> acqIdsToRm;
351 350 auto cend = m_AcqIdentifierToAcqRequestMap.cend();
352 351 for (auto it = m_AcqIdentifierToAcqRequestMap.cbegin(); it != cend; ++it) {
353 352 if (it->second.m_VarRequestId == varRequestId) {
354 353 acqIdsToRm << it->first;
355 354 }
356 355 }
357 356 unlock();
358 357 // run aborting or removing of acqIdsToRm
359 358
360 359 for (auto acqId : acqIdsToRm) {
361 360 removeAcqRequest(acqId);
362 361 }
363 362 qCDebug(LOG_VariableAcquisitionWorker())
364 363 << "VariableAcquisitionWorkerPrivate::cancelVarRequest end";
365 364 }
366 365
367 366 void VariableAcquisitionWorker::VariableAcquisitionWorkerPrivate::removeAcqRequest(
368 367 QUuid acqRequestId)
369 368 {
370 369 qCDebug(LOG_VariableAcquisitionWorker())
371 370 << "VariableAcquisitionWorkerPrivate::removeAcqRequest";
372 371 QUuid vIdentifier;
373 372 std::shared_ptr<IDataProvider> provider;
374 373 lockRead();
375 374 auto acqIt = m_AcqIdentifierToAcqRequestMap.find(acqRequestId);
376 375 if (acqIt != m_AcqIdentifierToAcqRequestMap.cend()) {
377 376 vIdentifier = acqIt->second.m_vIdentifier;
378 377 provider = acqIt->second.m_Provider;
379 378
380 379 auto it = m_VIdentifierToCurrrentAcqIdNextIdPairMap.find(vIdentifier);
381 380 if (it != m_VIdentifierToCurrrentAcqIdNextIdPairMap.cend()) {
382 381 if (it->second.first == acqRequestId) {
383 382 // acqRequest is currently running -> let's aborting it
384 383 unlock();
385 384
386 385 // Remove the current request from the worker
387 386 updateToNextRequest(vIdentifier);
388 387
389 388 // notify the request aborting to the provider
390 389 provider->requestDataAborting(acqRequestId);
391 390 }
392 391 else if (it->second.second == acqRequestId) {
393 392 it->second.second = QUuid();
394 393 unlock();
395 394 }
396 395 else {
397 396 unlock();
398 397 }
399 398 }
400 399 else {
401 400 unlock();
402 401 }
403 402 }
404 403 else {
405 404 unlock();
406 405 }
407 406
408 407 lockWrite();
409 408
410 409 m_AcqIdentifierToAcqDataPacketVectorMap.erase(acqRequestId);
411 410 m_AcqIdentifierToAcqRequestMap.erase(acqRequestId);
412 411
413 412 unlock();
414 413 qCDebug(LOG_VariableAcquisitionWorker())
415 414 << "VariableAcquisitionWorkerPrivate::removeAcqRequest END";
416 415 }
@@ -1,889 +1,956
1 1 #include <Variable/Variable.h>
2 2 #include <Variable/VariableAcquisitionWorker.h>
3 3 #include <Variable/VariableCacheStrategy.h>
4 4 #include <Variable/VariableCacheStrategyFactory.h>
5 5 #include <Variable/VariableController.h>
6 6 #include <Variable/VariableModel.h>
7 7 #include <Variable/VariableSynchronizationGroup.h>
8 8
9 9 #include <Data/DataProviderParameters.h>
10 10 #include <Data/IDataProvider.h>
11 11 #include <Data/IDataSeries.h>
12 12 #include <Data/VariableRequest.h>
13 13 #include <Time/TimeController.h>
14 14
15 15 #include <QMutex>
16 16 #include <QThread>
17 17 #include <QUuid>
18 18 #include <QtCore/QItemSelectionModel>
19 19
20 20 #include <deque>
21 21 #include <set>
22 22 #include <unordered_map>
23 23
24 24 Q_LOGGING_CATEGORY(LOG_VariableController, "VariableController")
25 25
26 26 namespace {
27 27
28 28 SqpRange computeSynchroRangeRequested(const SqpRange &varRange, const SqpRange &graphRange,
29 29 const SqpRange &oldGraphRange)
30 30 {
31 31 auto zoomType = VariableController::getZoomType(graphRange, oldGraphRange);
32 32
33 33 auto varRangeRequested = varRange;
34 34 switch (zoomType) {
35 35 case AcquisitionZoomType::ZoomIn: {
36 36 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
37 37 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
38 38 varRangeRequested.m_TStart += deltaLeft;
39 39 varRangeRequested.m_TEnd -= deltaRight;
40 40 break;
41 41 }
42 42
43 43 case AcquisitionZoomType::ZoomOut: {
44 44 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
45 45 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
46 46 varRangeRequested.m_TStart -= deltaLeft;
47 47 varRangeRequested.m_TEnd += deltaRight;
48 48 break;
49 49 }
50 50 case AcquisitionZoomType::PanRight: {
51 51 auto deltaLeft = graphRange.m_TStart - oldGraphRange.m_TStart;
52 52 auto deltaRight = graphRange.m_TEnd - oldGraphRange.m_TEnd;
53 53 varRangeRequested.m_TStart += deltaLeft;
54 54 varRangeRequested.m_TEnd += deltaRight;
55 55 break;
56 56 }
57 57 case AcquisitionZoomType::PanLeft: {
58 58 auto deltaLeft = oldGraphRange.m_TStart - graphRange.m_TStart;
59 59 auto deltaRight = oldGraphRange.m_TEnd - graphRange.m_TEnd;
60 60 varRangeRequested.m_TStart -= deltaLeft;
61 61 varRangeRequested.m_TEnd -= deltaRight;
62 62 break;
63 63 }
64 64 case AcquisitionZoomType::Unknown: {
65 65 qCCritical(LOG_VariableController())
66 66 << VariableController::tr("Impossible to synchronize: zoom type unknown");
67 67 break;
68 68 }
69 69 default:
70 70 qCCritical(LOG_VariableController()) << VariableController::tr(
71 71 "Impossible to synchronize: zoom type not take into account");
72 72 // No action
73 73 break;
74 74 }
75 75
76 76 return varRangeRequested;
77 77 }
78 78 }
79 79
80 80 struct VariableController::VariableControllerPrivate {
81 81 explicit VariableControllerPrivate(VariableController *parent)
82 82 : m_WorkingMutex{},
83 83 m_VariableModel{new VariableModel{parent}},
84 84 m_VariableSelectionModel{new QItemSelectionModel{m_VariableModel, parent}},
85 85 // m_VariableCacheStrategy{std::make_unique<VariableCacheStrategy>()},
86 86 m_VariableCacheStrategy{VariableCacheStrategyFactory::createCacheStrategy(
87 87 CacheStrategy::SingleThreshold)},
88 88 m_VariableAcquisitionWorker{std::make_unique<VariableAcquisitionWorker>()},
89 89 q{parent}
90 90 {
91 91
92 92 m_VariableAcquisitionWorker->moveToThread(&m_VariableAcquisitionWorkerThread);
93 93 m_VariableAcquisitionWorkerThread.setObjectName("VariableAcquisitionWorkerThread");
94 94 }
95 95
96 96
97 97 virtual ~VariableControllerPrivate()
98 98 {
99 99 qCDebug(LOG_VariableController()) << tr("VariableControllerPrivate destruction");
100 100 m_VariableAcquisitionWorkerThread.quit();
101 101 m_VariableAcquisitionWorkerThread.wait();
102 102 }
103 103
104 104
105 105 void processRequest(std::shared_ptr<Variable> var, const SqpRange &rangeRequested,
106 106 QUuid varRequestId);
107 107
108 108 std::shared_ptr<Variable> findVariable(QUuid vIdentifier);
109 109 std::shared_ptr<IDataSeries>
110 110 retrieveDataSeries(const QVector<AcquisitionDataPacket> acqDataPacketVector);
111 111
112 112 void registerProvider(std::shared_ptr<IDataProvider> provider);
113 113
114 114 void storeVariableRequest(QUuid varId, QUuid varRequestId, const VariableRequest &varRequest);
115 115 QUuid acceptVariableRequest(QUuid varId, std::shared_ptr<IDataSeries> dataSeries);
116 116 void updateVariableRequest(QUuid varRequestId);
117 117 void cancelVariableRequest(QUuid varRequestId);
118
118 void abortVariableRequest(QUuid varRequestId);
119 119 SqpRange getLastRequestedRange(QUuid varId);
120 120
121 121 QMutex m_WorkingMutex;
122 122 /// Variable model. The VariableController has the ownership
123 123 VariableModel *m_VariableModel;
124 124 QItemSelectionModel *m_VariableSelectionModel;
125 125
126 126
127 127 TimeController *m_TimeController{nullptr};
128 128 std::unique_ptr<VariableCacheStrategy> m_VariableCacheStrategy;
129 129 std::unique_ptr<VariableAcquisitionWorker> m_VariableAcquisitionWorker;
130 130 QThread m_VariableAcquisitionWorkerThread;
131 131
132 132 std::unordered_map<std::shared_ptr<Variable>, std::shared_ptr<IDataProvider> >
133 133 m_VariableToProviderMap;
134 134 std::unordered_map<std::shared_ptr<Variable>, QUuid> m_VariableToIdentifierMap;
135 135 std::map<QUuid, std::shared_ptr<VariableSynchronizationGroup> >
136 136 m_GroupIdToVariableSynchronizationGroupMap;
137 137 std::map<QUuid, QUuid> m_VariableIdGroupIdMap;
138 138 std::set<std::shared_ptr<IDataProvider> > m_ProviderSet;
139 139
140 140 std::map<QUuid, std::map<QUuid, VariableRequest> > m_VarRequestIdToVarIdVarRequestMap;
141 141
142 142 std::map<QUuid, std::deque<QUuid> > m_VarIdToVarRequestIdQueueMap;
143 143
144 144
145 145 VariableController *q;
146 146 };
147 147
148 148
149 149 VariableController::VariableController(QObject *parent)
150 150 : QObject{parent}, impl{spimpl::make_unique_impl<VariableControllerPrivate>(this)}
151 151 {
152 152 qCDebug(LOG_VariableController()) << tr("VariableController construction")
153 153 << QThread::currentThread();
154 154
155 155 connect(impl->m_VariableModel, &VariableModel::abortProgessRequested, this,
156 156 &VariableController::onAbortProgressRequested);
157 157
158 158 connect(impl->m_VariableAcquisitionWorker.get(),
159 159 &VariableAcquisitionWorker::variableCanceledRequested, this,
160 160 &VariableController::onAbortAcquisitionRequested);
161 161
162 162 connect(impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::dataProvided, this,
163 163 &VariableController::onDataProvided);
164 164 connect(impl->m_VariableAcquisitionWorker.get(),
165 165 &VariableAcquisitionWorker::variableRequestInProgress, this,
166 166 &VariableController::onVariableRetrieveDataInProgress);
167 167
168 168
169 169 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::started,
170 170 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::initialize);
171 171 connect(&impl->m_VariableAcquisitionWorkerThread, &QThread::finished,
172 172 impl->m_VariableAcquisitionWorker.get(), &VariableAcquisitionWorker::finalize);
173 173
174 174
175 175 impl->m_VariableAcquisitionWorkerThread.start();
176 176 }
177 177
178 178 VariableController::~VariableController()
179 179 {
180 180 qCDebug(LOG_VariableController()) << tr("VariableController destruction")
181 181 << QThread::currentThread();
182 182 this->waitForFinish();
183 183 }
184 184
185 185 VariableModel *VariableController::variableModel() noexcept
186 186 {
187 187 return impl->m_VariableModel;
188 188 }
189 189
190 190 QItemSelectionModel *VariableController::variableSelectionModel() noexcept
191 191 {
192 192 return impl->m_VariableSelectionModel;
193 193 }
194 194
195 195 void VariableController::setTimeController(TimeController *timeController) noexcept
196 196 {
197 197 impl->m_TimeController = timeController;
198 198 }
199 199
200 200 std::shared_ptr<Variable>
201 201 VariableController::cloneVariable(std::shared_ptr<Variable> variable) noexcept
202 202 {
203 203 if (impl->m_VariableModel->containsVariable(variable)) {
204 204 // Clones variable
205 205 auto duplicate = variable->clone();
206 206
207 207 // Adds clone to model
208 208 impl->m_VariableModel->addVariable(duplicate);
209 209
210 210 // Generates clone identifier
211 211 impl->m_VariableToIdentifierMap[duplicate] = QUuid::createUuid();
212 212
213 213 // Registers provider
214 214 auto variableProvider = impl->m_VariableToProviderMap.at(variable);
215 215 auto duplicateProvider = variableProvider != nullptr ? variableProvider->clone() : nullptr;
216 216
217 217 impl->m_VariableToProviderMap[duplicate] = duplicateProvider;
218 218 if (duplicateProvider) {
219 219 impl->registerProvider(duplicateProvider);
220 220 }
221 221
222 222 return duplicate;
223 223 }
224 224 else {
225 225 qCCritical(LOG_VariableController())
226 226 << tr("Can't create duplicate of variable %1: variable not registered in the model")
227 227 .arg(variable->name());
228 228 return nullptr;
229 229 }
230 230 }
231 231
232 232 void VariableController::deleteVariable(std::shared_ptr<Variable> variable) noexcept
233 233 {
234 234 if (!variable) {
235 235 qCCritical(LOG_VariableController()) << "Can't delete variable: variable is null";
236 236 return;
237 237 }
238 238
239 239 // Spreads in SciQlop that the variable will be deleted, so that potential receivers can
240 240 // make some treatments before the deletion
241 241 emit variableAboutToBeDeleted(variable);
242 242
243 243 // Deletes identifier
244 244 impl->m_VariableToIdentifierMap.erase(variable);
245 245
246 246 // Deletes provider
247 247 auto nbProvidersDeleted = impl->m_VariableToProviderMap.erase(variable);
248 248 qCDebug(LOG_VariableController())
249 249 << tr("Number of providers deleted for variable %1: %2")
250 250 .arg(variable->name(), QString::number(nbProvidersDeleted));
251 251
252 252
253 253 // Deletes from model
254 254 impl->m_VariableModel->deleteVariable(variable);
255 255 }
256 256
257 257 void VariableController::deleteVariables(
258 258 const QVector<std::shared_ptr<Variable> > &variables) noexcept
259 259 {
260 260 for (auto variable : qAsConst(variables)) {
261 261 deleteVariable(variable);
262 262 }
263 263 }
264 264
265 265 std::shared_ptr<Variable>
266 266 VariableController::createVariable(const QString &name, const QVariantHash &metadata,
267 267 std::shared_ptr<IDataProvider> provider) noexcept
268 268 {
269 269 if (!impl->m_TimeController) {
270 270 qCCritical(LOG_VariableController())
271 271 << tr("Impossible to create variable: The time controller is null");
272 272 return nullptr;
273 273 }
274 274
275 275 auto range = impl->m_TimeController->dateTime();
276 276
277 277 if (auto newVariable = impl->m_VariableModel->createVariable(name, metadata)) {
278 278 auto identifier = QUuid::createUuid();
279 279
280 280 // store the provider
281 281 impl->registerProvider(provider);
282 282
283 283 // Associate the provider
284 284 impl->m_VariableToProviderMap[newVariable] = provider;
285 285 qCInfo(LOG_VariableController()) << "createVariable: " << identifier;
286 286 impl->m_VariableToIdentifierMap[newVariable] = identifier;
287 287
288 288
289 289 auto varRequestId = QUuid::createUuid();
290 290 impl->processRequest(newVariable, range, varRequestId);
291 291 impl->updateVariableRequest(varRequestId);
292 292
293 293 return newVariable;
294 294 }
295 295 }
296 296
297 297 void VariableController::onDateTimeOnSelection(const SqpRange &dateTime)
298 298 {
299 299 // NOTE: Even if acquisition request is aborting, the graphe range will be changed
300 300 qCDebug(LOG_VariableController()) << "VariableController::onDateTimeOnSelection"
301 301 << QThread::currentThread()->objectName();
302 302 auto selectedRows = impl->m_VariableSelectionModel->selectedRows();
303 303 auto variables = QVector<std::shared_ptr<Variable> >{};
304 304
305 305 for (const auto &selectedRow : qAsConst(selectedRows)) {
306 306 if (auto selectedVariable = impl->m_VariableModel->variable(selectedRow.row())) {
307 307 variables << selectedVariable;
308 308
309 309 // notify that rescale operation has to be done
310 310 emit rangeChanged(selectedVariable, dateTime);
311 311 }
312 312 }
313 313
314 314 if (!variables.isEmpty()) {
315 315 this->onRequestDataLoading(variables, dateTime, true);
316 316 }
317 317 }
318 318
319 319 void VariableController::onDataProvided(QUuid vIdentifier, const SqpRange &rangeRequested,
320 320 const SqpRange &cacheRangeRequested,
321 321 QVector<AcquisitionDataPacket> dataAcquired)
322 322 {
323 323 auto retrievedDataSeries = impl->retrieveDataSeries(dataAcquired);
324 324 auto varRequestId = impl->acceptVariableRequest(vIdentifier, retrievedDataSeries);
325 325 if (!varRequestId.isNull()) {
326 326 impl->updateVariableRequest(varRequestId);
327 327 }
328 328 }
329 329
330 330 void VariableController::onVariableRetrieveDataInProgress(QUuid identifier, double progress)
331 331 {
332 332 qCDebug(LOG_VariableController())
333 333 << "TORM: variableController::onVariableRetrieveDataInProgress"
334 334 << QThread::currentThread()->objectName() << progress;
335 335 if (auto var = impl->findVariable(identifier)) {
336 336 impl->m_VariableModel->setDataProgress(var, progress);
337 337 }
338 338 else {
339 339 qCCritical(LOG_VariableController())
340 340 << tr("Impossible to notify progression of a null variable");
341 341 }
342 342 }
343 343
344 344 void VariableController::onAbortProgressRequested(std::shared_ptr<Variable> variable)
345 345 {
346 346 auto it = impl->m_VariableToIdentifierMap.find(variable);
347 347 if (it != impl->m_VariableToIdentifierMap.cend()) {
348 348 impl->m_VariableAcquisitionWorker->abortProgressRequested(it->second);
349 349
350 350 QUuid varRequestId;
351 351 auto varIdToVarRequestIdQueueMapIt = impl->m_VarIdToVarRequestIdQueueMap.find(it->second);
352 352 if (varIdToVarRequestIdQueueMapIt != impl->m_VarIdToVarRequestIdQueueMap.cend()) {
353 353 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
354 354 varRequestId = varRequestIdQueue.front();
355 355 impl->cancelVariableRequest(varRequestId);
356 356
357 357 // Finish the progression for the request
358 358 impl->m_VariableModel->setDataProgress(variable, 0.0);
359 359 }
360 360 else {
361 361 qCWarning(LOG_VariableController())
362 362 << tr("Aborting progression of inexistant variable request detected !!!")
363 363 << QThread::currentThread()->objectName();
364 364 }
365 365 }
366 366 else {
367 367 qCWarning(LOG_VariableController())
368 368 << tr("Aborting progression of inexistant variable detected !!!")
369 369 << QThread::currentThread()->objectName();
370 370 }
371 371 }
372 372
373 373 void VariableController::onAbortAcquisitionRequested(QUuid vIdentifier)
374 374 {
375 375 qCDebug(LOG_VariableController()) << "TORM: variableController::onAbortAcquisitionRequested"
376 376 << QThread::currentThread()->objectName() << vIdentifier;
377 377
378 378 if (auto var = impl->findVariable(vIdentifier)) {
379 379 this->onAbortProgressRequested(var);
380 380 }
381 381 else {
382 382 qCCritical(LOG_VariableController())
383 383 << tr("Impossible to abort Acquisition Requestof a null variable");
384 384 }
385 385 }
386 386
387 387 void VariableController::onAddSynchronizationGroupId(QUuid synchronizationGroupId)
388 388 {
389 389 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronizationGroupId"
390 390 << QThread::currentThread()->objectName()
391 391 << synchronizationGroupId;
392 392 auto vSynchroGroup = std::make_shared<VariableSynchronizationGroup>();
393 393 impl->m_GroupIdToVariableSynchronizationGroupMap.insert(
394 394 std::make_pair(synchronizationGroupId, vSynchroGroup));
395 395 }
396 396
397 397 void VariableController::onRemoveSynchronizationGroupId(QUuid synchronizationGroupId)
398 398 {
399 399 impl->m_GroupIdToVariableSynchronizationGroupMap.erase(synchronizationGroupId);
400 400 }
401 401
402 402 void VariableController::onAddSynchronized(std::shared_ptr<Variable> variable,
403 403 QUuid synchronizationGroupId)
404 404
405 405 {
406 406 qCDebug(LOG_VariableController()) << "TORM: VariableController::onAddSynchronized"
407 407 << synchronizationGroupId;
408 408 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(variable);
409 409 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
410 410 auto groupIdToVSGIt
411 411 = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
412 412 if (groupIdToVSGIt != impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
413 413 impl->m_VariableIdGroupIdMap.insert(
414 414 std::make_pair(varToVarIdIt->second, synchronizationGroupId));
415 415 groupIdToVSGIt->second->addVariableId(varToVarIdIt->second);
416 416 }
417 417 else {
418 418 qCCritical(LOG_VariableController())
419 419 << tr("Impossible to synchronize a variable with an unknown sycnhronization group")
420 420 << variable->name();
421 421 }
422 422 }
423 423 else {
424 424 qCCritical(LOG_VariableController())
425 425 << tr("Impossible to synchronize a variable with no identifier") << variable->name();
426 426 }
427 427 }
428 428
429 429 void VariableController::desynchronize(std::shared_ptr<Variable> variable,
430 430 QUuid synchronizationGroupId)
431 431 {
432 432 // Gets variable id
433 433 auto variableIt = impl->m_VariableToIdentifierMap.find(variable);
434 434 if (variableIt == impl->m_VariableToIdentifierMap.cend()) {
435 435 qCCritical(LOG_VariableController())
436 436 << tr("Can't desynchronize variable %1: variable identifier not found")
437 437 .arg(variable->name());
438 438 return;
439 439 }
440 440
441 441 // Gets synchronization group
442 442 auto groupIt = impl->m_GroupIdToVariableSynchronizationGroupMap.find(synchronizationGroupId);
443 443 if (groupIt == impl->m_GroupIdToVariableSynchronizationGroupMap.cend()) {
444 444 qCCritical(LOG_VariableController())
445 445 << tr("Can't desynchronize variable %1: unknown synchronization group")
446 446 .arg(variable->name());
447 447 return;
448 448 }
449 449
450 450 auto variableId = variableIt->second;
451 451
452 452 // Removes variable from synchronization group
453 453 auto synchronizationGroup = groupIt->second;
454 454 synchronizationGroup->removeVariableId(variableId);
455 455
456 456 // Removes link between variable and synchronization group
457 457 impl->m_VariableIdGroupIdMap.erase(variableId);
458 458 }
459 459
460 460 void VariableController::onRequestDataLoading(QVector<std::shared_ptr<Variable> > variables,
461 461 const SqpRange &range, bool synchronise)
462 462 {
463 463 // NOTE: oldRange isn't really necessary since oldRange == variable->range().
464 464
465 465 // we want to load data of the variable for the dateTime.
466 466 // First we check if the cache contains some of them.
467 467 // For the other, we ask the provider to give them.
468 468
469 469 auto varRequestId = QUuid::createUuid();
470 470 qCDebug(LOG_VariableController()) << "VariableController::onRequestDataLoading"
471 471 << QThread::currentThread()->objectName() << varRequestId;
472 472
473 473 for (const auto &var : variables) {
474 474 qCDebug(LOG_VariableController()) << "processRequest for" << var->name() << varRequestId;
475 475 impl->processRequest(var, range, varRequestId);
476 476 }
477 477
478 478 if (synchronise) {
479 479 // Get the group ids
480 480 qCDebug(LOG_VariableController())
481 481 << "TORM VariableController::onRequestDataLoading for synchro var ENABLE";
482 482 auto groupIds = std::set<QUuid>{};
483 483 auto groupIdToOldRangeMap = std::map<QUuid, SqpRange>{};
484 484 for (const auto &var : variables) {
485 485 auto varToVarIdIt = impl->m_VariableToIdentifierMap.find(var);
486 486 if (varToVarIdIt != impl->m_VariableToIdentifierMap.cend()) {
487 487 auto vId = varToVarIdIt->second;
488 488 auto varIdToGroupIdIt = impl->m_VariableIdGroupIdMap.find(vId);
489 489 if (varIdToGroupIdIt != impl->m_VariableIdGroupIdMap.cend()) {
490 490 auto gId = varIdToGroupIdIt->second;
491 491 groupIdToOldRangeMap.insert(std::make_pair(gId, var->range()));
492 492 if (groupIds.find(gId) == groupIds.cend()) {
493 493 qCDebug(LOG_VariableController()) << "Synchro detect group " << gId;
494 494 groupIds.insert(gId);
495 495 }
496 496 }
497 497 }
498 498 }
499 499
500 500 // We assume here all group ids exist
501 501 for (const auto &gId : groupIds) {
502 502 auto vSynchronizationGroup = impl->m_GroupIdToVariableSynchronizationGroupMap.at(gId);
503 503 auto vSyncIds = vSynchronizationGroup->getIds();
504 504 qCDebug(LOG_VariableController()) << "Var in synchro group ";
505 505 for (auto vId : vSyncIds) {
506 506 auto var = impl->findVariable(vId);
507 507
508 508 // Don't process already processed var
509 509 if (!variables.contains(var)) {
510 510 if (var != nullptr) {
511 511 qCDebug(LOG_VariableController()) << "processRequest synchro for"
512 512 << var->name();
513 513 auto vSyncRangeRequested = computeSynchroRangeRequested(
514 514 var->range(), range, groupIdToOldRangeMap.at(gId));
515 515 qCDebug(LOG_VariableController()) << "synchro RR" << vSyncRangeRequested;
516 516 impl->processRequest(var, vSyncRangeRequested, varRequestId);
517 517 }
518 518 else {
519 519 qCCritical(LOG_VariableController())
520 520
521 521 << tr("Impossible to synchronize a null variable");
522 522 }
523 523 }
524 524 }
525 525 }
526 526 }
527 527
528 528 impl->updateVariableRequest(varRequestId);
529 529 }
530 530
531 531
532 532 void VariableController::initialize()
533 533 {
534 534 qCDebug(LOG_VariableController()) << tr("VariableController init") << QThread::currentThread();
535 535 impl->m_WorkingMutex.lock();
536 536 qCDebug(LOG_VariableController()) << tr("VariableController init END");
537 537 }
538 538
539 539 void VariableController::finalize()
540 540 {
541 541 impl->m_WorkingMutex.unlock();
542 542 }
543 543
544 544 void VariableController::waitForFinish()
545 545 {
546 546 QMutexLocker locker{&impl->m_WorkingMutex};
547 547 }
548 548
549 549 AcquisitionZoomType VariableController::getZoomType(const SqpRange &range, const SqpRange &oldRange)
550 550 {
551 551 // t1.m_TStart <= t2.m_TStart && t2.m_TEnd <= t1.m_TEnd
552 552 auto zoomType = AcquisitionZoomType::Unknown;
553 553 if (range.m_TStart <= oldRange.m_TStart && oldRange.m_TEnd <= range.m_TEnd) {
554 554 qCDebug(LOG_VariableController()) << "zoomtype: ZoomOut";
555 555 zoomType = AcquisitionZoomType::ZoomOut;
556 556 }
557 557 else if (range.m_TStart > oldRange.m_TStart && range.m_TEnd > oldRange.m_TEnd) {
558 558 qCDebug(LOG_VariableController()) << "zoomtype: PanRight";
559 559 zoomType = AcquisitionZoomType::PanRight;
560 560 }
561 561 else if (range.m_TStart < oldRange.m_TStart && range.m_TEnd < oldRange.m_TEnd) {
562 562 qCDebug(LOG_VariableController()) << "zoomtype: PanLeft";
563 563 zoomType = AcquisitionZoomType::PanLeft;
564 564 }
565 565 else if (range.m_TStart > oldRange.m_TStart && oldRange.m_TEnd > range.m_TEnd) {
566 566 qCDebug(LOG_VariableController()) << "zoomtype: ZoomIn";
567 567 zoomType = AcquisitionZoomType::ZoomIn;
568 568 }
569 569 else {
570 570 qCDebug(LOG_VariableController()) << "getZoomType: Unknown type detected";
571 571 }
572 572 return zoomType;
573 573 }
574 574
575 575 void VariableController::VariableControllerPrivate::processRequest(std::shared_ptr<Variable> var,
576 576 const SqpRange &rangeRequested,
577 577 QUuid varRequestId)
578 578 {
579 579 auto varRequest = VariableRequest{};
580 580
581 581 auto it = m_VariableToIdentifierMap.find(var);
582 582 if (it != m_VariableToIdentifierMap.cend()) {
583 583
584 584 auto varId = it->second;
585 585
586 586 auto oldRange = getLastRequestedRange(varId);
587 587
588 588 // check for update oldRange to the last request range.
589 589 if (oldRange == INVALID_RANGE) {
590 590 oldRange = var->range();
591 591 }
592 592
593 593 auto varStrategyRangesRequested
594 594 = m_VariableCacheStrategy->computeRange(oldRange, rangeRequested);
595 595
596 // Use commented lines to remove the cache (run time)
597 // auto notInCacheRangeList = QVector<SqpRange>{varStrategyRangesRequested.second};
598 // auto inCacheRangeList = QVector<SqpRange>{};
596 599 auto notInCacheRangeList
597 600 = Variable::provideNotInCacheRangeList(oldRange, varStrategyRangesRequested.second);
598 601 auto inCacheRangeList
599 602 = Variable::provideInCacheRangeList(oldRange, varStrategyRangesRequested.second);
600 603
601 604 if (!notInCacheRangeList.empty()) {
602 605 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
603 606 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
604 607
605 608 // store VarRequest
606 609 storeVariableRequest(varId, varRequestId, varRequest);
607 610
608 611 auto varProvider = m_VariableToProviderMap.at(var);
609 612 if (varProvider != nullptr) {
610 613 auto varRequestIdCanceled = m_VariableAcquisitionWorker->pushVariableRequest(
611 614 varRequestId, varId, varStrategyRangesRequested.first,
612 615 varStrategyRangesRequested.second,
613 616 DataProviderParameters{std::move(notInCacheRangeList), var->metadata()},
614 617 varProvider);
615 618
616 619 if (!varRequestIdCanceled.isNull()) {
617 620 qCInfo(LOG_VariableAcquisitionWorker()) << tr("varRequestIdCanceled: ")
618 621 << varRequestIdCanceled;
619 cancelVariableRequest(varRequestIdCanceled);
622 // cancelVariableRequest(varRequestIdCanceled);
623 abortVariableRequest(varRequestIdCanceled);
620 624 }
621 625 }
622 626 else {
623 627 qCCritical(LOG_VariableController())
624 628 << "Impossible to provide data with a null provider";
625 629 }
626 630
627 631 if (!inCacheRangeList.empty()) {
628 632 emit q->updateVarDisplaying(var, inCacheRangeList.first());
629 633 }
630 634 }
631 635 else {
632 636 varRequest.m_RangeRequested = varStrategyRangesRequested.first;
633 637 varRequest.m_CacheRangeRequested = varStrategyRangesRequested.second;
634 638 // store VarRequest
635 639 storeVariableRequest(varId, varRequestId, varRequest);
636 640 acceptVariableRequest(
637 641 varId, var->dataSeries()->subDataSeries(varStrategyRangesRequested.second));
638 642 }
639 643 }
640 644 }
641 645
642 646 std::shared_ptr<Variable>
643 647 VariableController::VariableControllerPrivate::findVariable(QUuid vIdentifier)
644 648 {
645 649 std::shared_ptr<Variable> var;
646 650 auto findReply = [vIdentifier](const auto &entry) { return vIdentifier == entry.second; };
647 651
648 652 auto end = m_VariableToIdentifierMap.cend();
649 653 auto it = std::find_if(m_VariableToIdentifierMap.cbegin(), end, findReply);
650 654 if (it != end) {
651 655 var = it->first;
652 656 }
653 657 else {
654 658 qCCritical(LOG_VariableController())
655 659 << tr("Impossible to find the variable with the identifier: ") << vIdentifier;
656 660 }
657 661
658 662 return var;
659 663 }
660 664
661 665 std::shared_ptr<IDataSeries> VariableController::VariableControllerPrivate::retrieveDataSeries(
662 666 const QVector<AcquisitionDataPacket> acqDataPacketVector)
663 667 {
664 668 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size")
665 669 << acqDataPacketVector.size();
666 670 std::shared_ptr<IDataSeries> dataSeries;
667 671 if (!acqDataPacketVector.isEmpty()) {
668 672 dataSeries = acqDataPacketVector[0].m_DateSeries;
669 673 for (int i = 1; i < acqDataPacketVector.size(); ++i) {
670 674 dataSeries->merge(acqDataPacketVector[i].m_DateSeries.get());
671 675 }
672 676 }
673 677 qCDebug(LOG_VariableController()) << tr("TORM: retrieveDataSeries acqDataPacketVector size END")
674 678 << acqDataPacketVector.size();
675 679 return dataSeries;
676 680 }
677 681
678 682 void VariableController::VariableControllerPrivate::registerProvider(
679 683 std::shared_ptr<IDataProvider> provider)
680 684 {
681 685 if (m_ProviderSet.find(provider) == m_ProviderSet.end()) {
682 686 qCDebug(LOG_VariableController()) << tr("Registering of a new provider")
683 687 << provider->objectName();
684 688 m_ProviderSet.insert(provider);
685 689 connect(provider.get(), &IDataProvider::dataProvided, m_VariableAcquisitionWorker.get(),
686 690 &VariableAcquisitionWorker::onVariableDataAcquired);
687 691 connect(provider.get(), &IDataProvider::dataProvidedProgress,
688 692 m_VariableAcquisitionWorker.get(),
689 693 &VariableAcquisitionWorker::onVariableRetrieveDataInProgress);
690 694 connect(provider.get(), &IDataProvider::dataProvidedFailed,
691 695 m_VariableAcquisitionWorker.get(),
692 696 &VariableAcquisitionWorker::onVariableAcquisitionFailed);
693 697 }
694 698 else {
695 699 qCDebug(LOG_VariableController()) << tr("Cannot register provider, it already exists ");
696 700 }
697 701 }
698 702
699 703 void VariableController::VariableControllerPrivate::storeVariableRequest(
700 704 QUuid varId, QUuid varRequestId, const VariableRequest &varRequest)
701 705 {
702 706 // First request for the variable. we can create an entry for it
703 707 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
704 708 if (varIdToVarRequestIdQueueMapIt == m_VarIdToVarRequestIdQueueMap.cend()) {
705 709 auto varRequestIdQueue = std::deque<QUuid>{};
706 710 qCDebug(LOG_VariableController()) << tr("Store REQUEST in QUEUE");
707 711 varRequestIdQueue.push_back(varRequestId);
708 712 m_VarIdToVarRequestIdQueueMap.insert(std::make_pair(varId, std::move(varRequestIdQueue)));
709 713 }
710 714 else {
711 715 qCDebug(LOG_VariableController()) << tr("Store REQUEST in EXISTING QUEUE");
712 716 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
713 717 varRequestIdQueue.push_back(varRequestId);
714 718 }
715 719
716 720 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
717 721 if (varRequestIdToVarIdVarRequestMapIt == m_VarRequestIdToVarIdVarRequestMap.cend()) {
718 722 auto varIdToVarRequestMap = std::map<QUuid, VariableRequest>{};
719 723 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
720 724 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in MAP");
721 725 m_VarRequestIdToVarIdVarRequestMap.insert(
722 726 std::make_pair(varRequestId, std::move(varIdToVarRequestMap)));
723 727 }
724 728 else {
725 729 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
726 730 qCDebug(LOG_VariableController()) << tr("Store REQUESTID in EXISTING MAP");
727 731 varIdToVarRequestMap.insert(std::make_pair(varId, varRequest));
728 732 }
729 733 }
730 734
731 735 QUuid VariableController::VariableControllerPrivate::acceptVariableRequest(
732 736 QUuid varId, std::shared_ptr<IDataSeries> dataSeries)
733 737 {
734 738 QUuid varRequestId;
735 739 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
736 740 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
737 741 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
738 742 varRequestId = varRequestIdQueue.front();
739 743 auto varRequestIdToVarIdVarRequestMapIt
740 744 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
741 745 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
742 746 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
743 747 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
744 748 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
745 749 qCDebug(LOG_VariableController()) << tr("acceptVariableRequest");
746 750 auto &varRequest = varIdToVarRequestMapIt->second;
747 751 varRequest.m_DataSeries = dataSeries;
748 752 varRequest.m_CanUpdate = true;
749 753 }
750 754 else {
751 755 qCDebug(LOG_VariableController())
752 756 << tr("Impossible to acceptVariableRequest of a unknown variable id attached "
753 757 "to a variableRequestId")
754 758 << varRequestId << varId;
755 759 }
756 760 }
757 761 else {
758 762 qCCritical(LOG_VariableController())
759 763 << tr("Impossible to acceptVariableRequest of a unknown variableRequestId")
760 764 << varRequestId;
761 765 }
762 766
763 767 varRequestIdQueue.pop_front();
764 768 if (varRequestIdQueue.empty()) {
765 769 qCDebug(LOG_VariableController())
766 770 << tr("TORM Erase REQUEST because it has been accepted") << varId;
767 771 m_VarIdToVarRequestIdQueueMap.erase(varId);
768 772 }
769 773 }
770 774 else {
771 775 qCCritical(LOG_VariableController())
772 776 << tr("Impossible to acceptVariableRequest of a unknown variable id") << varId;
773 777 }
774 778
775 779 return varRequestId;
776 780 }
777 781
778 782 void VariableController::VariableControllerPrivate::updateVariableRequest(QUuid varRequestId)
779 783 {
780 784
781 785 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
782 786 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
783 787 bool processVariableUpdate = true;
784 788 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
785 789 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
786 790 (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) && processVariableUpdate;
787 791 ++varIdToVarRequestMapIt) {
788 792 processVariableUpdate &= varIdToVarRequestMapIt->second.m_CanUpdate;
789 793 qCDebug(LOG_VariableController()) << tr("updateVariableRequest")
790 794 << processVariableUpdate;
791 795 }
792 796
793 797 if (processVariableUpdate) {
794 798 for (auto varIdToVarRequestMapIt = varIdToVarRequestMap.cbegin();
795 799 varIdToVarRequestMapIt != varIdToVarRequestMap.cend(); ++varIdToVarRequestMapIt) {
796 800 if (auto var = findVariable(varIdToVarRequestMapIt->first)) {
797 801 auto &varRequest = varIdToVarRequestMapIt->second;
798 802 var->setRange(varRequest.m_RangeRequested);
799 803 var->setCacheRange(varRequest.m_CacheRangeRequested);
800 804 qCDebug(LOG_VariableController()) << tr("1: onDataProvided")
801 805 << varRequest.m_RangeRequested
802 806 << varRequest.m_CacheRangeRequested;
803 807 qCDebug(LOG_VariableController()) << tr("2: onDataProvided var points before")
804 808 << var->nbPoints()
805 809 << varRequest.m_DataSeries->nbPoints();
806 810 var->mergeDataSeries(varRequest.m_DataSeries);
807 811 qCDebug(LOG_VariableController()) << tr("3: onDataProvided var points after")
808 812 << var->nbPoints();
809 813
810 814 emit var->updated();
811 815 }
812 816 else {
813 817 qCCritical(LOG_VariableController())
814 818 << tr("Impossible to update data to a null variable");
815 819 }
816 820 }
817 821 // cleaning varRequestId
818 822 qCDebug(LOG_VariableController()) << tr("0: erase REQUEST in MAP ?")
819 823 << m_VarRequestIdToVarIdVarRequestMap.size();
820 824 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
821 825 qCDebug(LOG_VariableController()) << tr("1: erase REQUEST in MAP ?")
822 826 << m_VarRequestIdToVarIdVarRequestMap.size();
823 827 }
824 828 }
825 829 else {
826 830 qCCritical(LOG_VariableController())
827 831 << tr("Cannot updateVariableRequest for a unknow varRequestId") << varRequestId;
828 832 }
829 833 }
830 834
831 835 void VariableController::VariableControllerPrivate::cancelVariableRequest(QUuid varRequestId)
832 836 {
833 837 // cleaning varRequestId
834 838 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestId);
835 839
836 840 for (auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.begin();
837 841 varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.end();) {
838 842 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
839 843 varRequestIdQueue.erase(
840 844 std::remove(varRequestIdQueue.begin(), varRequestIdQueue.end(), varRequestId),
841 845 varRequestIdQueue.end());
842 846 if (varRequestIdQueue.empty()) {
843 847 varIdToVarRequestIdQueueMapIt
844 848 = m_VarIdToVarRequestIdQueueMap.erase(varIdToVarRequestIdQueueMapIt);
845 849
846 850 // Recompute if there is any next request based on the removed request.
847 851 }
848 852 else {
849 853 ++varIdToVarRequestIdQueueMapIt;
850 854 }
851 855 }
852 856 }
853 857
858 void VariableController::VariableControllerPrivate::abortVariableRequest(QUuid varRequestId)
859 {
860 auto varRequestIdsMap = std::map<QUuid, VariableRequest>{};
861 auto varRequestIdToVarIdVarRequestMapIt = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
862 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
863 varRequestIdsMap = varRequestIdToVarIdVarRequestMapIt->second;
864 }
865
866 auto nextUuidToRemove = QSet<QUuid>{};
867 auto varIdEnd = varRequestIdsMap.end();
868 for (auto varIdIt = varRequestIdsMap.begin(); varIdIt != varIdEnd;) {
869 auto currentVarId = varIdIt->first;
870 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(currentVarId);
871 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
872
873 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
874
875 auto varReqIdQueueEnd = varRequestIdQueue.end();
876 for (auto varReqIdQueueIt = varRequestIdQueue.begin();
877 varReqIdQueueIt != varRequestIdQueue.end(); ++varReqIdQueueIt) {
878 if (*varReqIdQueueIt == varRequestId) {
879 auto nextVarRequestIdToRm = varReqIdQueueIt;
880 ++nextVarRequestIdToRm;
881
882 if (nextVarRequestIdToRm == varReqIdQueueEnd) {
883 // The varRequestId is in progress for the current var, let's aborting it.
884 m_VariableAcquisitionWorker->abortProgressRequested(currentVarId);
885 }
886 else {
887 // There is at least one Request after
888 // let's add only new id to remove
889 if (!nextUuidToRemove.contains(*nextVarRequestIdToRm)) {
890 nextUuidToRemove << *nextVarRequestIdToRm;
891 }
892 }
893
894 varReqIdQueueIt = varRequestIdQueue.erase(varReqIdQueueIt);
895 // break is necessary here, we don"t need to iterate on the dequeue anymore and
896 // the iteration is broken because of the erase
897 break;
898 }
899 }
900
901 // beacause the process can modify the map under the iteration, we need to update the
902 // iterator only if no erase has been done
903 if (varRequestIdQueue.empty()) {
904 varIdIt = varRequestIdsMap.erase(varIdIt);
905 }
906 else {
907 ++varIdIt;
908 }
909 }
910 }
911
912 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
913 m_VarRequestIdToVarIdVarRequestMap.erase(varRequestIdToVarIdVarRequestMapIt);
914 }
915
916 for (auto nextVarRequestIdToRm : nextUuidToRemove) {
917 abortVariableRequest(nextVarRequestIdToRm);
918 }
919 }
920
854 921 SqpRange VariableController::VariableControllerPrivate::getLastRequestedRange(QUuid varId)
855 922 {
856 923 auto lastRangeRequested = SqpRange{INVALID_RANGE};
857 924 auto varIdToVarRequestIdQueueMapIt = m_VarIdToVarRequestIdQueueMap.find(varId);
858 925 if (varIdToVarRequestIdQueueMapIt != m_VarIdToVarRequestIdQueueMap.cend()) {
859 926 auto &varRequestIdQueue = varIdToVarRequestIdQueueMapIt->second;
860 927 auto varRequestId = varRequestIdQueue.back();
861 928 auto varRequestIdToVarIdVarRequestMapIt
862 929 = m_VarRequestIdToVarIdVarRequestMap.find(varRequestId);
863 930 if (varRequestIdToVarIdVarRequestMapIt != m_VarRequestIdToVarIdVarRequestMap.cend()) {
864 931 auto &varIdToVarRequestMap = varRequestIdToVarIdVarRequestMapIt->second;
865 932 auto varIdToVarRequestMapIt = varIdToVarRequestMap.find(varId);
866 933 if (varIdToVarRequestMapIt != varIdToVarRequestMap.cend()) {
867 934 auto &varRequest = varIdToVarRequestMapIt->second;
868 935 lastRangeRequested = varRequest.m_RangeRequested;
869 936 }
870 937 else {
871 938 qCDebug(LOG_VariableController())
872 939 << tr("Impossible to getLastRequestedRange of a unknown variable id attached "
873 940 "to a variableRequestId")
874 941 << varRequestId << varId;
875 942 }
876 943 }
877 944 else {
878 945 qCCritical(LOG_VariableController())
879 946 << tr("Impossible to getLastRequestedRange of a unknown variableRequestId")
880 947 << varRequestId;
881 948 }
882 949 }
883 950 else {
884 951 qDebug(LOG_VariableController())
885 952 << tr("Impossible to getLastRequestedRange of a unknown variable id") << varId;
886 953 }
887 954
888 955 return lastRangeRequested;
889 956 }
@@ -1,390 +1,390
1 1 #include <QObject>
2 2 #include <QtTest>
3 3
4 4 #include <memory>
5 5
6 6 #include <Data/DataProviderParameters.h>
7 7 #include <Data/IDataProvider.h>
8 8 #include <Data/ScalarSeries.h>
9 9 #include <Time/TimeController.h>
10 10 #include <Variable/Variable.h>
11 11 #include <Variable/VariableController.h>
12 12 #include <Variable/VariableModel.h>
13 13
14 14 namespace {
15 15
16 16 /// Delay after each operation on the variable before validating it (in ms)
17 17 const auto OPERATION_DELAY = 100;
18 18
19 19 /**
20 20 * Generates values according to a range. The value generated for a time t is the number of seconds
21 21 * of difference between t and a reference value (which is midnight -> 00:00:00)
22 22 *
23 23 * Example: For a range between 00:00:10 and 00:00:20, the generated values are
24 24 * {10,11,12,13,14,15,16,17,18,19,20}
25 25 */
26 26 std::vector<double> values(const SqpRange &range)
27 27 {
28 28 QTime referenceTime{0, 0};
29 29
30 30 std::vector<double> result{};
31 31
32 32 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
33 33 auto time = DateUtils::dateTime(i).time();
34 34 result.push_back(referenceTime.secsTo(time));
35 35 }
36 36
37 37 return result;
38 38 }
39 39
40 40 /// Provider used for the tests
41 41 class TestProvider : public IDataProvider {
42 42 std::shared_ptr<IDataProvider> clone() const { return std::make_shared<TestProvider>(); }
43 43
44 44 void requestDataLoading(QUuid acqIdentifier, const DataProviderParameters &parameters) override
45 45 {
46 46 const auto &ranges = parameters.m_Times;
47 47
48 48 for (const auto &range : ranges) {
49 49 // Generates data series
50 50 auto valuesData = values(range);
51 51
52 52 std::vector<double> xAxisData{};
53 53 for (auto i = range.m_TStart; i <= range.m_TEnd; ++i) {
54 54 xAxisData.push_back(i);
55 55 }
56 56
57 57 auto dataSeries = std::make_shared<ScalarSeries>(
58 58 std::move(xAxisData), std::move(valuesData), Unit{"t", true}, Unit{});
59 59
60 60 emit dataProvided(acqIdentifier, dataSeries, range);
61 61 }
62 62 }
63 63
64 64 void requestDataAborting(QUuid acqIdentifier) override
65 65 {
66 66 // Does nothing
67 67 }
68 68 };
69 69
70 70 /**
71 71 * Interface representing an operation performed on a variable controller.
72 72 * This interface is used in tests to apply a set of operations and check the status of the
73 73 * controller after each operation
74 74 */
75 75 struct IOperation {
76 76 virtual ~IOperation() = default;
77 77 /// Executes the operation on the variable controller
78 78 virtual void exec(VariableController &variableController) const = 0;
79 79 };
80 80
81 81 /**
82 82 *Variable creation operation in the controller
83 83 */
84 84 struct Create : public IOperation {
85 85 explicit Create(int index) : m_Index{index} {}
86 86
87 87 void exec(VariableController &variableController) const override
88 88 {
89 89 auto variable = variableController.createVariable(QString::number(m_Index), {},
90 90 std::make_unique<TestProvider>());
91 91 }
92 92
93 93 int m_Index; ///< The index of the variable to create in the controller
94 94 };
95 95
96 96 /**
97 97 * Variable move/shift operation in the controller
98 98 */
99 99 struct Move : public IOperation {
100 100 explicit Move(int index, const SqpRange &newRange, bool shift = false)
101 101 : m_Index{index}, m_NewRange{newRange}, m_Shift{shift}
102 102 {
103 103 }
104 104
105 105 void exec(VariableController &variableController) const override
106 106 {
107 107 if (auto variable = variableController.variableModel()->variable(m_Index)) {
108 108 variableController.onRequestDataLoading({variable}, m_NewRange, !m_Shift);
109 109 }
110 110 }
111 111
112 112 int m_Index; ///< The index of the variable to move
113 113 SqpRange m_NewRange; ///< The new range of the variable
114 114 bool m_Shift; ///< Performs a shift (
115 115 };
116 116
117 117 /**
118 118 * Variable synchronization/desynchronization operation in the controller
119 119 */
120 120 struct Synchronize : public IOperation {
121 121 explicit Synchronize(int index, QUuid syncId, bool synchronize = true)
122 122 : m_Index{index}, m_SyncId{syncId}, m_Synchronize{synchronize}
123 123 {
124 124 }
125 125
126 126 void exec(VariableController &variableController) const override
127 127 {
128 128 if (auto variable = variableController.variableModel()->variable(m_Index)) {
129 129 if (m_Synchronize) {
130 130 variableController.onAddSynchronized(variable, m_SyncId);
131 131 }
132 132 else {
133 133 variableController.desynchronize(variable, m_SyncId);
134 134 }
135 135 }
136 136 }
137 137
138 138 int m_Index; ///< The index of the variable to sync/desync
139 139 QUuid m_SyncId; ///< The synchronization group of the variable
140 140 bool m_Synchronize; ///< Performs sync or desync operation
141 141 };
142 142
143 143 /**
144 144 * Test Iteration
145 145 *
146 146 * A test iteration includes an operation to be performed, and a set of expected ranges after each
147 147 * operation. Each range is tested after the operation to ensure that:
148 148 * - the range of the variable is the expected range
149 149 * - the data of the variable are those generated for the expected range
150 150 */
151 151 struct Iteration {
152 152 std::shared_ptr<IOperation> m_Operation; ///< Operation to perform
153 153 std::map<int, SqpRange> m_ExpectedRanges; ///< Expected ranges (by variable index)
154 154 };
155 155
156 156 using Iterations = std::vector<Iteration>;
157 157
158 158 } // namespace
159 159
160 160 Q_DECLARE_METATYPE(Iterations)
161 161
162 162 class TestVariableSync : public QObject {
163 163 Q_OBJECT
164 164
165 165 private slots:
166 166 /// Input data for @sa testSync()
167 167 void testSync_data();
168 168
169 169 /// Tests synchronization between variables through several operations
170 170 void testSync();
171 171 };
172 172
173 173 namespace {
174 174
175 175 void testSyncCase1()
176 176 {
177 177 // Id used to synchronize variables in the controller
178 178 auto syncId = QUuid::createUuid();
179 179
180 180 /// Generates a range according to a start time and a end time (the date is the same)
181 181 auto range = [](const QTime &startTime, const QTime &endTime) {
182 182 return SqpRange{DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, startTime, Qt::UTC}),
183 183 DateUtils::secondsSinceEpoch(QDateTime{{2017, 1, 1}, endTime, Qt::UTC})};
184 184 };
185 185
186 186 auto initialRange = range({12, 0}, {13, 0});
187 187
188 188 Iterations iterations{};
189 189 // Creates variables var0, var1 and var2
190 190 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
191 191 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
192 192 iterations.push_back(
193 193 {std::make_shared<Create>(2), {{0, initialRange}, {1, initialRange}, {2, initialRange}}});
194 194
195 195 // Adds variables into the sync group (ranges don't need to be tested here)
196 196 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
197 197 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
198 198 iterations.push_back({std::make_shared<Synchronize>(2, syncId)});
199 199
200 200 // Moves var0: ranges of var0, var1 and var2 change
201 201 auto newRange = range({12, 30}, {13, 30});
202 202 iterations.push_back(
203 203 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
204 204
205 205 // Moves var1: ranges of var0, var1 and var2 change
206 206 newRange = range({13, 0}, {14, 0});
207 207 iterations.push_back(
208 208 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
209 209
210 210 // Moves var2: ranges of var0, var1 and var2 change
211 211 newRange = range({13, 30}, {14, 30});
212 212 iterations.push_back(
213 213 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, newRange}}});
214 214
215 215 // Desyncs var2 and moves var0:
216 216 // - ranges of var0 and var1 change
217 217 // - range of var2 doesn't change anymore
218 218 auto var2Range = newRange;
219 219 newRange = range({13, 45}, {14, 45});
220 220 iterations.push_back({std::make_shared<Synchronize>(2, syncId, false)});
221 221 iterations.push_back(
222 222 {std::make_shared<Move>(0, newRange), {{0, newRange}, {1, newRange}, {2, var2Range}}});
223 223
224 224 // Shifts var0: although var1 is synchronized with var0, its range doesn't change
225 225 auto var1Range = newRange;
226 226 newRange = range({14, 45}, {15, 45});
227 227 iterations.push_back({std::make_shared<Move>(0, newRange, true),
228 228 {{0, newRange}, {1, var1Range}, {2, var2Range}}});
229 229
230 230 // Moves var0 through several operations:
231 231 // - range of var0 changes
232 232 // - range or var1 changes according to the previous shift (one hour)
233 233 auto moveVar0 = [&iterations](const auto &var0NewRange, const auto &var1ExpectedRange) {
234 234 iterations.push_back(
235 235 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var1ExpectedRange}}});
236 236 };
237 237 // Pan left
238 238 moveVar0(range({14, 30}, {15, 30}), range({13, 30}, {14, 30}));
239 239 // Pan right
240 240 moveVar0(range({16, 0}, {17, 0}), range({15, 0}, {16, 0}));
241 241 // Zoom in
242 242 moveVar0(range({16, 30}, {16, 45}), range({15, 30}, {15, 45}));
243 243 // Zoom out
244 moveVar0(range({12, 0}, {18, 0}), range({11, 0}, {17, 0}));
244 moveVar0(range({16, 15}, {17, 0}), range({15, 15}, {16, 0}));
245 245
246 246 QTest::newRow("sync1") << syncId << initialRange << std::move(iterations) << 200;
247 247 }
248 248
249 249 void testSyncCase2()
250 250 {
251 251 // Id used to synchronize variables in the controller
252 252 auto syncId = QUuid::createUuid();
253 253
254 254 /// Generates a range according to a start time and a end time (the date is the same)
255 255 auto dateTime = [](int year, int month, int day, int hours, int minutes, int seconds) {
256 256 return DateUtils::secondsSinceEpoch(
257 257 QDateTime{{year, month, day}, QTime{hours, minutes, seconds}, Qt::UTC});
258 258 };
259 259
260 260 auto initialRange = SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)};
261 261
262 262 Iterations iterations{};
263 263 // Creates variables var0 and var1
264 264 iterations.push_back({std::make_shared<Create>(0), {{0, initialRange}}});
265 265 iterations.push_back({std::make_shared<Create>(1), {{0, initialRange}, {1, initialRange}}});
266 266
267 267 // Adds variables into the sync group (ranges don't need to be tested here)
268 268 iterations.push_back({std::make_shared<Synchronize>(0, syncId)});
269 269 iterations.push_back({std::make_shared<Synchronize>(1, syncId)});
270 270
271 271
272 272 // Moves var0 through several operations:
273 273 // - range of var0 changes
274 274 // - range or var1 changes according to the previous shift (one hour)
275 275 auto moveVar0 = [&iterations](const auto &var0NewRange) {
276 276 iterations.push_back(
277 277 {std::make_shared<Move>(0, var0NewRange), {{0, var0NewRange}, {1, var0NewRange}}});
278 278 };
279 279 moveVar0(SqpRange{dateTime(2017, 1, 1, 12, 0, 0), dateTime(2017, 1, 1, 13, 0, 0)});
280 280 moveVar0(SqpRange{dateTime(2017, 1, 1, 14, 0, 0), dateTime(2017, 1, 1, 15, 0, 0)});
281 281 moveVar0(SqpRange{dateTime(2017, 1, 1, 8, 0, 0), dateTime(2017, 1, 1, 9, 0, 0)});
282 282 // moveVar0(SqpRange{dateTime(2017, 1, 1, 7, 30, 0), dateTime(2017, 1, 1, 9, 30, 0)});
283 283 moveVar0(SqpRange{dateTime(2017, 1, 1, 2, 0, 0), dateTime(2017, 1, 1, 4, 0, 0)});
284 284 moveVar0(SqpRange{dateTime(2017, 1, 1, 6, 0, 0), dateTime(2017, 1, 1, 8, 0, 0)});
285 285
286 286 moveVar0(SqpRange{dateTime(2017, 1, 10, 6, 0, 0), dateTime(2017, 1, 15, 8, 0, 0)});
287 287 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 1, 25, 8, 0, 0)});
288 288 moveVar0(SqpRange{dateTime(2017, 1, 2, 6, 0, 0), dateTime(2017, 1, 8, 8, 0, 0)});
289 289
290 290 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
291 291 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
292 292 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
293 293 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
294 294 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
295 295 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
296 296 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
297 297 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
298 298 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
299 299 moveVar0(SqpRange{dateTime(2017, 4, 10, 6, 0, 0), dateTime(2017, 6, 15, 8, 0, 0)});
300 300 moveVar0(SqpRange{dateTime(2017, 1, 17, 6, 0, 0), dateTime(2017, 2, 25, 8, 0, 0)});
301 301 moveVar0(SqpRange{dateTime(2017, 7, 2, 6, 0, 0), dateTime(2017, 10, 8, 8, 0, 0)});
302 302
303 303
304 304 QTest::newRow("sync2") << syncId << initialRange << iterations << 4000;
305 305 // QTest::newRow("sync3") << syncId << initialRange << iterations << 5000;
306 306 }
307 307 }
308 308
309 309 void TestVariableSync::testSync_data()
310 310 {
311 311 // ////////////// //
312 312 // Test structure //
313 313 // ////////////// //
314 314
315 315 QTest::addColumn<QUuid>("syncId");
316 316 QTest::addColumn<SqpRange>("initialRange");
317 317 QTest::addColumn<Iterations>("iterations");
318 318 QTest::addColumn<int>("operationDelay");
319 319
320 320 // ////////// //
321 321 // Test cases //
322 322 // ////////// //
323 323
324 324 testSyncCase1();
325 testSyncCase2();
325 // testSyncCase2();
326 326 }
327 327
328 328 void TestVariableSync::testSync()
329 329 {
330 330 // Inits controllers
331 331 TimeController timeController{};
332 332 VariableController variableController{};
333 333 variableController.setTimeController(&timeController);
334 334
335 335 QFETCH(QUuid, syncId);
336 336 QFETCH(SqpRange, initialRange);
337 337 timeController.onTimeToUpdate(initialRange);
338 338
339 339 // Synchronization group used
340 340 variableController.onAddSynchronizationGroupId(syncId);
341 341
342 342 auto validateRanges = [&variableController](const auto &expectedRanges) {
343 343 for (const auto &expectedRangeEntry : expectedRanges) {
344 344 auto variableIndex = expectedRangeEntry.first;
345 345 auto expectedRange = expectedRangeEntry.second;
346 346
347 347 // Gets the variable in the controller
348 348 auto variable = variableController.variableModel()->variable(variableIndex);
349 349
350 350 // Compares variable's range to the expected range
351 351 QVERIFY(variable != nullptr);
352 352 auto range = variable->range();
353 353 QCOMPARE(range, expectedRange);
354 354
355 355 // Compares variable's data with values expected for its range
356 356 auto dataSeries = variable->dataSeries();
357 357 QVERIFY(dataSeries != nullptr);
358 358
359 359 auto it = dataSeries->xAxisRange(range.m_TStart, range.m_TEnd);
360 360 auto expectedValues = values(range);
361 361 qInfo() << std::distance(it.first, it.second) << expectedValues.size();
362 362 QVERIFY(std::equal(it.first, it.second, expectedValues.cbegin(), expectedValues.cend(),
363 363 [](const auto &dataSeriesIt, const auto &expectedValue) {
364 364 return dataSeriesIt.value() == expectedValue;
365 365 }));
366 366 }
367 367 };
368 368
369 369 // For each iteration:
370 370 // - execute operation
371 371 // - compare the variables' state to the expected states
372 372 QFETCH(Iterations, iterations);
373 373 QFETCH(int, operationDelay);
374 374 for (const auto &iteration : iterations) {
375 375 iteration.m_Operation->exec(variableController);
376 376 QTest::qWait(operationDelay);
377 377
378 378 validateRanges(iteration.m_ExpectedRanges);
379 379 }
380 380
381 381 for (const auto &iteration : iterations) {
382 382 iteration.m_Operation->exec(variableController);
383 383 }
384 384 QTest::qWait(operationDelay);
385 385 validateRanges(iterations.back().m_ExpectedRanges);
386 386 }
387 387
388 388 QTEST_MAIN(TestVariableSync)
389 389
390 390 #include "TestVariableSync.moc"
General Comments 3
Under Review
author

Auto status change to "Under Review"

Approved
author

Merge lasted acquisition developpement on main Sciqlop branch

You need to be logged in to leave comments. Login now