SecondLevelCacheStatistics for a region return an empty list

I am working on issue [TRUNK-6047] Add utility methods to invalidate database caches - OpenMRS Issues where i have got to copy, modify and paste RESTWS-866 into core.
There has been alternation in hibernate used in the current version of openmrs-core and that used in 1.9.10 release hence some methods are undefined.
I have opened up a PR for the work done at the moment.

Well, drama started while verifying that entities exist in a single Region (for this case org.openmrs.Person.names) before evicting a single entity, all of them or clearing the whole cache.

Below is the testing logic.

//SessionFactory sf = (SessionFactory) applicationContext.getBean("sessionFactory");
PersonName name = Context.getPersonService().getPersonName(PERSON_NAME_ID_2);
//Load the person so that the names are also stored  in person names collection region
Context.getPersonService().getPerson(name.getPerson().getPersonId());

//Let's have the name in a query cache
sf.getCurrentSession().createCriteria(PERSON_NAME_CLASS)
	.add(Restrictions.eq("personNameId", PERSON_NAME_ID_2))
	.setCacheable(true)
	.setCacheRegion(QUERY_REGION)
	.list();

The entity exists in the Cache: because the following assert passes.

assertTrue(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_2));

Tests that are failing:

assertNotNull(sf.getStatistics().getSecondLevelCacheStatistics(Person.class.getName() + ".names")
	.getEntries().get(name.getPerson().getPersonId()));
assertEquals(1, sf.getStatistics().getCacheRegionStatistics(QUERY_REGION).getElementCountInMemory());

The above methods have to pass before i call may eviction methods i have added in Context.

cc @dkayiwa @wyclif @ibacher

To quote from the Hibernate docs: “By default, the statistics are not collected because this incurs an additional processing and memory overhead.” So, most likely, we just haven’t enabled Hibernate statistics… and I probably wouldn’t do that just for this use case. Why do you need those two tests to pass? Just remove them. sf.getCache().containsEntry() seems to be enough to prove whether or not the entity is in the cache.

2 Likes

Alright @ibacher I understand.

Those assertions are meant to ensure that query caches are discarded, I think the name second-level-statistics is a little confusing here, they are not really hit/miss statistics. Basically if you comment out the calls to sf.getCache().evictQueryRegions() in your new methods, the tests should fail otherwise should pass

The reason you are getting back null or empty lists is because you have not actually enabled the query cach

@ibacher @wyclif Sorry to bring this again, it seamed clear until i tried it again.
It’s like hibernate.generate_statistics and hibernate.cache.use_second_level_cache are set to true in core, otherwise, this could not be the configuration file used by hibernate :thinking:
Actually sf.getStatistics().isStatisticsEnabled() returns true.

I thought this is done through .setCacheable(true) which I did while creating a query.
Even hibernate.cache.use_second_level_cache is also set to true in core-api

What could be going wrong here?? Is there any other way we could test the existence of query regions??

You also need to enable query cache too in the hibernate properties, .setCacheable(true) alone won’t work

i have added hibernate.cache.use_query_cache=true to the hibernate.default.properties but still the magic isn’t working

am still getting null with

sf.getStatistics().getSecondLevelCacheStatistics(Person.class.getName() + ".names")
	.getEntries()

However, am still pushing trying. Most resources on Google prompt doing what i have done

Inside a test, you probably need to override this method rather than editing the properties directly. E.g.,

public Properties getRuntimeProperties() {
    Properties runtimeProperties = super.getRuntimeProperties();
    runtimeProperties.setProperty("hibernate.cache.use_query_cache", true);
}
1 Like

Hello @ibacher this has also failed. I am still getting null

overrode the method with @Override annotation hence its called in my test methods before any queries are done

@Override
public Properties getRuntimeProperties() {
    Properties runtimeProperties = super.getRuntimeProperties();
    runtimeProperties.setProperty("hibernate.cache.use_query_cache", true);
}
...

I thought that may be i needed to restart the context after adding the property with Context.getContextDAO().startup(runtimeProperties).
On trying it, it was throwing an org.openmrs.api.APIException: contextDAO is null yet Context.getContextDAO() returns an org.openmrs.api.db.hibernate.HibernateContextDAO hence not null

Can you trying adding a hibernate.default.properties file in the test resources folder and see if that works? Possibly with just that one property. Though I’d think overriding getRuntimeProperties should work too

1 Like

I have copied and pasted https://github.com/openmrs/openmrs-core/blob/master/api/src/main/resources/hibernate.default.properties into https://github.com/openmrs/openmrs-core/tree/master/api/src/test/resources and rebuilt the whole project, but its still now working

After setting the property in the override method, when i check whether it exists runtimeProperties.containsKey("hibernate.cache.use_query_cache"), I get true meaning it exists.

Is there a way i can re-run reload or refresh, in other wards, make the configurations be picked again? I have tried Context.getContextDAO().startup(runtimeProperties) but it complains that contextDAO is null

Maybe there is something i need to add in openmrs-core/ehcache.xml at master · openmrs/openmrs-core · GitHub

I am going to give this one more day of trial. If it doesn’t work out, i will try and see if there is any other way of enabling query-cache other than relaying on the environment variables.