Showing
1 changed file
with
69 additions
and
16 deletions
... | ... | @@ -36,8 +36,56 @@ interface AggData { |
36 | 36 | aggValue: any; |
37 | 37 | } |
38 | 38 | |
39 | -interface AggregationMap { | |
40 | - [key: string]: Map<number, AggData>; | |
39 | +class AggDataMap { | |
40 | + rangeChanged = false; | |
41 | + private minTs = Number.MAX_SAFE_INTEGER; | |
42 | + private map = new Map<number, AggData>(); | |
43 | + | |
44 | + set(ts: number, data: AggData) { | |
45 | + if (ts < this.minTs) { | |
46 | + this.rangeChanged = true; | |
47 | + this.minTs = ts; | |
48 | + } | |
49 | + this.map.set(ts, data); | |
50 | + } | |
51 | + | |
52 | + get(ts: number): AggData { | |
53 | + return this.map.get(ts); | |
54 | + } | |
55 | + | |
56 | + delete(ts: number) { | |
57 | + this.map.delete(ts); | |
58 | + } | |
59 | + | |
60 | + forEach(callback: (value: AggData, key: number, map: Map<number, AggData>) => void, thisArg?: any) { | |
61 | + this.map.forEach(callback, thisArg); | |
62 | + } | |
63 | + | |
64 | + size(): number { | |
65 | + return this.map.size; | |
66 | + } | |
67 | +} | |
68 | + | |
69 | +class AggregationMap { | |
70 | + aggMap: {[key: string]: AggDataMap} = {}; | |
71 | + | |
72 | + detectRangeChanged(): boolean { | |
73 | + let changed = false; | |
74 | + for (const key of Object.keys(this.aggMap)) { | |
75 | + const aggDataMap = this.aggMap[key]; | |
76 | + if (aggDataMap.rangeChanged) { | |
77 | + changed = true; | |
78 | + aggDataMap.rangeChanged = false; | |
79 | + } | |
80 | + } | |
81 | + return changed; | |
82 | + } | |
83 | + | |
84 | + clearRangeChangedFlags() { | |
85 | + for (const key of Object.keys(this.aggMap)) { | |
86 | + this.aggMap[key].rangeChanged = false; | |
87 | + } | |
88 | + } | |
41 | 89 | } |
42 | 90 | |
43 | 91 | declare type AggFunction = (aggData: AggData, value?: any) => void; |
... | ... | @@ -170,7 +218,7 @@ export class DataAggregator { |
170 | 218 | updateIntervalScheduledTime = false; |
171 | 219 | } |
172 | 220 | if (update) { |
173 | - this.aggregationMap = {}; | |
221 | + this.aggregationMap = new AggregationMap(); | |
174 | 222 | this.updateAggregatedData(data.data); |
175 | 223 | } else { |
176 | 224 | this.aggregationMap = this.processAggregatedData(data.data); |
... | ... | @@ -178,12 +226,17 @@ export class DataAggregator { |
178 | 226 | if (updateIntervalScheduledTime) { |
179 | 227 | this.intervalScheduledTime = this.utils.currentPerfTime(); |
180 | 228 | } |
229 | + this.aggregationMap.clearRangeChangedFlags(); | |
181 | 230 | this.onInterval(history, detectChanges); |
182 | 231 | } else { |
183 | 232 | this.updateAggregatedData(data.data); |
184 | 233 | if (history) { |
185 | 234 | this.intervalScheduledTime = this.utils.currentPerfTime(); |
186 | 235 | this.onInterval(history, detectChanges); |
236 | + } else { | |
237 | + if (this.aggregationMap.detectRangeChanged()) { | |
238 | + this.onInterval(false, detectChanges, true); | |
239 | + } | |
187 | 240 | } |
188 | 241 | } |
189 | 242 | } |
... | ... | @@ -203,7 +256,7 @@ export class DataAggregator { |
203 | 256 | } |
204 | 257 | } |
205 | 258 | |
206 | - private onInterval(history?: boolean, detectChanges?: boolean) { | |
259 | + private onInterval(history?: boolean, detectChanges?: boolean, rangeChanged?: boolean) { | |
207 | 260 | const now = this.utils.currentPerfTime(); |
208 | 261 | this.elapsed += now - this.intervalScheduledTime; |
209 | 262 | this.intervalScheduledTime = now; |
... | ... | @@ -211,9 +264,10 @@ export class DataAggregator { |
211 | 264 | clearTimeout(this.intervalTimeoutHandle); |
212 | 265 | this.intervalTimeoutHandle = null; |
213 | 266 | } |
267 | + const intervalTimeout = rangeChanged ? this.aggregationTimeout - this.elapsed : this.aggregationTimeout; | |
214 | 268 | if (!history) { |
215 | 269 | const delta = Math.floor(this.elapsed / this.subsTw.aggregation.interval); |
216 | - if (delta || !this.data) { | |
270 | + if (delta || !this.data || rangeChanged) { | |
217 | 271 | const tickTs = delta * this.subsTw.aggregation.interval; |
218 | 272 | if (this.subsTw.quickInterval) { |
219 | 273 | const currentDate = this.getCurrentTime(); |
... | ... | @@ -234,7 +288,7 @@ export class DataAggregator { |
234 | 288 | this.updatedData = false; |
235 | 289 | } |
236 | 290 | if (!history) { |
237 | - this.intervalTimeoutHandle = setTimeout(this.onInterval.bind(this), this.aggregationTimeout); | |
291 | + this.intervalTimeoutHandle = setTimeout(this.onInterval.bind(this), intervalTimeout); | |
238 | 292 | } |
239 | 293 | } |
240 | 294 | |
... | ... | @@ -242,8 +296,8 @@ export class DataAggregator { |
242 | 296 | this.tsKeyNames.forEach((key) => { |
243 | 297 | this.dataBuffer[key] = []; |
244 | 298 | }); |
245 | - for (const key of Object.keys(this.aggregationMap)) { | |
246 | - const aggKeyData = this.aggregationMap[key]; | |
299 | + for (const key of Object.keys(this.aggregationMap.aggMap)) { | |
300 | + const aggKeyData = this.aggregationMap.aggMap[key]; | |
247 | 301 | let keyData = this.dataBuffer[key]; |
248 | 302 | aggKeyData.forEach((aggData, aggTimestamp) => { |
249 | 303 | if (aggTimestamp <= this.startTs) { |
... | ... | @@ -300,12 +354,12 @@ export class DataAggregator { |
300 | 354 | |
301 | 355 | private processAggregatedData(data: SubscriptionData): AggregationMap { |
302 | 356 | const isCount = this.subsTw.aggregation.type === AggregationType.COUNT; |
303 | - const aggregationMap: AggregationMap = {}; | |
357 | + const aggregationMap = new AggregationMap(); | |
304 | 358 | for (const key of Object.keys(data)) { |
305 | - let aggKeyData = aggregationMap[key]; | |
359 | + let aggKeyData = aggregationMap.aggMap[key]; | |
306 | 360 | if (!aggKeyData) { |
307 | - aggKeyData = new Map<number, AggData>(); | |
308 | - aggregationMap[key] = aggKeyData; | |
361 | + aggKeyData = new AggDataMap(); | |
362 | + aggregationMap.aggMap[key] = aggKeyData; | |
309 | 363 | } |
310 | 364 | const keyData = data[key]; |
311 | 365 | keyData.forEach((kvPair) => { |
... | ... | @@ -326,10 +380,10 @@ export class DataAggregator { |
326 | 380 | private updateAggregatedData(data: SubscriptionData) { |
327 | 381 | const isCount = this.subsTw.aggregation.type === AggregationType.COUNT; |
328 | 382 | for (const key of Object.keys(data)) { |
329 | - let aggKeyData = this.aggregationMap[key]; | |
383 | + let aggKeyData = this.aggregationMap.aggMap[key]; | |
330 | 384 | if (!aggKeyData) { |
331 | - aggKeyData = new Map<number, AggData>(); | |
332 | - this.aggregationMap[key] = aggKeyData; | |
385 | + aggKeyData = new AggDataMap(); | |
386 | + this.aggregationMap.aggMap[key] = aggKeyData; | |
333 | 387 | } |
334 | 388 | const keyData = data[key]; |
335 | 389 | keyData.forEach((kvPair) => { |
... | ... | @@ -374,4 +428,3 @@ export class DataAggregator { |
374 | 428 | } |
375 | 429 | |
376 | 430 | } |
377 | - | ... | ... |