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

FIX: Remove some unnecessary ClassInfo calls in DataObjectSchema #7670

Merged
merged 1 commit into from
Dec 5, 2017

Conversation

kinglozzer
Copy link
Member

@kinglozzer kinglozzer commented Dec 1, 2017

ClassInfo::ancestry() will include ViewableData and DataObject in its results. Subsequent calls to DataObjectSchema::databaseFields(ViewableData::class) are a waste of time of course, as there are no database fields on those classes.

Below profile is for a homepage load on a blank install, but the performance difference will only grow the more DataObject classes are referenced during a given request.

screen shot 2017-12-05 at 12 23 47

@@ -201,6 +201,11 @@ public function fieldSpecs($classOrInstance, $options = 0)
$db = [];
$classes = $uninherited ? [$class] : ClassInfo::ancestry($class);
foreach ($classes as $tableClass) {
// Skip irrelevant parent classes
if ($tableClass !== DataObject::class && !is_subclass_of($tableClass, DataObject::class)) {
Copy link
Member Author

@kinglozzer kinglozzer Dec 1, 2017

Choose a reason for hiding this comment

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

@tractorcow Omitting the $tableClass !== DataObject::class saves around another 500 method calls. As far as I can tell $this->databaseFields(DataObject::class); doesn’t return anything, do you think that would be safe?

It looks like the fixed fields will always be forcibly included by cacheDatabaseFields() anyway

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice job. :)

@@ -394,6 +399,10 @@ public function databaseIndexes($class, $aggregated = true)
*/
public function classHasTable($class)
{
if (!is_subclass_of($class, DataObject::class)) {
return false;
}
Copy link
Member Author

@kinglozzer kinglozzer Dec 1, 2017

Choose a reason for hiding this comment

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

Somehow ViewableData gets passed in here, I haven’t yet tracked down why but this seems like a reasonable change anyway.

It is causing the test failure... normally $schema->classHasTable('NonExistentClass') would pass the class name over to databaseFields() and therefore ClassInfo::class_name() which triggers an exception (instead of returning false like the new behaviour would). We could either remove that assertion, or if that would be deemed an API change replace it with a direct class_exists() here.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think removing the assertion is ok... It's kind of stupid IMO, we probably should have been catching it

Copy link
Contributor

Choose a reason for hiding this comment

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

It's from dataClassesFor() not properly filtering is_subclass_of() the way you have been doing (correctly).

@dhensby
Copy link
Contributor

dhensby commented Dec 4, 2017

This seems reasonable to me - the exception throwing is the only thing we need to take a view on regarding if that's an API issue as people could be relying on it...

@kinglozzer
Copy link
Member Author

I’ve removed the test assertion for an exception to be thrown in classHasTable(), and also prevented unnecessary calls to DataObjectSchema::databaseFields(DataObject::class), so this is now a “kitchen sink, let me know if anything needs to come out” PR 😝.

Also, as this is targeting ClassInfo calls, this should still offer a performance improvement even if the caching outlined in #7384 is implemented.

@@ -138,11 +138,11 @@ public function tableName($class)
*/
public function baseDataClass($class)
{
$class = ClassInfo::class_name($class);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we not add the if (!is_subclass_of($tableClass, DataObject::class)) check here?

Copy link
Member Author

Choose a reason for hiding this comment

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

It does handle that at the end of the method, but I suppose we could move it to the start before the while loop

@@ -394,6 +399,10 @@ public function databaseIndexes($class, $aggregated = true)
*/
public function classHasTable($class)
{
if (!is_subclass_of($class, DataObject::class)) {
return false;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It's from dataClassesFor() not properly filtering is_subclass_of() the way you have been doing (correctly).

@tractorcow tractorcow merged commit 01b48e2 into silverstripe:4.0 Dec 5, 2017
@kinglozzer kinglozzer deleted the dataobject-schema-ancestry branch December 6, 2017 09:11
@kinglozzer kinglozzer restored the dataobject-schema-ancestry branch December 14, 2017 15:45
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.

3 participants