Skip to content

Commit

Permalink
Don't spin up extraneous run-loops and overload schedule
Browse files Browse the repository at this point in the history
  • Loading branch information
runspired committed Dec 21, 2016
1 parent 989d4c6 commit 7efa6a1
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 37 deletions.
7 changes: 7 additions & 0 deletions addon/-private/adapters/build-url-mixin.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ export default Ember.Mixin.create({
@return {String} url
*/
buildURL(modelName, id, snapshot, requestType, query) {
let token = heimdall.start('adapter.buildUrl');
let ret = this.__measuredBuildURL(modelName, id, snapshot, requestType, query);
heimdall.stop(token);
return ret;
},

__measuredBuildURL(modelName, id, snapshot, requestType, query) {
switch (requestType) {
case 'findRecord':
return this.urlForFindRecord(id, modelName, snapshot);
Expand Down
26 changes: 9 additions & 17 deletions addon/-private/system/model/internal-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export default class InternalModel {
this._isDestroyed = false;
this.isError = false;
this.error = null;
this._isUpdatingRecordArrays = false;

// caches for lazy getters
this._modelClass = null;
Expand Down Expand Up @@ -376,7 +377,7 @@ export default class InternalModel {
}

becameReady() {
emberRun.schedule('actions', this.store.recordArrayManager, this.store.recordArrayManager.recordWasLoaded, this);
this.store.recordArrayManager.recordWasLoaded(this);
}

didInitializeData() {
Expand Down Expand Up @@ -521,7 +522,7 @@ export default class InternalModel {
*/
adapterDidDirty() {
this.send('becomeDirty');
this.updateRecordArraysLater();
this.updateRecordArrays();
}

/*
Expand Down Expand Up @@ -654,7 +655,7 @@ export default class InternalModel {
setups[i].setup(this);
}

this.updateRecordArraysLater();
this.updateRecordArrays();
}

_unhandledEvent(state, name, context) {
Expand All @@ -673,6 +674,7 @@ export default class InternalModel {
if (this._deferredTriggers.push(args) !== 1) {
return;
}

emberRun.schedule('actions', this, this._triggerDeferredTriggers);
}

Expand Down Expand Up @@ -784,8 +786,9 @@ export default class InternalModel {
@private
*/
updateRecordArrays() {
this._updatingRecordArraysLater = false;
this.store._dataWasUpdated(this);
if (this._isUpdatingRecordArrays) { return; }
this._isUpdatingRecordArrays = true;
this.store.recordArrayManager.recordDidChange(this);
}

setId(id) {
Expand Down Expand Up @@ -843,24 +846,13 @@ export default class InternalModel {
this._inFlightAttributes = new EmptyObject();

this.send('didCommit');
this.updateRecordArraysLater();
this.updateRecordArrays();

if (!data) { return; }

this.record._notifyProperties(changedKeys);
}

/*
@method updateRecordArraysLater
@private
*/
updateRecordArraysLater() {
// quick hack (something like this could be pushed into run.once
if (this._updatingRecordArraysLater) { return; }
this._updatingRecordArraysLater = true;
emberRun.schedule('actions', this, this.updateRecordArrays);
}

addErrorMessageToAttribute(attribute, message) {
get(this.getRecord(), 'errors')._add(attribute, message);
}
Expand Down
2 changes: 1 addition & 1 deletion addon/-private/system/model/states.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ function didSetProperty(internalModel, context) {
internalModel.send('becomeDirty');
}

internalModel.updateRecordArraysLater();
internalModel.updateRecordArrays();
}

// Implementation notes:
Expand Down
56 changes: 40 additions & 16 deletions addon/-private/system/record-array-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const {
_addRecordToRecordArray,
_recordWasChanged,
_recordWasDeleted,
_flushLoadedRecords,
array_flatten,
array_remove,
create,
Expand All @@ -41,6 +42,7 @@ const {
'_addInternalModelToRecordArray',
'_recordWasChanged',
'_recordWasDeleted',
'_flushLoadedRecords',
'array_fatten',
'array_remove',
'create',
Expand Down Expand Up @@ -80,12 +82,13 @@ export default Ember.Object.extend({
});

this.changedRecords = [];
this.loadedRecords = [];
this._adapterPopulatedRecordArrays = [];
},

recordDidChange(record) {
recordDidChange(internalModel) {
heimdall.increment(recordDidChange);
if (this.changedRecords.push(record) !== 1) { return; }
if (this.changedRecords.push(internalModel) !== 1) { return; }

emberRun.schedule('actions', this, this.updateRecordArrays);
},
Expand All @@ -108,17 +111,22 @@ export default Ember.Object.extend({
*/
updateRecordArrays() {
heimdall.increment(updateRecordArrays);
this.changedRecords.forEach(internalModel => {
let updated = this.changedRecords;

for (let i = 0, l = updated.length; i < l; i++) {
let internalModel = updated[i];

if (internalModel.isDestroyed ||
internalModel.currentState.stateName === 'root.deleted.saved') {
internalModel.currentState.stateName === 'root.deleted.saved') {
this._recordWasDeleted(internalModel);
} else {
this._recordWasChanged(internalModel);
}
});

this.changedRecords.length = 0;
internalModel._isUpdatingRecordArrays = false;
}

updated.length = 0;
},

_recordWasDeleted(internalModel) {
Expand Down Expand Up @@ -146,19 +154,35 @@ export default Ember.Object.extend({
//Need to update live arrays on loading
recordWasLoaded(internalModel) {
heimdall.increment(recordWasLoaded);
let modelName = internalModel.modelName;
let recordArrays = this.filteredRecordArrays.get(modelName);
let filter;
if (this.loadedRecords.push(internalModel) !== 1) { return; }

recordArrays.forEach(array => {
filter = get(array, 'filterFunction');
this.updateFilterRecordArray(array, filter, modelName, internalModel);
});
emberRun.schedule('actions', this, this._flushLoadedRecords);
},

_flushLoadedRecords() {
heimdall.increment(_flushLoadedRecords);
let internalModels = this.loadedRecords;

for (let i = 0, l = internalModels.length; i < l; i++) {
let internalModel = internalModels[i];
let modelName = internalModel.modelName;

let recordArrays = this.filteredRecordArrays.get(modelName);
let filter;

if (this.liveRecordArrays.has(modelName)) {
let liveRecordArray = this.liveRecordArrays.get(modelName);
this._addInternalModelToRecordArray(liveRecordArray, internalModel);
for (let j = 0, rL = recordArrays.length; j < rL; j++) {
let array = recordArrays[j];
filter = get(array, 'filterFunction');
this.updateFilterRecordArray(array, filter, modelName, internalModel);
}

if (this.liveRecordArrays.has(modelName)) {
let liveRecordArray = this.liveRecordArrays.get(modelName);
this._addInternalModelToRecordArray(liveRecordArray, internalModel);
}
}

this.loadedRecords.length = 0;
},

/**
Expand Down
4 changes: 2 additions & 2 deletions addon/-private/system/relationships/state/relationship.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export default class Relationship {
}
record._implicitRelationships[this.inverseKeyForImplicit].addRecord(this.record);
}
this.record.updateRecordArraysLater();
this.record.updateRecordArrays();
}
this.setHasData(true);
}
Expand Down Expand Up @@ -257,7 +257,7 @@ export default class Relationship {
return;
}
this.willSync = true;
this.store._backburner.join(() => this.store._backburner.schedule('syncRelationships', this, this.flushCanonical));
this.store._updateRelationshipState(this);
}

updateLink(link) {
Expand Down
29 changes: 28 additions & 1 deletion addon/-private/system/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ Store = Service.extend({
*/
// used for coalescing record save requests
this._pendingSave = [];
// used for coalescing relationship updates
this._updatedRelationships = [];
// used for coalescing relationship setup needs
this._pushedInternalModels = [];
// stores a reference to the flush for relationship setup
Expand Down Expand Up @@ -1235,7 +1237,9 @@ Store = Service.extend({
let modelClass = this._modelFor(modelName);
heimdall.stop(modelToken);

let arrayToken = heimdall.start('_query:createAdapterPopulatedRecordArray');
array = array || this.recordArrayManager.createAdapterPopulatedRecordArray(modelName, query);
heimdall.stop(arrayToken);

let adapterToken = heimdall.start('initial-adapterFor-lookup');
let adapter = this.adapterFor(modelName);
Expand All @@ -1244,7 +1248,10 @@ Store = Service.extend({
assert("You tried to load a query but you have no adapter (for " + modelName + ")", adapter);
assert("You tried to load a query but your adapter does not implement `query`", typeof adapter.query === 'function');

let pA = promiseArray(_query(adapter, this, modelClass, query, array));
let promise = _query(adapter, this, modelClass, query, array);
let promiseArrayToken = heimdall.start('promiseArray()');
let pA = promiseArray(promise);
heimdall.stop(promiseArrayToken);
instrument(() => {
pA.finally(() => { heimdall.stop(token); });
});
Expand Down Expand Up @@ -2376,6 +2383,7 @@ Store = Service.extend({

_setupRelationships() {
heimdall.increment(_setupRelationships);
let setupToken = heimdall.start('store._setupRelationships');
let pushed = this._pushedInternalModels;
this._pushedInternalModels = [];
this._relationshipFlush = null;
Expand All @@ -2388,6 +2396,7 @@ Store = Service.extend({
let data = pushed[i + 1];
setupRelationships(this, internalModel, data);
}
heimdall.stop(setupToken);
},

/**
Expand Down Expand Up @@ -2640,6 +2649,24 @@ Store = Service.extend({
this.unloadAll();
},

_updateRelationshipState(relationship) {
if (this._updatedRelationships.push(relationship) !== 1) {
return;
}

this._backburner.schedule('syncRelationships', this, this._flushUpdatedRelationships);
},

_flushUpdatedRelationships() {
let updated = this._updatedRelationships;

for (let i = 0, l = updated.length; i < l; i++) {
updated[i].flushCanonical();
}

updated.length = 0;
},

_pushResourceIdentifier(relationship, resourceIdentifier) {
if (isNone(resourceIdentifier)) {
return;
Expand Down
2 changes: 2 additions & 0 deletions tests/dummy/app/routes/query/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ export default Route.extend({
// We call toArray() to force materialization for benchmarking
// otherwise we would need to consume the RecordArray in our UI
// and clutter our benchmarks and make it harder to time.
let toArrayToken = heimdall.start('queryResult.toArray');
records.toArray();
heimdall.stop(toArrayToken);
heimdall.stop(token);
window.result = heimdall.toString();

Expand Down

0 comments on commit 7efa6a1

Please sign in to comment.