Skip to content

Commit

Permalink
BENCH this: return to using an array for pushed internal models
Browse files Browse the repository at this point in the history
  • Loading branch information
runspired committed Apr 20, 2017
1 parent c57b892 commit eec7047
Showing 1 changed file with 49 additions and 57 deletions.
106 changes: 49 additions & 57 deletions addon/-private/system/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,8 +235,7 @@ Store = Service.extend({
// used for coalescing relationship updates
this._updatedRelationships = [];
// used for coalescing relationship setup needs
this._hasPushedInternalModels = false;
this._pushedInternalModels = Object.create(null);
this._pushedInternalModels = [];

// used for coalescing internal model updates
this._updatedInternalModels = [];
Expand Down Expand Up @@ -2409,84 +2408,77 @@ Store = Service.extend({
return;
}

let hash = this._pushedInternalModels;
let queue = hash[internalModel.modelName] = hash[internalModel.modelName] || [];
queue.push(internalModel, data);

if (!this._hasPushedInternalModels) {
this._hasPushedInternalModels = true;
this._backburner.schedule('normalizeRelationships', this, this._setupRelationships);
if (this._pushedInternalModels.push(internalModel, data) !== 2) {
return;
}

this._backburner.schedule('normalizeRelationships', this, this._setupRelationships);
},

_setupRelationships() {
heimdall.increment(_setupRelationships);
let setupToken = heimdall.start('store._setupRelationships');
let pushed = this._pushedInternalModels;
let modelNames = Object.keys(pushed);
let store = this;

this._hasPushedInternalModels = false;
this._pushedInternalModels = Object.create(null);

// Cache the inverse maps for each modelClass that we visit during this
// payload push. In the common case where we are pushing many more
// instances than types we want to minimize the cost of looking up the
// inverse map and the overhead of Ember.get adds up.
let modelNameToInverseMap = Object.create(null);
let modelNameToRelationshipsMap = Object.create(null);

for (let modelNameIndex = 0; modelNameIndex < modelNames.length; modelNameIndex ++) {
let queue = pushed[modelNames[modelNameIndex]];
let modelClass = queue[0].modelClass;
let relationshipsByName = get(modelClass, 'relationshipsByName');
let relationshipNames = relationshipsByName._keys.list;
for (let i = 0; i < pushed.length; i += 2) {
let data = pushed [i + 1];

// This will convert relationships specified as IDs into DS.Model instances
// (possibly unloaded) and also create the data structures used to track
// relationships.
for (let queueIndex = 0; queueIndex < queue.length; queueIndex += 2) {
let internalModel = queue[queueIndex];
let relationships = internalModel._relationships;
let data = queue[queueIndex + 1];
if (!data.relationships) {
continue;
}

if (!data.relationships) {
continue;
}
let internalModel = pushed[i];
let modelName = internalModel.modelName;
let relationshipsByName = modelNameToRelationshipsMap[modelName];

if (relationshipsByName === undefined) {
relationshipsByName = modelNameToRelationshipsMap[modelName] = get(internalModel.modelClass, 'relationshipsByName');
}

for (let keyIndex = 0; keyIndex < relationshipNames.length; keyIndex++) {
let relationshipName = relationshipNames[keyIndex];
let relationshipNames = relationshipsByName._keys.list;
let relationships = internalModel._relationships;

if (data.relationships[relationshipName]) {
let relationshipRequiresNotification = relationships.has(relationshipName) ||
isInverseRelationshipInitialized(store, internalModel, data, relationshipName, modelNameToInverseMap);
for (let keyIndex = 0; keyIndex < relationshipNames.length; keyIndex++) {
let relationshipName = relationshipNames[keyIndex];

if (relationshipRequiresNotification) {
let relationshipData = data.relationships[relationshipName];
relationships.get(relationshipName).push(relationshipData);
}
if (data.relationships[relationshipName]) {
let relationshipRequiresNotification = relationships.has(relationshipName) ||
isInverseRelationshipInitialized(store, internalModel, data, relationshipName, modelNameToInverseMap);

// in debug, assert payload validity eagerly
runInDebug(() => {
let relationshipMeta = relationshipsByName.get(relationshipName);
let relationshipData = data.relationships[relationshipName];
if (!relationshipData || !relationshipMeta) {
return;
}
if (relationshipRequiresNotification) {
let relationshipData = data.relationships[relationshipName];
relationships.get(relationshipName).push(relationshipData);
}

if (relationshipData.links) {
let isAsync = relationshipMeta.options && relationshipIsAsync(relationshipMeta);
warn(`You pushed a record of type '${internalModel.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , {
id: 'ds.store.push-link-for-sync-relationship'
});
} else if (relationshipData.data) {
if (relationshipMeta.kind === 'belongsTo') {
assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${relationshipName} being ${inspect(relationshipData.data)}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data));
} else if (relationshipMeta.kind === 'hasMany') {
assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data));
}
// in debug, assert payload validity eagerly
runInDebug(() => {
let relationshipMeta = relationshipsByName.get(relationshipName);
let relationshipData = data.relationships[relationshipName];
if (!relationshipData || !relationshipMeta) {
return;
}

if (relationshipData.links) {
let isAsync = relationshipMeta.options && relationshipIsAsync(relationshipMeta);
warn(`You pushed a record of type '${internalModel.modelName}' with a relationship '${relationshipName}' configured as 'async: false'. You've included a link but no primary data, this may be an error in your payload.`, isAsync || relationshipData.data , {
id: 'ds.store.push-link-for-sync-relationship'
});
} else if (relationshipData.data) {
if (relationshipMeta.kind === 'belongsTo') {
assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${relationshipName} being ${inspect(relationshipData.data)}, but ${relationshipName} is a belongsTo relationship so the value must not be an array. You should probably check your data payload or serializer.`, !Array.isArray(relationshipData.data));
} else if (relationshipMeta.kind === 'hasMany') {
assert(`A ${internalModel.modelName} record was pushed into the store with the value of ${relationshipName} being '${inspect(relationshipData.data)}', but ${relationshipName} is a hasMany relationship so the value must be an array. You should probably check your data payload or serializer.`, Array.isArray(relationshipData.data));
}
});
}
}
});
}
}
}
Expand Down

0 comments on commit eec7047

Please sign in to comment.