Author: norman
Date: Mon Feb  7 07:15:54 2011
New Revision: 1067867

URL: http://svn.apache.org/viewvc?rev=1067867&view=rev
Log:
Share the UidToMsnConverter between MailboxSession's to reduce memory usage. 
See IMAP-255

Modified:
    
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
    
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
    
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/UidToMsnConverter.java

Modified: 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java?rev=1067867&r1=1067866&r2=1067867&view=diff
==============================================================================
--- 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
 (original)
+++ 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/AbstractSelectionProcessor.java
 Mon Feb  7 07:15:54 2011
@@ -19,7 +19,6 @@
 
 package org.apache.james.imap.processor;
 
-import java.util.Iterator;
 import java.util.List;
 
 import javax.mail.Flags;
@@ -28,8 +27,8 @@ import org.apache.james.imap.api.ImapCom
 import org.apache.james.imap.api.ImapSessionUtils;
 import org.apache.james.imap.api.display.HumanReadableText;
 import org.apache.james.imap.api.message.response.StatusResponse;
-import org.apache.james.imap.api.message.response.StatusResponseFactory;
 import org.apache.james.imap.api.message.response.StatusResponse.ResponseCode;
+import org.apache.james.imap.api.message.response.StatusResponseFactory;
 import org.apache.james.imap.api.process.ImapProcessor;
 import org.apache.james.imap.api.process.ImapSession;
 import org.apache.james.imap.api.process.SelectedMailbox;
@@ -44,7 +43,6 @@ import org.apache.james.mailbox.MailboxN
 import org.apache.james.mailbox.MailboxPath;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
-import org.apache.james.mailbox.SearchQuery;
 import org.apache.james.mailbox.MessageManager.MetaData;
 
 abstract class AbstractSelectionProcessor<M extends 
AbstractMailboxSelectionRequest> extends AbstractMailboxProcessor<M> {
@@ -197,14 +195,9 @@ abstract class AbstractSelectionProcesso
     private SelectedMailbox createNewSelectedMailbox(final MessageManager 
mailbox,
             final MailboxSession mailboxSession, ImapSession session, 
MailboxPath path)
             throws MailboxException {
-        SearchQuery query = new SearchQuery();
-        query.andCriteria(SearchQuery.all());
-        
-        // use search here to allow implementation a better way to improve 
selects on mailboxes. 
-        // See https://issues.apache.org/jira/browse/IMAP-192
-        final Iterator<Long> it = mailbox.search(query, mailboxSession);
+       
 
-        final SelectedMailbox sessionMailbox = new 
SelectedMailboxImpl(getMailboxManager(), it, mailboxSession, path);
+        final SelectedMailbox sessionMailbox = new 
SelectedMailboxImpl(getMailboxManager(), mailboxSession, path);
         session.selected(sessionMailbox);
         return sessionMailbox;
     }

Modified: 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java?rev=1067867&r1=1067866&r2=1067867&view=diff
==============================================================================
--- 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
 (original)
+++ 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/SelectedMailboxImpl.java
 Mon Feb  7 07:15:54 2011
@@ -21,7 +21,6 @@ package org.apache.james.imap.processor.
 
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Iterator;
 import java.util.Set;
 import java.util.TreeSet;
 
@@ -45,7 +44,7 @@ public class SelectedMailboxImpl impleme
 
     private boolean recentUidRemoved;
 
-    public SelectedMailboxImpl(final MailboxManager mailboxManager, final 
Iterator<Long> uids,
+    public SelectedMailboxImpl(final MailboxManager mailboxManager,
             final MailboxSession mailboxSession, final MailboxPath path) 
throws MailboxException {
         recentUids = new TreeSet<Long>();
         recentUidRemoved = false;
@@ -54,8 +53,7 @@ public class SelectedMailboxImpl impleme
         // Ignore events from our session
         events.setSilentFlagChanges(true);
         mailboxManager.addListener(path, events, mailboxSession);
-        converter = new UidToMsnConverter(uids);
-        mailboxManager.addListener(path, converter, mailboxSession);
+        converter = UidToMsnConverter.get(mailboxManager, path, 
mailboxSession);
     }
 
     /**

Modified: 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/UidToMsnConverter.java
URL: 
http://svn.apache.org/viewvc/james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/UidToMsnConverter.java?rev=1067867&r1=1067866&r2=1067867&view=diff
==============================================================================
--- 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/UidToMsnConverter.java
 (original)
+++ 
james/imap/trunk/processor/src/main/java/org/apache/james/imap/processor/base/UidToMsnConverter.java
 Mon Feb  7 07:15:54 2011
@@ -20,22 +20,35 @@
 package org.apache.james.imap.processor.base;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
 
 import org.apache.james.imap.api.process.SelectedMailbox;
+import org.apache.james.mailbox.MailboxException;
 import org.apache.james.mailbox.MailboxListener;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxPath;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.SearchQuery;
 
 /**
- * {@link MailboxListener} which takes care of maintaining a mapping between 
message uids and msn (index)
+ * {@link UidToMsnConverter} takes care of maintaining a mapping between 
message uids and msn (index) by register a {@link MailboxListener} for a {@link 
MailboxPath}
+ * 
+ * See {@link UidToMsnConverter} is shared across different {@link 
MailboxSession}'s for the same {@link MailboxPath} to reduce memory usage. See 
IMAP-255
  * 
  *
- * TODO: This is a major memory hog
- * TODO: Each concurrent session requires one, and typical clients now open 
many
  */
-public class UidToMsnConverter implements MailboxListener {
+public class UidToMsnConverter {
+    // Hold all cached UidToMsnConverter
+    private final static Map<MailboxPath, UidToMsnConverter> converters = new 
HashMap<MailboxPath, UidToMsnConverter>();
+    
     private SortedMap<Integer, Long> msnToUid;
 
     private SortedMap<Long, Integer> uidToMsn;
@@ -44,9 +57,87 @@ public class UidToMsnConverter implement
 
     private int highestMsn = 0;
 
-    private boolean closed = false;
+    // hold the reference count for a shared UidToMsnConverter
+    private AtomicInteger references = new AtomicInteger(0);
+    
+    /**
+     * Return a instance of the {@link UidToMsnConverter} which can be a new 
one or a shared if there is already a {@link UidToMsnConverter} for the given
+     * {@link MailboxPath}.
+     * 
+     * @param manager
+     * @param path
+     * @param session
+     * @return converter
+     * @throws MailboxException
+     */
+    public static UidToMsnConverter get(MailboxManager manager, MailboxPath 
path, MailboxSession session) throws MailboxException {
+        boolean found = false;
+        UidToMsnConverter converter = null;
+        
+        // see if we have a converter for the path
+        synchronized (converters) {
+            converter = converters.get(path);
+            if (converter == null) {
+                converter = new UidToMsnConverter();
+                converters.put(path, converter);
+            } else {
+                found = true;
+            }
+        }
+        
+        // now be sure we only return the converter if the one which exists is 
init. So to be sure we synchronize on it
+        synchronized (converter) {
+            final UidToMsnConverter c = converter;
+            // the converter was not found before so we need to init it to get 
a list of all uids
+            if (!found) {
+                converter.init(manager.getMailbox(path, session), session);
+                manager.addListener(path, new MailboxListener() {
+                    
+                    /*
+                     * (non-Javadoc)
+                     * @see org.apache.james.mailbox.MailboxListener#isClosed()
+                     */
+                    public synchronized boolean isClosed() {
+                        return c.references.get() < 1;
+                    }
+                    
+                    /*
+                     * (non-Javadoc)
+                     * @see 
org.apache.james.mailbox.MailboxListener#event(org.apache.james.mailbox.MailboxListener.Event)
+                     */
+                    public void event(Event event) {
+                        if (event instanceof MessageEvent) {
+                            final MessageEvent messageEvent = (MessageEvent) 
event;
+                            final long uid = messageEvent.getSubjectUid();
+                            if (event instanceof Added) {
+                                c.add(uid);
+                            }
+
+                        }                    
+                    }
+                }, session);
+            }
+            
+            // increment the reference count so can handle the close 
operations in the right manner
+            converter.references.incrementAndGet();
+            return converter;
+        }
+        
+    }
+    
+    // Should only get accessed throw the static factory method
+    private UidToMsnConverter() {
+    }
+
+    private void init(MessageManager mailbox, MailboxSession mailboxSession) 
throws MailboxException {
+        SearchQuery query = new SearchQuery();
+        query.andCriteria(SearchQuery.all());
+
+        // use search here to allow implementation a better way to improve
+        // selects on mailboxes.
+        // See https://issues.apache.org/jira/browse/IMAP-192
+        final Iterator<Long> uids = mailbox.search(query, mailboxSession);
 
-    public UidToMsnConverter(final Iterator<Long> uids) {
         msnToUid = new TreeMap<Integer, Long>();
         uidToMsn = new TreeMap<Long, Integer>();
         if (uids != null) {
@@ -57,7 +148,7 @@ public class UidToMsnConverter implement
                 highestMsn = msn;
                 msnToUid.put(msn, uid);
                 uidToMsn.put(uid, msn);
-                
+
                 msn++;
             }
 
@@ -137,18 +228,7 @@ public class UidToMsnConverter implement
         }
     }
 
-    /**
-     * @see 
org.apache.james.mailbox.MailboxListener#event(org.apache.james.mailbox.MailboxListener.Event)
-     */
-    public synchronized void event(Event event) {
-        if (event instanceof MessageEvent) {
-            final MessageEvent messageEvent = (MessageEvent) event;
-            final long uid = messageEvent.getSubjectUid();
-            if (event instanceof Added) {
-                add(uid);
-            }
-        }
-    }
+ 
 
     
     /**
@@ -177,16 +257,11 @@ public class UidToMsnConverter implement
      * Close this {@link MailboxListener} and dispose all stored stuff 
      */
     public synchronized void close() {
-        uidToMsn.clear();
-        msnToUid.clear();
-        closed = true;
+        if (references.incrementAndGet() == 0) {
+            uidToMsn.clear();
+            msnToUid.clear();
+        }
     }
     
-    /*
-     * (non-Javadoc)
-     * @see org.apache.james.mailbox.MailboxListener#isClosed()
-     */
-    public synchronized boolean isClosed() {
-        return closed;
-    }
+
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to