diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-01-25 16:29:00 +0100 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-02-06 08:38:08 +0100 |
commit | 9b84aff4b68c3cef3328c85ac12418048b169cee (patch) | |
tree | 7014f685e6a8c850f0be7965e1e656d3de72a15d /common | |
parent | 0a0c197ed487c343675b62dff8456932c8d5ff7f (diff) | |
download | sink-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.cpp | 2 | ||||
-rw-r--r-- | common/domain/applicationdomaintype.h | 3 | ||||
-rw-r--r-- | common/mailpreprocessor.cpp | 83 | ||||
-rw-r--r-- | common/mailpreprocessor.h | 2 |
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 | ||
91 | qint64 Sink::latestDatabaseVersion() | 91 | qint64 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 | ||
30 | using namespace Sink; | 30 | using namespace Sink; |
31 | 31 | ||
32 | QString MailPropertyExtractor::getFilePathFromMimeMessagePath(const QString &s) const | ||
33 | { | ||
34 | return s; | ||
35 | } | ||
36 | |||
37 | struct 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 | |||
91 | static Sink::ApplicationDomain::Mail::Contact getContact(const KMime::Headers::Generics::MailboxList *header) | 32 | static 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 | ||
107 | static void updatedIndexedProperties(Sink::ApplicationDomain::Mail &mail, KMime::Message::Ptr msg) | 48 | void 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 | ||
157 | void MailPropertyExtractor::newEntity(Sink::ApplicationDomain::Mail &mail) | 108 | void 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 | ||
166 | void MailPropertyExtractor::modifiedEntity(const Sink::ApplicationDomain::Mail &oldMail, Sink::ApplicationDomain::Mail &newMail) | 113 | void 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; |
29 | protected: | 29 | protected: |
30 | virtual QString getFilePathFromMimeMessagePath(const QString &) const; | 30 | static void updatedIndexedProperties(Sink::ApplicationDomain::Mail &mail, const QByteArray &data); |
31 | }; | 31 | }; |
32 | 32 | ||