-
Notifications
You must be signed in to change notification settings - Fork 409
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
fix: made type-metadata.storage.ts much faster #2212
fix: made type-metadata.storage.ts much faster #2212
Conversation
Changed the data modeling of type-metadata storage to store the data in maps instead of arrays. This results in a dramatic improvement of application startup time since many of the lookups for metadata are now in O(1) instead of O(n)
OK, I see failing e2e tests here, but the ones I ran locally with |
You might need to clear your local jest cache (with --clearCache) - perhaps you're not actually executing those tests |
Yep, I didn't notice that I was running only the graphql package tests. Working on solving the breaking tests now. |
Changed the data modeling of type-metadata storage to store the data in maps instead of arrays. This results in a dramatic improvement of application startup time since many of the lookups for metadata are now in O(1) instead of O(n)
Changed the data modeling of type-metadata storage to store the data in maps instead of arrays. This results in a dramatic improvement of application startup time since many of the lookups for metadata are now in O(1) instead of O(n)
All test pass! |
} from '../metadata'; | ||
import { ObjectTypeMetadata } from '../metadata/object-type.metadata'; | ||
|
||
export class MapByName<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we create a dedicated folder, let's say, "collections" and then have a file per class there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, that's a good idea. I didn't know where to place this file but your suggestion is appropriate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Changed the data modeling of type-metadata storage to store the data in maps instead of arrays. This results in a dramatic improvement of application startup time since many of the lookups for metadata are now in O(1) instead of O(n)
@@ -0,0 +1,15 @@ | |||
export class ArrayCollection<T> extends Array<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extending built-in collections is typically considered a bad practice. Any reason we cant use Array directly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, for every collection that we are saving per metadata class, we also need to save a global collection of all the classes collections in a flat array.
I thought the easiest way to do that is to hook on arrays push and I shift methods, but it maybe bette to have this class create an internal array and expose the required methods
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pushed another fix, now I'm wrapping the array instead of extending it. Good comment!
Changed the data modeling of type-metadata storage to store the data in maps instead of arrays. This results in a dramatic improvement of application startup time since many of the lookups for metadata are now in O(1) instead of O(n)
any update on this? |
@@ -0,0 +1,35 @@ | |||
export class ArrayCollection<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still doesn't seem right. ArrayCollection
class basically wraps another array inside and hooks into some of the methods (push and unshit) to simply insert these elements into the global array . We should - at the very least - rename this class so it properly describes what's doing under the hood.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. Do you think that ArrayWithUpdateHooks is appropriate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about ArrayWithGlobalCacheCollection
? Not sure which one is better tbh
export class ArrayCollection<T> { | ||
private array: T[] = []; | ||
|
||
constructor(private globalArray: Array<T>) {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
constructor(private globalArray: Array<T>) {} | |
constructor(private readonly globalArray: Array<T>) {} |
@@ -0,0 +1,35 @@ | |||
export class ArrayCollection<T> { | |||
private array: T[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
private array: T[] = []; | |
private readonly array: T[] = []; |
import { MetadataListByNameCollection } from './metadata.list.by.name.collection'; | ||
import { PropertyDirectiveMetadata } from '../metadata'; | ||
|
||
export class FieldDirectiveCollection extends MetadataListByNameCollection<PropertyDirectiveMetadata> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename file to field-directive.collection.ts
if (this.sdls.has(value.sdl) && this.fieldNames.has(value.fieldName)) | ||
return; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (this.sdls.has(value.sdl) && this.fieldNames.has(value.fieldName)) | |
return; | |
if (this.sdls.has(value.sdl) && this.fieldNames.has(value.fieldName)) { | |
return; | |
} |
style: for the sake of consistency
|
||
this.sdls.add(value.sdl); | ||
this.fieldNames.add(value.fieldName); | ||
this.globalArray && this.globalArray.push(value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this.globalArray && this.globalArray.push(value); | |
this.globalArray?.push(value); |
@@ -0,0 +1,37 @@ | |||
import { MetadataByNameCollection } from './metadata.by.name.collection'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rename file to metadata-list-by-name.collection.ts
@@ -0,0 +1,26 @@ | |||
export class MetadataByNameCollection<T> { | |||
protected map = new Map<string, T>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this._objectType = val; | ||
this.all.objectType.push(val); | ||
} | ||
get objectType() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: missing blank lines between getters and setters
@@ -0,0 +1,150 @@ | |||
import { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should have a dedicated test file per collection (as we now have them - collection classes - in dedicated files as well)
Changed the data modeling of type-metadata storage to store the data in maps instead of arrays. This results in a dramatic improvement of application startup time since many of the lookups for metadata are now in O(1) instead of O(n)
Changed the data modeling of type-metadata storage to store the data in maps instead of arrays. This results in a dramatic improvement of application startup time since many of the lookups for metadata are now in O(1) instead of O(n)
Fixed all comments, thanks! |
Hey @kamilmysliwiec, can we merge this? |
@kamilmysliwiec we are waiting on an update for this, if you can help us this would be great |
Changed the data modeling of type-metadata storage to store the data in maps instead of arrays.
This results in a dramatic improvement of application startup time since many of the lookups for metadata are now in O(1) instead of O(n)
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
This change mainly modified type-metadata.storage.ts file. This file stored all the objects' metadata in arrays, and during an application bootstrap, it would iterate all the data multiple times to filter the required metadata (mostly filter by class type, but also property field names and more).
What I did was to modify how the data is stored with multiple new classes which store the metadata within Maps, thus retrieving the correct data is a simple get instead of a filter.
From my tests on my (pretty large) GQL project, the bootstrap time went from 90s to 8s.
What is the current behavior?
Issue Number: #2206
What is the new behavior?
Does this PR introduce a breaking change?
Other information