Ignore:
Timestamp:
08/30/10 23:01:34 (21 months ago)
Author:
octorian
Message:

Post-load cache cleanup

Location:
trunk/LogicMail/src/org/logicprobe/LogicMail/model
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/LogicMail/src/org/logicprobe/LogicMail/model/MailFileManager.java

    r693 r697  
    3535import java.io.IOException; 
    3636import java.util.Enumeration; 
     37import java.util.Hashtable; 
    3738import java.util.Vector; 
    3839 
     
    436437        } 
    437438         
     439        public synchronized void removeStaleMessageNodes(MailboxNode mailboxNode, String[] uidsToRetain) throws IOException { 
     440            if(cacheUrl == null) { return; } 
     441             
     442            Hashtable retentionSet = new Hashtable(); 
     443            for(int i=0; i<uidsToRetain.length; i++) { 
     444                retentionSet.put(uidsToRetain[i], Boolean.TRUE); 
     445            } 
     446             
     447        String[] fileUrls = getMessageFiles(mailboxNode); 
     448        Vector fileUrlsToDelete = new Vector(); 
     449        for(int i=0; i<fileUrls.length; i++) { 
     450            int p = fileUrls[i].lastIndexOf('/'); 
     451            int q = fileUrls[i].lastIndexOf('.'); 
     452            if(p != -1 && q != -1 && p < q) { 
     453                String messageUid = fileUrls[i].substring(p + 1, q); 
     454                if(!retentionSet.containsKey(messageUid)) { 
     455                    fileUrlsToDelete.addElement(fileUrls[i]); 
     456                } 
     457            } 
     458        } 
     459         
     460        int size = fileUrlsToDelete.size(); 
     461        for(int i=0; i<size; i++) { 
     462            try { 
     463                FileConnection fc = (FileConnection)Connector.open((String)fileUrlsToDelete.elementAt(i)); 
     464                if(fc.exists() && fc.canRead()) { 
     465                    fc.delete(); 
     466                } 
     467            } catch (IOException exp) { 
     468                if (EventLogger.getMinimumLevel() >= EventLogger.DEBUG_INFO) { 
     469                    EventLogger.logEvent(AppInfo.GUID, 
     470                            ("Error deleting message from cache: " + exp.toString()).getBytes(), 
     471                            EventLogger.DEBUG_INFO); 
     472                } 
     473            } 
     474        } 
     475        } 
     476         
    438477        public synchronized void removeMessageNodes(MailboxNode mailboxNode, MessageToken[] messageTokens) throws IOException { 
    439478        if(cacheUrl == null) { return; } 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/model/MailboxNode.java

    r693 r697  
    7777    private Vector pendingExpungeMessages = new Vector(); 
    7878     
     79    /** Set of messages being loaded from cache. */ 
    7980    private Hashtable messagesBeingLoaded = new Hashtable(); 
     81    /** Map of unapplied message flag updates received from the server. */ 
    8082    private Hashtable unappliedFlagUpdates = new Hashtable(); 
     83    /** Set of messages known to the server. */ 
     84    private Hashtable messagesKnownToServer = new Hashtable(); 
     85     
     86    /** Flag to keep track of external requests for cache cleanup. */ 
     87    private boolean removeMessagesNotOnServerRequested; 
     88     
     89    /** Flag to keep track of initial cache load process. */ 
     90    private boolean cacheLoadInProgress; 
    8191     
    8292    /** 
     
    637647        } 
    638648 
    639  
    640649    /** 
    641650     * Removes all messages not marked as existing on the server. 
    642651     */ 
    643     void removeMessagesNotOnServer() { 
     652        void removeMessagesNotOnServer() { 
    644653        synchronized(messages) { 
    645             Vector messagesToRemove = new Vector(); 
    646              
    647             // Populate a list of the messages to remove 
    648             int size = messages.size(); 
    649             for(int i=0; i<size; i++) { 
    650                 MessageNode messageNode = (MessageNode)messages.elementAt(i); 
    651                 if(!messageNode.existsOnServer()) { 
    652                     messagesToRemove.addElement(messageNode); 
    653                 } 
    654             } 
    655              
    656             size = messagesToRemove.size(); 
    657             if(size == 0) { return; } 
    658              
     654            // If cache load is in progress, take note of request and return 
     655            if(cacheLoadInProgress) { 
     656                removeMessagesNotOnServerRequested = true; 
     657            } 
     658            else { 
     659                removeMessagesNotOnServerImpl(); 
     660            } 
     661        } 
     662        } 
     663         
     664    private void removeMessagesNotOnServerImpl() { 
     665        Vector messagesToRemove = new Vector(); 
     666        Vector messagesToRetain = new Vector(); 
     667         
     668        // Populate a list of the messages to remove 
     669        int size = messages.size(); 
     670        for(int i=0; i<size; i++) { 
     671            MessageNode messageNode = (MessageNode)messages.elementAt(i); 
     672            if(!messageNode.existsOnServer()) { 
     673                messagesToRemove.addElement(messageNode); 
     674            } 
     675            else { 
     676                String messageUid = messageNode.getMessageToken().getMessageUid(); 
     677                messagesToRetain.addElement(messageUid); 
     678                messagesKnownToServer.remove(messageUid); 
     679            } 
     680        } 
     681         
     682        // Iterate through any remaining items in our server-known message set, 
     683        // and add them to the retention list. 
     684        for(Enumeration e = messagesKnownToServer.keys(); e.hasMoreElements(); ) { 
     685            messagesToRetain.addElement(e.nextElement()); 
     686        } 
     687         
     688        size = messagesToRemove.size(); 
     689        if(size > 0) { 
    659690            MessageNode[] removedMessageNodes = new MessageNode[size]; 
    660             MessageToken[] tokensToRemove = new MessageToken[size]; 
    661691            for(int i=0; i<size; i++) { 
    662692                MessageNode messageNode = (MessageNode)messagesToRemove.elementAt(i); 
     
    666696                messageTokenMap.remove(messageNode.getMessageToken()); 
    667697                messageTokenUidSet.remove(messageNode.getMessageToken().getMessageUid()); 
    668                 tokensToRemove[i] = messageNode.getMessageToken(); 
    669698                removedMessageNodes[i] = messageNode; 
    670699            } 
    671700             
    672701            if(this.getParentAccount().getStatus() != AccountNode.STATUS_LOCAL) { 
    673                 (new RemoveFromCacheThread(tokensToRemove)).start(); 
     702                (new RemoveFromCacheThread(messagesToRetain)).start(); 
    674703            } 
    675704            updateUnseenMessages(false); 
    676705            fireMailboxStatusChanged(MailboxNodeEvent.TYPE_DELETED_MESSAGES, removedMessageNodes); 
    677706        } 
     707        else { 
     708            if(this.getParentAccount().getStatus() != AccountNode.STATUS_LOCAL) { 
     709                (new RemoveFromCacheThread(messagesToRetain)).start(); 
     710            } 
     711        } 
    678712    } 
    679713         
    680714    private class RemoveFromCacheThread extends Thread { 
    681         private MessageToken[] messageTokens; 
     715        private String[] uidsToRetain; 
    682716         
    683         public RemoveFromCacheThread(MessageToken[] messageTokens) { 
    684             this.messageTokens = messageTokens; 
     717        public RemoveFromCacheThread(Vector uidsToRetain) { 
     718            this.uidsToRetain = new String[uidsToRetain.size()]; 
     719            uidsToRetain.copyInto(this.uidsToRetain); 
    685720        } 
    686721         
     
    688723            yield(); 
    689724            try { 
    690                 MailFileManager.getInstance().removeMessageNodes(MailboxNode.this, messageTokens); 
     725                MailFileManager.getInstance().removeStaleMessageNodes(MailboxNode.this, uidsToRetain); 
    691726            } catch (IOException e) { 
    692727                EventLogger.logEvent(AppInfo.GUID, 
     
    712747    boolean updateMessageFlags(MessageToken messageToken, MessageFlags messageFlags) { 
    713748        boolean result = false; 
    714         synchronized(messages) { 
    715             if(messagesBeingLoaded.containsKey(messageToken.getMessageUid())) { 
    716                 unappliedFlagUpdates.put(messageToken.getMessageUid(), new Object[] { messageToken, messageFlags }); 
    717                 result = true; 
    718             } 
    719             else { 
    720                 MessageNode messageNode = (MessageNode)messageTokenMap.get(messageToken); 
    721                 if(messageNode != null) { 
    722                     // Message already exists in the mailbox, and just needs 
    723                     // its flags updated. 
    724                     messageNode.setFlags(MessageNode.convertMessageFlags(messageFlags)); 
    725  
    726                     // Update the token based on the token that came along 
    727                     // with the flags.  This will update any volatile state 
    728                     // information, such as POP message indices 
    729                     messageNode.getMessageToken().updateToken(messageToken); 
    730                     messageNode.setExistsOnServer(true); 
    731  
     749        synchronized(fetchLock) { 
     750            synchronized(messages) { 
     751                // If this method is called during the initial flags fetch, then 
     752                // track all messages updates are received for.  This is how we 
     753                // build a collection of messages that exist on the server, for the 
     754                // purposes of cache cleanup. 
     755                 
     756                    if(fetchFlagsOnly) { 
     757                        messagesKnownToServer.put(messageToken.getMessageUid(), Boolean.TRUE); 
     758                    } 
     759                if(messagesBeingLoaded.containsKey(messageToken.getMessageUid())) { 
     760                    unappliedFlagUpdates.put(messageToken.getMessageUid(), new Object[] { messageToken, messageFlags }); 
    732761                    result = true; 
     762                } 
     763                else { 
     764                    MessageNode messageNode = (MessageNode)messageTokenMap.get(messageToken); 
     765                    if(messageNode != null) { 
     766                        // Message already exists in the mailbox, and just needs 
     767                        // its flags updated. 
     768                        messageNode.setFlags(MessageNode.convertMessageFlags(messageFlags)); 
     769     
     770                        // Update the token based on the token that came along 
     771                        // with the flags.  This will update any volatile state 
     772                        // information, such as POP message indices 
     773                        messageNode.getMessageToken().updateToken(messageToken); 
     774                        messageNode.setExistsOnServer(true); 
     775     
     776                        result = true; 
     777                    } 
    733778                } 
    734779            } 
     
    9971042            if(parentAccount.getAccountConfig() != null) { 
    9981043                if(fetchThread == null || !fetchThread.isAlive()) { 
     1044                    synchronized(messages) { 
     1045                        cacheLoadInProgress = true; 
     1046                    } 
     1047                     
    9991048                    // Request flags and tokens for recent messages from the mail store 
    10001049                    parentAccount.getMailStore().requestFolderMessagesRecent( 
     
    10221071     
    10231072    private class RefreshMessagesThread extends Thread implements MessageNodeCallback { 
     1073        private Vector messagesToAdd = new Vector(); 
     1074         
    10241075        public RefreshMessagesThread() { 
    10251076             
     
    10301081            try { 
    10311082                MailFileManager.getInstance().readMessageNodes(MailboxNode.this, this); 
     1083                addLoadedMessages(); 
     1084                 
     1085                // If the server fetch completed before the cache load, then 
     1086                // execute the pending post-load cache cleanup. 
     1087                synchronized(messages) { 
     1088                    cacheLoadInProgress = false; 
     1089                    if(removeMessagesNotOnServerRequested) { 
     1090                        removeMessagesNotOnServerRequested = false; 
     1091                        removeMessagesNotOnServerImpl(); 
     1092                    } 
     1093                } 
    10321094            } catch (IOException e) { 
    10331095                EventLogger.logEvent(AppInfo.GUID, 
     
    10421104            synchronized(messages) { 
    10431105                if(messageTokenUidSet.containsKey(messageUid)) { 
     1106                    // Don't load messages that have already been loaded 
    10441107                    result = false; 
    10451108                } 
    10461109                else { 
     1110                    // Keep track of messages that will be loaded 
    10471111                    messagesBeingLoaded.put(messageUid, Boolean.TRUE); 
    10481112                    result = true; 
     
    10651129                    } 
    10661130                } 
    1067                 MailboxNode.this.addMessage(messageNode); 
    1068             } 
     1131                messagesToAdd.addElement(messageNode); 
     1132                if(messagesToAdd.size() == 4) { 
     1133                    addLoadedMessages(); 
     1134                } 
     1135            } 
     1136        } 
     1137         
     1138        private void addLoadedMessages() { 
     1139            int size = messagesToAdd.size(); 
     1140            if(size == 0) { return; } 
     1141             
     1142            MessageNode[] messageArray = new MessageNode[size]; 
     1143            messagesToAdd.copyInto(messageArray); 
     1144            messagesToAdd.removeAllElements(); 
     1145            MailboxNode.this.addMessages(messageArray); 
    10691146        } 
    10701147    } 
Note: See TracChangeset for help on using the changeset viewer.