Download & Extend

filter_list_format() hits database too often / filter_format_save() doesn't save all filters

Project:Drupal core
Version:7.x-dev
Component:filter.module
Category:bug report
Priority:critical
Assigned:sun
Status:closed (fixed)
Issue tags:Performance

Issue Summary

When listing formats - i.e. a comment form on node view, we do an individual query for each format. Attached patch stops that by building the array of filters the first time we call the function, so that subsequent calls only fetch from static instead. Needs some cleanup since variable naming gets a bit tangly in there, but removes two queries on a default 'article' view in HEAD.

AttachmentSizeStatusTest resultOperations
filters.patch2.85 KBIdleFailed: 14709 passes, 12 fails, 0 exceptionsView details

Comments

#1

Status:needs review» needs work

The last submitted patch failed testing.

#2

Status:needs work» needs review

New patch, fixed tests, added caching for the query, avoids doing the extra work on the filters up front in case they don't actually get used.

HEAD:
Executed 72 queries in 45.77 milliseconds.

Patch:
Executed 70 queries in 46.68 milliseconds

#3

And the patch. I'm not sure why we call filter_list_formats() with an id of 0 on admin/config/content/filter/add, for now added a line to protect against this, not ideal but maybe sun can take a look?

AttachmentSizeStatusTest resultOperations
filters.patch1.41 KBIdlePassed on all environments.View details

#4

So, we reduced the number of queries, but we actually got slower?

#5

subscribing

I need to think about this edge-case.

#6

@Dries, devel query timings has something like a 50-100% standard deviation and isn't to be trusted unless it's dozens of queries or a huge filesort or something - page execution time is similarly unreliable, so those pastes are only for the query count (which is reliable as long as you have a warm cache).

It's also likely that benchmarks won't be conclusive with just these couple of queries, although I'm happy to run them.

The reason I post these patches is because:

* Less round trips to the database and less PHP overhead executing queries is worth having even when the queries themselves are small and indexed.
* 2-3 queries quickly adds up when it's multiplied across multiple issues and subsystems.

#7

+++ modules/filter/filter.module 1 Dec 2009 02:21:09 -0000
@@ -556,15 +556,18 @@ function filter_list_format($format_id)
+    // filter_list_format() is called with the non-existing $filter_id of 0 when
+    // creating a new filter. When that occurs, return an empty array.
+    $result = isset($filters['all'][$format_id]) ? $filters['all'][$format_id] : array();

Whatever we do, we want to remove this condition.

Actually, I think that invoking filter_list_format() for new formats is totally wrong, so this bears a fix elsewhere, which we may want to include here, not sure.

#8

In this case, devel was accurate, because I was missing an index change on the {filter} table, leading to a 10ms query, whoops!

Thought of a benchmarking scenario, not the most realistic in the world but not impossible either.

I added a bunch of input formats so that were 15 enabled on the site, gave anonymous user access to 14, access to and view comments, then benchmarked node/1 ab -c1 -n1000

HEAD:
Requests per second: 9.83 [#/sec]
Executed 65 queries in 36.52 milliseconds.

With patch:
Requests per second: 10.51 [#/sec]
Executed 52 queries in 23.04 milliseconds.

I don't know any sites with 14 input formats, but I do know some with 6 or more. So that 7% change probably equates to 2-3% on a more realistic site.

We still need to resolve the admin/config/content/filter issue though per #7.

AttachmentSizeStatusTest resultOperations
filters.patch1.41 KBIdlePassed on all environments.View details

#9

I need to see what breaks.

AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.9.patch1.27 KBIdleFailed on MySQL 5.0 ISAM, with: 15,421 pass(es), 0 fail(s), and 94 exception(es).View details

#10

Status:needs review» needs work

The last submitted patch failed testing.

#11

Title:Reduce database hits from filter_list_formats()» filter_list_format() hits database too often
Category:task» bug report
Assigned to:Anonymous» sun
Status:needs work» needs review

Here we go.

AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.11.patch2.41 KBIdleFailed on MySQL 5.0 ISAM, with: 15,445 pass(es), 0 fail(s), and 2 exception(es).View details

#12

Status:needs review» needs work

The last submitted patch failed testing.

#13

Status:needs work» needs review

Looks fine.
Index didn't make it into any of the patches, properly added this time.

Same benchmark as above, this time with 5 formats.

HEAD: 8.80 [#/sec]
Patch: 9.10 [#/sec]

AttachmentSizeStatusTest resultOperations
filters.patch3.39 KBIdleFailed on MySQL 5.0 ISAM, with: 15,446 pass(es), 0 fail(s), and 2 exception(es).View details

#14

Title:filter_list_format() hits database too often» filter_list_format() hits database too often / filter_format_save() doesn't save all filters

This patch nicely exposes a bug I already encountered in #394466-28: Full HTML description on node form is not descriptive enough, but didn't create an issue for yet.

filter_format_save() needs to save all available filters for a text format, regardless of their status.

This patch should hopefully fix it.

AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.13.patch3.31 KBIdleFailed on MySQL 5.0 ISAM, with: 15,511 pass(es), 43 fail(s), and 36 exception(es).View details

#15

Title:filter_list_format() hits database too often / filter_format_save() doesn't save all filters» filter_list_format() hits database too often
Status:needs review» needs work

Cross-posted with the bot.

#16

Title:filter_list_format() hits database too often» filter_list_format() hits database too often / filter_format_save() doesn't save all filters
Status:needs work» needs review

cross-posted. Merged in that index change.

AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.15.patch4.31 KBIdleFailed on MySQL 5.0 ISAM, with: 15,494 pass(es), 43 fail(s), and 36 exception(es).View details

#17

Title:filter_list_format() hits database too often / filter_format_save() doesn't save all filters» filter_list_format() hits database too often

And with sun. This patch merges #13 and #14.

AttachmentSizeStatusTest resultOperations
filter.patch4.29 KBIdleFailed on MySQL 5.0 ISAM, with: 15,481 pass(es), 43 fail(s), and 36 exception(es).View details

#18

omg. Either of those two should be fine :p

#19

LOL :)

Nope, yours uses a strange update function number :P

Let's hope that tests pass on #16 and be done with it :)

#20

Status:needs review» needs work

The last submitted patch failed testing.

#21

Just ran #16 locally and it has the same failures.

#22

Status:needs work» needs review

ok, that was quite a challenge. I'm totally happy that we have *so extensive tests* for filter.module. Changing this code lead to subsequent different fails in filter tests, which is awesome.

AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.22.patch10.79 KBIdleFailed on MySQL 5.0 ISAM, with: 15,528 pass(es), 0 fail(s), and 1,735 exception(es).View details

#23

Status:needs review» needs work

The last submitted patch failed testing.

#24

Status:needs work» needs review

oh nice, this also requires us to finally fix the installer. :)

AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.24.patch17.33 KBIdleFailed on MySQL 5.0 ISAM, with: 15,523 pass(es), 17 fail(s), and 4 exception(es).View details

#25

Status:needs review» needs work

The last submitted patch failed testing.

#26

Status:needs work» needs review

Also fixing PHP module's raw data query insertions...

AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.26.patch18.85 KBIdleFailed on MySQL 5.0 ISAM, with: 15,518 pass(es), 15 fail(s), and 4 exception(es).View details

#27

Title:filter_list_format() hits database too often» filter_list_format() hits database too often / filter_format_save() doesn't save all filters

#28

Status:needs review» needs work

The last submitted patch failed testing.

#29

Status:needs work» needs review
AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.29.patch18.98 KBIdleFailed on MySQL 5.0 ISAM, with: 15,529 pass(es), 15 fail(s), and 4 exception(es).View details

#30

Status:needs review» needs work

The last submitted patch failed testing.

#31

Status:needs work» needs review
AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.31.patch19.26 KBIdleFailed on MySQL 5.0 ISAM, with: 15,526 pass(es), 17 fail(s), and 4 exception(es).View details

#32

Status:needs review» needs work

The last submitted patch failed testing.

#33

Status:needs work» needs review

Holy cow!

This turned into a true bugfest.

AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.33.patch23.24 KBIdleFailed on MySQL 5.0 ISAM, with: 15,565 pass(es), 2 fail(s), and 0 exception(es).View details

#34

Priority:normal» critical

erm, considering all the filter system and installation profile bugs that are fixed in this patch, bumping to critical.

#35

Status:needs review» needs work

The last submitted patch failed testing.

#36

Status:needs work» needs review

Thanks, catch! You saved us from monster post-release headaches!

AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.36.patch25.69 KBIdlePassed on all environments.View details

#37

Status:needs review» needs work

I spent some time looking at this and it looks good. The latest patch doesn't seem to apply though, and might need a quick reroll. Otherwise RTBC, IMO.

#38

Status:needs work» needs review

Re-rolled against HEAD.

Also, to summarize these changes:

  • filter_list_format() needlessly executed one query per text format to retrieve all filters in it. It now performs only one query.
  • filter_list_format() was needlessly invoked on the text format add form, where we can be sure that no filters exist in the database yet. It no longer is invoked now.
  • That, however, lead to the problem that filter_list_format() returned default filter settings for all filters without configured settings before. Since it is no longer invoked during initial text format creation, filters in new text formats did not contain any settings. Hence, the merging of default filter settings was moved into filter_format_save().
  • That, however, lead to the problem that system.install and php.install executed raw database queries to insert initial text formats and filters without using the Filter API, so the initially created text formats contained filters without any settings. This was changed so that this code properly uses the Filter API to create text formats. I already had this change on my todo list, and when doing so, I also wanted to move this code into installation profiles (because that's where it belongs), which is now included in this patch.
  • That, however, triggered a yet invisible critical bug: Since module hooks are not weighed after module dependencies (only by module weight and filename), and php.module comes therefore before system.module, the "PHP code" text format was suddenly the default format in PHP module's tests. That is, because all text formats were saved with a weight of 0, so PHP's text format was inserted first, and the default installation profile simply assumed that text format ID 1 would be "Filtered HTML". Hence, anonymous users and authenticated users were granted the permission to use PHP code instead of Filtered HTML. Likewise, PHP module's tests as well as some other tests did the very same fragile assumption, so they tried to test evaluation of PHP code with the last text format id in the database, which was now "Plain text".
AttachmentSizeStatusTest resultOperations
drupal.filter-list-format.37.patch25.68 KBIdlePassed on all environments.View details

#39

Note that some of the critical issues I mentioned in the summary would not exist with #573852: Rename {filter_format}.name to .title and replace .format with machine-readable .name - i.e. if modules and tests were able to refer to text format "php_code" or "filtered_html" instead of MAX(format) or 1. But unfortunately, that's way too much for D7, because it would require us to change all 'format' columns throughout core, and on top of that, it would conflict with my plans for D8. :-(

Erm, so this was just FYI. ;)

#40

Status:needs review» reviewed & tested by the community

Looks fine here, Dries already reviewed, let's get this in before it reaches 40k ;)

#41

Status:reviewed & tested by the community» fixed

Committed to CVS HEAD. Great job.

#42

Status:fixed» closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

nobody click here