summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2018-01-25 16:29:00 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2018-02-06 08:38:08 +0100
commit9b84aff4b68c3cef3328c85ac12418048b169cee (patch)
tree7014f685e6a8c850f0be7965e1e656d3de72a15d /common
parent0a0c197ed487c343675b62dff8456932c8d5ff7f (diff)
downloadsink-9b84aff4b68c3cef3328c85ac12418048b169cee.tar.gz
sink-9b84aff4b68c3cef3328c85ac12418048b169cee.zip
Store all BLOB properties inline.
BLOB properties had a couple of intended purposes: * Allow large payloads to be streamed directly to disk, and then be handled by reference. * Allow zero-copy handling. * Keep the database values compact so we can avoid traversing large BLOBS. However, they came at the cost of code-complexity, and we lost all the benefits of our storage layer, such as transactions. Measurements showed, that for email (the intended primary usecase), the overhead is hardly measurable, with most parts performing better, or at least not worse. We additionally also gain file-system independence, which may help on other platforms. The biggest drawback is probably that large payloads need to be written to disk twice, because of the synchronizer queue (once for the queue, once for the actual data).
Diffstat (limited to 'common')
-rw-r--r--common/definitions.cpp2
-rw-r--r--common/domain/applicationdomaintype.h3
-rw-r--r--common/mailpreprocessor.cpp83
-rw-r--r--common/mailpreprocessor.h2
4 files changed, 17 insertions, 73 deletions
diff --git a/common/definitions.cpp b/common/definitions.cpp
index 1f4c0cf..b22137a 100644
--- a/common/definitions.cpp
+++ b/common/definitions.cpp
@@ -90,5 +90,5 @@ QString Sink::resourceStorageLocation(const QByteArray &resourceInstanceIdentifi
90 90
91qint64 Sink::latestDatabaseVersion() 91qint64 Sink::latestDatabaseVersion()
92{ 92{
93 return 0; 93 return 1;
94} 94}
diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h
index 77754c1..8a0daef 100644
--- a/common/domain/applicationdomaintype.h
+++ b/common/domain/applicationdomaintype.h
@@ -439,7 +439,8 @@ struct SINK_EXPORT Mail : public Entity {
439 SINK_PROPERTY(bool, Unread, unread); 439 SINK_PROPERTY(bool, Unread, unread);
440 SINK_PROPERTY(bool, Important, important); 440 SINK_PROPERTY(bool, Important, important);
441 SINK_REFERENCE_PROPERTY(Folder, Folder, folder); 441 SINK_REFERENCE_PROPERTY(Folder, Folder, folder);
442 SINK_BLOB_PROPERTY(MimeMessage, mimeMessage); 442 // SINK_BLOB_PROPERTY(MimeMessage, mimeMessage);
443 SINK_PROPERTY(QByteArray, MimeMessage, mimeMessage);
443 SINK_EXTRACTED_PROPERTY(bool, FullPayloadAvailable, fullPayloadAvailable); 444 SINK_EXTRACTED_PROPERTY(bool, FullPayloadAvailable, fullPayloadAvailable);
444 SINK_PROPERTY(bool, Draft, draft); 445 SINK_PROPERTY(bool, Draft, draft);
445 SINK_PROPERTY(bool, Trash, trash); 446 SINK_PROPERTY(bool, Trash, trash);
diff --git a/common/mailpreprocessor.cpp b/common/mailpreprocessor.cpp
index b1cb1d5..8f5a77d 100644
--- a/common/mailpreprocessor.cpp
+++ b/common/mailpreprocessor.cpp
@@ -29,65 +29,6 @@
29 29
30using namespace Sink; 30using namespace Sink;
31 31
32QString MailPropertyExtractor::getFilePathFromMimeMessagePath(const QString &s) const
33{
34 return s;
35}
36
37struct MimeMessageReader {
38 MimeMessageReader(const QString &mimeMessagePath)
39 : f(mimeMessagePath),
40 mapped(0)
41 {
42 if (mimeMessagePath.isNull()) {
43 SinkTrace() << "No mime message";
44 return;
45 }
46 SinkTrace() << "Updating indexed properties " << mimeMessagePath;
47 if (!f.open(QIODevice::ReadOnly)) {
48 SinkWarning() << "Failed to open the file: " << mimeMessagePath;
49 return;
50 }
51 if (!f.size()) {
52 SinkWarning() << "The file is empty.";
53 return;
54 }
55 mapped = f.map(0, f.size());
56 if (!mapped) {
57 SinkWarning() << "Failed to map the file: " << f.errorString();
58 return;
59 }
60 }
61
62 KMime::Message::Ptr mimeMessage()
63 {
64 if (!mapped) {
65 return {};
66 }
67 QByteArray result;
68 //Seek for end of headers
69 const auto content = QByteArray::fromRawData(reinterpret_cast<const char*>(mapped), f.size());
70 int pos = content.indexOf("\r\n\r\n", 0);
71 int offset = 2;
72 if (pos < 0) {
73 pos = content.indexOf("\n\n", 0);
74 offset = 1;
75 }
76 if (pos > -1) {
77 const auto header = content.left(pos + offset); //header *must* end with "\n" !!
78 auto msg = KMime::Message::Ptr(new KMime::Message);
79 msg->setHead(KMime::CRLFtoLF(header));
80 msg->parse();
81 return msg;
82 }
83 SinkWarning() << "Failed to find end of headers" << content;
84 return {};
85 }
86
87 QFile f;
88 uchar *mapped;
89};
90
91static Sink::ApplicationDomain::Mail::Contact getContact(const KMime::Headers::Generics::MailboxList *header) 32static Sink::ApplicationDomain::Mail::Contact getContact(const KMime::Headers::Generics::MailboxList *header)
92{ 33{
93 const auto name = header->displayNames().isEmpty() ? QString() : header->displayNames().first(); 34 const auto name = header->displayNames().isEmpty() ? QString() : header->displayNames().first();
@@ -104,8 +45,18 @@ static QList<Sink::ApplicationDomain::Mail::Contact> getContactList(const KMime:
104 return list; 45 return list;
105} 46}
106 47
107static void updatedIndexedProperties(Sink::ApplicationDomain::Mail &mail, KMime::Message::Ptr msg) 48void MailPropertyExtractor::updatedIndexedProperties(Sink::ApplicationDomain::Mail &mail, const QByteArray &data)
108{ 49{
50 if (data.isEmpty()) {
51 return;
52 }
53 auto msg = KMime::Message::Ptr(new KMime::Message);
54 msg->setHead(KMime::CRLFtoLF(data));
55 msg->parse();
56 if (!msg) {
57 return;
58 }
59
109 mail.setExtractedSubject(msg->subject(true)->asUnicodeString()); 60 mail.setExtractedSubject(msg->subject(true)->asUnicodeString());
110 mail.setExtractedSender(getContact(msg->from(true))); 61 mail.setExtractedSender(getContact(msg->from(true)));
111 mail.setExtractedTo(getContactList(msg->to(true))); 62 mail.setExtractedTo(getContactList(msg->to(true)));
@@ -156,19 +107,11 @@ static void updatedIndexedProperties(Sink::ApplicationDomain::Mail &mail, KMime:
156 107
157void MailPropertyExtractor::newEntity(Sink::ApplicationDomain::Mail &mail) 108void MailPropertyExtractor::newEntity(Sink::ApplicationDomain::Mail &mail)
158{ 109{
159 MimeMessageReader mimeMessageReader(getFilePathFromMimeMessagePath(mail.getMimeMessagePath())); 110 updatedIndexedProperties(mail, mail.getMimeMessage());
160 auto msg = mimeMessageReader.mimeMessage();
161 if (msg) {
162 updatedIndexedProperties(mail, msg);
163 }
164} 111}
165 112
166void MailPropertyExtractor::modifiedEntity(const Sink::ApplicationDomain::Mail &oldMail, Sink::ApplicationDomain::Mail &newMail) 113void MailPropertyExtractor::modifiedEntity(const Sink::ApplicationDomain::Mail &oldMail, Sink::ApplicationDomain::Mail &newMail)
167{ 114{
168 MimeMessageReader mimeMessageReader(getFilePathFromMimeMessagePath(newMail.getMimeMessagePath())); 115 updatedIndexedProperties(newMail, newMail.getMimeMessage());
169 auto msg = mimeMessageReader.mimeMessage();
170 if (msg) {
171 updatedIndexedProperties(newMail, msg);
172 }
173} 116}
174 117
diff --git a/common/mailpreprocessor.h b/common/mailpreprocessor.h
index a24a8d3..d2e79ca 100644
--- a/common/mailpreprocessor.h
+++ b/common/mailpreprocessor.h
@@ -27,6 +27,6 @@ public:
27 virtual void newEntity(Sink::ApplicationDomain::Mail &mail) Q_DECL_OVERRIDE; 27 virtual void newEntity(Sink::ApplicationDomain::Mail &mail) Q_DECL_OVERRIDE;
28 virtual void modifiedEntity(const Sink::ApplicationDomain::Mail &oldMail, Sink::ApplicationDomain::Mail &newMail) Q_DECL_OVERRIDE; 28 virtual void modifiedEntity(const Sink::ApplicationDomain::Mail &oldMail, Sink::ApplicationDomain::Mail &newMail) Q_DECL_OVERRIDE;
29protected: 29protected:
30 virtual QString getFilePathFromMimeMessagePath(const QString &) const; 30 static void updatedIndexedProperties(Sink::ApplicationDomain::Mail &mail, const QByteArray &data);
31}; 31};
32 32