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