From b108e7a539d2ea638349a77ffe8cd8aee001e6c2 Mon Sep 17 00:00:00 2001 From: cketti Date: Thu, 15 Nov 2012 21:05:45 +0100 Subject: [PATCH] Don't fetch already downloaded messages found by a server-side search --- .../k9/controller/MessagingController.java | 24 +++--- src/com/fsck/k9/mail/store/LocalStore.java | 81 +++++++++++++++++++ 2 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/com/fsck/k9/controller/MessagingController.java b/src/com/fsck/k9/controller/MessagingController.java index 890d40053..d23d5799c 100644 --- a/src/com/fsck/k9/controller/MessagingController.java +++ b/src/com/fsck/k9/controller/MessagingController.java @@ -626,24 +626,28 @@ public class MessagingController implements Runnable { } List messages = remoteFolder.search(query, requiredFlags, forbiddenFlags); - if (listener != null) { - listener.remoteSearchServerQueryComplete(acct, folderName, messages.size()); - } if (K9.DEBUG) { Log.i("Remote Search", "Remote search got " + messages.size() + " results"); } - Collections.sort(messages, new UidReverseComparator()); + // There's no need to fetch messages already completely downloaded + List remoteMessages = localFolder.extractNewMessages(messages); + messages.clear(); - - int resultLimit = acct.getRemoteSearchNumResults(); - if (resultLimit > 0 && messages.size() > resultLimit) { - extraResults = messages.subList(resultLimit, messages.size()); - messages = messages.subList(0, resultLimit); + if (listener != null) { + listener.remoteSearchServerQueryComplete(acct, folderName, remoteMessages.size()); } - loadSearchResultsSynchronous(messages, localFolder, remoteFolder, listener); + Collections.sort(remoteMessages, new UidReverseComparator()); + + int resultLimit = acct.getRemoteSearchNumResults(); + if (resultLimit > 0 && remoteMessages.size() > resultLimit) { + extraResults = remoteMessages.subList(resultLimit, remoteMessages.size()); + remoteMessages = remoteMessages.subList(0, resultLimit); + } + + loadSearchResultsSynchronous(remoteMessages, localFolder, remoteFolder, listener); } catch (Exception e) { diff --git a/src/com/fsck/k9/mail/store/LocalStore.java b/src/com/fsck/k9/mail/store/LocalStore.java index f4120408a..21f03472f 100644 --- a/src/com/fsck/k9/mail/store/LocalStore.java +++ b/src/com/fsck/k9/mail/store/LocalStore.java @@ -15,6 +15,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -101,6 +102,14 @@ public class LocalStore extends Store implements Serializable { static private String GET_FOLDER_COLS = "id, name, unread_count, visible_limit, last_updated, status, push_state, last_pushed, flagged_count, integrate, top_group, poll_class, push_class, display_class"; + private static final String[] UID_CHECK_PROJECTION = { "uid" }; + + /** + * Number of UIDs to check for existence at once. + * + * @see LocalFolder#extractNewMessages(List) + */ + private static final int UID_CHECK_BATCH_SIZE = 500; protected static final int DB_VERSION = 45; @@ -3206,6 +3215,78 @@ public class LocalStore extends Store implements Serializable { return new ThreadInfo(id, messageId, rootId, parentId); } + + public List extractNewMessages(final List messages) + throws MessagingException { + + try { + return database.execute(false, new DbCallback>() { + @Override + public List doDbWork(final SQLiteDatabase db) throws WrappedException { + try { + open(OpenMode.READ_WRITE); + } catch (MessagingException e) { + throw new WrappedException(e); + } + + List result = new ArrayList(); + + List selectionArgs = new ArrayList(); + Set existingMessages = new HashSet(); + int start = 0; + + while (start < messages.size()) { + StringBuilder selection = new StringBuilder(); + + selection.append("folder_id = ? AND UID IN ("); + selectionArgs.add(Long.toString(mFolderId)); + + int count = Math.min(messages.size() - start, UID_CHECK_BATCH_SIZE); + + for (int i = start, end = start + count; i < end; i++) { + if (i > start) { + selection.append(",?"); + } else { + selection.append("?"); + } + + selectionArgs.add(messages.get(i).getUid()); + } + + selection.append(")"); + + Cursor cursor = db.query("messages", UID_CHECK_PROJECTION, + selection.toString(), selectionArgs.toArray(EMPTY_STRING_ARRAY), + null, null, null); + + try { + while (cursor.moveToNext()) { + String uid = cursor.getString(0); + existingMessages.add(uid); + } + } finally { + Utility.closeQuietly(cursor); + } + + for (int i = start, end = start + count; i < end; i++) { + Message message = messages.get(i); + if (!existingMessages.contains(message.getUid())) { + result.add(message); + } + } + + existingMessages.clear(); + selectionArgs.clear(); + start += count; + } + + return result; + } + }); + } catch (WrappedException e) { + throw(MessagingException) e.getCause(); + } + } } public static class LocalTextBody extends TextBody {