Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #3527 (closed enhancement: fixed)

Opened 3 years ago

Last modified 3 years ago

[XPATCH] faster components implementation

Reported by: skaes Assigned to: David
Priority: normal Milestone: 1.1
Component: ActionPack Version: 1.0.0
Severity: normal Keywords: components
Cc:

Description

This patch bundles a few changes to component rendering and ActionPack in general. The resulting implementation is much faster for components, but also speeds up ActiveRecordStore for new sessions considerably, because session saving can be lazy again.

The code is based on the assumption that rendered components should use the session settings of their embedding controller. While it was previously allowed to embed a session requiring component into a page whithout session management, or with a session :off specification, this will no longer work with this patch.

I think this is a reasonable restriction.

Currently, a page embedding n components will cause (n+1) session loads and (n+1) session saves. If the page access creates a new session, this will result in an additional save operation. With the patch in place, at most 1 load and 1 save will be made.

Patch description:

Two attr_accessors are added to AbstractRequest: :parent_controller and :flash. In render_component the current request gets duped and parent_controller of the new request gets assigned the current controller embedding the render_component call. This accessor is then checked inside ActionController::process to determine whether the session needs to be saved, whether the flash needs to be swept and whether persistent model associations need to be cleared. When duping the request, the current session gets passed to the sub_request as well.

The implementation eliminates the fire_flash, sweep_flash and clear_persistent_record_associations filters. This is not essential and could be reverted if need be. But I wonder whether the current implementation behaves as intended: if a before filter fails, the flash will not be swept and the associations are not cleared. So if someone accesses the flash or an association in a filter, the behaviour might not be as originally intended. Could I get some feedback on this, please?

A few other changes are contained in the patch:

HashWithIndifferentAccess gets a regular_update method(other_hash), which is a lot faster than calling update(other_hash) and can be used if other_hash is known to be indifferent_access compliant.

AbstractRequest and CGIRequest use @env internally instead of env. This saves 2 function calls per env access. CGIRequest#method is cached as well.

Performance data:

First, a page embedding 5 components:

Tested with ActiveRecordStore:

perf data file 1: 01-17.comp.slow_components.ar_store
  requests=1000, options=-bm=comp_test -fast_routes -fast_readers 
  -fast_connection -single_connection_cache_key -old_components
  -lib=stablep

perf data file 2: 01-17.comp.fast_components.ar_store
  requests=1000, options=-bm=comp_test -fast_routes -fast_readers
  -fast_connection -single_connection_cache_key -old_components
  -lib=stablep2

page             c1 real   c2 real  c1 r/s  c2 r/s  c1 ms/r  c2 ms/r  c1/c2
/test/comp_test  5.92573   5.07233   168.8   197.1     5.93     5.07   1.17

With SQLSessionStore:

perf data file 1: 01-17.comp.slow_components
  requests=1000, options=-bm=comp_test -mysql_session -fast_routes    
  -fast_readers -fast_connection -single_connection_cache_key
  -old_components -lib=stablep

perf data file 2: 01-17.comp.fast_components
  requests=1000, options=-bm=comp_test -mysql_session -fast_routes
  -fast_readers -fast_connection -single_connection_cache_key
  -old_components -lib=stablep2

page             c1 real   c2 real  c1 r/s  c2 r/s  c1 ms/r  c2 ms/r  c1/c2
/test/comp_test  4.35981   3.63821   229.4   274.9     4.36     3.64   1.20

Comparing requests which don't use components show improvement as well:

perf data file 1: 01-17.all.slow_components.ar_store
  requests=1000, options=-bm=all -fast_routes -fast_readers -fast_connection -single_connection
_cache_key -old_components -lib=stablep

perf data file 2: 01-17.all.fast_components.ar_store
  requests=1000, options=-bm=all -fast_routes -fast_readers -fast_connection -single_connection
_cache_key -old_components -lib=stablep2

page                            c1 real   c2 real  c1 r/s  c2 r/s  c1 ms/r  c2 ms/r  c1/c2
/empty/index                    3.64878   2.66773   274.1   374.9     3.65     2.67   1.37
/welcome/index                  3.78321   2.81584   264.3   355.1     3.78     2.82   1.34
/rezept/index                   2.94626   2.93406   339.4   340.8     2.95     2.93   1.00
/rezept/myknzlpzl               2.94806   2.93190   339.2   341.1     2.95     2.93   1.01
/rezept/show/713                4.99503   4.95098   200.2   202.0     5.00     4.95   1.01
/rezept/cat/Hauptspeise         5.89972   5.86025   169.5   170.6     5.90     5.86   1.01
/rezept/cat/Hauptspeise?page=5  6.00105   5.96334   166.6   167.7     6.00     5.96   1.01
/rezept/letter/G                5.95500   5.91001   167.9   169.2     5.95     5.91   1.01

This shows that pages which create new sessions receive around 35% speedup.

perf data file 1: 01-17.all.slow_components
  requests=1000, options=-bm=all -mysql_session -fast_routes -fast_readers
  -fast_connection -single_connection_cache_key -OT -lib=stablep

perf data file 2: 01-17.all.fast_components
  requests=1000, options=-bm=all -mysql_session -fast_routes -fast_readers
  -fast_connection -single_connection_cache_key -OT -lib=stablep2

page                            c1 real   c2 real  c1 r/s  c2 r/s  c1 ms/r  c2 ms/r  c1/c2
/empty/index                    1.31928   1.25701   758.0   795.5     1.32     1.26   1.05
/welcome/index                  1.49112   1.47056   670.6   680.0     1.49     1.47   1.01
/rezept/index                   1.57464   1.55000   635.1   645.2     1.57     1.55   1.02
/rezept/myknzlpzl               1.57047   1.54025   636.8   649.2     1.57     1.54   1.02
/rezept/show/713                3.56991   3.52824   280.1   283.4     3.57     3.53   1.01
/rezept/cat/Hauptspeise         4.38857   4.34247   227.9   230.3     4.39     4.34   1.01
/rezept/cat/Hauptspeise?page=5  4.49025   4.44238   222.7   225.1     4.49     4.44   1.01
/rezept/letter/G                4.43585   4.38071   225.4   228.3     4.44     4.38   1.01

This shows that request processing is 5% faster than before (/empty/index). Action cached pages receive a 2% improvement. Even relativley complex pages retrieving around 30 objects from the database see a 1% improvement.

Attachments

faster_components_trunk.patch (26.5 kB) - added by skaes on 01/18/06 19:23:57.
faster_components_trunk.2.patch (28.0 kB) - added by skaes on 01/25/06 08:48:00.

Change History

01/18/06 19:23:57 changed by skaes

  • attachment faster_components_trunk.patch added.

01/24/06 08:51:29 changed by jw@innerewut.de

This also fixes #3194 (flash not clearing with components and ActiveRecord SessionStore).

01/25/06 08:48:00 changed by skaes

  • attachment faster_components_trunk.2.patch added.

01/25/06 08:58:40 changed by skaes

I removed the :flash and :parent_controller from AbstractRequest. Instead the signature of AC::Base.process is changed from

def process(request, response)

to

def process(request, response, parent_controller=nil)

and AC::Base.initialize gets (parent_controller=nil) as parameter.

The question whether flash.sweep and clear_persistent_model_associations should be called even if the before filter chain is aborted is still open. I think they should. If we decide to call them always, the variable @before_filter_chain_aborted could be eliminated, further simplifying the implementation.

02/09/06 20:05:23 changed by bitsweat

  • status changed from new to closed.
  • resolution set to fixed.

(In [3563]) Major components cleanup and speedup. Closes #3527.

02/09/06 20:07:47 changed by bitsweat

  • keywords set to components.
  • milestone set to 1.1.