From 852e51328165163b794a5a16d11c2de0b1c4f9d7 Mon Sep 17 00:00:00 2001 From: Matthew Brace Date: Sun, 7 Dec 2008 20:55:26 +0000 Subject: [PATCH] Modified fetch() to call fetchEnvelope() which runs recursively, grabbing message ENVELOPEs 10 at a time rather than attempting all 100 at once. Shows a significant performance increase and a significant reduction in memory usage. --- src/com/fsck/k9/mail/store/WebDavStore.java | 178 +++++++++++++------- 1 file changed, 114 insertions(+), 64 deletions(-) diff --git a/src/com/fsck/k9/mail/store/WebDavStore.java b/src/com/fsck/k9/mail/store/WebDavStore.java index 48466725c..7d3bfa4e1 100644 --- a/src/com/fsck/k9/mail/store/WebDavStore.java +++ b/src/com/fsck/k9/mail/store/WebDavStore.java @@ -871,7 +871,7 @@ public class WebDavStore extends Store { public void fetch(Message[] messages, FetchProfile fp, MessageRetrievalListener listener) throws MessagingException { HashMap uidToReadStatus = new HashMap(); - HashMap envelopes = new HashMap(); + if (messages == null || messages.length == 0) { return; @@ -883,64 +883,7 @@ public class WebDavStore extends Store { * Listener isn't started yet since it isn't a per-message lookup. */ if (fp.contains(FetchProfile.Item.ENVELOPE)) { - DefaultHttpClient httpclient = new DefaultHttpClient(); - String messageBody = new String(); - String[] uids = new String[messages.length]; - - for (int i = 0, count = messages.length; i < count; i++) { - uids[i] = messages[i].getUid(); - } - - httpclient.setCookieStore(WebDavStore.this.mAuthCookies); - messageBody = getMessageEnvelopeXml(uids); - - try { - int status_code = -1; - StringEntity messageEntity = new StringEntity(messageBody); - HttpGeneric httpmethod = new HttpGeneric(this.mFolderUrl); - HttpResponse response; - HttpEntity entity; - - messageEntity.setContentType("text/xml"); - httpmethod.setMethod("SEARCH"); - httpmethod.setEntity(messageEntity); - httpmethod.setHeader("Brief", "t"); - - response = httpclient.execute(httpmethod); - status_code = response.getStatusLine().getStatusCode(); - - if (status_code < 200 || - status_code > 300) { - throw new IOException("Error getting message envelopes, returned HTTP Response code " + status_code); - } - - entity = response.getEntity(); - - if (entity != null) { - try { - InputStream istream = entity.getContent(); - SAXParserFactory spf = SAXParserFactory.newInstance(); - SAXParser sp = spf.newSAXParser(); - XMLReader xr = sp.getXMLReader(); - WebDavHandler myHandler = new WebDavHandler(); - ParsedDataSet dataset; - - xr.setContentHandler(myHandler); - xr.parse(new InputSource(istream)); - - dataset = myHandler.getDataSet(); - envelopes = dataset.getMessageEnvelopes(); - } catch (SAXException se) { - Log.e(k9.LOG_TAG, "SAXException in fetch() " + se); - } catch (ParserConfigurationException pce) { - Log.e(k9.LOG_TAG, "ParserConfigurationException in fetch() " + pce); - } - } - } catch (UnsupportedEncodingException uee) { - Log.e(k9.LOG_TAG, "UnsupportedEncodingException: " + uee); - } catch (IOException ioe) { - Log.e(k9.LOG_TAG, "IOException: " + ioe); - } + fetchEnvelope(messages, listener); } /** @@ -1014,7 +957,7 @@ public class WebDavStore extends Store { throw new MessagingException("WebDavStore fetch called with non-WebDavMessage"); } WebDavMessage wdMessage = (WebDavMessage) messages[i]; - + if (listener != null) { listener.messageStarted(wdMessage.getUid(), i, count); } @@ -1023,10 +966,6 @@ public class WebDavStore extends Store { wdMessage.setFlagInternal(Flag.SEEN, uidToReadStatus.get(wdMessage.getUid())); } - if (fp.contains(FetchProfile.Item.ENVELOPE)) { - wdMessage.setNewHeaders(envelopes.get(wdMessage.getUid())); - } - /** * Set the body to null if it's asking for the structure because * we don't support it yet. @@ -1114,6 +1053,117 @@ public class WebDavStore extends Store { } } + /** + * Fetches and parses the message envelopes for the supplied messages. + * The idea is to have this be recursive so that we do a series of medium calls + * instead of one large massive call or a large number of smaller calls. + * Call it a happy balance + */ + private void fetchEnvelope(Message[] startMessages, MessageRetrievalListener listener) throws MessagingException { + HashMap envelopes = new HashMap(); + Message[] messages = new Message[10]; + if (startMessages == null || + startMessages.length == 0) { + return; + } + + if (startMessages.length > 10) { + Message[] newMessages = new Message[startMessages.length - 10]; + for (int i = 0, count = startMessages.length; i < count; i++) { + if (i < 10) { + messages[i] = startMessages[i]; + } else { + newMessages[i - 10] = startMessages[i]; + } + } + /** System.arraycopy(startMessages, 0, messages, 0, 10); + System.arraycopy(startMessages, 10, newMessages, 0, startMessages.length - 10);*/ + fetchEnvelope(newMessages, listener); + } else { + messages = startMessages; + } + + DefaultHttpClient httpclient = new DefaultHttpClient(); + String messageBody = new String(); + String[] uids = new String[messages.length]; + + for (int i = 0, count = messages.length; i < count; i++) { + uids[i] = messages[i].getUid(); + } + + httpclient.setCookieStore(WebDavStore.this.mAuthCookies); + messageBody = getMessageEnvelopeXml(uids); + + try { + int status_code = -1; + StringEntity messageEntity = new StringEntity(messageBody); + HttpGeneric httpmethod = new HttpGeneric(this.mFolderUrl); + HttpResponse response; + HttpEntity entity; + + messageEntity.setContentType("text/xml"); + httpmethod.setMethod("SEARCH"); + httpmethod.setEntity(messageEntity); + httpmethod.setHeader("Brief", "t"); + + response = httpclient.execute(httpmethod); + status_code = response.getStatusLine().getStatusCode(); + + if (status_code < 200 || + status_code > 300) { + throw new IOException("Error getting message flags, returned HTTP Response code " + status_code); + } + + entity = response.getEntity(); + + if (entity != null) { + try { + InputStream istream = entity.getContent(); + SAXParserFactory spf = SAXParserFactory.newInstance(); + SAXParser sp = spf.newSAXParser(); + XMLReader xr = sp.getXMLReader(); + WebDavHandler myHandler = new WebDavHandler(); + ParsedDataSet dataset; + + xr.setContentHandler(myHandler); + xr.parse(new InputSource(istream)); + + dataset = myHandler.getDataSet(); + envelopes = dataset.getMessageEnvelopes(); + } catch (SAXException se) { + Log.e(k9.LOG_TAG, "SAXException in fetch() " + se); + } catch (ParserConfigurationException pce) { + Log.e(k9.LOG_TAG, "ParserConfigurationException in fetch() " + pce); + } + } + } catch (UnsupportedEncodingException uee) { + Log.e(k9.LOG_TAG, "UnsupportedEncodingException: " + uee); + } catch (IOException ioe) { + Log.e(k9.LOG_TAG, "IOException: " + ioe); + } + + for (int i = 0, count = messages.length; i < count; i++) { + if (!(messages[i] instanceof WebDavMessage)) { + throw new MessagingException("WebDavStore fetch called with non-WebDavMessage"); + } + WebDavMessage wdMessage = (WebDavMessage) messages[i]; + + if (listener != null) { + listener.messageStarted(messages[i].getUid(), i, count); + } + /** + ((WebDavMessage) messages[i]).setNewHeaders(envelopes.get(((WebDavMessage) messages[i]).getUid())); + ((WebDavMessage) messages[i]).setFlagInternal(Flag.SEEN, envelopes.get(((WebDavMessage) messages[i]).getUid()).getReadStatus()); + */ + wdMessage.setNewHeaders(envelopes.get(wdMessage.getUid())); + wdMessage.setFlagInternal(Flag.SEEN, envelopes.get(wdMessage.getUid()).getReadStatus()); + + if (listener != null) { + listener.messageFinished(messages[i], i, count); + } + } + } + @Override public Flag[] getPermanentFlags() throws MessagingException { return PERMANENT_FLAGS;