Sort and merge incoming telemetry (#5042)

* use sort and merge sorted strategy for incoming data
* add shortcut for merging to beginning or end of existing rows

Co-authored-by: Andrew Henry <akhenry@gmail.com>
This commit is contained in:
David Tsay 2022-04-22 16:51:47 -07:00 committed by GitHub
parent 1ed253cb07
commit 5236f1c796
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -29,10 +29,6 @@ define(
_, _,
EventEmitter EventEmitter
) { ) {
const LESS_THAN = -1;
const EQUAL = 0;
const GREATER_THAN = 1;
/** /**
* @constructor * @constructor
*/ */
@ -80,10 +76,7 @@ define(
this.rows = []; this.rows = [];
} }
for (let row of rowsToAdd) { this.sortAndMergeRows(rowsToAdd);
let index = this.sortedIndex(this.rows, row);
this.rows.splice(index, 0, row);
}
// we emit filter no matter what to trigger // we emit filter no matter what to trigger
// an update of visible rows // an update of visible rows
@ -92,58 +85,85 @@ define(
} }
} }
sortedLastIndex(rows, testRow) { sortAndMergeRows(rows) {
return this.sortedIndex(rows, testRow, _.sortedLastIndex); const sortedRowsToAdd = this.sortCollection(rows);
}
/**
* Finds the correct insertion point for the given row.
* Leverages lodash's `sortedIndex` function which implements a binary search.
* @private
*/
sortedIndex(rows, testRow, lodashFunction = _.sortedIndexBy) {
if (this.rows.length === 0) { if (this.rows.length === 0) {
return 0; this.rows = sortedRowsToAdd;
return;
} }
const testRowValue = this.getValueForSortColumn(testRow); const firstIncomingRow = sortedRowsToAdd[0];
const firstValue = this.getValueForSortColumn(this.rows[0]); const lastIncomingRow = sortedRowsToAdd[sortedRowsToAdd.length - 1];
const lastValue = this.getValueForSortColumn(this.rows[this.rows.length - 1]); const firstExistingRow = this.rows[0];
const lastExistingRow = this.rows[this.rows.length - 1];
if (this.firstRowInSortOrder(lastIncomingRow, firstExistingRow)
=== lastIncomingRow
) {
this.rows = [...sortedRowsToAdd, ...this.rows];
} else if (this.firstRowInSortOrder(lastExistingRow, firstIncomingRow)
=== lastExistingRow
) {
this.rows = [...this.rows, ...sortedRowsToAdd];
} else {
this.mergeSortedRows(sortedRowsToAdd);
}
}
sortCollection(rows) {
const sortedRows = _.orderBy(
rows,
row => row.getParsedValue(this.sortOptions.key), this.sortOptions.direction
);
return sortedRows;
}
mergeSortedRows(rows) {
const mergedRows = [];
let i = 0;
let j = 0;
while (i < this.rows.length && j < rows.length) {
const existingRow = this.rows[i];
const incomingRow = rows[j];
if (this.firstRowInSortOrder(existingRow, incomingRow) === existingRow) {
mergedRows.push(existingRow);
i++;
} else {
mergedRows.push(incomingRow);
j++;
}
}
// tail of existing rows is all that is left to merge
if (i < this.rows.length) {
for (i; i < this.rows.length; i++) {
mergedRows.push(this.rows[i]);
}
}
// tail of incoming rows is all that is left to merge
if (j < rows.length) {
for (j; j < rows.length; j++) {
mergedRows.push(rows[j]);
}
}
this.rows = mergedRows;
}
firstRowInSortOrder(row1, row2) {
const val1 = this.getValueForSortColumn(row1);
const val2 = this.getValueForSortColumn(row2);
if (this.sortOptions.direction === 'asc') { if (this.sortOptions.direction === 'asc') {
if (testRowValue > lastValue) { return val1 <= val2 ? row1 : row2;
return this.rows.length;
} else if (testRowValue === lastValue) {
// Maintain stable sort
return this.rows.length;
} else if (testRowValue <= firstValue) {
return 0;
} else { } else {
return lodashFunction(rows, testRow, (thisRow) => { return val1 >= val2 ? row1 : row2;
return this.getValueForSortColumn(thisRow);
});
}
} else {
if (testRowValue >= firstValue) {
return 0;
} else if (testRowValue < lastValue) {
return this.rows.length;
} else if (testRowValue === lastValue) {
// Maintain stable sort
return this.rows.length;
} else {
// Use a custom comparison function to support descending sort.
return lodashFunction(rows, testRow, (thisRow) => {
const thisRowValue = this.getValueForSortColumn(thisRow);
if (testRowValue === thisRowValue) {
return EQUAL;
} else if (testRowValue < thisRowValue) {
return LESS_THAN;
} else {
return GREATER_THAN;
}
});
}
} }
} }