Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79c65d4c authored by Vincent Breitmoser's avatar Vincent Breitmoser
Browse files

don't load all local message metadata into memory during synchronize

parent a357963d
Loading
Loading
Loading
Loading
+11 −13
Original line number Diff line number Diff line
@@ -796,11 +796,7 @@ public class MessagingController {
            final LocalFolder localFolder = tLocalFolder;
            localFolder.open(Folder.OPEN_MODE_RW);
            localFolder.updateLastUid();
            List<? extends Message> localMessages = localFolder.getMessages(null);
            Map<String, Message> localUidMap = new HashMap<>();
            for (Message message : localMessages) {
                localUidMap.put(message.getUid(), message);
            }
            Map<String, Long> localUidMap = localFolder.getAllMessagesAndEffectiveDates();

            if (providedRemoteFolder != null) {
                if (K9.DEBUG)
@@ -899,8 +895,9 @@ public class MessagingController {
                    for (MessagingListener l : getListeners(listener)) {
                        l.synchronizeMailboxHeadersProgress(account, folder, headerProgress.get(), messageCount);
                    }
                    Message localMessage = localUidMap.get(thisMess.getUid());
                    if (localMessage == null || !localMessage.olderThan(earliestDate)) {
                    Long localMessageDateRaw = localUidMap.get(thisMess.getUid());
                    Date localMessageDate = localMessageDateRaw != null ? new Date(localMessageDateRaw) : null;
                    if (localMessageDate == null || !localMessageDate.before(earliestDate)) {
                        remoteMessages.add(thisMess);
                        remoteUidMap.put(thisMess.getUid(), thisMess);
                    }
@@ -921,14 +918,15 @@ public class MessagingController {
             */
            MoreMessages moreMessages = localFolder.getMoreMessages();
            if (account.syncRemoteDeletions()) {
                List<Message> destroyMessages = new ArrayList<>();
                for (Message localMessage : localMessages) {
                    if (remoteUidMap.get(localMessage.getUid()) == null) {
                        destroyMessages.add(localMessage);
                List<String> destroyMessageUids = new ArrayList<>();
                for (String localMessageUid : localUidMap.keySet()) {
                    if (remoteUidMap.get(localMessageUid) == null) {
                        destroyMessageUids.add(localMessageUid);
                    }
                }

                if (!destroyMessages.isEmpty()) {
                List<LocalMessage> destroyMessages = localFolder.getMessagesByUids(destroyMessageUids);
                if (!destroyMessageUids.isEmpty()) {
                    moreMessages = MoreMessages.UNKNOWN;

                    localFolder.destroyMessages(destroyMessages);
@@ -941,7 +939,7 @@ public class MessagingController {
                }
            }
            // noinspection UnusedAssignment, free memory early? (better break up the method!)
            localMessages = null;
            localUidMap = null;

            if (moreMessages == MoreMessages.UNKNOWN) {
                updateMoreMessages(remoteFolder, localFolder, earliestDate, remoteStart);
+37 −0
Original line number Diff line number Diff line
@@ -865,6 +865,43 @@ public class LocalFolder extends Folder<LocalMessage> implements Serializable {
        }
    }

    public Map<String,Long> getAllMessagesAndEffectiveDates() throws MessagingException {
        try {
            return  localStore.database.execute(false, new DbCallback<Map<String, Long>>() {
                @Override
                public Map<String, Long> doDbWork(final SQLiteDatabase db) throws WrappedException, UnavailableStorageException {
                    Cursor cursor = null;
                    HashMap<String, Long> result = new HashMap<>();

                    try {
                        open(OPEN_MODE_RO);

                        cursor = db.rawQuery(
                                "SELECT uid, date " +
                                        "FROM messages " +
                                        "WHERE empty = 0 AND deleted = 0 AND " +
                                        "folder_id = ? ORDER BY date DESC",
                                new String[] { Long.toString(mFolderId) });

                        while (cursor.moveToNext()) {
                            String uid = cursor.getString(0);
                            Long date = cursor.isNull(1) ? null : cursor.getLong(1);
                            result.put(uid, date);
                        }
                    } catch (MessagingException e) {
                        throw new WrappedException(e);
                    } finally {
                        Utility.closeQuietly(cursor);
                    }

                    return result;
                }
            });
        } catch (WrappedException e) {
            throw(MessagingException) e.getCause();
        }
    }

    public List<LocalMessage> getMessages(MessageRetrievalListener<LocalMessage> listener) throws MessagingException {
        return getMessages(listener, true);
    }
+8 −4
Original line number Diff line number Diff line
package com.fsck.k9.controller;


import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
@@ -26,7 +27,6 @@ import com.fsck.k9.mailstore.LocalMessage;
import com.fsck.k9.mailstore.LocalStore;
import com.fsck.k9.notification.NotificationController;
import com.fsck.k9.search.LocalSearch;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -65,6 +65,7 @@ import static org.mockito.Mockito.when;
public class MessagingControllerTest {
    private static final String FOLDER_NAME = "Folder";
    private static final int MAXIMUM_SMALL_MESSAGE_SIZE = 1000;
    private static final String MESSAGE_UID1 = "message-uid1";


    private MessagingController controller;
@@ -573,7 +574,9 @@ public class MessagingControllerTest {
        messageCountInRemoteFolder(0);
        LocalMessage localCopyOfRemoteDeletedMessage = mock(LocalMessage.class);
        when(account.syncRemoteDeletions()).thenReturn(true);
        when(localFolder.getMessages(null)).thenReturn(Collections.singletonList(localCopyOfRemoteDeletedMessage));
        when(localFolder.getAllMessagesAndEffectiveDates()).thenReturn(Collections.singletonMap(MESSAGE_UID1, 0L));
        when(localFolder.getMessagesByUids(any(List.class)))
                .thenReturn(Collections.singletonList(localCopyOfRemoteDeletedMessage));

        controller.synchronizeMailboxSynchronous(account, FOLDER_NAME, listener, remoteFolder);

@@ -606,7 +609,8 @@ public class MessagingControllerTest {
        when(account.syncRemoteDeletions()).thenReturn(true);
        when(account.getEarliestPollDate()).thenReturn(dateOfEarliestPoll);
        when(localMessage.olderThan(dateOfEarliestPoll)).thenReturn(true);
        when(localFolder.getMessages(null)).thenReturn(Collections.singletonList(localMessage));
        when(localFolder.getAllMessagesAndEffectiveDates()).thenReturn(Collections.singletonMap(MESSAGE_UID1, 0L));
        when(localFolder.getMessagesByUids(any(List.class))).thenReturn(Collections.singletonList(localMessage));

        controller.synchronizeMailboxSynchronous(account, FOLDER_NAME, listener, remoteFolder);

@@ -638,9 +642,9 @@ public class MessagingControllerTest {

        verify(remoteFolder, atLeastOnce()).fetch(any(List.class), fetchProfileCaptor.capture(),
                any(MessageRetrievalListener.class));
        assertEquals(2, fetchProfileCaptor.getAllValues().get(0).size());
        assertTrue(fetchProfileCaptor.getAllValues().get(0).contains(FetchProfile.Item.FLAGS));
        assertTrue(fetchProfileCaptor.getAllValues().get(0).contains(FetchProfile.Item.ENVELOPE));
        assertEquals(2, fetchProfileCaptor.getAllValues().get(0).size());
    }

    @Test