MyFaces2 State Saving Performance Improvements
Student: Marius PETOI (petoi_marius AT yahoo DOT com, marius.petoi AT codebeat DOT ro)
Organization : Apache Software Foundation
Mentor : Martin MARINSCHEK < martin.marinschek AT apache DOT org >
This project’s aim is to study the current state saving performance of MyFaces 2.0 and to find where this could be improved and the means by which it can be done.
The first steps for improving the state-saving performance were already made by introducing partial state saving. This implies saving on each request rather than the entire state, just the differences of the last saved state. This way, the memory consumption is reduced. Measurements show that the memory consumption improvement is reduced to about 20% of the initial value. This is the starting point for the current project. More detailed measures should be done at first and determine what else might be improved. Then, these improvements should be implemented. Just taking a glance over state saving, an improvement which could be done is implementing the partial view state saving in table components.
In JSF 2.0 there is the possibility to partially save the state of the page in the ExternalContext. This means that at the first request the entire state is saved, but afterwards only the differences from this are saved. MyFaces 2.0 introduces the “StateManagementStrategy”, which is an interface for strategies used for saving and respectively loading the view. The default MyFaces strategy implemented so far, upon saving the view checks whether there has been a previously saved view. If so, it saves just the differences between the old state and the new, actual state. If not, the entire state is saved in the external context request map.
At the moment, the saved state contains the component tree together with properties for each component (a list of its children and facets, together with the list of listeners, the behaviours map, etc). Every component is responsible for creating its own “state” object, which is afterwards included in the parent’s state object. In the end, the “state” of the UIViewRoot and the tree of components is saved in the ExternalContext. The actual state is written in the response by ResponseManager objects. The ResponseManager used so far is the HtmlResponseStateManager, which writes to the response the HTML code representing the actual saved state. Also, this manager object retrieves the state from the external context, when a request is received.
Upon restore, the UIViewRoot is constructed using the information stored in the ExternalContext and using the existing UIViewRoot (the UIViewRoot from the last request). This is done in the Restore View phase of the JSF lifecycle.
On the other hand, all component classes implement the interface PartialStateHolder, which extends StateHolder. StateHolder is an interface which contains methods for saving and loading state. Its extension, PartialStateHolder contains three extra methods: clearInitialState, initialStateMarked and markInitialState, which help to the implementation of partial state saving. All components that have a partial saving of their state implement this interface. The difference between full state and partial state is made using two wrapper marker classes: _AttachedStateWrapper and _AttachedDeltaWrapper.
In the Application object, a StateManager is held. The actual state manager used at the moment is JspStateManagerImpl. In the restore view phase of the JSF lifecycle, the "restoreView" method of the StateManager is invoked. This retrieves the StateManagementStrategy, which traverses the component tree and for each of the components restores its state(this means that the "restoreState" metod of the component is invoked). Also the tree of components is updated by taking into account the added and removed components. Upon saving, the added and removed components are saved, as well as the difference in state for each of the components. For each of the components, the "saveState" method is invoked.
In the base class for all components, UIComponentBase, the method "restoreState" builds the component based either on the full state or based on the old state and the saved "delta". The difference between the two is made by using the two different wrappers for states: _AttachedStateWrapper and _AttachedDeltaWrapper. In addition to these, there is another wrapper class for lists: _DeltaList, which adds to the normal list partial saving and restoring functionalities. Upon restore state, for lists, the elements that do not exist are added, while the state for the existing ones is updated.
The state in UIComponentBase is: faces listeners, behaviors map and system event listener class map. In addition to these, there is the StateHelper, which was initially designed to hold properties which are not components (for example properties which have only a String value, for which there is no "delta"). The implementing class used for partial state saving is _DeltaStateHelper, which for a certain component stores the initial value and the deltas, which represent the values of the properties at some stages for some properties retrieved with a key.
However, there are some properties which are components and which are saved in the StateHelper. For objects saved in the StateHelper, partial state saving is not used, as the entire object is saved at each stage. One example of such objects for which partial state saving is skipped are PhaseListeners. For UIOutput objects, only data of elementary types are saved in the StateHelper. For UIInput objects, the ValueChangeListeners are components that do not have a partial saved state.
This project is intended to take a deeper look into what exactly is saved at the moment. The saved state should be analyzed and see whether anything can be skipped. A good starting point for this is looking at what components save in their StateHelper. Memory profiling should be done and see which part of the saved state occupies the most memory. Afterwards, we should see how much of this is really used and what can be dismissed. Also, the table component does not have partial state saving at all.
In the end, after all the improvements will have been implemented, the memory profiling should be done again and see how much the gain was.
This project will follow the guidelines of the Apache Foundation.
As this involves the core of MyFaces, every change will have a big impact on the community, on all the component sets using the MyFaces implementation. Therefore, every change that we decide to make must be carefully thought.
April 27 - May 3
Study state saving in the JSF implementation from Oracle, Mojarra. Reading documentation and studying code.
May 4 - May 10
May 11 – May 24
Doing profiling on the current MyFaces implementation. See what can be improved, where the state saved can be diminished. Decide on the changes which are to be made.
May 25 - July 5
Implementing the improvements which were decided in the previous period.
July 6 - July 12
Preparing for mid-term evaluations: running profiling with the improved state saving and working on mid-term evaluation criteria. At the end of this period, based on profiling results, new changes should be considered.
July 13 - July 25
Implementing the new improvements.
July 26 - August 9
Profiling, testing and bug fixing.
August 9 - August 16
Preparing tutorials and presentations, improving documentation. Preparing for final evaluation and getting the final release ready.
I graduated the Politehnica University Timisoara, Romania, Department of Computer Science having the highest average mark on the class of 2008. At the moment, I am a student in the 2nd year at the master programme “Advanced Computer Systems”.
I am a big open source fan and supporter. Since September 2009, I have been working for Codebeat, the subsidiary of IRIAN, which is the main contributor in the Apache MyFaces project. At Apache MyFaces, other than providing some patches, I've worked on developing a new skinning module based on the skinning from Trinidad. Also, I started writing a new set of layouting components for JSF 2.0. I am a Trinidad contributor, provided several patches and made several bug fixes.
I will graduate in June and I have only the dissertation thesis in June. I already started my dissertation thesis, it is almost finished, so there will be no problems with my commitment for Google Summer of Code. Currently, I am working full time, but the company I am working for supports me with this project and are directly involved with MyFaces. I guarantee that, I can work 30 hours a week on my project.