← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 17264: Approvals, getUserDataApprovals, introduced caches to avoid database-call-per-resultset-row

 

------------------------------------------------------------
revno: 17264
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Fri 2014-10-24 14:15:42 +0200
message:
  Approvals, getUserDataApprovals, introduced caches to avoid database-call-per-resultset-row
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/PeriodType.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/PeriodType.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/PeriodType.java	2014-10-24 11:45:30 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/period/PeriodType.java	2014-10-24 12:15:42 +0000
@@ -247,7 +247,6 @@
         {
             return periodCache.get( getCacheKey( date ), new Callable<Period>()
             {
-                @Override
                 public Period call() throws Exception
                 {
                     return createPeriod( createCalendarInstance( date ) );
@@ -284,7 +283,6 @@
         {
             return periodCache.get( getCacheKey( calendar, date ), new Callable<Period>()
             {
-                @Override
                 public Period call() throws Exception
                 {
                     return createPeriod( calendar.fromIso( DateTimeUnit.fromJdkDate( date ) ), calendar );

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java	2014-10-24 11:45:30 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/dataapproval/hibernate/HibernateDataApprovalStore.java	2014-10-24 12:15:42 +0000
@@ -32,6 +32,9 @@
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 
 import org.hibernate.Criteria;
 import org.hibernate.criterion.Restrictions;
@@ -53,6 +56,9 @@
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.support.rowset.SqlRowSet;
 
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+
 /**
  * @author Jim Grace
  */
@@ -60,6 +66,18 @@
     extends HibernateGenericStore<DataApproval>
     implements DataApprovalStore
 {
+    private static Cache<Integer, Period> PERIOD_CACHE = CacheBuilder.newBuilder()
+        .expireAfterAccess( 10, TimeUnit.MINUTES ).initialCapacity( 1000 )
+        .maximumSize( 2000 ).build();
+
+    private static Cache<Integer, DataElementCategoryOptionCombo> OPTION_COMBO_CACHE = CacheBuilder.newBuilder()
+        .expireAfterAccess( 10, TimeUnit.MINUTES ).initialCapacity( 10000 )
+        .maximumSize( 50000 ).build();
+
+    private static Cache<Integer, OrganisationUnit> ORGANISATION_UNIT_CACHE = CacheBuilder.newBuilder()
+        .expireAfterAccess( 10, TimeUnit.MINUTES ).initialCapacity( 10000 )
+        .maximumSize( 50000 ).build();
+
     // -------------------------------------------------------------------------
     // Dependencies
     // -------------------------------------------------------------------------
@@ -248,44 +266,72 @@
         
         Set<DataApproval> userDataApprovals = new HashSet<>();
 
-        while ( rowSet.next() )
-        {
-            Integer attributeOptionComboId = rowSet.getInt( 1 );
-            Integer periodId = rowSet.getInt( 2 );
-            Integer level = rowSet.getInt( 3 );
-            Integer orgUnitId = rowSet.getInt( 4 );
-            Boolean accepted = rowSet.getBoolean( 5 );
-
-            if ( attributeOptionComboId == previousAttributeOptionComboId && periodId == previousPeriodId && level > previousLevel )
-            {
-                continue;
-            }
-
-            previousAttributeOptionComboId = attributeOptionComboId;
-            previousPeriodId = periodId;
-            previousLevel = level;
-
-            DataElementCategoryOptionCombo attributeOptionCombo = categoryService.getDataElementCategoryOptionCombo( attributeOptionComboId );
-            Period period = periodService.getPeriod( periodId );
-            DataApprovalLevel dataApprovalLevel = ( level == null ? null : levelMap.get( level ) );
-            OrganisationUnit orgUnit = ( orgUnitId == null ? null : organisationUnitService.getOrganisationUnit( orgUnitId ) );
-
-            //TODO: currently special cased for PEFPAR's requirements. Can we make it more generic?
-            if ( level > 1 && attributeOptionCombo.equals( defaultOptionCombo ) )
-            {
-                for ( OrganisationUnit ou : getUserOrgsAtLevel( 3 ) )
-                {
-                    DataApproval da = new DataApproval( dataApprovalLevel, null, period, ou, attributeOptionCombo, accepted, null, null );
-
-                    userDataApprovals.add( da );
-                }
-
-                continue;
-            }
-            
-            DataApproval da = new DataApproval( dataApprovalLevel, null, period, orgUnit, attributeOptionCombo, accepted, null, null );
-
-            userDataApprovals.add( da );
+        try
+        {
+            while ( rowSet.next() )
+            {
+                final Integer aoc = rowSet.getInt( 1 );
+                final Integer pe = rowSet.getInt( 2 );
+                final Integer level = rowSet.getInt( 3 );
+                final Integer ou = rowSet.getInt( 4 );
+                final Boolean accepted = rowSet.getBoolean( 5 );
+    
+                if ( aoc == previousAttributeOptionComboId && pe == previousPeriodId && level > previousLevel )
+                {
+                    continue;
+                }
+    
+                previousAttributeOptionComboId = aoc;
+                previousPeriodId = pe;
+                previousLevel = level;
+    
+                DataApprovalLevel dataApprovalLevel = ( level == null ? null : levelMap.get( level ) );
+                
+                DataElementCategoryOptionCombo optionCombo = ( aoc == null || aoc == 0 ? null : OPTION_COMBO_CACHE.get( aoc, new Callable<DataElementCategoryOptionCombo>()
+                {
+                    public DataElementCategoryOptionCombo call() throws ExecutionException
+                    {
+                        return categoryService.getDataElementCategoryOptionCombo( aoc );
+                    }
+                } ) );
+                
+                Period period = ( pe == null || pe == 0 ? null : PERIOD_CACHE.get( pe, new Callable<Period>()
+                {
+                    public Period call() throws ExecutionException
+                    {
+                        return periodService.getPeriod( pe );
+                    }
+                } ) );
+                
+                OrganisationUnit orgUnit = ( ou == null || ou == 0 ? null : ORGANISATION_UNIT_CACHE.get( ou, new Callable<OrganisationUnit>()
+                {
+                    public OrganisationUnit call() throws ExecutionException
+                    {
+                        return organisationUnitService.getOrganisationUnit( ou );
+                    }
+                } ) );
+    
+                //TODO: currently special cased for PEFPAR's requirements. Can we make it more generic?
+                if ( level > 1 && optionCombo.equals( defaultOptionCombo ) )
+                {
+                    for ( OrganisationUnit unit : getUserOrgsAtLevel( 3 ) )
+                    {
+                        DataApproval da = new DataApproval( dataApprovalLevel, null, period, unit, optionCombo, accepted, null, null );
+    
+                        userDataApprovals.add( da );
+                    }
+    
+                    continue;
+                }
+                
+                DataApproval da = new DataApproval( dataApprovalLevel, null, period, orgUnit, optionCombo, accepted, null, null );
+    
+                userDataApprovals.add( da );
+            }
+        }
+        catch ( ExecutionException ex )
+        {
+            throw new RuntimeException( ex );
         }
 
         return userDataApprovals;