@@ -0,0 +1,53 | |||||
|
1 | #include <QThreadPool> | |||
|
2 | #include <QRunnable> | |||
|
3 | #include <QObject> | |||
|
4 | #include <QReadWriteLock> | |||
|
5 | ||||
|
6 | #include "Variable/VariableSynchronizationGroup2.h" | |||
|
7 | #include <Variable/Variable.h> | |||
|
8 | #include <Common/containers.h> | |||
|
9 | #include <Common/debug.h> | |||
|
10 | #include <Data/DataProviderParameters.h> | |||
|
11 | #include <Data/DateTimeRangeHelper.h> | |||
|
12 | #include <Data/DateTimeRange.h> | |||
|
13 | #include <Data/IDataProvider.h> | |||
|
14 | ||||
|
15 | struct VCTransaction | |||
|
16 | { | |||
|
17 | VCTransaction(QUuid refVar, DateTimeRange range, int ready) | |||
|
18 | :refVar{refVar},range{range},ready{ready} | |||
|
19 | {} | |||
|
20 | QUuid refVar; | |||
|
21 | DateTimeRange range; | |||
|
22 | int ready; | |||
|
23 | QReadWriteLock lock; | |||
|
24 | }; | |||
|
25 | ||||
|
26 | class TransactionExe:public QObject,public QRunnable | |||
|
27 | { | |||
|
28 | Q_OBJECT | |||
|
29 | std::shared_ptr<Variable> _variable; | |||
|
30 | std::shared_ptr<IDataProvider> _provider; | |||
|
31 | std::vector<DateTimeRange> _ranges; | |||
|
32 | DateTimeRange _range; | |||
|
33 | DateTimeRange _cacheRange; | |||
|
34 | public: | |||
|
35 | TransactionExe(const std::shared_ptr<Variable>& variable, const std::shared_ptr<IDataProvider>& provider, | |||
|
36 | const std::vector<DateTimeRange>& ranges, DateTimeRange range, DateTimeRange cacheRange) | |||
|
37 | :_variable{variable}, _provider{provider},_ranges{ranges},_range{range},_cacheRange{cacheRange} | |||
|
38 | { | |||
|
39 | setAutoDelete(true); | |||
|
40 | } | |||
|
41 | void run()override | |||
|
42 | { | |||
|
43 | std::vector<IDataSeries*> data; | |||
|
44 | for(auto range:_ranges) | |||
|
45 | { | |||
|
46 | data.push_back(_provider->getData(DataProviderParameters{{range}, _variable->metadata()})); | |||
|
47 | } | |||
|
48 | _variable->updateData(data, _range, _cacheRange, true); | |||
|
49 | emit transactionComplete(); | |||
|
50 | } | |||
|
51 | signals: | |||
|
52 | void transactionComplete(); | |||
|
53 | }; |
@@ -0,0 +1,67 | |||||
|
1 | #include <cmath> | |||
|
2 | #include <algorithm> | |||
|
3 | #include <numeric> | |||
|
4 | #include <QtTest> | |||
|
5 | #include <QObject> | |||
|
6 | #include <Variable/VariableController2.h> | |||
|
7 | #include <Data/DateTimeRange.h> | |||
|
8 | #include <Data/IDataProvider.h> | |||
|
9 | #include <Data/ScalarSeries.h> | |||
|
10 | #include <Data/DataProviderParameters.h> | |||
|
11 | #include <Common/containers.h> | |||
|
12 | ||||
|
13 | #include <TestUtils/TestProviders.h> | |||
|
14 | ||||
|
15 | #define TEST_VC2_FIXTURE(slope) \ | |||
|
16 | VariableController2 vc; \ | |||
|
17 | auto provider = std::make_shared<SimpleRange<slope>>();\ | |||
|
18 | ||||
|
19 | #define TEST_VC2_CREATE_DEFAULT_VARS(name1, name2, name3)\ | |||
|
20 | auto range = DateTimeRange::fromDateTime(QDate(2018,8,7),QTime(14,00),\ | |||
|
21 | QDate(2018,8,7),QTime(16,00));\ | |||
|
22 | auto name1 = vc.createVariable("name1", {}, provider, range);\ | |||
|
23 | auto name2 = vc.createVariable("name1", {}, provider, range);\ | |||
|
24 | auto name3 = vc.createVariable("name1", {}, provider, range);\ | |||
|
25 | vc.synchronize(name1,name2);\ | |||
|
26 | ||||
|
27 | ||||
|
28 | class TestVariableController2Async : public QObject | |||
|
29 | { | |||
|
30 | Q_OBJECT | |||
|
31 | public: | |||
|
32 | explicit TestVariableController2Async(QObject *parent = nullptr) : QObject(parent){} | |||
|
33 | signals: | |||
|
34 | ||||
|
35 | private slots: | |||
|
36 | void initTestCase(){} | |||
|
37 | void cleanupTestCase(){} | |||
|
38 | ||||
|
39 | void testSimplePan() | |||
|
40 | { | |||
|
41 | TEST_VC2_FIXTURE(2); | |||
|
42 | auto range = DateTimeRange::fromDateTime(QDate(2018,8,7),QTime(14,00), | |||
|
43 | QDate(2018,8,7),QTime(16,00)); | |||
|
44 | int variableUpdated=0; | |||
|
45 | auto var1 = vc.createVariable("var1", {}, provider, range); | |||
|
46 | auto var2 = vc.createVariable("var2", {}, provider, range); | |||
|
47 | auto var3 = vc.createVariable("var3", {}, provider, range); | |||
|
48 | connect(&(*var2),&Variable::updated, [&variableUpdated](){variableUpdated+=1;}); | |||
|
49 | vc.synchronize(var1,var2); | |||
|
50 | vc.asyncChangeRange(var1,range+Seconds<double>{10000.}); | |||
|
51 | vc.asyncChangeRange(var1,range+Seconds<double>{50000.}); | |||
|
52 | vc.asyncChangeRange(var1,range+Seconds<double>{100000.}); | |||
|
53 | vc.asyncChangeRange(var1,range+Seconds<double>{150000.}); | |||
|
54 | while(!vc.isReady(var1) || !vc.isReady(var2)) | |||
|
55 | { | |||
|
56 | QCoreApplication::processEvents(); | |||
|
57 | } | |||
|
58 | } | |||
|
59 | ||||
|
60 | ||||
|
61 | }; | |||
|
62 | ||||
|
63 | ||||
|
64 | QTEST_MAIN(TestVariableController2Async) | |||
|
65 | ||||
|
66 | #include "TestVariableController2Async.moc" | |||
|
67 |
@@ -91,6 +91,7 FILE (GLOB_RECURSE core_SRCS | |||||
91 | ./include/Variable/VariableCacheController.h |
|
91 | ./include/Variable/VariableCacheController.h | |
92 | ./include/Variable/VariableController.h |
|
92 | ./include/Variable/VariableController.h | |
93 | ./include/Variable/VariableController2.h |
|
93 | ./include/Variable/VariableController2.h | |
|
94 | ./include/Variable/private/VCTransaction.h | |||
94 | ./include/Time/TimeController.h |
|
95 | ./include/Time/TimeController.h | |
95 | ./include/Settings/ISqpSettingsBindable.h |
|
96 | ./include/Settings/ISqpSettingsBindable.h | |
96 | ./include/Settings/SqpSettingsDefs.h |
|
97 | ./include/Settings/SqpSettingsDefs.h |
@@ -36,6 +36,10 struct DateTimeRangeTransformation | |||||
36 | return SciQLop::numeric::almost_equal(zoom, other.zoom, 1) && |
|
36 | return SciQLop::numeric::almost_equal(zoom, other.zoom, 1) && | |
37 | SciQLop::numeric::almost_equal<double>(shift, other.shift, 1); |
|
37 | SciQLop::numeric::almost_equal<double>(shift, other.shift, 1); | |
38 | } |
|
38 | } | |
|
39 | DateTimeRangeTransformation merge(const DateTimeRangeTransformation& other) const | |||
|
40 | { | |||
|
41 | return DateTimeRangeTransformation{zoom*other.zoom,shift+other.shift}; | |||
|
42 | } | |||
39 | }; |
|
43 | }; | |
40 |
|
44 | |||
41 | /** |
|
45 | /** | |
@@ -155,6 +159,7 template <class T> | |||||
155 | DateTimeRange& operator-=(DateTimeRange&r, Seconds<T> offset) |
|
159 | DateTimeRange& operator-=(DateTimeRange&r, Seconds<T> offset) | |
156 | { |
|
160 | { | |
157 | shift(r,-offset); |
|
161 | shift(r,-offset); | |
|
162 | return r; | |||
158 | } |
|
163 | } | |
159 |
|
164 | |||
160 | template <class T> |
|
165 | template <class T> |
@@ -62,7 +62,13 public: | |||||
62 | DataSeriesType type() const noexcept; |
|
62 | DataSeriesType type() const noexcept; | |
63 |
|
63 | |||
64 | QVariantHash metadata() const noexcept; |
|
64 | QVariantHash metadata() const noexcept; | |
|
65 | ||||
|
66 | void updateData(const std::vector<IDataSeries*>& dataSeries, | |||
|
67 | const DateTimeRange& newRange, const DateTimeRange& newCacheRange, | |||
|
68 | bool notify=true); | |||
|
69 | ||||
65 | DEPRECATE( |
|
70 | DEPRECATE( | |
|
71 | ||||
66 | bool contains(const DateTimeRange &range) const noexcept; |
|
72 | bool contains(const DateTimeRange &range) const noexcept; | |
67 | bool intersect(const DateTimeRange &range) const noexcept; |
|
73 | bool intersect(const DateTimeRange &range) const noexcept; | |
68 | bool isInside(const DateTimeRange &range) const noexcept; |
|
74 | bool isInside(const DateTimeRange &range) const noexcept; | |
@@ -70,20 +76,9 DEPRECATE( | |||||
70 | bool cacheContains(const DateTimeRange &range) const noexcept; |
|
76 | bool cacheContains(const DateTimeRange &range) const noexcept; | |
71 | bool cacheIntersect(const DateTimeRange &range) const noexcept; |
|
77 | bool cacheIntersect(const DateTimeRange &range) const noexcept; | |
72 | bool cacheIsInside(const DateTimeRange &range) const noexcept; |
|
78 | bool cacheIsInside(const DateTimeRange &range) const noexcept; | |
73 | ) |
|
|||
74 | DEPRECATE( |
|
|||
75 | QVector<DateTimeRange> provideNotInCacheRangeList(const DateTimeRange &range) const noexcept; |
|
79 | QVector<DateTimeRange> provideNotInCacheRangeList(const DateTimeRange &range) const noexcept; | |
76 | QVector<DateTimeRange> provideInCacheRangeList(const DateTimeRange &range) const noexcept; |
|
80 | QVector<DateTimeRange> provideInCacheRangeList(const DateTimeRange &range) const noexcept; | |
77 | ) |
|
|||
78 | DEPRECATE( |
|
|||
79 | void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept; |
|
81 | void mergeDataSeries(std::shared_ptr<IDataSeries> dataSeries) noexcept; | |
80 | ) |
|
|||
81 |
|
||||
82 | void updateData(const std::vector<IDataSeries*>& dataSeries, |
|
|||
83 | const DateTimeRange& newRange, const DateTimeRange& newCacheRange, |
|
|||
84 | bool notify=true); |
|
|||
85 |
|
||||
86 | DEPRECATE( |
|
|||
87 | static QVector<DateTimeRange> provideNotInCacheRangeList(const DateTimeRange &oldRange, |
|
82 | static QVector<DateTimeRange> provideNotInCacheRangeList(const DateTimeRange &oldRange, | |
88 | const DateTimeRange &nextRange); |
|
83 | const DateTimeRange &nextRange); | |
89 |
|
84 | |||
@@ -91,6 +86,7 DEPRECATE( | |||||
91 | const DateTimeRange &nextRange); |
|
86 | const DateTimeRange &nextRange); | |
92 | ) |
|
87 | ) | |
93 |
|
88 | |||
|
89 | operator QUuid() {return _uuid;} | |||
94 | QUuid ID(){return _uuid;} |
|
90 | QUuid ID(){return _uuid;} | |
95 | signals: |
|
91 | signals: | |
96 | void updated(); |
|
92 | void updated(); |
@@ -31,6 +31,8 public: | |||||
31 | void asyncChangeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r); |
|
31 | void asyncChangeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r); | |
32 | const std::set<std::shared_ptr<Variable>> variables(); |
|
32 | const std::set<std::shared_ptr<Variable>> variables(); | |
33 |
|
33 | |||
|
34 | bool isReady(const std::shared_ptr<Variable>& variable); | |||
|
35 | ||||
34 | void synchronize(const std::shared_ptr<Variable>& var, const std::shared_ptr<Variable>& with); |
|
36 | void synchronize(const std::shared_ptr<Variable>& var, const std::shared_ptr<Variable>& with); | |
35 |
|
37 | |||
36 |
|
38 |
@@ -64,8 +64,12 public: | |||||
64 | return this->_variables; |
|
64 | return this->_variables; | |
65 | } |
|
65 | } | |
66 |
|
66 | |||
|
67 | inline QUuid ID(){return _ID;} | |||
|
68 | ||||
|
69 | operator QUuid() {return _ID;} | |||
67 | private: |
|
70 | private: | |
68 | std::set<QUuid> _variables; |
|
71 | std::set<QUuid> _variables; | |
|
72 | QUuid _ID = QUuid::createUuid(); | |||
69 | }; |
|
73 | }; | |
70 |
|
74 | |||
71 | #endif // SCIQLOP_VARIABLESYNCHRONIZATIONGROUP2_H |
|
75 | #endif // SCIQLOP_VARIABLESYNCHRONIZATIONGROUP2_H |
@@ -1,33 +1,181 | |||||
|
1 | #include <QQueue> | |||
|
2 | #include <QThreadPool> | |||
|
3 | #include <QRunnable> | |||
|
4 | #include <QObject> | |||
|
5 | ||||
1 | #include "Variable/VariableController2.h" |
|
6 | #include "Variable/VariableController2.h" | |
2 | #include "Variable/VariableSynchronizationGroup2.h" |
|
7 | #include "Variable/VariableSynchronizationGroup2.h" | |
3 | #include <Common/containers.h> |
|
8 | #include <Common/containers.h> | |
4 | #include <Common/debug.h> |
|
9 | #include <Common/debug.h> | |
5 | #include <Data/DataProviderParameters.h> |
|
10 | #include <Data/DataProviderParameters.h> | |
6 | #include <Data/DateTimeRangeHelper.h> |
|
11 | #include <Data/DateTimeRangeHelper.h> | |
|
12 | #include <Data/DateTimeRange.h> | |||
7 | #include <Variable/VariableCacheStrategyFactory.h> |
|
13 | #include <Variable/VariableCacheStrategyFactory.h> | |
|
14 | #include <Variable/private/VCTransaction.h> | |||
|
15 | ||||
|
16 | class Transactions | |||
|
17 | { | |||
|
18 | QReadWriteLock _mutex{QReadWriteLock::Recursive}; | |||
|
19 | std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> _nextTransactions; | |||
|
20 | std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> _pendingTransactions; | |||
|
21 | public: | |||
|
22 | void addEntry(QUuid id) | |||
|
23 | { | |||
|
24 | QWriteLocker lock{&_mutex}; | |||
|
25 | _nextTransactions[id] = std::nullopt; | |||
|
26 | _pendingTransactions[id] = std::nullopt; | |||
|
27 | } | |||
|
28 | ||||
|
29 | void removeEntry(QUuid id) | |||
|
30 | { | |||
|
31 | QWriteLocker lock{&_mutex}; | |||
|
32 | _nextTransactions.erase(id); | |||
|
33 | _pendingTransactions.erase(id); | |||
|
34 | } | |||
|
35 | ||||
|
36 | std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> pendingTransactions() | |||
|
37 | { | |||
|
38 | QReadLocker lock{&_mutex}; | |||
|
39 | return _pendingTransactions; | |||
|
40 | } | |||
|
41 | ||||
|
42 | std::map<QUuid,std::optional<std::shared_ptr<VCTransaction>>> nextTransactions() | |||
|
43 | { | |||
|
44 | QReadLocker lock{&_mutex}; | |||
|
45 | return _nextTransactions; | |||
|
46 | } | |||
|
47 | ||||
|
48 | std::optional<std::shared_ptr<VCTransaction>> start(QUuid id) | |||
|
49 | { | |||
|
50 | QWriteLocker lock{&_mutex}; | |||
|
51 | _pendingTransactions[id] = _nextTransactions[id]; | |||
|
52 | _nextTransactions[id] = std::nullopt; | |||
|
53 | return _pendingTransactions[id]; | |||
|
54 | } | |||
|
55 | ||||
|
56 | void enqueue(QUuid id, std::shared_ptr<VCTransaction> transaction) | |||
|
57 | { | |||
|
58 | QWriteLocker lock{&_mutex}; | |||
|
59 | _nextTransactions[id] = transaction; | |||
|
60 | } | |||
|
61 | ||||
|
62 | void complete(QUuid id) | |||
|
63 | { | |||
|
64 | QWriteLocker lock{&_mutex}; | |||
|
65 | _pendingTransactions[id] = std::nullopt; | |||
|
66 | } | |||
|
67 | ||||
|
68 | bool active(QUuid id) | |||
|
69 | { | |||
|
70 | QReadLocker lock{&_mutex}; | |||
|
71 | return _nextTransactions[id].has_value() && _pendingTransactions[id].has_value(); | |||
|
72 | } | |||
|
73 | }; | |||
8 |
|
74 | |||
9 | class VariableController2::VariableController2Private |
|
75 | class VariableController2::VariableController2Private | |
10 | { |
|
76 | { | |
|
77 | QThreadPool _ThreadPool; | |||
11 | QMap<QUuid,std::shared_ptr<Variable>> _variables; |
|
78 | QMap<QUuid,std::shared_ptr<Variable>> _variables; | |
12 | QMap<QUuid,std::shared_ptr<IDataProvider>> _providers; |
|
79 | QMap<QUuid,std::shared_ptr<IDataProvider>> _providers; | |
13 | QMap<QUuid,std::shared_ptr<VariableSynchronizationGroup2>> _synchronizationGroups; |
|
80 | QMap<QUuid,std::shared_ptr<VariableSynchronizationGroup2>> _synchronizationGroups; | |
|
81 | Transactions _transactions; | |||
|
82 | QReadWriteLock _lock{QReadWriteLock::Recursive}; | |||
14 | std::unique_ptr<VariableCacheStrategy> _cacheStrategy; |
|
83 | std::unique_ptr<VariableCacheStrategy> _cacheStrategy; | |
|
84 | ||||
15 | bool p_contains(const std::shared_ptr<Variable>& variable) |
|
85 | bool p_contains(const std::shared_ptr<Variable>& variable) | |
16 | { |
|
86 | { | |
17 | return _providers.contains(variable->ID()); |
|
87 | QReadLocker lock{&_lock}; | |
|
88 | return _providers.contains(*variable); | |||
18 | } |
|
89 | } | |
19 | bool v_contains(const std::shared_ptr<Variable>& variable) |
|
90 | bool v_contains(const std::shared_ptr<Variable>& variable) | |
20 | { |
|
91 | { | |
|
92 | QReadLocker lock{&_lock}; | |||
21 | return SciQLop::containers::contains(this->_variables, variable); |
|
93 | return SciQLop::containers::contains(this->_variables, variable); | |
22 | } |
|
94 | } | |
23 | bool sg_contains(const std::shared_ptr<Variable>& variable) |
|
95 | bool sg_contains(const std::shared_ptr<Variable>& variable) | |
24 | { |
|
96 | { | |
25 | return _synchronizationGroups.contains(variable->ID()); |
|
97 | QReadLocker lock{&_lock}; | |
|
98 | return _synchronizationGroups.contains(*variable); | |||
26 | } |
|
99 | } | |
27 |
|
100 | |||
28 | void _changeRange(const std::shared_ptr<Variable>& var, DateTimeRange r) |
|
101 | void _transactionComplete(QUuid group, std::shared_ptr<VCTransaction> transaction) | |
|
102 | { | |||
|
103 | { | |||
|
104 | QWriteLocker lock{&transaction->lock}; | |||
|
105 | transaction->ready -=1; | |||
|
106 | } | |||
|
107 | if(transaction->ready==0) | |||
|
108 | { | |||
|
109 | _transactions.complete(group); | |||
|
110 | } | |||
|
111 | this->_processTransactions(); | |||
|
112 | } | |||
|
113 | void _processTransactions() | |||
|
114 | { | |||
|
115 | QWriteLocker lock{&_lock}; | |||
|
116 | auto nextTransactions = _transactions.nextTransactions(); | |||
|
117 | auto pendingTransactions = _transactions.pendingTransactions(); | |||
|
118 | for( auto [groupID, newTransaction] : nextTransactions) | |||
|
119 | { | |||
|
120 | if(newTransaction.has_value() && !pendingTransactions[groupID].has_value()) | |||
|
121 | { | |||
|
122 | _transactions.start(groupID); | |||
|
123 | auto refVar = _variables[newTransaction.value()->refVar]; | |||
|
124 | auto ranges = _computeAllRangesInGroup(refVar,newTransaction.value()->range); | |||
|
125 | for( auto const& [ID, range] : ranges) | |||
|
126 | { | |||
|
127 | auto provider = _providers[ID]; | |||
|
128 | auto variable = _variables[ID]; | |||
|
129 | auto [missingRanges, newCacheRange] = _computeMissingRanges(variable,range); | |||
|
130 | auto exe = new TransactionExe(_variables[ID], provider, missingRanges, range, newCacheRange); | |||
|
131 | QObject::connect(exe, | |||
|
132 | &TransactionExe::transactionComplete, | |||
|
133 | [groupID=groupID,transaction=newTransaction.value(),this]() | |||
|
134 | { | |||
|
135 | this->_transactionComplete(groupID, transaction); | |||
|
136 | } | |||
|
137 | ); | |||
|
138 | _ThreadPool.start(exe); | |||
|
139 | } | |||
|
140 | } | |||
|
141 | } | |||
|
142 | } | |||
|
143 | ||||
|
144 | std::map<QUuid,DateTimeRange> _computeAllRangesInGroup(const std::shared_ptr<Variable>& refVar, DateTimeRange r) | |||
|
145 | { | |||
|
146 | std::map<QUuid,DateTimeRange> ranges; | |||
|
147 | if(!DateTimeRangeHelper::hasnan(r)) | |||
|
148 | { | |||
|
149 | auto group = _synchronizationGroups[*refVar]; | |||
|
150 | if(auto transformation = DateTimeRangeHelper::computeTransformation(refVar->range(),r); | |||
|
151 | transformation.has_value()) | |||
|
152 | { | |||
|
153 | for(auto varId:group->variables()) | |||
|
154 | { | |||
|
155 | auto var = _variables[varId]; | |||
|
156 | auto newRange = var->range().transform(transformation.value()); | |||
|
157 | ranges[varId] = newRange; | |||
|
158 | } | |||
|
159 | } | |||
|
160 | else // force new range to all variables -> may be weird if more than one var in the group | |||
|
161 | // @TODO ensure that there is no side effects | |||
|
162 | { | |||
|
163 | for(auto varId:group->variables()) | |||
|
164 | { | |||
|
165 | auto var = _variables[varId]; | |||
|
166 | ranges[varId] = r; | |||
|
167 | } | |||
|
168 | } | |||
|
169 | } | |||
|
170 | else | |||
|
171 | { | |||
|
172 | SCIQLOP_ERROR(VariableController2Private, "Invalid range containing NaN"); | |||
|
173 | } | |||
|
174 | return ranges; | |||
|
175 | } | |||
|
176 | ||||
|
177 | std::pair<std::vector<DateTimeRange>,DateTimeRange> _computeMissingRanges(const std::shared_ptr<Variable>& var, DateTimeRange r) | |||
29 | { |
|
178 | { | |
30 | auto provider = _providers[var->ID()]; |
|
|||
31 | DateTimeRange newCacheRange; |
|
179 | DateTimeRange newCacheRange; | |
32 | std::vector<DateTimeRange> missingRanges; |
|
180 | std::vector<DateTimeRange> missingRanges; | |
33 | if(DateTimeRangeHelper::hasnan(var->cacheRange())) |
|
181 | if(DateTimeRangeHelper::hasnan(var->cacheRange())) | |
@@ -40,6 +188,20 class VariableController2::VariableController2Private | |||||
40 | newCacheRange = _cacheStrategy->computeRange(var->cacheRange(),r); |
|
188 | newCacheRange = _cacheStrategy->computeRange(var->cacheRange(),r); | |
41 | missingRanges = newCacheRange - var->cacheRange(); |
|
189 | missingRanges = newCacheRange - var->cacheRange(); | |
42 | } |
|
190 | } | |
|
191 | return {missingRanges,newCacheRange}; | |||
|
192 | } | |||
|
193 | ||||
|
194 | void _changeRange(QUuid id, DateTimeRange r) | |||
|
195 | { | |||
|
196 | _lock.lockForRead(); | |||
|
197 | auto var = _variables[id]; | |||
|
198 | _lock.unlock(); | |||
|
199 | _changeRange(var,r); | |||
|
200 | } | |||
|
201 | void _changeRange(const std::shared_ptr<Variable>& var, DateTimeRange r) | |||
|
202 | { | |||
|
203 | auto provider = _providers[*var]; | |||
|
204 | auto [missingRanges, newCacheRange] = _computeMissingRanges(var,r); | |||
43 | std::vector<IDataSeries*> data; |
|
205 | std::vector<IDataSeries*> data; | |
44 | for(auto range:missingRanges) |
|
206 | for(auto range:missingRanges) | |
45 | { |
|
207 | { | |
@@ -52,19 +214,36 public: | |||||
52 | :_cacheStrategy(VariableCacheStrategyFactory::createCacheStrategy(CacheStrategy::SingleThreshold)) |
|
214 | :_cacheStrategy(VariableCacheStrategyFactory::createCacheStrategy(CacheStrategy::SingleThreshold)) | |
53 | { |
|
215 | { | |
54 | Q_UNUSED(parent); |
|
216 | Q_UNUSED(parent); | |
|
217 | this->_ThreadPool.setMaxThreadCount(32); | |||
55 | } |
|
218 | } | |
56 |
|
219 | |||
57 |
~VariableController2Private() |
|
220 | ~VariableController2Private() | |
|
221 | { | |||
|
222 | while (this->_ThreadPool.activeThreadCount()) | |||
|
223 | { | |||
|
224 | this->_ThreadPool.waitForDone(100); | |||
|
225 | } | |||
|
226 | } | |||
58 |
|
227 | |||
59 | std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata, std::shared_ptr<IDataProvider> provider) |
|
228 | std::shared_ptr<Variable> createVariable(const QString &name, const QVariantHash &metadata, std::shared_ptr<IDataProvider> provider) | |
60 | { |
|
229 | { | |
|
230 | QWriteLocker lock{&_lock}; | |||
61 | auto newVar = std::make_shared<Variable>(name,metadata); |
|
231 | auto newVar = std::make_shared<Variable>(name,metadata); | |
62 |
this->_variables[newVar |
|
232 | this->_variables[*newVar] = newVar; | |
63 |
this->_providers[newVar |
|
233 | this->_providers[*newVar] = std::move(provider); | |
64 |
|
|
234 | auto group = std::make_shared<VariableSynchronizationGroup2>(newVar->ID()); | |
|
235 | this->_synchronizationGroups[*newVar] = group; | |||
|
236 | this->_transactions.addEntry(*group); | |||
65 | return newVar; |
|
237 | return newVar; | |
66 | } |
|
238 | } | |
67 |
|
239 | |||
|
240 | bool hasPendingTransactions(const std::shared_ptr<Variable>& variable) | |||
|
241 | { | |||
|
242 | QReadLocker lock{&_lock}; | |||
|
243 | auto group = _synchronizationGroups[*variable]; | |||
|
244 | return _transactions.active(*group); | |||
|
245 | } | |||
|
246 | ||||
68 | void deleteVariable(const std::shared_ptr<Variable>& variable) |
|
247 | void deleteVariable(const std::shared_ptr<Variable>& variable) | |
69 | { |
|
248 | { | |
70 | /* |
|
249 | /* | |
@@ -72,44 +251,32 public: | |||||
72 | * this means we got the var controller in an inconsistent state |
|
251 | * this means we got the var controller in an inconsistent state | |
73 | */ |
|
252 | */ | |
74 | if(v_contains(variable)) |
|
253 | if(v_contains(variable)) | |
75 | this->_variables.remove(variable->ID()); |
|
254 | { | |
|
255 | QWriteLocker lock{&_lock}; | |||
|
256 | this->_variables.remove(*variable); | |||
|
257 | } | |||
76 | if(p_contains(variable)) |
|
258 | if(p_contains(variable)) | |
77 | this->_providers.remove(variable->ID()); |
|
259 | { | |
|
260 | QWriteLocker lock{&_lock}; | |||
|
261 | this->_providers.remove(*variable); | |||
|
262 | } | |||
78 | else |
|
263 | else | |
79 | SCIQLOP_ERROR(VariableController2Private, "No provider found for given variable"); |
|
264 | SCIQLOP_ERROR(VariableController2Private, "No provider found for given variable"); | |
80 | } |
|
265 | } | |
81 |
|
266 | |||
82 | void asyncChangeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r) |
|
267 | void asyncChangeRange(const std::shared_ptr<Variable>& variable, const DateTimeRange& r) | |
83 | { |
|
268 | { | |
84 |
|
||||
85 | } |
|
|||
86 |
|
||||
87 | void changeRange(const std::shared_ptr<Variable>& variable, DateTimeRange r) |
|
|||
88 | { |
|
|||
89 | if(p_contains(variable)) |
|
269 | if(p_contains(variable)) | |
90 | { |
|
270 | { | |
91 | if(!DateTimeRangeHelper::hasnan(r)) |
|
271 | if(!DateTimeRangeHelper::hasnan(r)) | |
92 | { |
|
272 | { | |
93 |
auto group = _synchronizationGroups[variable |
|
273 | auto group = _synchronizationGroups[*variable]; | |
94 | if(auto transformation = DateTimeRangeHelper::computeTransformation(variable->range(),r); |
|
274 | // Just overwrite next transaction | |
95 | transformation.has_value()) |
|
|||
96 | { |
|
|||
97 | for(auto varId:group->variables()) |
|
|||
98 | { |
|
|||
99 | auto var = _variables[varId]; |
|
|||
100 | auto newRange = var->range().transform(transformation.value()); |
|
|||
101 | _changeRange(var,newRange); |
|
|||
102 | } |
|
|||
103 | } |
|
|||
104 | else // force new range to all variables -> may be weird if more than one var in the group |
|
|||
105 | // @TODO ensure that there is no side effects |
|
|||
106 | { |
|
|||
107 | for(auto varId:group->variables()) |
|
|||
108 |
|
|
275 | { | |
109 | auto var = _variables[varId]; |
|
276 | QWriteLocker lock{&_lock}; | |
110 | _changeRange(var,r); |
|
277 | _transactions.enqueue(*group,std::make_shared<VCTransaction>(variable->ID(), r, static_cast<int>(group->variables().size()))); | |
111 | } |
|
|||
112 | } |
|
278 | } | |
|
279 | _processTransactions(); | |||
113 | } |
|
280 | } | |
114 | else |
|
281 | else | |
115 | { |
|
282 | { | |
@@ -122,16 +289,25 public: | |||||
122 | } |
|
289 | } | |
123 | } |
|
290 | } | |
124 |
|
291 | |||
|
292 | void changeRange(const std::shared_ptr<Variable>& variable, DateTimeRange r) | |||
|
293 | { | |||
|
294 | auto ranges = _computeAllRangesInGroup(variable,r); | |||
|
295 | for( auto const& [ID, range] : ranges) | |||
|
296 | { | |||
|
297 | _changeRange(ID,range); | |||
|
298 | } | |||
|
299 | } | |||
|
300 | ||||
125 | void synchronize(const std::shared_ptr<Variable>& var, const std::shared_ptr<Variable>& with) |
|
301 | void synchronize(const std::shared_ptr<Variable>& var, const std::shared_ptr<Variable>& with) | |
126 | { |
|
302 | { | |
127 | if(v_contains(var) && v_contains(with)) |
|
303 | if(v_contains(var) && v_contains(with)) | |
128 | { |
|
304 | { | |
129 | if(sg_contains(var) && sg_contains(with)) |
|
305 | if(sg_contains(var) && sg_contains(with)) | |
130 | { |
|
306 | { | |
131 |
|
307 | QWriteLocker lock{&_lock}; | ||
132 | auto dest_group = this->_synchronizationGroups[with->ID()]; |
|
308 | auto dest_group = this->_synchronizationGroups[with->ID()]; | |
133 |
this->_synchronizationGroups[var |
|
309 | this->_synchronizationGroups[*var] = dest_group; | |
134 |
dest_group->addVariable(var |
|
310 | dest_group->addVariable(*var); | |
135 | } |
|
311 | } | |
136 | else |
|
312 | else | |
137 | { |
|
313 | { | |
@@ -147,6 +323,7 public: | |||||
147 | const std::set<std::shared_ptr<Variable>> variables() |
|
323 | const std::set<std::shared_ptr<Variable>> variables() | |
148 | { |
|
324 | { | |
149 | std::set<std::shared_ptr<Variable>> vars; |
|
325 | std::set<std::shared_ptr<Variable>> vars; | |
|
326 | QReadLocker lock{&_lock}; | |||
150 | for(const auto &var:_variables) |
|
327 | for(const auto &var:_variables) | |
151 | { |
|
328 | { | |
152 | vars.insert(var); |
|
329 | vars.insert(var); | |
@@ -192,8 +369,12 const std::set<std::shared_ptr<Variable> > VariableController2::variables() | |||||
192 | return impl->variables(); |
|
369 | return impl->variables(); | |
193 | } |
|
370 | } | |
194 |
|
371 | |||
|
372 | bool VariableController2::isReady(const std::shared_ptr<Variable> &variable) | |||
|
373 | { | |||
|
374 | return impl->hasPendingTransactions(variable); | |||
|
375 | } | |||
|
376 | ||||
195 | void VariableController2::synchronize(const std::shared_ptr<Variable> &var, const std::shared_ptr<Variable> &with) |
|
377 | void VariableController2::synchronize(const std::shared_ptr<Variable> &var, const std::shared_ptr<Variable> &with) | |
196 | { |
|
378 | { | |
197 | impl->synchronize(var, with); |
|
379 | impl->synchronize(var, with); | |
198 | } |
|
380 | } | |
199 |
|
@@ -46,4 +46,5 declare_test(TestDownloader TestDownloader Network/TestDownloader.cpp "sciqlopco | |||||
46 |
|
46 | |||
47 |
|
47 | |||
48 | declare_test(TestVariableController2 TestVariableController2 Variable/TestVariableController2.cpp "sciqlopcore;TestUtils;Qt5::Test") |
|
48 | declare_test(TestVariableController2 TestVariableController2 Variable/TestVariableController2.cpp "sciqlopcore;TestUtils;Qt5::Test") | |
|
49 | declare_test(TestVariableController2Async TestVariableController2Async Variable/TestVariableController2Async.cpp "sciqlopcore;TestUtils;Qt5::Test") | |||
49 | declare_test(TestVariableController2WithSync TestVariableController2WithSync Variable/TestVariableController2WithSync.cpp "sciqlopcore;TestUtils;Qt5::Test") |
|
50 | declare_test(TestVariableController2WithSync TestVariableController2WithSync Variable/TestVariableController2WithSync.cpp "sciqlopcore;TestUtils;Qt5::Test") |
General Comments 0
You need to be logged in to leave comments.
Login now