Details
Description
Some days ago there was a discussion on dev list titled:
[core] performance: performance hints
With the following intention (proposed by Martin Koci):
MK>> is it possible to introduce performance hints in myfaces-core? Hints
MK>> similar to javax.faces.component.visit.VisitHint but related to
MK>> performance improvements. Example:
MK>> For dataTable like:
MK>> <a:dataTable
MK>> <a:column>
MK>> #
MK>> it's completely unnecessary to save per-row state. Currently there is no
MK>> elegant way how to do read-only table (state per-row is always
MK>> maintained). If user wants (fast) readOnly table, he/she must extend
MK>> UIData and re-implemenent setRowIndex method. But hint say
MK>> "org.apache.myfaces.core.UIData.saveRowState"=false can solve it
MK>> elegantly - if present (in component.getAttributes()) UIData skips
MK>> row-state-saving and restoring methods entirely.
MK>> Lifespan of those hints can be request (faceContext.attributes) or view
MK>> (component.attributes)
The discussion there was to create or not a hint but a review of the default algorithm was never done. In theory, UIData.setRowIndex do the following tasks:
1. If the component is in row -1 (no row), take a "snapshot" of the components that implements EditableValueHolder, to restore them later when rows are traversed.
2. If the component is in a row, save the current state of EditableValueHolder components.
3. Move to the selected row.
4. If no state saved found, restore EditableValueHolder components from saved initial state.
5. If state saved found, restore EditableValueHolder components from stored saved state.
After an in-deep analysis, the conclusion was it is not really necessary to create the hint. Instead, we can create a better algorithm that take advantage of
the fact that add a non transient EditableValueHolder component inside a dataTable row on render response time leads to a illegal state.
Since UIData.setRowIndex is a code that is called multiple times, specially for large datatable sets. Doing some performance tests, it was notice the current
algorithm uses a lot of memory resources. The proposal is do the following:
1. Iterate using index instead iterator for children. This can duplicate the lines of code
2. Do not create Object[]
instances, use a private static final variable.
3. Cache DataListener[].
4. If no EditableValueHolder instances found, skip state saving code, but reset all ids.
5. Prevent unnecessary calls to getContainerClientId().
6. Provide initial size for created ArrayList instances to reduce memory usage.
7. Iterate over row state using index, instead iterator, and take advantage instances are ArrayList.
8. Do not instantiate ArrayList, unless it is necessary.
Tests done shows a really big improvement, specially when non EditableValueHolder component instances are inside the datatable, which is a very common use case.
Based on this patch we can do other things like:
1. Port this code to UIRepeat.
2. Port this code to Tomahawk.
3. Reuse already created state instances, which can improve performance on postback requests.