Blogs
Issue
In Liferay 6.1, the staging site is extremely slow if versioning is enabled. It can take 30 seconds to 10 minutes to refresh a page on the staging site (depends on how many contents/portlets on your page).
Cause
If you enable hibernate show SQL by setting the log level to DEBUG for "org.hibernate.SQL" category in "Server Administration" or use JAVA profiler, you will find the following SQL is executed hundreds of times which slows down the staging site a lot:
The AOP class com.liferay.portal.service.impl.LayoutSetLocalServiceStagingAdvice has a pointcut on LayoutSetLocalService. The LayoutSetLocalService can be called hundreds of times in one page refresh. Each time the LayoutSetLocalService is getting called, the LayoutSetLocalServiceStagingAdvice.wrapLayoutSet() will be invoked.
If we look at the code: com.liferay.portal.service.impl.LayoutSetLocalServiceStagingAdvice.wrapLayoutSet()
It will first calls LayoutSetStagingHandler layoutSetStagingHandler = LayoutStagingUtil.getLayoutSetStagingHandler(layoutSet);
Check the code com.liferay.portal.staging.LayoutStagingImpl.getLayoutSetStagingHandler(LayoutSet layoutSet):
The above method will always return null because layoutSet is not a proxy class.
It will return null back to the LayoutSetLocalServiceStagingAdvice.wrapLayoutSet() method. Then the (LayoutSet)ProxyUtil.newProxyInstance( PACLClassLoaderUtil.getPortalClassLoader(), new Class[] {LayoutSet.class}, new LayoutSetStagingHandler(layoutSet)) will be to create a new proxy class to warp the LayoutSet.
Here comes important part: When creating a new LayoutSetStagingHandler(layoutSet), it will call the com.liferay.portal.service.persistence.LayoutSetBranchFinderImpl.findByMaster(long groupId, boolean privateLayout) method. But the LayoutSetBranchFinderImpl finder method does not have the Liferay finder cache enabled, so Liferay will query the database every time it is getting called.
So, each time LayoutSetLocalService is getting called, there will be at least one database query to the LayoutSetBranch table, which makes the staging site very slow.
Solution
The best solution in my mind is to change the way how Liferay handles the branching/versioning in Liferay staging or to reduce the call to LayoutSetLocalService class. But it requires a lot of work. I am still working on it and will send a pull request if I can finish it.
Another solution is to use ext plugin to overwrite the LayoutSetBranchFinderImpl class to add the Liferay finder cache and overwrite LayoutSetBranchPersistenceImpl class to clear the Liferay finder cache upon create/update/delete.
If you do not want to use ext environment, here is a workaround using hook plugin:
Override the com.liferay.portal.service.LayoutSetBranchLocalService in the hook plugin:
Implement the com.kzhang.liferay.portal.service.LayoutSetBranchLocalServiceWrapper:
The main idea is to leverage getLayoutSetBranches(groupId, privateLayout) method to get the master LayoutSetBranch instead of using the finder method, because the getLayoutSetBranches() method has Liferay entity cache enabled. But as you can see, it has a silly for loop in the code which is not cool.
After deployed the hook, the page loading time is reduced from 3 minutes to 2 seconds.
Or, what you can do is: you can use getLayoutSetBranch(groupId, privateLayout, "main-variation") instead of getLayoutSetBranches(groupId, privateLayout) to get better performance if you never change the name of the master branch (the default name of the master branch is "main-variation").

