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.

Reply via email to