Steps to reproduce:

1. Create a content type along these lines:

  • ~35 fields total
  • 5 multivalue field collection fields

2. Make the field collections translatable and Lingotek-aware
3. Create a node of this content type, filling some of the field collections up with around 40 members or so. Fill in the rest of the fields too.
4. Save the node.

It takes a long time. On a production site we were seeing save times of up to 8 minutes. I know this is a lot of fields, bear with me :)

I used xhprof to see what was going on. See the attached PDF. One thing stood out: about 57% of the runtime was spent in lingotek_node_load_default(). I believe I have a solution which involves adding a static cache to the node revision loaded in that function, so that it doesn't have to do a db query and a node load each time.

Please evaluate the impact of this fix. I did add some invalidation logic in lingotek_node_presave so that in the odd case where a node is saved a second time in a runtime, if it is adding a new revision, it will force a subsequent lingotek_node_load_default() to hit the db again.

Comments

dpolant created an issue. See original summary.

dpolant’s picture

StatusFileSize
new461.25 KB
dpolant’s picture

StatusFileSize
new1.35 KB
dpolant’s picture

Issue summary: View changes
jbhovik’s picture

Assigned: Unassigned » jbhovik

Hey dpolant,

Thanks for reporting. Eight minutes is definitely a long time. Also thanks for your patch; I'll apply it and take a look.

jbhovik’s picture

StatusFileSize
new40.73 KB
new113.71 KB
new40.25 KB

Hello again dpolant,

I wanted to ask what performance increase you've seen applying your patch. I also wanted to make sure I understand the problem correctly; I haven't seen a significant performance increase within my local site. I created a content type with 30 text fields and 5 field collection fields. I added 40 fields to each field collection, 20 text fields, and 20 long text fields. Then I enabled all fields for translation within Lingotek. See node_fields.png and fc_fields.png for screenshots. Here are my test times.

Without the patch:
6.13 seconds
5.62 seconds
5.88 seconds
5.46 seconds
5.51 seconds
5.41 seconds
5.64 seconds
5.59 seconds
5.35 seconds
5.80 seconds
Average: 5.6 seconds

With patch:
5.73 seconds
5.82 seconds
5.69 seconds
5.57 seconds
5.56 seconds
5.29 seconds
5.62 seconds
5.23 seconds
5.37 seconds
5.23 seconds
Average: 5.5 seconds

I also used xhprof to profile the page creation. See lingotek_node_load_default.png. My xhprof report had less calls to lingotek_node_load_default (only 6 without the patch applied), but I may not have it setup correctly.

Your patch contains good logic, but I want to make sure I'm replicating the use case accurately.

dpolant’s picture

I think the important thing is to have a lot of FC entities being saved at once rather than there being a lot of field instances. In our case there might be close to 100 total FCs being saved when you click "save" on the node where we're seeing this problem. That might be the operative thing b/c the problem is when lingotek_node_load_default fires on each entity update.

damienmckenna’s picture

@jbhovek: Out of interest, with your test scenario what is the average page request time if the Lingotek functionality is disabled entirely?

jbhovik’s picture

dpolant,

I wrote a script that programmatically creates 100 field collections containing 10 text fields, equaling 1000 fields. I'm seeing some performance increase with this scenario.

Without patch:
31.96 seconds
31.35 seconds
31.13 seconds
31.58 seconds
31.18 seconds
30.89 seconds
31.29 seconds
31.30 seconds
30.77 seconds
32.09 seconds

With patch:
17.66 seconds
15.95 seconds
15.55 seconds
15.51 seconds
15.41 seconds
14.95 seconds
15.54 seconds
15.29 seconds
15.27 seconds
15.56 seconds

DamienMcKenna, the times are better without Lingotek.

Without Lingotek:
14.92 seconds
14.16 seconds
14.06 seconds
13.71 seconds
13.20 seconds
13.75 seconds
13.26 seconds
13.70 seconds
13.43 seconds
13.34 seconds

damienmckenna’s picture

@jbhovik: Thanks for the extra stats. It seems clear that for complicated sites the module could cause performance problems.

Would you mind updating the script? We could help expand it to also test Paragraphs, etc.

jbhovik’s picture

@dpolant and @DamienMcKenna,

The other place Lingotek makes a lot of queries is in the lingotek_entity_load() function. This may account for the extra time added by Lingotek. These queries are only run if it's an admin page, drush, or cron.

I wrote a script that adds 10 text fields to an existing paragraph bundle ("my_paragraph_bundle"). I wrote a second script that adds paragraph fields to a content type (paragraph_content_type). Here are the times.

Without patch:
4.90 seconds
5.23 seconds
5.38 seconds
5.98 seconds
5.13 seconds

Average: 5.32

With patch:
4.56 seconds
5.73 seconds
4.96 seconds
5.35 seconds
5.45 seconds

Average: 5.21

The two scenarios are pretty close. I didn't perform a "without Lingotek" test because each test took quite a while since you have to click the "Add new paragraph" buttons. I bet the times would be similar without Lingotek.

I'm attaching the scripts (ran in devel) I used to create the test content. For the paragraphs, make sure you create a paragraph bundle named "my_paragraph_bundle" so addFieldsToParagraphBundle.txt and addParagraphsToNodes.txt have something to run against. The "delete" scripts remove the created fields if you're so inclined. Thanks again for your patch--we're currently QAing it.

jbhovik’s picture

@dpolant and @DamienMcKenna,

As an update, we don't see any unwanted effects from applying your patch. Feel free to use it in environments. We would still recommend testing it out on a test environment first. We'll include the patch in our next release.

  • jbhovik committed 0db6b7a on 7.x-7.x authored by dpolant
    Issue #2908594 INT-2424 by dpolant, jbhovik: Performance problems on...

  • jbhovik committed 1105428 on 7.x-7.x authored by dpolant
    Issue #2908594 INT-2424 by dpolant, jbhovik: Performance problems on...
jbhovik’s picture

@dpolant and @DamienMcKenna,

Just so you know, we did find a problem with the patch in QA. The node_presave hook code was causing edited nodes to not register as edited, so we moved that logic into lingotek_entity_changed(), since this function is where the Lingotek module checks for edits to content. Thanks again for your contribution--we've released your code in 7.23.

damienmckenna’s picture

Status: Active » Fixed

@jbhovik: That's awesome, thanks!

Status: Fixed » Closed (fixed)

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