Skip to content

Commit

Permalink
TRUNK-6047: Add utility methods to invalidate database caches (#4421)
Browse files Browse the repository at this point in the history
  • Loading branch information
IamMujuziMoses authored Aug 5, 2024
1 parent e52c2a1 commit f4d8a38
Show file tree
Hide file tree
Showing 4 changed files with 162 additions and 0 deletions.
30 changes: 30 additions & 0 deletions api/src/main/java/org/openmrs/api/context/Context.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@

import org.aopalliance.aop.Advice;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.SessionFactory;
import org.openmrs.Allergen;
import org.openmrs.GlobalProperty;
import org.openmrs.OpenmrsObject;
import org.openmrs.PersonName;
import org.openmrs.Privilege;
import org.openmrs.Role;
Expand Down Expand Up @@ -890,6 +892,34 @@ public static void evictFromSession(Object obj) {
getContextDAO().evictFromSession(obj);
}

/**
* Evicts the entity data for a particular entity instance.
*
* @param object entity instance to evict from the DB cache
*/
public static void evictEntity(OpenmrsObject object) {
log.debug("Clearing DB cache for entity: {} with id: {}", object.getClass(), object.getId());
getContextDAO().evictEntity(object);
}

/**
* Evicts all entity data of a particular class from the given region.
*
* @param entityClass entity class to evict from the DB cache
*/
public static void evictAllEntities(Class<?> entityClass) {
log.debug("Clearing DB cache for entities of type: {}", entityClass);
getContextDAO().evictAllEntities(entityClass);
}

/**
* Evicts data from all cache regions.
*/
public static void clearEntireCache() {
log.debug("Clearing DB cache from all regions");
getContextDAO().clearEntireCache();
}

/**
* Starts the OpenMRS System Should be called prior to any kind of activity
*
Expand Down
25 changes: 25 additions & 0 deletions api/src/main/java/org/openmrs/api/db/ContextDAO.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import java.util.Properties;
import java.util.concurrent.Future;

import org.hibernate.SessionFactory;
import org.openmrs.OpenmrsObject;
import org.openmrs.User;
import org.openmrs.api.context.Context;
import org.openmrs.api.context.ContextAuthenticationException;
Expand Down Expand Up @@ -120,6 +122,29 @@ public interface ContextDAO {
*/
public void evictFromSession(Object obj);

/**
* Evicts the entity data for a particular entity instance.
*
* @param object entity instance to evict from the DB cache
* @see org.openmrs.api.context.Context#evictEntity(OpenmrsObject)
*/
public void evictEntity(OpenmrsObject object);

/**
* Evicts all entity data of a particular class from the given region.
* @param entityClass entity class to evict from the DB cache
* @see org.openmrs.api.context.Context#evictAllEntities(Class)
*/
public void evictAllEntities(Class<?> entityClass);

/**
* Evicts data from all cache regions.
*
* @see org.openmrs.api.context.Context#clearEntireCache()
*/
public void clearEntireCache();

/**
* Used to re-read the state of the given instance from the underlying database.
* @since 2.0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.hibernate.stat.Statistics;
import org.hibernate.type.StandardBasicTypes;
import org.openmrs.GlobalProperty;
import org.openmrs.OpenmrsObject;
import org.openmrs.User;
import org.openmrs.api.context.Context;
import org.openmrs.api.context.ContextAuthenticationException;
Expand Down Expand Up @@ -371,6 +372,32 @@ public void clearSession() {
public void evictFromSession(Object obj) {
sessionFactory.getCurrentSession().evict(obj);
}

/**
* @see org.openmrs.api.db.ContextDAO#evictEntity(OpenmrsObject)
*/
@Override
public void evictEntity(OpenmrsObject obj) {
sessionFactory.getCache().evictEntity(obj.getClass(), obj.getId());
}

/**
* @see org.openmrs.api.db.ContextDAO#evictAllEntities(Class)
*/
@Override
public void evictAllEntities(Class<?> entityClass) {
sessionFactory.getCache().evictEntityRegion(entityClass);
sessionFactory.getCache().evictCollectionRegions();
sessionFactory.getCache().evictQueryRegions();
}

/**
* @see org.openmrs.api.db.ContextDAO#clearEntireCache()
*/
@Override
public void clearEntireCache() {
sessionFactory.getCache().evictAllRegions();
}

/**
* @see org.openmrs.api.db.ContextDAO#refreshEntity(Object)
Expand Down
80 changes: 80 additions & 0 deletions api/src/test/java/org/openmrs/api/context/ContextTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@
import java.util.Locale;
import java.util.Map;

import org.hibernate.SessionFactory;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import org.openmrs.Location;
import org.openmrs.OpenmrsObject;
import org.openmrs.Patient;
import org.openmrs.Person;
import org.openmrs.PersonName;
import org.openmrs.User;
Expand All @@ -34,6 +37,7 @@
import org.openmrs.test.jupiter.BaseContextSensitiveTest;
import org.openmrs.util.LocaleUtility;
import org.openmrs.util.OpenmrsConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.Validator;

/**
Expand All @@ -43,6 +47,13 @@
*/
public class ContextTest extends BaseContextSensitiveTest {

private static final Class PERSON_NAME_CLASS = PersonName.class;
private static final Integer PERSON_NAME_ID_2 = 2;
private static final Integer PERSON_NAME_ID_8 = 8;

@Autowired
private SessionFactory sf;

/**
* Methods in this class might authenticate with a different user, so log that user out after
* this whole junit class is done.
Expand Down Expand Up @@ -273,4 +284,73 @@ public void becomeUser_shouldChangeLocaleWhenBecomeAnotherUser() {

Context.logout();
}

/**
* @see org.openmrs.api.context.Context#evictEntity(OpenmrsObject)
*/
@Test
public void evictEntity_shouldClearTheEntityFromCaches() {
// Load the person so that the names are also stored in the cache
PersonName name = Context.getPersonService().getPersonName(PERSON_NAME_ID_2);
Context.getPersonService().getPersonName(PERSON_NAME_ID_8);

// Assert that the names have been added to cache
assertTrue(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_2));
assertTrue(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_8));

// evictEntity
Context.evictEntity(name);

// Assert that the entity name has been removed from cache
assertFalse(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_2));
assertTrue(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_8));
}

/**
* @see org.openmrs.api.context.Context#evictAllEntities(Class)
*/
@Test
public void evictAllEntities_shouldClearAllEntityFromCaches() {
// Load the person and patient so that they are stored in the cache
Context.getPersonService().getPersonName(PERSON_NAME_ID_2);
Context.getPersonService().getPersonName(PERSON_NAME_ID_8);
Context.getPatientService().getPatient(PERSON_NAME_ID_2);

// Assert that the entities have been added to cache
assertTrue(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_2));
assertTrue(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_8));
assertTrue(sf.getCache().containsEntity(Patient.class, PERSON_NAME_ID_2));

// evictAllEntities
Context.evictAllEntities(PERSON_NAME_CLASS);

// Assert that the class entities have been removed from cache
assertFalse(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_2));
assertFalse(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_8));
assertTrue(sf.getCache().containsEntity(Patient.class, PERSON_NAME_ID_2));
}

/**
* @see org.openmrs.api.context.Context#clearEntireCache()
*/
@Test
public void clearEntireCache_shouldClearEntireCache() {
// Load the person and patient so that they are stored in the cache
Context.getPersonService().getPersonName(PERSON_NAME_ID_2);
Context.getPersonService().getPersonName(PERSON_NAME_ID_8);
Context.getPatientService().getPatient(PERSON_NAME_ID_2);

// Assert that the entities have been added to cache
assertTrue(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_2));
assertTrue(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_8));
assertTrue(sf.getCache().containsEntity(Patient.class, PERSON_NAME_ID_2));

// clearEntireCache
Context.clearEntireCache();

// Assert that all entities have been removed from cache
assertFalse(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_2));
assertFalse(sf.getCache().containsEntity(PERSON_NAME_CLASS, PERSON_NAME_ID_8));
assertFalse(sf.getCache().containsEntity(Patient.class, PERSON_NAME_ID_2));
}
}

0 comments on commit f4d8a38

Please sign in to comment.