Announcement Announcement Module
Collapse
No announcement yet.
Share cache manager with hibernate Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Share cache manager with hibernate

    Is it possible to define an ehcache cache manager in my applicationContext and to use it in both hibernate and my caches.

    It can't figure out how I can pass my cache manager to hibernate. Does this mean that if I use ehcache for my own purpose I will have two cache manager : one for hibernate and one for me ? Is it a problem ?

    Thanx

    Seb

  • #2
    EhCache uses only one CacheManager instance - singleton. So you will always get the same instance, no matter wher you use it.
    But at the moment ehcache doesn't count instance requests, which is not a good thing when doing a manager shutdown - it closes it on first call, although other parts of app might still use it.

    I fixed this part:

    public void shutdown() {
    if (isAlive()) {
    released();
    return;
    } else if (status == STATUS_SHUTDOWN) {

    /**
    * Counting the number of times the instance has been requested.
    * So when different libraries or parts of app use getInstance method
    * it get incremented and when that same code calls (it should!) shutdown it gets decremented.
    * So that we don't get warning log output on shut down.
    */

    private void requested() {
    instanceRequestCount++;
    }

    private void released() {
    instanceRequestCount--;
    }

    public boolean isAlive() {
    return (status == STATUS_ALIVE && instanceRequestCount > 0);
    }

    public static CacheManager create() throws CacheException {
    synchronized (CacheManager.class) {
    if (instance == null) {
    if (LOG.isDebugEnabled()) {
    LOG.debug("Creating new CacheManager with default config");
    }
    instance = new CacheManager();
    } else {
    if (LOG.isDebugEnabled()) {
    LOG.debug("Attempting to create an existing instance. Existing instance returned.");
    }
    }
    instance.requested();
    return instance;
    }
    }

    Comment


    • #3
      One other solution (but I depends on your requirements) is to use a different cache provider like OSCache. Take a look at it - it's well supported and has plenty of nifty features.

      Comment


      • #4
        Now that EhCache supports multiple CacheManagers, I am wondering how to ensure that I use the same one for Hibernate as for my other caching needs.

        I am using "declarative caching" via Spring Modules 0.7, and I thought it would be smart to use EhCache as the backing cache considering that I'm already using it for Hibernate. I configured a cache provider in one of my xml files as follows:

        Code:
        <bean id="cacheManager"
          class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        </bean>
        
        <bean id="cacheProviderFacade"
          class="org.springmodules.cache.provider.ehcache.EhCacheFacade">
          <property name="cacheManager" ref="cacheManager" />
        </bean>
        I have omitted the part where I configure the target bean and the method names to cache.

        For hibernate, I have my hibernate.cacheProvider property set to org.hibernate.cache.EhCacheProvider.

        Everything works fine, in the sense that things get cached as expected.

        However, when I start up my web app, I get a warning message that indicates I am using two separate CacheManagers:

        CacheManager.detectAndFixDiskStorePathConflict(271 ) | Creating a new instance of CacheManager using the diskStorePath "C:\Tools\tomcat-5.5.16\temp" which is already used by an existing CacheManager.
        The source of the configuration was classpath.
        The diskStore path for this CacheManager will be set to C:\Tools\tomcat-5.5.16\temp\ehcache_auto_created_1170880092968.
        To avoid this warning consider using the CacheManager factory methods to create a singleton CacheManager or specifying a separate ehcache configuration (ehcache.xml) for each CacheManager instance.
        So it seems that Hibernate is instantiating a CacheManager, and then my declarative caching is instantiating a different one using the same ehcache.xml config file and thus colliding on the disk store path.

        I could pretty easily create a second ehcache.xml and then use two CacheManagers, but I'd prefer to use just one. I tried setting the property "shared" to "true" on my cacheManager bean, but that didn't cause the warning message to go away like I had hoped.

        How can I get Hibernate and the declarative caching to use the same CacheManager?

        Comment


        • #5
          I'm pretty sure there is already a defect in JIRA regarding this. When I was looking into sharing the cache between Hibernate and Acegi, I wondered if this was possible. I'm not sure about the current state as I didn't set a watch on it.

          Comment


          • #6
            Ok, I think this might have been it..........
            http://opensource.atlassian.com/proj...rowse/SPR-1966

            Comment


            • #7
              Solved the problem with our own EhCacheProvider, that uses the global instance instead of creating is own:


              Code:
              package dummy;
              
              import java.net.URL;
              import java.util.Properties;
              import java.util.logging.Level;
              import java.util.logging.Logger;
              import net.sf.ehcache.CacheManager;
              import org.hibernate.cache.Cache;
              import org.hibernate.cache.CacheException;
              import org.hibernate.cache.CacheProvider;
              import org.hibernate.cache.Timestamper;
              import org.hibernate.cfg.Environment;
              import org.hibernate.util.ConfigHelper;
              
              import org.hibernate.util.StringHelper;
              
              public class EhCacheProvider implements CacheProvider
              {
                private static Logger logger = Logger.getLogger(EhCacheProvider.class.getName());
              
                private CacheManager cacheManager;
              
                public Cache buildCache(String name, Properties properties) throws CacheException
                {
                  try
                  {
                    net.sf.ehcache.Cache cache = cacheManager.getCache(name);
                    if (cache == null)
                    {
                      logger.warning("Could not find configuration [" + name + "]; using defaults.");
                      cacheManager.addCache(name);
                      cache = cacheManager.getCache(name);
                      logger.config("started EHCache region: " + name);
                    }
                    else
                    {
                      logger.config("found EHCache region: " + name);
                    }
                    return new EhCache(cache);
                  }
                  catch (net.sf.ehcache.CacheException e)
                  {
                    throw new CacheException(e);
                  }
                }
              
                public long nextTimestamp()
                {
                  return Timestamper.next();
                }
              
                public void start(Properties properties) throws CacheException
                {
                  cacheManager=CacheManager.getInstance();
                }
              
                public void stop()
                {
                  // Spring will do this already
                }
              
                public boolean isMinimalPutsEnabledByDefault()
                {
                  return false;
                }
              
                public CacheManager getCacheManager()
                {
                  return cacheManager;
                }
              
                public void setCacheManager(CacheManager manager)
                {
                  cacheManager = manager;
                }
                
                private class EhCache extends org.hibernate.cache.EhCache
                {
                  public EhCache(net.sf.ehcache.Cache cache) {
                    super(cache);
                  }
              
                  public void destroy() throws CacheException
                  {
                    // Spring will do this already
                  }
              
                }
              
              }
              XML configuration as follows (Important: use depends-on, to make sure, the cache regions already exist):
              Code:
              	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" depends-on="lastCacheRegion">
              		<property name="hibernateProperties">
              			<props>
              				<prop key="hibernate.cache.provider_class">dummy.EhCacheProvider</prop>
              				...
              			</props>
              		</property>
              		...
              	</bean>
              Hope, that helps.

              Comment


              • #8
                I would be nice if the JIRA issue was fixed though . Have to get voting.

                Comment


                • #9
                  No need to patch this yourself, at least not anymore with ehcache1.2.3, it
                  comes with a SingletonEhCacheProvider, as in

                  Code:
                  hibernate.cache.provider_class=net.sf.ehcache.hibernate.SingletonEhCacheProvider

                  Comment


                  • #10
                    I've tried replacing EhCacheProvider with SingletonEhCacheProvider, but it doesn't seem to make any difference. I still get the Warning
                    "Creating a new instance of CacheManager using the diskStorePath "C:\xxx\Temp\" which is already used by an existing CacheManager. ...."

                    I'm using ehcache-1.2.4.

                    In my LocalSessionFactoryBean I've set the hibernate.cache.provider_class as a property of hibernateProperties, which is getting picked up correctly.
                    But in another part of my config I've already got a org.springframework.cache.ehcache.EhCacheManagerFa ctoryBean set up as a cacheManager for a CasAuthenticationProvider.

                    Anything else I can try to get them to point to the same instance?

                    Comment


                    • #11
                      It's worth checking that you have the "shared" property set to true on your EhCacheManagerFactoryBean definition...

                      Comment


                      • #12
                        Originally posted by robmoore View Post
                        It's worth checking that you have the "shared" property set to true on your EhCacheManagerFactoryBean definition...
                        Above suggestion solved the problem for me. I am unsure why the shared prop is there in the first place since the EhCacheManagerFactoryBean bean was specified as singleton but at least setting the prop as follows fixed the problem. Thanks!

                        Code:
                            <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" scope="singleton">
                                <property name="shared" value="true"/>
                                <property name="configLocation">
                                    <value>classpath:ehcache.xml</value>
                                </property>
                            </bean>

                        Comment

                        Working...
                        X