Skip to content

Commit

Permalink
SAK-42188 - Improve Announcement performance (sakaiproject#7159)
Browse files Browse the repository at this point in the history
* SAK-42188 - Improve Announcement performance

This commit adds a cache for announcement that improves performance accessing to messages.

* squash
  • Loading branch information
adrianmticarum authored and ern committed Aug 13, 2019
1 parent c8f9b5a commit 409ab1b
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.sakaiproject.announcement.impl;

import java.util.List;
import java.util.Observable;
import java.util.Observer;

import org.sakaiproject.announcement.api.AnnouncementService;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.api.EventTrackingService;
import org.sakaiproject.memory.api.Cache;
import org.sakaiproject.memory.api.MemoryService;
import org.sakaiproject.message.api.Message;

import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AnnouncementObserver implements Observer {

@Setter
private EventTrackingService eventTrackingService;
@Setter
private MemoryService memoryService;
private Cache<String, List<Message>> messagesCache;

public void init() {
eventTrackingService.addLocalObserver(this);
messagesCache = memoryService.getCache("org.sakaiproject.announcement.tool.messages.cache");
}

public void destroy() {
eventTrackingService.deleteObserver(this);
}

public void update(Observable arg0, Object arg) {
if (!(arg instanceof Event)) {
return;
}

final Event event = (Event) arg;
final String eventType = event.getEvent();

if (eventType != null) {
String channelName = getChannel(event);
switch(eventType) {
case AnnouncementService.SECURE_ANNC_ADD:
case AnnouncementService.SECURE_ANNC_UPDATE_ANY:
case AnnouncementService.SECURE_ANNC_UPDATE_OWN:
case AnnouncementService.SECURE_ANNC_REMOVE_ANY:
case AnnouncementService.SECURE_ANNC_REMOVE_OWN:
log.debug("Announcement event: {}", eventType);
messagesCache.remove(channelName);
break;
default:
break;
}
}
}

private String getChannel(final Event event) {
final String[] resourceSplitted = event.getResource().split("/");
final String site = resourceSplitted[3];
return "/announcement/channel/" + site + "/main";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="org.sakaiproject.announcement.impl.AnnouncementObserver"
class="org.sakaiproject.announcement.impl.AnnouncementObserver"
init-method="init" destroy-method="destroy">
<property name="memoryService">
<ref bean="org.sakaiproject.memory.api.MemoryService" />
</property>
<property name="eventTrackingService">
<ref bean="org.sakaiproject.event.api.EventTrackingService" />
</property>
</bean>

<bean id="org.sakaiproject.announcement.api.AnnouncementService"
class="org.sakaiproject.announcement.impl.DbAnnouncementService"
init-method="init"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1235,6 +1235,10 @@
# the deprecated setting has no effect anymore (since before 2.5)
# memory.org.sakaiproject.site.impl.SiteCacheImpl.cache=timeToLiveSeconds=300,timeToIdleSeconds=300,maxElementsInMemory=10000

# ANNOUNCEMENTS cache - Minutes to cache messages of each channel; set to 0 to disable caching.
# memory.org.sakaiproject.announcement.tool.messages.cache=timeToLiveSeconds=300,timeToIdleSeconds=300, maxElementsInMemory=1000


## Users Pre-caching
## Controls the users precaching process on the Sakai servers,
## The goal is to make it easier to access large sites because users are generally fetched on demand
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,50 +25,87 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.time.Instant;
import java.util.*;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.Vector;


import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import lombok.extern.slf4j.Slf4j;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import org.sakaiproject.api.app.scheduler.ScheduledInvocationManager;
import org.sakaiproject.authz.api.AuthzGroupService;
import org.sakaiproject.authz.api.AuthzPermissionException;
import org.sakaiproject.authz.api.GroupNotDefinedException;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.api.ServerConfigurationService;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.entity.api.*;
import org.sakaiproject.entity.api.Entity;
import org.sakaiproject.entity.api.EntityManager;
import org.sakaiproject.entity.api.EntityNotDefinedException;
import org.sakaiproject.entity.api.EntityPermissionException;
import org.sakaiproject.entity.api.HttpAccess;
import org.sakaiproject.entity.api.Reference;
import org.sakaiproject.entity.api.ResourceProperties;
import org.sakaiproject.entity.api.ResourcePropertiesEdit;
import org.sakaiproject.entity.api.Summary;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.api.EventTrackingService;
import org.sakaiproject.event.api.NotificationService;
import org.sakaiproject.exception.*;
import org.sakaiproject.exception.IdInvalidException;
import org.sakaiproject.exception.IdUnusedException;
import org.sakaiproject.exception.IdUsedException;
import org.sakaiproject.exception.InUseException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.id.api.IdManager;
import org.sakaiproject.javax.Filter;
import org.sakaiproject.javax.PagingPosition;
import org.sakaiproject.memory.api.Cache;
import org.sakaiproject.memory.api.MemoryService;
import org.sakaiproject.message.api.*;
import org.sakaiproject.message.api.Message;
import org.sakaiproject.message.api.MessageChannel;
import org.sakaiproject.message.api.MessageChannelEdit;
import org.sakaiproject.message.api.MessageEdit;
import org.sakaiproject.message.api.MessageHeader;
import org.sakaiproject.message.api.MessageHeaderEdit;
import org.sakaiproject.message.api.MessageService;
import org.sakaiproject.site.api.Group;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.SiteService;
import org.sakaiproject.site.api.ToolConfiguration;
import org.sakaiproject.thread_local.api.ThreadLocalManager;
import org.sakaiproject.time.api.Time;
import org.sakaiproject.time.api.TimeService;
import org.sakaiproject.tool.api.*;
import org.sakaiproject.tool.api.Session;
import org.sakaiproject.tool.api.SessionBindingEvent;
import org.sakaiproject.tool.api.SessionBindingListener;
import org.sakaiproject.tool.api.SessionManager;
import org.sakaiproject.tool.api.ToolSession;
import org.sakaiproject.user.api.User;
import org.sakaiproject.user.api.UserDirectoryService;
import org.sakaiproject.user.api.UserNotDefinedException;
import org.sakaiproject.util.*;
import org.sakaiproject.util.BaseResourcePropertiesEdit;
import org.sakaiproject.util.DoubleStorageUser;
import org.sakaiproject.util.EntityCollections;
import org.sakaiproject.util.FormattedText;
import org.sakaiproject.util.Validator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import lombok.Setter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;

/**
* BaseMessage is...
Expand All @@ -91,6 +128,9 @@ public abstract class BaseMessage implements MessageService, DoubleStorageUser
/** added to allow for scheduled notifications */
private static final String SCHED_INV_UUID = "schInvUuid";
//private static final String SCHINV_DELETE_EVENT = "schInv.delete";

private Cache<String, List<Message>> messagesCache;

/**********************************************************************************************************************************************************************************************************************************************************
* Constructors, Dependencies and their setter methods
*********************************************************************************************************************************************************************************************************************************************************/
Expand Down Expand Up @@ -162,7 +202,7 @@ public void init()
// construct a storage helper and read
m_storage = newStorage();
m_storage.open();

messagesCache = m_memoryService.getCache("org.sakaiproject.announcement.tool.messages.cache");
log.info("init()");
}
catch (Throwable t)
Expand Down Expand Up @@ -3006,18 +3046,15 @@ protected Message findMessage(String messageId)
*
* @return a List of all messages in the channel.
*/
protected List findMessages()
{
// if we have done this already in this thread, use that
List msgs = (List) m_threadLocalManager.get(getReference() + ".msgs");
if (msgs == null)
{
protected List findMessages() {
List msgs;
final List<Message> cachedMessages = messagesCache.get(getReference());
if (cachedMessages != null) {
msgs = cachedMessages;
} else {
msgs = m_storage.getMessages(this);

// "cache" the mesasge in the current service in case they are needed again in this thread...
m_threadLocalManager.set(getReference() + ".msgs", msgs);
messagesCache.put(getReference(), msgs);
}

return msgs;
} // findMessages

Expand Down

0 comments on commit 409ab1b

Please sign in to comment.