• Bug
  • Status: Closed
  • 0 Showstopper
  • Resolution: Fixed
  • ehcache-core
  • drb
  • Reporter: bgranvea
  • September 26, 2009
  • 0
  • Watchers: 1
  • July 27, 2012
  • September 30, 2009

Description

I use EHCache as an Hibernate 2nd level cache with default policy (LRU). I’ve noticed that the performances degrade when the cache is full and that elements are evicted.

After investigation, I’ve found that LruPolicy evicts elements which have lastAccessTime=0, that is which have just been loaded from the database! This looks very unefficient.

Moreover, this bug triggers Hibernate message “org.hibernate.cache.ReadWriteCache - An item was expired by the cache while it was locked” because sometimes the evicted element was in a running transaction.

Comments

Boris Granveaud 2009-09-26

I’m not sure of how to submit a patch, so please don’t go mad if it isn’t the good way to do it :)

I solved the problem by patching Element and initializing lastAccessTime at creation. I’m not sure why its value is set at 0 for the moment, is it on purpose? Anyway, here is the patch:

public Element(Object key, Object value, long version) {
    this.key = key;
    this.value = value;
    this.version = version;
    creationTime = System.currentTimeMillis();
    lastAccessTime = System.currentTimeMillis();
    hitCount = 0;
}

public final void resetAccessStatistics() {
    lastAccessTime = System.currentTimeMillis();
    nextToLastAccessTime = 0;
    hitCount = 0;
}

However, even with this patch, it didn’t solve my real problem which is that at some point in the benchmark of my Hibernate application, the database gets overloaded. It just happens later now. I finally managed to solve this by using the old LruMemoryStore (-Dnet.sf.ehcache.use.classic.lru=true).

From what I understand, the findEvictionCandidate algorithm which uses element sampling (15 samples) is not optimal for me. My cache contains 200000 elements so the oldest elements can stay very long without being evicted.

Steve Harris 2009-09-30

Can we develop a set of steps that reproduce this issue?

gluck 2009-09-30

I took a look at the patch you submitted.

In 1.5 both puts and gets count as “use”. In 1.6 only gets do.

So, though your patch does not completely solve Hibernate (we probable need to update the plugin for that, which we will do) your patch does highlight a very serious problem in the eviction algorithm.

I have added the following test to LruMemoryStoreTest which shows the issue. The change identified in your patch fixes this issue.

/** * Test the LRU policy */ @Test public void testProbabilisticEvictionPolicy() throws Exception { createMemoryOnlyStore(MemoryStoreEvictionPolicy.LRU, 500);

    //Make sure that the store is empty to start with
    assertEquals(0, cache.getSize());

    // Populate the store till the max limit
    Element element = new Element("key1", "value1");
    for (int i = 0; i < 500; i++) {
        cache.put(new Element("" + i, "value1"));
    }
    Thread.sleep(1010);
    for (int i = 0; i < 500; i++) {
        cache.get("" + i);
    }

    //evict some
    for (int i = 501; i < 750; i++) {
        cache.put(new Element("" + i, "value1"));
    }

    int lastPutCount = 0;
    for (int i = 501; i < 750; i++) {
        if (cache.get("" + i) != null) {
            lastPutCount++;
        }
    }

    assertTrue("Ineffective eviction algorithm. Less than 230 of the last 249 put Elements remain.", lastPutCount >= 230);
}

I think as a result 1.7’s evictors for LRU, LFU and FIFO will behave much more like 1.5.

I will close this issue and add a new one for Hibernate locking cache Elements.

Fix in 1.7.

Greg