80 Layout Caching
In the context of memory profile analsysis we are documenting the current bahavior of some caches in UserIstance class.
Abstract:
A cache is a repository used to store previously fetched resources, also known as objects. Caching provides two main benefits to a web application
- Your web application will be more responsive to the user because the interpreter will get access to your content more quickly. A responsive application is a key facet to increased customer satisfaction.
- The load on your Web servers is theoretically reduced at least in terms of CPU utilization. It might put more pressure on the memory utilization.
Caching Strategy:
To implement a successful caching mechanism a very well planned caching strategy is a key factor. The key issues that needs to be resolved are as follows
- Which pages should be cached
- Cache whole pages or page fragments
- Where caching should take place
- How to invalidate the cached data
UserInstance Cache:
Two member variables of UserInstance class are used to maintain this cache implementation (a home grown cache implementation).
- systemCache (see UP-1145)
- systemCharacterCache
If caching is enabled and character caching is NOT enabled then the SAX that represents the user's layout for the folder (tab) they are requesting will be attempted to be cached in the systemCache. If character caching is enabled, the serialized form of that layout will be stored in systemCharacterCache. Both indexed by the cacheKey from constructCacheKey(), which incidentally, has a bad side effect. If you look in processUserLayoutParameters() it manually binds the username to the theme preferences. This guarantees that no two users can share any cache entries. If the character cache is enabled, the system cache is not used.
Both of these caches are tied to the user session. That means the cached objects are only good for one particular user session and nothing will be shared with the other users. Is it really the intent of the design? I don't know but the fact is the current caching strategy is probably not the optimal. Following scenario will explain it.
Imagine user's layout has three tabs (tab 1, tab 2 and tab 3). Tab 1 is the default tab.
- User login and the both cache keys are not present so no cache hit. One interesting point is that not only is the user id included in the key, but also the user name. Much of the XHTML document is stored in the systemCharacterCache at end of processing.
- User clicks on the tab 2 - No cache hit was found and a new cache key is generated the page is put in the cache.
- User clicks on tab 3 - No cache hit and a new cache key is generated the page is put in the cache.
- User clicks on the tab 1 (the default tab) - No cache hit was found and a new cache key is generated the page is put in the cache.
- Now if user clicks on any other tab (without doing anything) then user will have a cache hit.
- User clicks on "preferences" (options) - No cache hit was found.
Note: Provided which tab was user on every time user click on options will cause a cache miss unless user was on the same tab last time when hits the options screen. - User click on choose skin screen. It will be a cache hit.
- User changes the skin and it will be cache miss. Now after user do this, all the stored cache keys for all the tabs will no longer good and user will have cache miss for every tab he/she goes too. But we are still keeping the old cacheKeys. If user will change back to previous skin then these cacheKeys will be found (Should we invalidate explicitly all the keys and remove all the cached objects from the map sine we know for sure the previous key will not be valid for any tab unless user change back to previously set skin.)
- Now imagine another user logged in and if user will go through step 1 through 8 will experience similar results because these caches are not shared within the users sessions.
Above scenario proves that this cache implementation is not very optimal you are keeping lots of data in the memory making a user session fat than it really need to be. One might argue that user might do lots of actions on one tab if it has cached data then cache is serving its purpose.
Lets take a look how good this assumption is (Assume the current tab is tab 1 and we have it stored in the cache)
- If user clicks on any channel to minimize, it will be cache miss.
- If user clicks on same channel to restore it to its original size, it will be cache miss.
- If user interacts with one channel within the tab then it is a character cache hit.
- Channel that tends to go in focus mode (e.g email) will have cache miss.
- After that if you interact with the channel it will be cache hit. Eg. If you navigate through pages of the channels it will be cache hit.
Cache key dissection
The following is a dissection of the cache key.
399820,userLayoutRootNode,system1activeTab=1userLayoutRoot=rootnewNodeID=authenticated=true(folder:s10087: 50%,)(folder:s10057:50%,)(folder:s10083:50%,)(folder:s10101:50%,)(folder:s10080:50%,)(folder:s10075:50%,)( folder:s10099:50%,)(folder:s10097:50%,)(folder:s10070:50%,)(folder:s10095:50%,)(folder:s10064:50%,)(folder: s10091:50%,)userName=JohnDoeskin=spring(channel:n10077:false,)(channel:n10058:false,)7885417921252830597
<person-id><comma><req-method-node-id><comma><upref-cache-key><ulayout-mgr-cache-key>
Key component |
Value |
---|---|
<person-id> |
399820 |
<comma> |
, |
<req-method-node-id> |
userLayoutRootNode |
<comma> |
, |
<upref-cache-key> |
system1activeTab=1userLayoutRoot=rootnewNodeID=authenticated=true(folder:s10087:50%,)(folder:s10057:50%,)(folder:s10083:50%,)(folder:s10101:50%,)(folder:s10080:50%,)(folder:s10075:50%,)(folder:s10099:50%,)(folder:s10097:50%,)(folder:s10070:50%,)(folder:s10095:50%,)(folder:s10064:50%,)(folder:s10091:50%,)userName=John Doeskin=spring(channel:n10077:false,)(channel:n10058:false,) |
<ulayout-mgr-cache-key> |
7885417921252830597 |
How each value is obtained:
1. <person-id>: 399820
- an integer identifier - obtained from the UserInstance instance:
getPerson().getID()
2. <req-method-node-id>: userLayoutRootNode
- obtained as follows:
(new UPFileSpec(req)).getMethodNodeId()
where the req is the HttpServletRequest. For example:
https://my.rutgers.edu/portal/tag.a0f28b48b5675695.render.userLayoutRootNode.target.n10062.uP?
command=EditBookmark#n10062,
<req-method-node-id> would be "userLayoutRootNode"
3. <upref-cache-key>: system1activeTab=1userLayoutRoot=rootnewNodeID=authenticated=true(folder:s10087:50%,)(folder:s10057:50%,)(fold
er:s10083:50%,)(folder:s10101:50%,)(folder:s10080:50%,)(folder:s10075:50%,)(folder:s10099:50%,)(folder:s10097:
50%,)(folder:s10070:50%,)(folder:s10095:50%,)(folder:s10064:50%,)(folder:s10091:50%,)userName=John Doeskin=spring(channel:n10077:false,)(channel:n10058:false,)
- definition in UserPreferences.java, obtained by:
uPreferencesManager.getUserPreferences().getCacheKey()
defined as follows:
[UPC:system]<profile-id><structure-upref><theme-upref>
For the example above:
[UPC:system]: system
<profile-id>: 1
<structure-upref>: activeTab=1userLayoutRoot=rootnewNodeID=authenticated=true(folder:s10087:50%,)(folder:s10057:50%,)(folder:
s10083:50%,)(folder:s10101:50%,)(folder:s10080:50%,)(folder:s10075:50%,)(folder:s10099:50%,)(folder:s10097:
50%,)(folder:s10070:50%,)(folder:s10095:50%,)(folder:s10064:50%,)(folder:s10091:50%,)
<theme-upref>: userName=JohnDoeskin=spring(channel:n10077:false,)(channel:n10058:false,)
a. [UPC:system] an optional String value ("system") prepended to System profiles
b. <profile-id>
- integer defined in UserProfile.getProfileId()
c. <structure-upref>
- a concatentation of cache keys from StructureStylesheetUserPreferences.getCacheKey()
and it's super-classes:
<str-stylesh-upref><str-theme-stylesh-upref><str-struct-stylesh-upref>
i. <str-stylesh-upref>: activeTab=1userLayoutRoot=rootnewNodeID=authenticated=true
- defined in: StylesheetUserPreferences.getCacheKey()
ii. <str-theme-stylesh-upref>: (None found in example: otherwise, would look like (channel:nnnnn:false,)
- defined in: ThemeStylesheetUserPreferences.getCacheKey()
iii. <str-struct-stylesh-upref>:
(folder:s10087:50%,)(folder:s10057:50%,)(folder:s10083:50%,)(folder:s10101:50%,)(folder:s10080:50%,)(folder:
s10075:50%,)(folder:s10099:50%,)(folder:s10097:50%,)(folder:s10070:50%,)(folder:s10095:50%,)(folder:s10064:
50%,)(folder:s10091:50%,)
- defined in: StructureStylesheetUserPreferences.getCacheKey()
d. <theme-upref>
- a concatenation of cache keys from ThemeStylesheetUserPreferences.getCacheKey()
<thm-stylesh-upref><thm-theme-stylesh-upref>
i. <thm-stylesh-upref>: userName=John Doeskin=spring
- defined in: StylesheetUserPreferences.getCacheKey()
ii. <thm-theme-stylesh-upref>: (channel:n10077:false,)(channel:n10058:false,)
- defined in: ThemeStylesheetUserPreferences.getCacheKey()
4. <ulayout-mgr-cache-key>: 7885417921252830597
- defined in SimpleUserLayoutManager.getCacheKey() - it is a random long
Notes
I believe there are thread contention issues with these two variables (systemCache UP-1145 and systemCharacterCache) since both are not synchronized and reads and updates are not made within the synchronized blocks either.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html lang="en" xml:lang="en"><head><title>myRutgers</title><meta content="text/html; charset=iso-8859-1" http-equiv="content-type" /><link type="image/x-icon" href="favicon.ico" rel="Shortcut Icon" /><link type="text/css" href="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/skin/myrutgers1.css" rel="stylesheet" /></head><body><div id="portal-page-header"><div id="logo"><img alt="myRutgers Logo" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/institutional/uportal_logo_grid.gif" height="60" width="255" /></div> <div id="tabs"><ul><li><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_root=root&uP_sparam=activeTab&activeTab=1"><span>Everyday</span></a></li><li><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_root=root&uP_sparam=activeTab&activeTab=2"><span>Libraries</span></a></li><li id="active-tab"><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_root=root&uP_sparam=activeTab&activeTab=3"><span>Campus Life</span></a></li><li><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_root=root&uP_sparam=activeTab&activeTab=4"><span>Administration</span></a></li><li><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_root=root&uP_sparam=activeTab&activeTab=5"><span>Reporting Tools</span></a></li><li><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_root=root&uP_sparam=activeTab&activeTab=6"><span>myTab</span></a></li></ul></div></div><div id="portal-page-body"><table width="100%" cellspacing="15" cellpadding="0"><tr><td valign="top" width="50%"><div class="portlet-toolbar"><div><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_tcattr=minimized&minimized_channelId=n10081&minimized_n10081_value=true#n10081"><img title="shade" alt="shade" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/max.gif" /></a><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_root=n10081"><img title="maximize" alt="maximize" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/focus.gif" /></a><a onclick="return confirm('Are you sure you want to remove this channel?')" href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_remove_target=n10081"><img title="remove" alt="remove" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/remove.gif" /></a></div><a name="n10081"><h2 id="n10081">Maps and Buildings</h2></a></div><div class="portlet clearfix"> </div><div class="portlet-toolbar"><div><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_tcattr=minimized&minimized_channelId=n10082&minimized_n10082_value=true#n10082"><img title="shade" alt="shade" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/max.gif" /></a><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_root=n10082"><img title="maximize" alt="maximize" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/focus.gif" /></a><a onclick="return confirm('Are you sure you want to remove this channel?')" href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_remove_target=n10082"><img title="remove" alt="remove" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/remove.gif" /></a></div><a name="n10082"><h2 id="n10082">Athletics</h2></a></div><div class="portlet clearfix"> </div></td><td valign="top" width="50%"><div class="portlet-toolbar"><div><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_tcattr=minimized&minimized_channelId=n10084&minimized_n10084_value=true#n10084"><img title="shade" alt="shade" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/max.gif" /></a><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_root=n10084"><img title="maximize" alt="maximize" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/focus.gif" /></a><a onclick="return confirm('Are you sure you want to remove this channel?')" href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_remove_target=n10084"><img title="remove" alt="remove" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/remove.gif" /></a></div><a name="n10084"><h2 id="n10084">Parking/Transportation</h2></a></div><div class="portlet clearfix"> </div><div class="portlet-toolbar"><div><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_tcattr=minimized&minimized_channelId=n10085&minimized_n10085_value=true#n10085"><img title="shade" alt="shade" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/max.gif" /></a><a href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_root=n10085"><img title="maximize" alt="maximize" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/focus.gif" /></a><a onclick="return confirm('Are you sure you want to remove this channel?')" href="tag.90299c0feb91b440.render.userLayoutRootNode.uP?uP_remove_target=n10085"><img title="remove" alt="remove" height="19" width="19" src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers1/controls/remove.gif" /></a></div><a name="n10085"><h2 id="n10085">Buses/Shuttles</h2></a></div><div class="portlet clearfix"> </div></td></tr></table></div><div id="portal-page-footer"><div><a href="http://www.rutgers.edu/" target="_blank"><img src="media/edu/rutgers/acs/portal/layout/tab-column/rutgers-theme/myrutgers/institutional/rutgers_footer_logo.gif" title="Go to Rutgers home page" alt="Rutgers Logo" height="30" width="99" /></a></div><p> Links to campus web sites: <a href="http://camden-www.rutgers.edu/" target="_blank">Camden</a>, <a href="http://rutgers-newark.rutgers.edu/" target="_blank">Newark</a>, <a href="http://nbp.rutgers.edu/" target="_blank">New Brunswick/Piscataway</a>, <a href="http://www.rutgers.edu/" target="_blank">Rutgers University</a>. <br /> For assistance, contact the Help Desks in: <a href="http://rucs.camden.rutgers.edu/" target="_blank">Camden</a>, <a href="http://www.ncs.rutgers.edu/helpdesk/" target="_blank">Newark</a>, or <a href="http://www.nbcs.rutgers.edu/helpdesk/hdnew/" target="_blank">New Brunswick/Piscataway</a>. </p></div></body></html>