Author: jalkanen
Date: Tue May 6 11:05:02 2008
New Revision: 653863
URL: http://svn.apache.org/viewvc?rev=653863&view=rev
Log:
JSPWIKI-50: Added more caches to CachingAttachmentProvider to make
RecentChanges faster. Kudos to Harry Metske.
Modified:
incubator/jspwiki/trunk/ChangeLog
incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/Release.java
incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/providers/CachingAttachmentProvider.java
Modified: incubator/jspwiki/trunk/ChangeLog
URL:
http://svn.apache.org/viewvc/incubator/jspwiki/trunk/ChangeLog?rev=653863&r1=653862&r2=653863&view=diff
==============================================================================
--- incubator/jspwiki/trunk/ChangeLog (original)
+++ incubator/jspwiki/trunk/ChangeLog Tue May 6 11:05:02 2008
@@ -1,3 +1,11 @@
+2008-05-06 Janne Jalkanen <[EMAIL PROTECTED]>
+
+ * 2.7.0-svn-19
+
+ * [JSPWIKI-50] Improved performance of RecentChangesPlugin by
+ adding better caching to the CachingAttachmentProvider. Thanks
+ to Harry Metske!
+
2008-05-05 Janne Jalkanen <[EMAIL PROTECTED]>
* 2.7.0-svn-18
Modified: incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/Release.java
URL:
http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/Release.java?rev=653863&r1=653862&r2=653863&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/Release.java (original)
+++ incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/Release.java Tue May 6
11:05:02 2008
@@ -77,7 +77,7 @@
* <p>
* If the build identifier is empty, it is not added.
*/
- public static final String BUILD = "18";
+ public static final String BUILD = "19";
/**
* This is the generic version string you should use
Modified:
incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/providers/CachingAttachmentProvider.java
URL:
http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/providers/CachingAttachmentProvider.java?rev=653863&r1=653862&r2=653863&view=diff
==============================================================================
---
incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/providers/CachingAttachmentProvider.java
(original)
+++
incubator/jspwiki/trunk/src/com/ecyrd/jspwiki/providers/CachingAttachmentProvider.java
Tue May 6 11:05:02 2008
@@ -32,6 +32,7 @@
import com.ecyrd.jspwiki.util.ClassUtil;
import com.opensymphony.oscache.base.Cache;
import com.opensymphony.oscache.base.NeedsRefreshException;
+import com.opensymphony.oscache.base.events.*;
/**
* Provides a caching attachment provider. This class rests on top of a
@@ -61,16 +62,25 @@
private Cache m_cache;
private long m_cacheMisses = 0;
- private long m_cacheHits = 0;
+ private long m_cacheHits = 0;
+
+ /**
+ * This cache contains Attachment objects and is keyed by attachment name.
+ * This provides for quickly giving recently changed attachments (for the
RecentChanges plugin)
+ */
+ private Cache m_attCache;
/** The extension to append to directory names to denote an attachment
directory. */
public static final String DIR_EXTENSION = "-att";
-
+
/** Property that supplies the directory used to store attachments. */
public static final String PROP_STORAGEDIR =
"jspwiki.basicAttachmentProvider.storageDir";
// FIXME: Make settable.
private int m_refreshPeriod = 60*10; // 10 minutes at the moment
+
+ private boolean m_gotall = false;
+ private CachedAttachmentCollector m_allCollector = new
CachedAttachmentCollector();
/**
* [EMAIL PROTECTED]
@@ -79,14 +89,21 @@
throws NoRequiredPropertyException,
IOException
{
- log.debug("Initing CachingAttachmentProvider");
+ log.info("Initing CachingAttachmentProvider");
//
- // Construct an unlimited cache.
+ // Construct an unlimited cache of Collection objects
//
m_cache = new Cache( true, false, true );
//
+ // Construct an unlimited cache for the individual Attachment objects.
+ // Attachment name is key, the Attachment object is the cached object
+ //
+ m_attCache = new Cache(true, false, true);
+
m_attCache.addCacheEventListener(m_allCollector,CacheEntryEventListener.class);
+
+ //
// Find and initialize real provider.
//
String classname = WikiEngine.getRequiredProperty( properties,
@@ -130,6 +147,8 @@
m_provider.putAttachmentData( att, data );
m_cache.flushEntry( att.getParentName() );
+ att.setLastModified(new Date());
+ m_attCache.putInCache(att.getName(), att);
}
/**
@@ -187,9 +206,9 @@
return new ArrayList();
}
- private Collection cloneCollection( Collection c )
+ private <T> Collection<T> cloneCollection( Collection<T> c )
{
- ArrayList list = new ArrayList();
+ ArrayList<T> list = new ArrayList<T>();
list.addAll( c );
@@ -210,8 +229,31 @@
public List listAllChanged( Date timestamp )
throws ProviderException
{
- // FIXME: Should cache
- return m_provider.listAllChanged( timestamp );
+ List all = null;
+ //
+ // we do a one-time build up of the cache, after this the cache is
updated for every attachment add/delete
+ if (m_gotall == false)
+ {
+ all = m_provider.listAllChanged(timestamp);
+
+ // Put all pages in the cache :
+
+ synchronized (this)
+ {
+ for (Iterator i = all.iterator(); i.hasNext();)
+ {
+ Attachment att = (Attachment) i.next();
+ m_attCache.putInCache(att.getName(), att);
+ }
+ m_gotall = true;
+ }
+ }
+ else
+ {
+ all = m_allCollector.getAllItems();
+ }
+
+ return all;
}
/**
@@ -331,7 +373,7 @@
throws ProviderException
{
// This isn't strictly speaking correct, but it does not really matter
- m_cache.putInCache( att.getParentName(), null );
+ m_cache.removeEntry( att.getParentName() );
m_provider.deleteVersion( att );
}
@@ -341,7 +383,8 @@
public void deleteAttachment( Attachment att )
throws ProviderException
{
- m_cache.putInCache( att.getParentName(), null );
+ m_cache.removeEntry( att.getParentName() );
+ m_attCache.removeEntry( att.getName() );
m_provider.deleteAttachment( att );
}
@@ -370,7 +413,98 @@
throws ProviderException
{
m_provider.moveAttachmentsForPage(oldParent, newParent);
- m_cache.putInCache( newParent, null ); // FIXME
- m_cache.putInCache( oldParent, null );
+ m_cache.removeEntry( newParent );
+ m_cache.removeEntry( oldParent );
}
+
+ /**
+ * Keep a list of all Attachments in the OSCache (OSCache does not provide
+ * something like that) Idea copied from CacheItemCollector The cache is
used to
+ * speed up the getRecentChanges function
+ *
+ * @author Harry Metske
+ * @since 2.5
+ */
+ private static class CachedAttachmentCollector implements
CacheEntryEventListener
+ {
+ private static final Logger log = Logger.getLogger(
CachedAttachmentCollector.class );
+
+ private Map<String, Attachment> m_allItems = new HashMap<String,
Attachment>();
+
+ /**
+ * Returns a clone of the set - you cannot manipulate this.
+ *
+ * @return
+ */
+ public List getAllItems()
+ {
+ List<Attachment> ret = new LinkedList<Attachment>();
+ ret.addAll( m_allItems.values() );
+ log.info( "returning " + ret.size() + " attachments" );
+ return ret;
+ }
+
+ public void cacheEntryRemoved( CacheEntryEvent aEvent )
+ {
+ if( aEvent != null )
+ {
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "attachment cache entry removed: " +
aEvent.getKey() );
+ }
+ Attachment item = (Attachment) aEvent.getEntry().getContent();
+
+ if( item != null )
+ {
+ m_allItems.remove( item.getName() );
+ }
+ }
+ }
+
+ public void cacheEntryUpdated( CacheEntryEvent aEvent )
+ {
+ if( log.isDebugEnabled() )
+ {
+ log.debug( "attachment cache entry updated: " +
aEvent.getKey() );
+ }
+
+ Attachment item = (Attachment) aEvent.getEntry().getContent();
+
+ if( item != null )
+ {
+ // Item added or replaced.
+ m_allItems.put( item.getName(), item );
+ }
+ else
+ {
+ m_allItems.remove( aEvent.getKey() );
+ }
+ }
+
+ public void cacheEntryAdded( CacheEntryEvent aEvent )
+ {
+ cacheEntryUpdated( aEvent );
+ }
+
+ public void cachePatternFlushed( CachePatternEvent aEvent )
+ {
+ // do nothing
+ }
+
+ public void cacheGroupFlushed( CacheGroupEvent aEvent )
+ {
+ // do nothing
+ }
+
+ public void cacheFlushed( CachewideEvent aEvent )
+ {
+ // do nothing
+ }
+
+ public void cacheEntryFlushed( CacheEntryEvent aEvent )
+ {
+ cacheEntryRemoved( aEvent );
+ }
+ }
+
}