Skip to content

Commit

Permalink
option to specify sort worker and task executor
Browse files Browse the repository at this point in the history
  • Loading branch information
sgratzl committed Dec 8, 2018
1 parent 70ffce3 commit abad235
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 17 deletions.
34 changes: 23 additions & 11 deletions src/provider/LocalDataProvider.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {ISequence, lazySeq} from '../internal/interable';
import Column, {defaultGroup, IColumnDesc, IDataRow, IGroup, IndicesArray, INumberColumn, IOrderedGroup, mapIndices} from '../model';
import Column, {defaultGroup, IColumnDesc, ICompareValue, IDataRow, IGroup, IndicesArray, INumberColumn, IOrderedGroup, mapIndices} from '../model';
import Ranking, {EDirtyReason} from '../model/Ranking';
import ACommonDataProvider from './ACommonDataProvider';
import ADataProvider from './ADataProvider';
import {IDataProviderOptions} from './interfaces';
import {chooseByLength, CompareLookup, ISortWorker, sortComplex, WorkerSortWorker} from './sort';
import {ScheduleRenderTasks} from './tasks';
import {chooseByLength, CompareLookup, ISortWorker, local, sortComplex, WorkerSortWorker} from './sort';
import {DirectRenderTasks, IRenderTaskExectutor, ScheduleRenderTasks} from './tasks';


export interface ILocalDataProviderOptions {
Expand All @@ -19,6 +19,16 @@ export interface ILocalDataProviderOptions {
* default: false
*/
jumpToSearchResult: boolean;

/**
* specify the sort worker to use local = direct or webworker = run in a webworker
*/
sortWorker: 'local' | 'webworker';

/**
* specify the task executor to use direct = no delay, scheduled = run when idle
*/
taskExecutor: 'direct' | 'scheduled';
}

interface ISortHelper {
Expand All @@ -36,21 +46,26 @@ export default class LocalDataProvider extends ACommonDataProvider {
*/
filterGlobally: false,

jumpToSearchResult: false
jumpToSearchResult: false,

sortWorker: 'local',
taskExecutor: 'direct'
};

private readonly reorderAll: () => void;

private _dataRows: IDataRow[];
private filter: ((row: IDataRow) => boolean) | null = null;
private readonly sortWorker: ISortWorker = new WorkerSortWorker();
private readonly tasks: ScheduleRenderTasks;
private readonly sortWorker: ISortWorker;
private readonly tasks: IRenderTaskExectutor;

constructor(private _data: any[], columns: IColumnDesc[] = [], options: Partial<ILocalDataProviderOptions & IDataProviderOptions> = {}) {
super(columns, options);
Object.assign(this.options, options);
this._dataRows = toRows(_data);
this.tasks = new ScheduleRenderTasks(this._dataRows);
this.sortWorker = this.options.sortWorker === 'local' ? local : new WorkerSortWorker();
this.tasks = this.options.taskExecutor === 'direct' ? new DirectRenderTasks() : new ScheduleRenderTasks();
this.tasks.setData(this._dataRows);

const that = this;
this.reorderAll = function (this: {source?: Ranking, type: string}) {
Expand Down Expand Up @@ -142,7 +157,6 @@ export default class LocalDataProvider extends ACommonDataProvider {
}

this.tasks.dirtyRanking(ranking, 'data');
this.tasks.abortAll((t) => t.id.startsWith(`r${ranking.id}:`));

super.cleanUpRanking(ranking);
}
Expand Down Expand Up @@ -215,8 +229,7 @@ export default class LocalDataProvider extends ACommonDataProvider {
const sortTask = this.sortWorker.sort(g.rows, singleGroup, lookups);

// compute sort group value as task
const groupSortTask = groupLookup ? this.tasks
.push(`r${ranking.id}:${group.name}`, () => ranking.toGroupCompareValue(this.view(g.rows), group)) : [];
const groupSortTask = groupLookup ? this.tasks.groupCompare(ranking, group, this.view(g.rows)).then((r) => r) : <ICompareValue[]>[];

return Promise.all([sortTask, groupSortTask]).then(([order, groupC]) => {
if (groupLookup && Array.isArray(groupC)) {
Expand Down Expand Up @@ -254,7 +267,6 @@ export default class LocalDataProvider extends ACommonDataProvider {
sort(ranking: Ranking, _dirtyReason?: EDirtyReason) {
// TOOD optimize to just clear groups if the filter hasn't changed
this.tasks.dirtyRanking(ranking, 'summary');
this.tasks.abortAll((t) => t.id.startsWith(`r${ranking.id}:`));

if (this._data.length === 0) {
return {groups: [], index2pos: []};
Expand Down
44 changes: 38 additions & 6 deletions src/provider/tasks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {IStatistics, ICategoricalStatistics, IDateStatistics, IAdvancedBoxPlotData, computeDateStats, computeNormalizedStats, computeHist, computeBoxPlot} from '../internal/math';
import {IDataRow, INumberColumn, IDateColumn, ISetColumn, IOrderedGroup, IndicesArray, Ranking, ICategoricalLikeColumn} from '../model';
import Column from '../model/Column';
import {IDataRow, INumberColumn, IDateColumn, ISetColumn, IOrderedGroup, IndicesArray, Ranking, ICategoricalLikeColumn, IGroup} from '../model';
import Column, {ICompareValue} from '../model/Column';
import {ISequence, lazySeq} from '../internal/interable';
import {IAbortAblePromise, ABORTED, abortAbleAll} from 'lineupengine';
import TaskScheduler from '../internal/scheduler';
Expand Down Expand Up @@ -61,13 +61,21 @@ export interface IRenderTasks {
summaryDateStats(col: Column & IDateColumn): IRenderTask<{summary: IDateStatistics, data: IDateStatistics}>;
}

export interface IRenderTaskExectutor extends IRenderTasks {
setData(data: IDataRow[]): void;
dirtyColumn(col: Column, type: 'data' | 'summary' | 'group'): void;
dirtyRanking(ranking: Ranking, type: 'data' | 'summary' | 'group'): void;

export class DirectRenderTasks implements IRenderTasks {
groupCompare(ranking: Ranking, group: IGroup, rows: ISequence<IDataRow>): IRenderTask<ICompareValue[]>;
}


export class DirectRenderTasks implements IRenderTaskExectutor {
private readonly byIndex = (i: number) => this.data[i];

private readonly dataCache = new Map<string, any>();

constructor(private data: IDataRow[]) {
constructor(private data: IDataRow[] = []) {

}

Expand All @@ -76,17 +84,35 @@ export class DirectRenderTasks implements IRenderTasks {
this.dataCache.clear();
}

dirtyColumn(col: Column) {
dirtyColumn(col: Column, type: 'data' | 'summary' | 'group') {
if (type !== 'data') {
// only data is cached
return;
}
this.dataCache.delete(col.id);
this.dataCache.delete(`${col.id}.raw`);
this.dataCache.delete(`${col.id}.b`);
this.dataCache.delete(`${col.id}.braw`);
}

dirtyRanking(ranking: Ranking, type: 'data' | 'summary' | 'group') {
if (type !== 'data') {
return;
}

for (const col of ranking.flatColumns) {
this.dirtyColumn(col, 'data');
}
}

private byOrder(indices: IndicesArray) {
return lazySeq(indices).map(this.byIndex);
}

groupCompare(ranking: Ranking, group: IGroup, rows: ISequence<IDataRow>) {
return taskNow(ranking.toGroupCompareValue(rows, group));
}

groupRows<T>(_col: Column, group: IOrderedGroup, _key: string, compute: (rows: ISequence<IDataRow>) => T) {
return taskNow(compute(this.byOrder(group.order)));
}
Expand Down Expand Up @@ -191,7 +217,7 @@ export class DirectRenderTasks implements IRenderTasks {
}


export class ScheduleRenderTasks extends TaskScheduler implements IRenderTasks {
export class ScheduleRenderTasks extends TaskScheduler implements IRenderTaskExectutor {
private readonly byIndex = (i: number) => this.data[i];

private readonly cache = new Map<string, any>();
Expand Down Expand Up @@ -244,12 +270,18 @@ export class ScheduleRenderTasks extends TaskScheduler implements IRenderTasks {
this.abort(key);
}
}
// group compare tasks
this.abortAll((t) => t.id.startsWith(`r${ranking.id}:`));
}

private byOrder(indices: IndicesArray) {
return lazySeq(indices).map(this.byIndex);
}

groupCompare(ranking: Ranking, group: IGroup, rows: ISequence<IDataRow>) {
return taskLater(this.push(`r${ranking.id}:${group.name}`, () => ranking.toGroupCompareValue(rows, group)));
}

groupRows<T>(col: Column, group: IOrderedGroup, key: string, compute: (rows: ISequence<IDataRow>) => T) {
return this.cached(`${col.id}:a:group:${group.name}:${key}`, () => compute(this.byOrder(group.order)));
}
Expand Down

0 comments on commit abad235

Please sign in to comment.