From d964dc55a9981af38c978366b642842885d37d5d Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Fri, 2 Oct 2015 13:35:42 +0200
Subject: [PATCH] OO-1616: use update statement instead of lock for update,
 only set the last usage of the repository entry of a course element once per
 click

---
 .../olat/course/run/RunMainController.java    | 16 +++++++
 .../course/run/navigation/NodeClickedRef.java | 11 -----
 .../olat/repository/RepositoryService.java    | 17 +++++++-
 .../manager/RepositoryEntryStatisticsDAO.java | 42 +++++++++----------
 .../database/postgresql/setupDatabase.sql     |  2 +-
 5 files changed, 52 insertions(+), 36 deletions(-)

diff --git a/src/main/java/org/olat/course/run/RunMainController.java b/src/main/java/org/olat/course/run/RunMainController.java
index 18ebd074575..e284eaf203d 100644
--- a/src/main/java/org/olat/course/run/RunMainController.java
+++ b/src/main/java/org/olat/course/run/RunMainController.java
@@ -93,8 +93,10 @@ import org.olat.group.ui.edit.BusinessGroupModifiedEvent;
 import org.olat.modules.cp.TreeNodeEvent;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
+import org.olat.repository.RepositoryService;
 import org.olat.repository.model.RepositoryEntrySecurity;
 import org.olat.util.logging.activity.LoggingResourceable;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * Description: <br>
@@ -134,6 +136,8 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 	private Link nextLink, previousLink;
 	private GlossaryMarkupItemController glossaryMarkerCtr;
 	
+	@Autowired
+	private RepositoryService repositoryService;
 	
 	/**
 	 * Constructor for the run main controller
@@ -431,8 +435,18 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 		contentP.setContent(currentNodeController.getInitialComponent());
 		
 		updateNextPrevious();
+		updateLastUsage(nclr.getCalledCourseNode());
 		return true;
 	}
+	
+	private void updateLastUsage(CourseNode calledCourseNode) {
+		if(calledCourseNode != null && calledCourseNode.needsReferenceToARepositoryEntry()) {
+			RepositoryEntry referencedRe = calledCourseNode.getReferencedRepositoryEntry();
+			if(referencedRe != null) {
+				repositoryService.setLastUsageNowFor(referencedRe);
+			}
+		}
+	}
 
 	/**
 	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest,
@@ -611,6 +625,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 				currentNodeController = nclr.getRunController();
 				Component nodeComp = currentNodeController.getInitialComponent();
 				contentP.setContent(nodeComp);
+				updateLastUsage(nclr.getCalledCourseNode());
 			}
 			
 			if(nclr.getSelectedNodeId() != null && nclr.getOpenNodeIds() != null) {
@@ -636,6 +651,7 @@ public class RunMainController extends MainLayoutBasicController implements Gene
 			currentNodeController.dispose();
 		}
 		currentNodeController = nclr.getRunController();
+		updateLastUsage(nclr.getCalledCourseNode());
 		Component nodeComp = currentNodeController.getInitialComponent();
 		contentP.setContent(nodeComp);
 		addToHistory(ureq, currentNodeController);
diff --git a/src/main/java/org/olat/course/run/navigation/NodeClickedRef.java b/src/main/java/org/olat/course/run/navigation/NodeClickedRef.java
index f0d55848d87..36afa61a634 100644
--- a/src/main/java/org/olat/course/run/navigation/NodeClickedRef.java
+++ b/src/main/java/org/olat/course/run/navigation/NodeClickedRef.java
@@ -27,12 +27,9 @@ package org.olat.course.run.navigation;
 
 import java.util.List;
 
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.gui.components.tree.TreeModel;
 import org.olat.core.gui.control.Controller;
 import org.olat.course.nodes.CourseNode;
-import org.olat.repository.RepositoryEntry;
-import org.olat.repository.RepositoryService;
 
 /**
  * Description: <br>
@@ -148,14 +145,6 @@ public class NodeClickedRef {
 	 */
 	public Controller getRunController() {
 		if(calledCourseNode == null || nodeConstructionResult == null) return null;
-		if(calledCourseNode.needsReferenceToARepositoryEntry()) {
-			RepositoryEntry referencedRe = calledCourseNode.getReferencedRepositoryEntry();
-			if(referencedRe != null) {
-				CoreSpringFactory.getImpl(RepositoryService.class).setLastUsageNowFor(referencedRe);
-			}
-		}
 		return nodeConstructionResult.getRunController();
 	}
-
 }
-
diff --git a/src/main/java/org/olat/repository/RepositoryService.java b/src/main/java/org/olat/repository/RepositoryService.java
index 5bf667a94ae..6a1d93754f2 100644
--- a/src/main/java/org/olat/repository/RepositoryService.java
+++ b/src/main/java/org/olat/repository/RepositoryService.java
@@ -84,11 +84,26 @@ public interface RepositoryService {
 	 */
 	public void deleteRepositoryEntryAndBaseGroups(RepositoryEntry entry);
 	
-
+	/**
+	 * Increment the launch counter and the last usage date.
+	 * 
+	 * @param re The repository entry
+	 */
 	public void incrementLaunchCounter(RepositoryEntry re);
 	
+	/**
+	 * Increment the download counter and the last usage date.
+	 * 
+	 * @param re The repository entry
+	 */
 	public void incrementDownloadCounter(RepositoryEntry re);
 	
+	/**
+	 * Update the last usage of the specified repository entry
+	 * with a granularity of 1 minute.
+	 * 
+	 * @param re The repository entry
+	 */
 	public void setLastUsageNowFor(RepositoryEntry re);
 
 	public Group getDefaultGroup(RepositoryEntryRef ref);
diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryStatisticsDAO.java b/src/main/java/org/olat/repository/manager/RepositoryEntryStatisticsDAO.java
index 80e0f489929..bfa744017f5 100644
--- a/src/main/java/org/olat/repository/manager/RepositoryEntryStatisticsDAO.java
+++ b/src/main/java/org/olat/repository/manager/RepositoryEntryStatisticsDAO.java
@@ -61,14 +61,12 @@ public class RepositoryEntryStatisticsDAO implements UserRatingsDelegate, UserCo
 	 * Increment the launch counter.
 	 * @param re
 	 */
-	public synchronized void incrementLaunchCounter(RepositoryEntry re) {
-		RepositoryEntryStatistics stats = loadStatisticsForUpdate(re);
-		if(stats != null) {
-			stats.setLaunchCounter(stats.getLaunchCounter() + 1);
-			stats.setLastUsage(new Date());
-			dbInstance.getCurrentEntityManager().merge(stats);
-		}
-		dbInstance.commit();
+	public void incrementLaunchCounter(RepositoryEntry re) {
+		String updateQuery = "update repoentrystats set launchCounter=launchCounter+1, lastUsage=:now where key=:statsKey";
+		dbInstance.getCurrentEntityManager().createQuery(updateQuery)
+			.setParameter("statsKey", re.getStatistics().getKey())
+			.setParameter("now", new Date())
+			.executeUpdate();
 	}
 
 	/**
@@ -76,30 +74,28 @@ public class RepositoryEntryStatisticsDAO implements UserRatingsDelegate, UserCo
 	 * @param re
 	 */
 	public void incrementDownloadCounter(RepositoryEntry re) {
-		RepositoryEntryStatistics stats = loadStatisticsForUpdate(re);
-		if(stats != null) {
-			stats.setDownloadCounter(stats.getDownloadCounter() + 1);
-			stats.setLastUsage(new Date());
-			dbInstance.getCurrentEntityManager().merge(stats);
-		}
-		dbInstance.commit();
+		String updateQuery = "update repoentrystats set downloadCounter=downloadCounter+1, lastUsage=:now where key=:statsKey";
+		dbInstance.getCurrentEntityManager().createQuery(updateQuery)
+			.setParameter("statsKey", re.getStatistics().getKey())
+			.setParameter("now", new Date())
+			.executeUpdate();
 	}
 
 	/**
-	 * Set last-usage date to to now for certain repository-entry.
+	 * Set last-usage date to now for the specified repository entry
+	 * with a granularity of 1 minute.
 	 * @param 
 	 */
 	public void setLastUsageNowFor(RepositoryEntry re) {
 		if (re == null) return;
 		
 		Date newUsage = new Date();
-		RepositoryEntryStatistics stats = loadStatistics(re);
-		Date lastUsage = stats.getLastUsage();
-		//update every minute and not shorter
-		if(lastUsage == null || (newUsage.getTime() - lastUsage.getTime()) > 60000) {
-			stats.setLastUsage(newUsage);
-			dbInstance.getCurrentEntityManager().merge(stats);
-			dbInstance.commit();
+		if(re.getStatistics().getLastUsage().getTime() + 60000 < newUsage.getTime()) {
+			String updateQuery = "update repoentrystats set lastUsage=:now where key=:statsKey";
+			dbInstance.getCurrentEntityManager().createQuery(updateQuery)
+				.setParameter("statsKey", re.getStatistics().getKey())
+				.setParameter("now", new Date())
+				.executeUpdate();
 		}
 	}
 	
diff --git a/src/main/resources/database/postgresql/setupDatabase.sql b/src/main/resources/database/postgresql/setupDatabase.sql
index f84636e4b99..1ebd076078f 100644
--- a/src/main/resources/database/postgresql/setupDatabase.sql
+++ b/src/main/resources/database/postgresql/setupDatabase.sql
@@ -1731,7 +1731,7 @@ alter table o_checkpoint add constraint FK9E30F4B661159ZZZ foreign key (checklis
 create index idx_chpt_checklist_fk on o_checkpoint (checklist_fk);
 
 -- plock
--- index created asset_idx on unique constraint
+create index asset_idx on o_plock (asset);
 
 -- property
 alter table o_property add constraint FKB60B1BA5190E5 foreign key (grp) references o_gp_business;
-- 
GitLab