Commit 0f9cecafbd7d5399506108f6227de2d4dad6ad4a

Authored by Igor Kulikov
1 parent fbb3d85e

Improve data aggregator to send updates on late data

@@ -36,8 +36,56 @@ interface AggData { @@ -36,8 +36,56 @@ interface AggData {
36 aggValue: any; 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 declare type AggFunction = (aggData: AggData, value?: any) => void; 91 declare type AggFunction = (aggData: AggData, value?: any) => void;
@@ -170,7 +218,7 @@ export class DataAggregator { @@ -170,7 +218,7 @@ export class DataAggregator {
170 updateIntervalScheduledTime = false; 218 updateIntervalScheduledTime = false;
171 } 219 }
172 if (update) { 220 if (update) {
173 - this.aggregationMap = {}; 221 + this.aggregationMap = new AggregationMap();
174 this.updateAggregatedData(data.data); 222 this.updateAggregatedData(data.data);
175 } else { 223 } else {
176 this.aggregationMap = this.processAggregatedData(data.data); 224 this.aggregationMap = this.processAggregatedData(data.data);
@@ -178,12 +226,17 @@ export class DataAggregator { @@ -178,12 +226,17 @@ export class DataAggregator {
178 if (updateIntervalScheduledTime) { 226 if (updateIntervalScheduledTime) {
179 this.intervalScheduledTime = this.utils.currentPerfTime(); 227 this.intervalScheduledTime = this.utils.currentPerfTime();
180 } 228 }
  229 + this.aggregationMap.clearRangeChangedFlags();
181 this.onInterval(history, detectChanges); 230 this.onInterval(history, detectChanges);
182 } else { 231 } else {
183 this.updateAggregatedData(data.data); 232 this.updateAggregatedData(data.data);
184 if (history) { 233 if (history) {
185 this.intervalScheduledTime = this.utils.currentPerfTime(); 234 this.intervalScheduledTime = this.utils.currentPerfTime();
186 this.onInterval(history, detectChanges); 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,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 const now = this.utils.currentPerfTime(); 260 const now = this.utils.currentPerfTime();
208 this.elapsed += now - this.intervalScheduledTime; 261 this.elapsed += now - this.intervalScheduledTime;
209 this.intervalScheduledTime = now; 262 this.intervalScheduledTime = now;
@@ -211,9 +264,10 @@ export class DataAggregator { @@ -211,9 +264,10 @@ export class DataAggregator {
211 clearTimeout(this.intervalTimeoutHandle); 264 clearTimeout(this.intervalTimeoutHandle);
212 this.intervalTimeoutHandle = null; 265 this.intervalTimeoutHandle = null;
213 } 266 }
  267 + const intervalTimeout = rangeChanged ? this.aggregationTimeout - this.elapsed : this.aggregationTimeout;
214 if (!history) { 268 if (!history) {
215 const delta = Math.floor(this.elapsed / this.subsTw.aggregation.interval); 269 const delta = Math.floor(this.elapsed / this.subsTw.aggregation.interval);
216 - if (delta || !this.data) { 270 + if (delta || !this.data || rangeChanged) {
217 const tickTs = delta * this.subsTw.aggregation.interval; 271 const tickTs = delta * this.subsTw.aggregation.interval;
218 if (this.subsTw.quickInterval) { 272 if (this.subsTw.quickInterval) {
219 const currentDate = this.getCurrentTime(); 273 const currentDate = this.getCurrentTime();
@@ -234,7 +288,7 @@ export class DataAggregator { @@ -234,7 +288,7 @@ export class DataAggregator {
234 this.updatedData = false; 288 this.updatedData = false;
235 } 289 }
236 if (!history) { 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,8 +296,8 @@ export class DataAggregator {
242 this.tsKeyNames.forEach((key) => { 296 this.tsKeyNames.forEach((key) => {
243 this.dataBuffer[key] = []; 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 let keyData = this.dataBuffer[key]; 301 let keyData = this.dataBuffer[key];
248 aggKeyData.forEach((aggData, aggTimestamp) => { 302 aggKeyData.forEach((aggData, aggTimestamp) => {
249 if (aggTimestamp <= this.startTs) { 303 if (aggTimestamp <= this.startTs) {
@@ -300,12 +354,12 @@ export class DataAggregator { @@ -300,12 +354,12 @@ export class DataAggregator {
300 354
301 private processAggregatedData(data: SubscriptionData): AggregationMap { 355 private processAggregatedData(data: SubscriptionData): AggregationMap {
302 const isCount = this.subsTw.aggregation.type === AggregationType.COUNT; 356 const isCount = this.subsTw.aggregation.type === AggregationType.COUNT;
303 - const aggregationMap: AggregationMap = {}; 357 + const aggregationMap = new AggregationMap();
304 for (const key of Object.keys(data)) { 358 for (const key of Object.keys(data)) {
305 - let aggKeyData = aggregationMap[key]; 359 + let aggKeyData = aggregationMap.aggMap[key];
306 if (!aggKeyData) { 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 const keyData = data[key]; 364 const keyData = data[key];
311 keyData.forEach((kvPair) => { 365 keyData.forEach((kvPair) => {
@@ -326,10 +380,10 @@ export class DataAggregator { @@ -326,10 +380,10 @@ export class DataAggregator {
326 private updateAggregatedData(data: SubscriptionData) { 380 private updateAggregatedData(data: SubscriptionData) {
327 const isCount = this.subsTw.aggregation.type === AggregationType.COUNT; 381 const isCount = this.subsTw.aggregation.type === AggregationType.COUNT;
328 for (const key of Object.keys(data)) { 382 for (const key of Object.keys(data)) {
329 - let aggKeyData = this.aggregationMap[key]; 383 + let aggKeyData = this.aggregationMap.aggMap[key];
330 if (!aggKeyData) { 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 const keyData = data[key]; 388 const keyData = data[key];
335 keyData.forEach((kvPair) => { 389 keyData.forEach((kvPair) => {
@@ -374,4 +428,3 @@ export class DataAggregator { @@ -374,4 +428,3 @@ export class DataAggregator {
374 } 428 }
375 429
376 } 430 }
377 -