From 5a5aca401d47014759a8bb689866f16a97f97ae2 Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Mon, 4 Mar 2013 13:43:00 +0100 Subject: [PATCH] OO-449: with the changes of cache implementation, refactor the cache to have 1 unique cache and not a cache / course --- .../olat/course/assessment/NewCacheKey.java | 78 +++++++++++++++++++ .../NewCachePersistingAssessmentManager.java | 78 +++++++++---------- src/main/resources/infinispan-config.xml | 7 ++ 3 files changed, 124 insertions(+), 39 deletions(-) create mode 100644 src/main/java/org/olat/course/assessment/NewCacheKey.java diff --git a/src/main/java/org/olat/course/assessment/NewCacheKey.java b/src/main/java/org/olat/course/assessment/NewCacheKey.java new file mode 100644 index 00000000000..30b8f2c3308 --- /dev/null +++ b/src/main/java/org/olat/course/assessment/NewCacheKey.java @@ -0,0 +1,78 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.course.assessment; + +import java.io.Serializable; + +/** + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class NewCacheKey implements Serializable { + + private static final long serialVersionUID = 4257100091138814545L; + + private Long courseId; + private Long identityKey; + + public NewCacheKey() { + // + } + + public NewCacheKey(Long courseId, Long identityKey) { + this.courseId = courseId; + this.identityKey = identityKey; + } + + public Long getCourseId() { + return courseId; + } + + public void setCourseId(Long courseId) { + this.courseId = courseId; + } + + public Long getIdentityKey() { + return identityKey; + } + + public void setIdentityKey(Long identityKey) { + this.identityKey = identityKey; + } + + @Override + public int hashCode() { + return (courseId == null ? 32876 : courseId.hashCode()) + + (identityKey == null ? 7525 : identityKey.hashCode()); + } + + @Override + public boolean equals(Object obj) { + if(this == obj) { + return true; + } + if(obj instanceof NewCacheKey) { + NewCacheKey key = (NewCacheKey)obj; + return courseId != null && courseId.equals(key.courseId) + && identityKey != null && identityKey.equals(key.identityKey); + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java b/src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java index d0de0f878d1..013a896f9ab 100644 --- a/src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java +++ b/src/main/java/org/olat/course/assessment/NewCachePersistingAssessmentManager.java @@ -120,8 +120,9 @@ public class NewCachePersistingAssessmentManager extends BasicManager implements private static final Integer INTEGER_ZERO = new Integer(0); // the cache per assessment manager instance (=per course) - private CacheWrapper<Long,HashMap<String, Serializable>> courseCache; + private CacheWrapper<NewCacheKey,HashMap<String, Serializable>> courseCache; private OLATResourceable ores; + // we cannot store the ref to cpm here, since at the time where the assessmentManager is initialized, the given course is not fully initialized yet. //does not work: final CoursePropertyManager cpm; @@ -144,9 +145,9 @@ public class NewCachePersistingAssessmentManager extends BasicManager implements */ private NewCachePersistingAssessmentManager(ICourse course) { this.ores = course; - String cacheName = "Course@" + course.getResourceableId(); + //String cacheName = "Course@" + course.getResourceableId(); courseCache = CoordinatorManager.getInstance().getCoordinator().getCacher() - .getCache(AssessmentManager.class.getSimpleName(), cacheName); + .getCache(AssessmentManager.class.getSimpleName(), "newpersisting"); } /** * @param identity the identity for which to properties are to be loaded. @@ -236,45 +237,44 @@ public class NewCachePersistingAssessmentManager extends BasicManager implements */ private Map<String, Serializable> getOrLoadScorePassedAttemptsMap(Identity identity, List<Property> properties, boolean prepareForNewData) { - synchronized(courseCache) { // o_clusterOK by:fj : we sync on the cache to protect access within the monitor "one user in a course". - // a user is only active on one node at the same time. - HashMap<String, Serializable> m = courseCache.get(identity.getKey()); - if (m == null) { - // cache entry (=all data of the given identity in this course) has expired or has never been stored yet into the cache. - // or has been invalidated (in cluster mode when puts occurred from an other node for the same cache) - m = new HashMap<String, Serializable>(); - // load data - List<Property> loadedProperties = properties == null ? loadPropertiesFor(Collections.singletonList(identity)) : properties; - for (Property property:loadedProperties) { - addPropertyToCache(m, property); - } - - //If property not found, prefill with default value. - if(!m.containsKey(ATTEMPTS)) { - m.put(ATTEMPTS, INTEGER_ZERO); - } - if(!m.containsKey(SCORE)) { - m.put(SCORE, FLOAT_ZERO); - } - if(!m.containsKey(LAST_MODIFIED)) { - m.put(LAST_MODIFIED, null); - } - - // we use a putSilent here (no invalidation notifications to other cluster nodes), since - // we did not generate new data, but simply asked to reload it. - if (prepareForNewData) { - courseCache.update(identity.getKey(), m); - } else { - courseCache.put(identity.getKey(), m); - } + // a user is only active on one node at the same time. + NewCacheKey cacheKey = new NewCacheKey(ores.getResourceableId(), identity.getKey()); + HashMap<String, Serializable> m = courseCache.get(cacheKey); + if (m == null) { + // cache entry (=all data of the given identity in this course) has expired or has never been stored yet into the cache. + // or has been invalidated (in cluster mode when puts occurred from an other node for the same cache) + m = new HashMap<String, Serializable>(); + // load data + List<Property> loadedProperties = properties == null ? loadPropertiesFor(Collections.singletonList(identity)) : properties; + for (Property property:loadedProperties) { + addPropertyToCache(m, property); + } + + //If property not found, prefill with default value. + if(!m.containsKey(ATTEMPTS)) { + m.put(ATTEMPTS, INTEGER_ZERO); + } + if(!m.containsKey(SCORE)) { + m.put(SCORE, FLOAT_ZERO); + } + if(!m.containsKey(LAST_MODIFIED)) { + m.put(LAST_MODIFIED, null); + } + + // we use a putSilent here (no invalidation notifications to other cluster nodes), since + // we did not generate new data, but simply asked to reload it. + if (prepareForNewData) { + courseCache.update(cacheKey, m); } else { - // still in cache. - if (prepareForNewData) { // but we need to notify that data has changed: we reput the data into the cache - a little hacky yes - courseCache.update(identity.getKey(), m); - } + courseCache.put(cacheKey, m); + } + } else { + // still in cache. + if (prepareForNewData) { // but we need to notify that data has changed: we reput the data into the cache - a little hacky yes + courseCache.update(cacheKey, m); } - return m; } + return m; } // package local for perf. reasons, threadsafe. diff --git a/src/main/resources/infinispan-config.xml b/src/main/resources/infinispan-config.xml index a8219708fef..07d47f89995 100644 --- a/src/main/resources/infinispan-config.xml +++ b/src/main/resources/infinispan-config.xml @@ -39,6 +39,13 @@ <transaction transactionMode="NON_TRANSACTIONAL" /> </namedCache> + <namedCache name="AssessmentManager@newpersisting"> + <locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000" useLockStriping="false"/> + <eviction maxEntries="20000" strategy="LRU"/> + <expiration maxIdle="900000" wakeUpInterval="5000"/> + <transaction transactionMode="NON_TRANSACTIONAL" /> + </namedCache> + <!-- Hibernate cache --> -- GitLab