Remove reference to last page from idle SecondLevelCachePageMap
----------------------------------------------------------------
Key: WICKET-2889
URL: https://issues.apache.org/jira/browse/WICKET-2889
Project: Wicket
Issue Type: Improvement
Components: wicket
Affects Versions: 1.4.8
Environment: Wicket 1.4.8, Java 1.6.0_20 amd64, Ubuntu Hardy
Reporter: Stefan Fussenegger
Priority: Minor
Currently, the last used page per PageMap is kept in memory to avoid
deserialization overhead. After looking at a heap dump of my application, I
found that this strategy is pretty memory intensive: about 170M for 1500
session (115K per session) in the case of my application.
To reduce this overhead, I'd suggest to drop the last page for "idle" PageMaps.
A PageMap could be considered idle as soon as a user doesn't access a page for
10 minutes. I'd argue that it's pretty unlikely that a user accesses any page
after 10 minutes (admittedly depending on the application itself) anyway. In
cases the user becomes active again, the deserialization overhead should be
acceptable. As our application's sessions expire after 30 minutes, this feature
would save 2/3 or about 113M of 170M on memory.
public void expireLastPage() {
if (sessionId != null && lastPage instanceof Page) {
IPageStore store = getPageStore();
if (store instanceof ISerializationAwarePageStore) {
lastPage =
((ISerializationAwarePageStore)store).prepareForSerialization(sessionId, page)
}
}
}
A LinkedHashMap at application scope could be used to expire idle PageMaps,
e.g. using
private void setLastPage(Page lastPage) {
this.lastPage = lastPage;
// (re)add to map
LinkedHashMap<SecondLevelCachePageMap, Long> map =
Application.get().getMetaData(LAST_PAGE_EXPIRE_MAP);
map.remove(this);
map.put(this, System.currentTimeMillis());
}
A thread could then periodically check for idle PageMaps:
void run() {
Iterator<Map.Entry<SecondLevelCachePageMap, Long>> iter =
Application.get().getMetaData(LAST_PAGE_EXPIRE_MAP).iterator();
while (iter.hasNext()) {
Map.Entry<SecondLevelCachePageMap, Long> e = iter.next();
if (isIdle(e.getValue())) break;
e.getKey().expireLastPage();
iter.remove();
}
}
(the code is just to clarify the idea. for synchronization and encapsulation
purposes, the map should certainly be wrapped inside a new class).
Alternatively, pages could be expired if a configured capacity of the map is
exceeded. In this case it would be pretty hard to select a sane default that
suits most applications out of the box.
Please comment if this sound like an acceptable addition. I'd be happy to
submit a patch (or at least a a patch that would allow to easily extend the
current implementation). I'd really appreciate it this feature would find it's
way into 1.4.x, preferably as optionally configurable.
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.