Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factory cache #4704

Merged
merged 1 commit into from Dec 13, 2016
Merged

Factory cache #4704

merged 1 commit into from Dec 13, 2016

Conversation

runspired
Copy link
Contributor

@runspired runspired commented Dec 9, 2016

Needs benchmarking, review, may have been too aggressive in _modelFor use, dislike that modelFactoryFor is public, should discuss.

Also, one reason for WIP is that this builds off of #4664, may be easier to review once that lands and I rebase ;)


clear() {
if (this._records) {
let records = this._records.slice();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't appear to purge this._records membership, should we maybe instead do.

let records = this._records;
this._records = []; // or maybe null

That way, we release anything currently retained by this._records and don't need to copy the this._records array via slice

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll look into it. This is the same logic preserved from before, and it's unclear if emptying this has ramifications, I think it does (I think individual records are currently responsible for removing themselves). This is a data flow story I will untangle soon in order to also help us unlock better change tracking for record arrays.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Our tests still pass with this in place, so I've made this change.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@runspired sounds good, making this change should prevent a potential mem leak.

return null;
}
return this.store._modelFor(this.modelName);
}),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

readOnly

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change made.


export default class IdentityMap {
constructor() {
this._map = new EmptyObject();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Object.create(null) may be fine, here. EmptyObject was more of a trick for mega mega hotspots to work-around a strange perf issue in older v8's.

In this case, I believe Object.create(null) will be best. (less caveats etc)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched to Object.create(null) but we should probably investigate which is currently better.

@stefanpenner
Copy link
Member

I'm 👍 with this direction, although the title of the PR is a-bit misleading, after reading the PR i feel much better.

We should be careful re: compat, but this change is worth doing!

/*
@private
*/
_modelFor(modelName) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see this remain a public API. modelFactoryFor should probably be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It remains public, the differentiator is that "public" APIs must always normalize the modelName while "private" APIs can assume a normalized modelName. We currently call this so often internally I wanted to avoid that unnecessary step.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also agree that modelFactoryFor should probably be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FTR, the reason we can't remove modelFactoryFor at the moment is because adapters use it to do a modelFor lookup without risk of erroring when a model isn't found when an unknown type is encountered in a payload (prints a warning, doesn't error).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@runspired
Copy link
Contributor Author

@stefanpenner
The requested changes are actually all for #4664 which this PR build on top of / branches from. I will be addressing the feedback there.

I believe this is also the reason for the confusion around the name. This PR creates a cache for the modelClass factories that we lookup. Previously, every call to modelFor would do a fresh owner._lookupFactory (potentially multiple if finding a mixin) + re-set factory.modelName. This turned out to be much more costly than one might expect, and as we currently call modelFor roughly 2N + X times per query (where N is number of records returned in a call), this really added up.

@stefanpenner
Copy link
Member

stefanpenner commented Dec 11, 2016

The requested changes are actually all for #4664 which this PR build on top of / branches from. I will be addressing the feedback there.

👍

I believe this is also the reason for the confusion around the name. This PR creates a cache for the modelClass factories that we lookup.

Yup, in the end the name seemed fine. The root cause of the confusion, was just words a words. And prior efforts that where funky used this name, but the current one feels good.

Previously, every call to modelFor would do a fresh owner._lookupFactory (potentially multiple if finding a mixin) + re-set factory.modelName. This turned out to be much more costly than one might expect, and as we currently call modelFor roughly 2N + X times per query (where N is number of records returned in a call), this really added up.

Ya, even very cheap things happening many many times ads up.

@runspired runspired force-pushed the factory-cache branch 2 times, most recently from 004a8b0 to a73dd3c Compare December 12, 2016 01:58
@bmac
Copy link
Member

bmac commented Dec 12, 2016

Overall this pr looks pretty good. Once #4664 lands I think this one should be ready to go.

@runspired runspired changed the title [WIP] Factory cache Factory cache Dec 13, 2016
@bmac bmac merged commit a1bac10 into emberjs:master Dec 13, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants