From ec1da36eaf2adfb5695f5c0d8ca92d23d31b56a5 Mon Sep 17 00:00:00 2001 From: Michael Lenaghan Date: Fri, 24 Oct 2014 17:56:49 -0400 Subject: Add an operation to fetch a parsed message. This avoids the copying of Data to NSData to Data which happens with the current approach. In one test case, a message with an ~18 MB attachment, the current (copying) approach peaked at ~150 MB of memory usage in my app. This new approach peaks at ~65 MB. Another test case, which often caused iOS to terminate my app, now peaks at ~90 MB. In addition to the improved memory usage this approach also means that message parsing is performed asynchronously. --- src/async/imap/MCAsyncIMAP.h | 1 + src/async/imap/MCIMAPAsyncConnection.cc | 36 +++++----- src/async/imap/MCIMAPAsyncConnection.h | 1 + src/async/imap/MCIMAPAsyncSession.cc | 32 +++++++-- src/async/imap/MCIMAPAsyncSession.h | 4 ++ .../imap/MCIMAPFetchParsedContentOperation.cc | 79 ++++++++++++++++++++++ src/async/imap/MCIMAPFetchParsedContentOperation.h | 53 +++++++++++++++ 7 files changed, 183 insertions(+), 23 deletions(-) create mode 100644 src/async/imap/MCIMAPFetchParsedContentOperation.cc create mode 100644 src/async/imap/MCIMAPFetchParsedContentOperation.h (limited to 'src/async') diff --git a/src/async/imap/MCAsyncIMAP.h b/src/async/imap/MCAsyncIMAP.h index da032c73..15c9e482 100755 --- a/src/async/imap/MCAsyncIMAP.h +++ b/src/async/imap/MCAsyncIMAP.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/src/async/imap/MCIMAPAsyncConnection.cc b/src/async/imap/MCIMAPAsyncConnection.cc index 3a6508d6..b2fc24c3 100755 --- a/src/async/imap/MCIMAPAsyncConnection.cc +++ b/src/async/imap/MCIMAPAsyncConnection.cc @@ -21,7 +21,7 @@ #include "MCIMAPCopyMessagesOperation.h" #include "MCIMAPFetchMessagesOperation.h" #include "MCIMAPFetchContentOperation.h" -#include "MCIMAPFetchContentOperation.h" +#include "MCIMAPFetchParsedContentOperation.h" #include "MCIMAPStoreFlagsOperation.h" #include "MCIMAPStoreLabelsOperation.h" #include "MCIMAPSearchOperation.h" @@ -43,51 +43,51 @@ using namespace mailcore; namespace mailcore { - + class IMAPOperationQueueCallback : public Object, public OperationQueueCallback { public: IMAPOperationQueueCallback(IMAPAsyncConnection * connection) { mConnection = connection; } - + virtual ~IMAPOperationQueueCallback() { } - + virtual void queueStartRunning() { mConnection->setQueueRunning(true); mConnection->owner()->operationRunningStateChanged(); mConnection->queueStartRunning(); } - + virtual void queueStoppedRunning() { mConnection->setQueueRunning(false); mConnection->tryAutomaticDisconnect(); mConnection->owner()->operationRunningStateChanged(); mConnection->queueStoppedRunning(); } - + private: IMAPAsyncConnection * mConnection; }; - + class IMAPConnectionLogger : public Object, public ConnectionLogger { public: IMAPConnectionLogger(IMAPAsyncConnection * connection) { mConnection = connection; } - + virtual ~IMAPConnectionLogger() { } - + virtual void log(void * sender, ConnectionLogType logType, Data * buffer) { mConnection->logConnection(logType, buffer); } - + private: IMAPAsyncConnection * mConnection; }; - + } IMAPAsyncConnection::IMAPAsyncConnection() @@ -292,7 +292,7 @@ void IMAPAsyncConnection::tryAutomaticDisconnect() if (mSession->isDisconnected()) { return; } - + bool scheduledAutomaticDisconnect = mScheduledAutomaticDisconnect; if (scheduledAutomaticDisconnect) { #if __APPLE__ @@ -301,7 +301,7 @@ void IMAPAsyncConnection::tryAutomaticDisconnect() cancelDelayedPerformMethod((Object::Method) &IMAPAsyncConnection::tryAutomaticDisconnectAfterDelay, NULL); #endif } - + mOwner->retain(); mScheduledAutomaticDisconnect = true; #if __APPLE__ @@ -309,7 +309,7 @@ void IMAPAsyncConnection::tryAutomaticDisconnect() #else performMethodAfterDelay((Object::Method) &IMAPAsyncConnection::tryAutomaticDisconnectAfterDelay, NULL, 30); #endif - + if (scheduledAutomaticDisconnect) { mOwner->release(); } @@ -318,10 +318,10 @@ void IMAPAsyncConnection::tryAutomaticDisconnect() void IMAPAsyncConnection::tryAutomaticDisconnectAfterDelay(void * context) { mScheduledAutomaticDisconnect = false; - + IMAPOperation * op = disconnectOperation(); op->start(); - + mOwner->release(); } @@ -373,11 +373,11 @@ void IMAPAsyncConnection::setConnectionLogger(ConnectionLogger * logger) ConnectionLogger * IMAPAsyncConnection::connectionLogger() { ConnectionLogger * result; - + pthread_mutex_lock(&mConnectionLoggerLock); result = mConnectionLogger; pthread_mutex_unlock(&mConnectionLoggerLock); - + return result; } diff --git a/src/async/imap/MCIMAPAsyncConnection.h b/src/async/imap/MCIMAPAsyncConnection.h index 50d1409a..b267f7c7 100755 --- a/src/async/imap/MCIMAPAsyncConnection.h +++ b/src/async/imap/MCIMAPAsyncConnection.h @@ -15,6 +15,7 @@ namespace mailcore { class IMAPCopyMessagesOperation; class IMAPFetchMessagesOperation; class IMAPFetchContentOperation; + class IMAPFetchParsedContentOperation; class IMAPIdleOperation; class IMAPFolderInfoOperation; class IMAPFolderStatusOperation; diff --git a/src/async/imap/MCIMAPAsyncSession.cc b/src/async/imap/MCIMAPAsyncSession.cc index ef3bb621..f3a55a5e 100755 --- a/src/async/imap/MCIMAPAsyncSession.cc +++ b/src/async/imap/MCIMAPAsyncSession.cc @@ -28,7 +28,7 @@ #include "MCIMAPCopyMessagesOperation.h" #include "MCIMAPFetchMessagesOperation.h" #include "MCIMAPFetchContentOperation.h" -#include "MCIMAPFetchContentOperation.h" +#include "MCIMAPFetchParsedContentOperation.h" #include "MCIMAPStoreFlagsOperation.h" #include "MCIMAPStoreLabelsOperation.h" #include "MCIMAPSearchOperation.h" @@ -52,7 +52,7 @@ IMAPAsyncSession::IMAPAsyncSession() mSessions = new Array(); mMaximumConnections = DEFAULT_MAX_CONNECTIONS; mAllowsFolderConcurrentAccessEnabled = true; - + mHostname = NULL; mPort = 0; mUsername = NULL; @@ -244,7 +244,7 @@ IMAPAsyncConnection * IMAPAsyncSession::session() session->setConnectionLogger(mConnectionLogger); session->setOwner(this); session->autorelease(); - + session->setHostname(mHostname); session->setPort(mPort); session->setUsername(mUsername); @@ -265,7 +265,7 @@ IMAPAsyncConnection * IMAPAsyncSession::session() session->setAutomaticConfigurationEnabled(false); } #endif - + return session; } @@ -283,7 +283,7 @@ IMAPAsyncConnection * IMAPAsyncSession::sessionForFolder(String * folder, bool u return s; } } - + s = matchingSessionForFolder(folder); s->setLastFolder(folder); return s; @@ -549,6 +549,28 @@ IMAPFetchContentOperation * IMAPAsyncSession::fetchMessageAttachmentByNumberOper return op; } +IMAPFetchParsedContentOperation * IMAPAsyncSession::fetchParsedMessageByUIDOperation(String * folder, uint32_t uid, bool urgent) +{ + IMAPFetchParsedContentOperation * op = new IMAPFetchParsedContentOperation(); + op->setMainSession(this); + op->setFolder(folder); + op->setUid(uid); + op->setUrgent(urgent); + op->autorelease(); + return op; +} + +IMAPFetchParsedContentOperation * IMAPAsyncSession::fetchParsedMessageByNumberOperation(String * folder, uint32_t number, bool urgent) +{ + IMAPFetchParsedContentOperation * op = new IMAPFetchParsedContentOperation(); + op->setMainSession(this); + op->setFolder(folder); + op->setNumber(number); + op->setUrgent(urgent); + op->autorelease(); + return op; +} + IMAPOperation * IMAPAsyncSession::storeFlagsByUIDOperation(String * folder, IndexSet * uids, IMAPStoreFlagsRequestKind kind, MessageFlag flags, Array * customFlags) { IMAPStoreFlagsOperation * op = new IMAPStoreFlagsOperation(); diff --git a/src/async/imap/MCIMAPAsyncSession.h b/src/async/imap/MCIMAPAsyncSession.h index a7ec90a0..05b1967c 100755 --- a/src/async/imap/MCIMAPAsyncSession.h +++ b/src/async/imap/MCIMAPAsyncSession.h @@ -23,6 +23,7 @@ namespace mailcore { class IMAPCopyMessagesOperation; class IMAPFetchMessagesOperation; class IMAPFetchContentOperation; + class IMAPFetchParsedContentOperation; class IMAPIdleOperation; class IMAPFolderInfoOperation; class IMAPFolderStatusOperation; @@ -137,6 +138,9 @@ namespace mailcore { virtual IMAPFetchContentOperation * fetchMessageAttachmentByNumberOperation(String * folder, uint32_t number, String * partID, Encoding encoding, bool urgent = false); + virtual IMAPFetchParsedContentOperation * fetchParsedMessageByUIDOperation(String * folder, uint32_t uid, bool urgent = false); + virtual IMAPFetchParsedContentOperation * fetchParsedMessageByNumberOperation(String * folder, uint32_t number, bool urgent = false); + virtual IMAPOperation * storeFlagsByUIDOperation(String * folder, IndexSet * uids, IMAPStoreFlagsRequestKind kind, MessageFlag flags, Array * customFlags = NULL); virtual IMAPOperation * storeFlagsByNumberOperation(String * folder, IndexSet * numbers, IMAPStoreFlagsRequestKind kind, MessageFlag flags, Array * customFlags = NULL); virtual IMAPOperation * storeLabelsByUIDOperation(String * folder, IndexSet * uids, IMAPStoreFlagsRequestKind kind, Array * labels); diff --git a/src/async/imap/MCIMAPFetchParsedContentOperation.cc b/src/async/imap/MCIMAPFetchParsedContentOperation.cc new file mode 100644 index 00000000..e32112e6 --- /dev/null +++ b/src/async/imap/MCIMAPFetchParsedContentOperation.cc @@ -0,0 +1,79 @@ +// +// IMAPFetchParsedContentOperation.cc +// mailcore2 +// +// Created by DINH Viêt Hoà on 1/12/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#include "MCIMAPFetchParsedContentOperation.h" + +#include "MCIMAPSession.h" +#include "MCIMAPAsyncConnection.h" + +using namespace mailcore; + +IMAPFetchParsedContentOperation::IMAPFetchParsedContentOperation() +{ + mUid = 0; + mNumber = 0; + mEncoding = Encoding7Bit; + mParser = NULL; +} + +IMAPFetchParsedContentOperation::~IMAPFetchParsedContentOperation() +{ + MC_SAFE_RELEASE(mParser); +} + +void IMAPFetchParsedContentOperation::setUid(uint32_t uid) +{ + mUid = uid; +} + +uint32_t IMAPFetchParsedContentOperation::uid() +{ + return mUid; +} + +void IMAPFetchParsedContentOperation::setNumber(uint32_t value) +{ + mNumber = value; +} + +uint32_t IMAPFetchParsedContentOperation::number() +{ + return mNumber; +} + +void IMAPFetchParsedContentOperation::setEncoding(Encoding encoding) +{ + mEncoding = encoding; +} + +Encoding IMAPFetchParsedContentOperation::encoding() +{ + return mEncoding; +} + +MessageParser * IMAPFetchParsedContentOperation::parser() +{ + return mParser; +} + +void IMAPFetchParsedContentOperation::main() +{ + ErrorCode error; + Data * data; + if (mUid != 0) { + data = session()->session()->fetchMessageByUID(folder(), mUid, this, &error); + } + else { + data = session()->session()->fetchMessageByNumber(folder(), mNumber, this, &error); + } + if (data) { + mParser = new mailcore::MessageParser(data); + } + setError(error); +} + diff --git a/src/async/imap/MCIMAPFetchParsedContentOperation.h b/src/async/imap/MCIMAPFetchParsedContentOperation.h new file mode 100644 index 00000000..0262a35b --- /dev/null +++ b/src/async/imap/MCIMAPFetchParsedContentOperation.h @@ -0,0 +1,53 @@ +// +// IMAPFetchParsedContentOperation.h +// mailcore2 +// +// Created by DINH Viêt Hoà on 1/12/13. +// Copyright (c) 2013 MailCore. All rights reserved. +// + +#ifndef MAILCORE_IMAPFETCHPARSEDCONTENTOPERATION_H + +#define MAILCORE_IMAPFETCHPARSEDCONTENTOPERATION_H + +#include + +#include + +#ifdef __cplusplus + +namespace mailcore { + + class IMAPFetchParsedContentOperation : public IMAPOperation { + public: + IMAPFetchParsedContentOperation(); + virtual ~IMAPFetchParsedContentOperation(); + + virtual void setUid(uint32_t uid); + virtual uint32_t uid(); + + virtual void setNumber(uint32_t value); + virtual uint32_t number(); + + virtual void setEncoding(Encoding encoding); + virtual Encoding encoding(); + + // Result. + virtual MessageParser * parser(); + + public: // subclass behavior + virtual void main(); + + private: + uint32_t mUid; + uint32_t mNumber; + Encoding mEncoding; + MessageParser * mParser; + + }; + +} + +#endif + +#endif -- cgit v1.2.3