diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-09-20 17:18:21 +0200 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2016-09-20 17:18:21 +0200 |
commit | ebc5c48c03b6145e604da7c313b35321d0a71142 (patch) | |
tree | 1cee00a9fa4faa4995c0a50f01703ac5672c8797 /common/domain/mail.cpp | |
parent | 4a14a6fade947aa830d3f21598a4a6ba7316b933 (diff) | |
download | sink-ebc5c48c03b6145e604da7c313b35321d0a71142.tar.gz sink-ebc5c48c03b6145e604da7c313b35321d0a71142.zip |
A first draft of the threading algorithm.
Diffstat (limited to 'common/domain/mail.cpp')
-rw-r--r-- | common/domain/mail.cpp | 117 |
1 files changed, 102 insertions, 15 deletions
diff --git a/common/domain/mail.cpp b/common/domain/mail.cpp index bb5ad58..859ebef 100644 --- a/common/domain/mail.cpp +++ b/common/domain/mail.cpp | |||
@@ -41,6 +41,7 @@ SINK_DEBUG_AREA("mail"); | |||
41 | 41 | ||
42 | static QMutex sMutex; | 42 | static QMutex sMutex; |
43 | 43 | ||
44 | using namespace Sink; | ||
44 | using namespace Sink::ApplicationDomain; | 45 | using namespace Sink::ApplicationDomain; |
45 | 46 | ||
46 | static TypeIndex &getIndex() | 47 | static TypeIndex &getIndex() |
@@ -49,26 +50,54 @@ static TypeIndex &getIndex() | |||
49 | static TypeIndex *index = 0; | 50 | static TypeIndex *index = 0; |
50 | if (!index) { | 51 | if (!index) { |
51 | index = new TypeIndex("mail"); | 52 | index = new TypeIndex("mail"); |
52 | index->addProperty<QByteArray>("uid"); | 53 | index->addProperty<QByteArray>(Mail::Uid::name); |
53 | index->addProperty<QByteArray>("sender"); | 54 | index->addProperty<QByteArray>(Mail::Sender::name); |
54 | index->addProperty<QByteArray>("senderName"); | 55 | index->addProperty<QByteArray>(Mail::SenderName::name); |
55 | index->addProperty<QString>("subject"); | 56 | index->addProperty<QString>(Mail::Subject::name); |
56 | index->addProperty<QDateTime>("date"); | 57 | index->addProperty<QDateTime>(Mail::Date::name); |
57 | index->addProperty<QByteArray>("folder"); | 58 | index->addProperty<QByteArray>(Mail::Folder::name); |
58 | index->addPropertyWithSorting<QByteArray, QDateTime>("folder", "date"); | 59 | index->addPropertyWithSorting<QByteArray, QDateTime>(Mail::Folder::name, Mail::Date::name); |
60 | index->addProperty<QByteArray>(Mail::MessageId::name); | ||
61 | index->addProperty<QByteArray>(Mail::ParentMessageId::name); | ||
59 | } | 62 | } |
60 | return *index; | 63 | return *index; |
61 | } | 64 | } |
62 | 65 | ||
63 | ResultSet TypeImplementation<Mail>::queryIndexes(const Sink::Query &query, const QByteArray &resourceInstanceIdentifier, QSet<QByteArray> &appliedFilters, QByteArray &appliedSorting, Sink::Storage::Transaction &transaction) | 66 | static void updateThreadingIndex(const QByteArray &identifier, const BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction) |
64 | { | 67 | { |
65 | return getIndex().query(query, appliedFilters, appliedSorting, transaction); | 68 | auto messageId = bufferAdaptor.getProperty(Mail::MessageId::name).toByteArray(); |
69 | auto parentMessageId = bufferAdaptor.getProperty(Mail::ParentMessageId::name).toByteArray(); | ||
70 | |||
71 | Index msgIdIndex("msgId", transaction); | ||
72 | Index msgIdThreadIdIndex("msgIdThreadId", transaction); | ||
73 | |||
74 | //Add the message to the index | ||
75 | Q_ASSERT(msgIdIndex.lookup(messageId).isEmpty()); | ||
76 | msgIdIndex.add(messageId, identifier); | ||
77 | |||
78 | //If parent is already available, add to thread of parent | ||
79 | QByteArray thread; | ||
80 | if (!parentMessageId.isEmpty() && !msgIdIndex.lookup(parentMessageId).isEmpty()) { | ||
81 | thread = msgIdThreadIdIndex.lookup(parentMessageId); | ||
82 | msgIdThreadIdIndex.add(messageId, thread); | ||
83 | } else { | ||
84 | thread = QUuid::createUuid().toByteArray(); | ||
85 | if (!parentMessageId.isEmpty()) { | ||
86 | //Register parent with thread for when it becomes available | ||
87 | msgIdThreadIdIndex.add(parentMessageId, thread); | ||
88 | } | ||
89 | } | ||
90 | Q_ASSERT(!thread.isEmpty()); | ||
91 | msgIdThreadIdIndex.add(messageId, thread); | ||
92 | |||
93 | //Look for parentMessageId and resolve to local id if available | ||
66 | } | 94 | } |
67 | 95 | ||
68 | void TypeImplementation<Mail>::index(const QByteArray &identifier, const BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction) | 96 | void TypeImplementation<Mail>::index(const QByteArray &identifier, const BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction) |
69 | { | 97 | { |
70 | SinkTrace() << "Indexing " << identifier; | 98 | SinkTrace() << "Indexing " << identifier; |
71 | getIndex().add(identifier, bufferAdaptor, transaction); | 99 | getIndex().add(identifier, bufferAdaptor, transaction); |
100 | updateThreadingIndex(identifier, bufferAdaptor, transaction); | ||
72 | } | 101 | } |
73 | 102 | ||
74 | void TypeImplementation<Mail>::removeIndex(const QByteArray &identifier, const BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction) | 103 | void TypeImplementation<Mail>::removeIndex(const QByteArray &identifier, const BufferAdaptor &bufferAdaptor, Sink::Storage::Transaction &transaction) |
@@ -91,6 +120,8 @@ QSharedPointer<ReadPropertyMapper<TypeImplementation<Mail>::Buffer> > TypeImplem | |||
91 | propertyMapper->addMapping<Mail::Draft, Buffer>(&Buffer::draft); | 120 | propertyMapper->addMapping<Mail::Draft, Buffer>(&Buffer::draft); |
92 | propertyMapper->addMapping<Mail::Trash, Buffer>(&Buffer::trash); | 121 | propertyMapper->addMapping<Mail::Trash, Buffer>(&Buffer::trash); |
93 | propertyMapper->addMapping<Mail::Sent, Buffer>(&Buffer::sent); | 122 | propertyMapper->addMapping<Mail::Sent, Buffer>(&Buffer::sent); |
123 | propertyMapper->addMapping<Mail::MessageId, Buffer>(&Buffer::messageId); | ||
124 | propertyMapper->addMapping<Mail::ParentMessageId, Buffer>(&Buffer::parentMessageId); | ||
94 | return propertyMapper; | 125 | return propertyMapper; |
95 | } | 126 | } |
96 | 127 | ||
@@ -110,16 +141,72 @@ QSharedPointer<WritePropertyMapper<TypeImplementation<Mail>::BufferBuilder> > Ty | |||
110 | propertyMapper->addMapping<Mail::Draft>(&BufferBuilder::add_draft); | 141 | propertyMapper->addMapping<Mail::Draft>(&BufferBuilder::add_draft); |
111 | propertyMapper->addMapping<Mail::Trash>(&BufferBuilder::add_trash); | 142 | propertyMapper->addMapping<Mail::Trash>(&BufferBuilder::add_trash); |
112 | propertyMapper->addMapping<Mail::Sent>(&BufferBuilder::add_sent); | 143 | propertyMapper->addMapping<Mail::Sent>(&BufferBuilder::add_sent); |
144 | propertyMapper->addMapping<Mail::MessageId>(&BufferBuilder::add_messageId); | ||
145 | propertyMapper->addMapping<Mail::ParentMessageId>(&BufferBuilder::add_parentMessageId); | ||
113 | return propertyMapper; | 146 | return propertyMapper; |
114 | } | 147 | } |
115 | 148 | ||
116 | DataStoreQuery TypeImplementation<Mail>::prepareQuery(const Sink::Query &query, Sink::Storage::Transaction &transaction) | 149 | class ThreadedDataStoreQuery : public DataStoreQuery |
150 | { | ||
151 | public: | ||
152 | typedef QSharedPointer<ThreadedDataStoreQuery> Ptr; | ||
153 | using DataStoreQuery::DataStoreQuery; | ||
154 | |||
155 | protected: | ||
156 | ResultSet postSortFilter(ResultSet &resultSet) Q_DECL_OVERRIDE | ||
157 | { | ||
158 | auto query = mQuery; | ||
159 | if (query.threadLeaderOnly) { | ||
160 | auto rootCollection = QSharedPointer<QMap<QByteArray, QDateTime>>::create(); | ||
161 | auto filter = [this, query, rootCollection](const QByteArray &uid, const Sink::EntityBuffer &entity) -> bool { | ||
162 | //TODO lookup thread | ||
163 | //if we got thread already in the result set compare dates and if newer replace | ||
164 | //else insert | ||
165 | |||
166 | const auto messageId = getProperty(entity.entity(), ApplicationDomain::Mail::MessageId::name).toByteArray(); | ||
167 | |||
168 | Index msgIdIndex("msgId", mTransaction); | ||
169 | Index msgIdThreadIdIndex("msgIdThreadId", mTransaction); | ||
170 | auto thread = msgIdThreadIdIndex.lookup(messageId); | ||
171 | SinkTrace() << "MsgId: " << messageId << " Thread: " << thread << getProperty(entity.entity(), ApplicationDomain::Mail::Date::name).toDateTime(); | ||
172 | |||
173 | if (rootCollection->contains(thread)) { | ||
174 | auto date = rootCollection->value(thread); | ||
175 | //The mail we have in our result already is newer, so we can ignore this one | ||
176 | if (date > getProperty(entity.entity(), ApplicationDomain::Mail::Date::name).toDateTime()) { | ||
177 | return false; | ||
178 | } | ||
179 | qWarning() << "############################################################################"; | ||
180 | qWarning() << "Found a newer mail, remove the old one"; | ||
181 | qWarning() << "############################################################################"; | ||
182 | } | ||
183 | rootCollection->insert(thread, getProperty(entity.entity(), ApplicationDomain::Mail::Date::name).toDateTime()); | ||
184 | return true; | ||
185 | }; | ||
186 | return createFilteredSet(resultSet, filter); | ||
187 | } else { | ||
188 | return resultSet; | ||
189 | } | ||
190 | } | ||
191 | }; | ||
192 | |||
193 | DataStoreQuery::Ptr TypeImplementation<Mail>::prepareQuery(const Sink::Query &query, Sink::Storage::Transaction &transaction) | ||
117 | { | 194 | { |
118 | auto mapper = initializeReadPropertyMapper(); | 195 | if (query.threadLeaderOnly) { |
119 | return DataStoreQuery(query, ApplicationDomain::getTypeName<Mail>(), transaction, getIndex(), [mapper](const Sink::Entity &entity, const QByteArray &property) { | 196 | auto mapper = initializeReadPropertyMapper(); |
197 | return ThreadedDataStoreQuery::Ptr::create(query, ApplicationDomain::getTypeName<Mail>(), transaction, getIndex(), [mapper](const Sink::Entity &entity, const QByteArray &property) { | ||
198 | |||
199 | const auto localBuffer = Sink::EntityBuffer::readBuffer<Buffer>(entity.local()); | ||
200 | return mapper->getProperty(property, localBuffer); | ||
201 | }); | ||
120 | 202 | ||
121 | const auto localBuffer = Sink::EntityBuffer::readBuffer<Buffer>(entity.local()); | 203 | } else { |
122 | return mapper->getProperty(property, localBuffer); | 204 | auto mapper = initializeReadPropertyMapper(); |
123 | }); | 205 | return DataStoreQuery::Ptr::create(query, ApplicationDomain::getTypeName<Mail>(), transaction, getIndex(), [mapper](const Sink::Entity &entity, const QByteArray &property) { |
206 | |||
207 | const auto localBuffer = Sink::EntityBuffer::readBuffer<Buffer>(entity.local()); | ||
208 | return mapper->getProperty(property, localBuffer); | ||
209 | }); | ||
210 | } | ||
124 | } | 211 | } |
125 | 212 | ||