Merge lp:~phablet-team/history-service/optimize_dbus_traffic into lp:history-service/staging

Proposed by Gustavo Pichorim Boiko
Status: Merged
Approved by: Tiago Salem Herrmann
Approved revision: 275
Merged at revision: 261
Proposed branch: lp:~phablet-team/history-service/optimize_dbus_traffic
Merge into: lp:history-service/staging
Prerequisite: lp:~phablet-team/history-service/sort_by_multiple_fields
Diff against target: 884 lines (+279/-210)
19 files modified
Ubuntu/History/historyeventmodel.cpp (+19/-33)
Ubuntu/History/historyeventmodel.h (+2/-5)
Ubuntu/History/historymodel.cpp (+79/-5)
Ubuntu/History/historymodel.h (+10/-0)
Ubuntu/History/historythreadmodel.cpp (+0/-19)
Ubuntu/History/historythreadmodel.h (+0/-1)
daemon/historydaemon.cpp (+41/-76)
daemon/historydaemon.h (+2/-1)
daemon/historyservicedbus.cpp (+83/-7)
daemon/historyservicedbus.h (+15/-0)
daemon/textchannelobserver.cpp (+0/-14)
daemon/textchannelobserver.h (+0/-2)
plugins/sqlite/schema/v18.sql (+14/-0)
plugins/sqlite/sqlitehistoryplugin.cpp (+2/-2)
src/eventview.cpp (+5/-1)
src/eventview.h (+3/-1)
src/managerdbus.cpp (+3/-10)
tests/Ubuntu.History/HistoryEventModelTest.cpp (+1/-1)
tests/libhistoryservice/ManagerTest.cpp (+0/-32)
To merge this branch: bzr merge lp:~phablet-team/history-service/optimize_dbus_traffic
Reviewer Review Type Date Requested Status
Tiago Salem Herrmann (community) Approve
Review via email: mp+317649@code.launchpad.net

Commit message

Reduce the dbus traffic when marking messages and threads as read.

Description of the change

Reduce the dbus traffic when marking messages and threads as read.

To post a comment you must log in.
266. By Gustavo Pichorim Boiko

Only update the new events

267. By Tiago Salem Herrmann

merge parent branch

268. By Tiago Salem Herrmann

fix build

269. By Gustavo Pichorim Boiko

Stop using the telepathy pending message status to mark messages as read as
that causes performance problems when dealing with a large number of messages.

270. By Gustavo Pichorim Boiko

Optimize thread removal by deleting the events using a sqlite trigger instead
of manually removing and notifying them.
Also make the thread and event removal asynchronous calls on dbus level as the
result will be notified back to us as signals.

271. By Gustavo Pichorim Boiko

Update tests

272. By Gustavo Pichorim Boiko

When threads are removed, make sure the events models get refreshed accordingly.

273. By Tiago Salem Herrmann

merge parent branch

274. By Tiago Salem Herrmann

revert wrong commit

Revision history for this message
Tiago Salem Herrmann (tiagosh) wrote :

Code looks good, but would be good to remove the qDebug()'s as they are getting triggered on every eventsAdded, modified and so on.

review: Needs Fixing
275. By Gustavo Pichorim Boiko

Remove debugs

Revision history for this message
Tiago Salem Herrmann (tiagosh) wrote :

looks good. thanks

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Ubuntu/History/historyeventmodel.cpp'
2--- Ubuntu/History/historyeventmodel.cpp 2017-03-22 20:18:11 +0000
3+++ Ubuntu/History/historyeventmodel.cpp 2017-03-22 20:18:11 +0000
4@@ -1,5 +1,5 @@
5 /*
6- * Copyright (C) 2013-2015 Canonical, Ltd.
7+ * Copyright (C) 2013-2017 Canonical, Ltd.
8 *
9 * Authors:
10 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
11@@ -29,7 +29,7 @@
12 #include <QTimerEvent>
13
14 HistoryEventModel::HistoryEventModel(QObject *parent) :
15- HistoryModel(parent), mCanFetchMore(true), mEventWritingTimer(0)
16+ HistoryModel(parent), mCanFetchMore(true)
17 {
18 // configure the roles
19 mRoles = HistoryModel::roleNames();
20@@ -318,23 +318,6 @@
21 return History::Manager::instance()->writeEvents(History::Events() << textEvent);
22 }
23
24-bool HistoryEventModel::markEventAsRead(const QString &accountId, const QString &threadId, const QString &eventId, int eventType)
25-{
26- History::Event event = History::Manager::instance()->getSingleEvent((History::EventType)eventType, accountId, threadId, eventId);
27- event.setNewEvent(false);
28- if (event.type() == History::EventTypeText) {
29- History::TextEvent textEvent = event;
30- textEvent.setReadTimestamp(QDateTime::currentDateTime());
31- event = textEvent;
32- }
33- mEventWritingQueue << event;
34- if (mEventWritingTimer != 0) {
35- killTimer(mEventWritingTimer);
36- }
37- mEventWritingTimer = startTimer(500);
38- return true;
39-}
40-
41 void HistoryEventModel::updateQuery()
42 {
43 // remove all events from the model
44@@ -374,6 +357,9 @@
45 SIGNAL(eventsRemoved(History::Events)),
46 SLOT(onEventsRemoved(History::Events)));
47 connect(mView.data(),
48+ SIGNAL(threadsRemoved(History::Threads)),
49+ SLOT(onThreadsRemoved(History::Threads)));
50+ connect(mView.data(),
51 SIGNAL(invalidated()),
52 SLOT(triggerQueryUpdate()));
53
54@@ -450,21 +436,21 @@
55 // should be handle internally in History::EventView?
56 }
57
58-void HistoryEventModel::timerEvent(QTimerEvent *event)
59+void HistoryEventModel::onThreadsRemoved(const History::Threads &threads)
60 {
61- HistoryModel::timerEvent(event);
62- if (event->timerId() == mEventWritingTimer) {
63- killTimer(mEventWritingTimer);
64- mEventWritingTimer = 0;
65-
66- if (mEventWritingQueue.isEmpty()) {
67- return;
68- }
69-
70- qDebug() << "Goint to update" << mEventWritingQueue.count() << "events.";
71- if (History::Manager::instance()->writeEvents(mEventWritingQueue)) {
72- qDebug() << "... succeeded!";
73- mEventWritingQueue.clear();
74+ // When a thread is removed we don't get event removed signals,
75+ // so we compare and find if we have an event matching that thread.
76+ // in case we find it, we invalidate the whole view as there might be
77+ // out of date cached data on the daemon side
78+ int count = rowCount();
79+ Q_FOREACH(const History::Thread &thread, threads) {
80+ for (int i = 0; i < count; ++i) {
81+ QModelIndex idx = index(i);
82+ if (idx.data(AccountIdRole).toString() == thread.accountId() &&
83+ idx.data(ThreadIdRole).toString() == thread.threadId()) {
84+ triggerQueryUpdate();
85+ return;
86+ }
87 }
88 }
89 }
90
91=== modified file 'Ubuntu/History/historyeventmodel.h'
92--- Ubuntu/History/historyeventmodel.h 2016-09-16 12:32:37 +0000
93+++ Ubuntu/History/historyeventmodel.h 2017-03-22 20:18:11 +0000
94@@ -1,5 +1,5 @@
95 /*
96- * Copyright (C) 2013-2015 Canonical, Ltd.
97+ * Copyright (C) 2013-2017 Canonical, Ltd.
98 *
99 * Authors:
100 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
101@@ -66,7 +66,6 @@
102
103 Q_INVOKABLE bool removeEvents(const QVariantList &eventsProperties);
104 Q_INVOKABLE bool writeEvents(const QVariantList &eventsProperties);
105- Q_INVOKABLE bool markEventAsRead(const QString &accountId, const QString &threadId, const QString &eventId, int eventType);
106 Q_INVOKABLE bool removeEventAttachment(const QString &accountId, const QString &threadId, const QString &eventId, int eventType, const QString &attachmentId);
107
108 protected Q_SLOTS:
109@@ -74,9 +73,9 @@
110 virtual void onEventsAdded(const History::Events &events);
111 virtual void onEventsModified(const History::Events &events);
112 virtual void onEventsRemoved(const History::Events &events);
113+ virtual void onThreadsRemoved(const History::Threads &threads);
114
115 protected:
116- void timerEvent(QTimerEvent *event);
117 History::Events fetchNextPage();
118
119 private:
120@@ -85,8 +84,6 @@
121 bool mCanFetchMore;
122 QHash<int, QByteArray> mRoles;
123 mutable QMap<History::TextEvent, QList<QVariant> > mAttachmentCache;
124- History::Events mEventWritingQueue;
125- int mEventWritingTimer;
126 };
127
128 #endif // HISTORYEVENTMODEL_H
129
130=== modified file 'Ubuntu/History/historymodel.cpp'
131--- Ubuntu/History/historymodel.cpp 2017-03-22 20:18:11 +0000
132+++ Ubuntu/History/historymodel.cpp 2017-03-22 20:18:11 +0000
133@@ -28,13 +28,14 @@
134 #include "textevent.h"
135 #include "manager.h"
136 #include "utils_p.h"
137+#include "voiceevent.h"
138 #include <QTimerEvent>
139 #include <QCryptographicHash>
140 #include <QDebug>
141
142 HistoryModel::HistoryModel(QObject *parent) :
143 QAbstractListModel(parent), mFilter(0), mSort(new HistoryQmlSort(this)),
144- mType(EventTypeText), mMatchContacts(false), mUpdateTimer(0), mWaitingForQml(false)
145+ mType(EventTypeText), mMatchContacts(false), mUpdateTimer(0), mEventWritingTimer(0), mThreadWritingTimer(0), mWaitingForQml(false)
146 {
147 // configure the roles
148 mRoles[AccountIdRole] = "accountId";
149@@ -406,10 +407,33 @@
150
151 void HistoryModel::timerEvent(QTimerEvent *event)
152 {
153- if (event->timerId() == mUpdateTimer && !mWaitingForQml) {
154- killTimer(mUpdateTimer);
155- mUpdateTimer = 0;
156- updateQuery();
157+ if (event->timerId() == mUpdateTimer) {
158+ if (!mWaitingForQml) {
159+ killTimer(mUpdateTimer);
160+ mUpdateTimer = 0;
161+ updateQuery();
162+ }
163+ } else if (event->timerId() == mEventWritingTimer) {
164+ killTimer(mEventWritingTimer);
165+ mEventWritingTimer = 0;
166+
167+ if (mEventWritingQueue.isEmpty()) {
168+ return;
169+ }
170+
171+ if (History::Manager::instance()->writeEvents(mEventWritingQueue)) {
172+ mEventWritingQueue.clear();
173+ }
174+ } else if (event->timerId() == mThreadWritingTimer) {
175+ killTimer(mThreadWritingTimer);
176+ mThreadWritingTimer = 0;
177+
178+ if (mThreadWritingQueue.isEmpty()) {
179+ return;
180+ }
181+
182+ History::Manager::instance()->markThreadsAsRead(mThreadWritingQueue);
183+ mThreadWritingQueue.clear();
184 }
185 }
186
187@@ -478,6 +502,56 @@
188 return data;
189 }
190
191+bool HistoryModel::markEventAsRead(const QVariantMap &eventProperties)
192+{
193+ History::Event event;
194+ History::EventType type = (History::EventType) eventProperties[History::FieldType].toInt();
195+ switch (type) {
196+ case History::EventTypeText:
197+ event = History::TextEvent::fromProperties(eventProperties);
198+ break;
199+ case History::EventTypeVoice:
200+ event = History::VoiceEvent::fromProperties(eventProperties);
201+ break;
202+ }
203+
204+ event.setNewEvent(false);
205+ if (event.type() == History::EventTypeText) {
206+ History::TextEvent textEvent = event;
207+ textEvent.setReadTimestamp(QDateTime::currentDateTime());
208+ event = textEvent;
209+ }
210+ // for repeated events, keep the last called one only
211+ if (mEventWritingQueue.contains(event)) {
212+ mEventWritingQueue.removeOne(event);
213+ }
214+ mEventWritingQueue << event;
215+ if (mEventWritingTimer != 0) {
216+ killTimer(mEventWritingTimer);
217+ }
218+ mEventWritingTimer = startTimer(500);
219+ return true;
220+}
221+
222+void HistoryModel::markThreadsAsRead(const QVariantList &threadsProperties)
223+{
224+ Q_FOREACH(const QVariant &entry, threadsProperties) {
225+ QVariantMap threadProperties = entry.toMap();
226+ History::Thread thread = History::Thread::fromProperties(threadProperties);
227+ if (!thread.isNull()) {
228+ if (mThreadWritingQueue.contains(thread)) {
229+ continue;
230+ }
231+ mThreadWritingQueue << thread;
232+ }
233+ }
234+
235+ if (mThreadWritingTimer != 0) {
236+ killTimer(mThreadWritingTimer);
237+ }
238+ mThreadWritingTimer = startTimer(2000);
239+}
240+
241 void HistoryModel::classBegin()
242 {
243 mWaitingForQml = true;
244
245=== modified file 'Ubuntu/History/historymodel.h'
246--- Ubuntu/History/historymodel.h 2016-11-09 17:42:27 +0000
247+++ Ubuntu/History/historymodel.h 2017-03-22 20:18:11 +0000
248@@ -23,6 +23,8 @@
249 #define HISTORYMODEL_H
250
251 #include "types.h"
252+#include "event.h"
253+#include "thread.h"
254 #include "historyqmlfilter.h"
255 #include "historyqmlsort.h"
256 #include <QAbstractListModel>
257@@ -175,6 +177,10 @@
258
259 Q_INVOKABLE virtual QVariant get(int row) const;
260
261+ // Marking events and threads as read
262+ Q_INVOKABLE bool markEventAsRead(const QVariantMap &eventProperties);
263+ Q_INVOKABLE void markThreadsAsRead(const QVariantList &threadsProperties);
264+
265 // QML parser status things
266 void classBegin();
267 void componentComplete();
268@@ -206,6 +212,10 @@
269
270 private:
271 QHash<int, QByteArray> mRoles;
272+ History::Events mEventWritingQueue;
273+ int mEventWritingTimer;
274+ History::Threads mThreadWritingQueue;
275+ int mThreadWritingTimer;
276 int mUpdateTimer;
277 bool mWaitingForQml;
278 };
279
280=== modified file 'Ubuntu/History/historythreadmodel.cpp'
281--- Ubuntu/History/historythreadmodel.cpp 2017-03-22 20:18:11 +0000
282+++ Ubuntu/History/historythreadmodel.cpp 2017-03-22 20:18:11 +0000
283@@ -232,25 +232,6 @@
284 return mRoles;
285 }
286
287-void HistoryThreadModel::markThreadsAsRead(const QVariantList &threadsProperties)
288-{
289- History::Threads threads;
290- Q_FOREACH(const QVariant &entry, threadsProperties) {
291- QVariantMap threadProperties = entry.toMap();
292- History::Thread thread = History::Thread::fromProperties(threadProperties);
293-
294- if (!thread.isNull()) {
295- threads << thread;
296- }
297- }
298-
299- if (threads.isEmpty()) {
300- return;
301- }
302-
303- History::Manager::instance()->markThreadsAsRead(threads);
304-}
305-
306 bool HistoryThreadModel::removeThreads(const QVariantList &threadsProperties)
307 {
308 History::Threads threads;
309
310=== modified file 'Ubuntu/History/historythreadmodel.h'
311--- Ubuntu/History/historythreadmodel.h 2017-03-22 20:18:11 +0000
312+++ Ubuntu/History/historythreadmodel.h 2017-03-22 20:18:11 +0000
313@@ -70,7 +70,6 @@
314 virtual QHash<int, QByteArray> roleNames() const;
315
316 Q_INVOKABLE bool removeThreads(const QVariantList &threadsProperties);
317- Q_INVOKABLE void markThreadsAsRead(const QVariantList &threadsProperties);
318
319 protected Q_SLOTS:
320 virtual void updateQuery();
321
322=== modified file 'daemon/historydaemon.cpp'
323--- daemon/historydaemon.cpp 2017-03-22 20:18:11 +0000
324+++ daemon/historydaemon.cpp 2017-03-22 20:18:11 +0000
325@@ -140,9 +140,6 @@
326 SIGNAL(messageSent(Tp::TextChannelPtr,Tp::Message,QString)),
327 SLOT(onMessageSent(Tp::TextChannelPtr,Tp::Message,QString)));
328 connect(&mTextObserver,
329- SIGNAL(messageRead(Tp::TextChannelPtr,Tp::ReceivedMessage)),
330- SLOT(onMessageRead(Tp::TextChannelPtr,Tp::ReceivedMessage)));
331- connect(&mTextObserver,
332 SIGNAL(channelAvailable(Tp::TextChannelPtr)),
333 SLOT(onTextChannelAvailable(Tp::TextChannelPtr)));
334 connect(&mTextObserver,
335@@ -590,38 +587,17 @@
336 return false;
337 }
338
339- // In order to remove a thread all we have to do is to remove all its items
340- // then it is going to be removed by removeEvents() once it detects the thread is
341- // empty.
342- QList<QVariantMap> events;
343- QMap<QString, QVariantMap> removedEmptyThreads;
344+ // If the thread has events
345+ mBackend->beginBatchOperation();
346 Q_FOREACH(const QVariantMap &thread, threads) {
347- QList<QVariantMap> thisEvents = mBackend->eventsForThread(thread);
348- if (thisEvents.isEmpty()) {
349- mBackend->beginBatchOperation();
350- if (!mBackend->removeThread(thread)) {
351- mBackend->rollbackBatchOperation();
352- return false;
353- }
354- mBackend->endBatchOperation();
355- QString hash = hashThread(thread);
356- removedEmptyThreads[hash] = thread;
357- continue;
358- }
359- events += thisEvents;
360- }
361-
362- if (!removedEmptyThreads.isEmpty()) {
363- mDBus.notifyThreadsRemoved(removedEmptyThreads.values());
364- }
365-
366- if (events.size() > 0) {
367- if(removeEvents(events)) {
368- return true;
369- }
370- }
371-
372- return false;
373+ if (!mBackend->removeThread(thread)) {
374+ mBackend->rollbackBatchOperation();
375+ return false;
376+ }
377+ }
378+ mBackend->endBatchOperation();
379+ mDBus.notifyThreadsRemoved(threads);
380+ return true;
381 }
382
383 void HistoryDaemon::onObserverCreated()
384@@ -1039,32 +1015,7 @@
385 return;
386 }
387
388- History::MessageStatus status;
389- switch (message.deliveryDetails().status()) {
390- case Tp::DeliveryStatusAccepted:
391- status = History::MessageStatusAccepted;
392- break;
393- case Tp::DeliveryStatusDeleted:
394- status = History::MessageStatusDeleted;
395- break;
396- case Tp::DeliveryStatusDelivered:
397- status = History::MessageStatusDelivered;
398- break;
399- case Tp::DeliveryStatusPermanentlyFailed:
400- status = History::MessageStatusPermanentlyFailed;
401- break;
402- case Tp::DeliveryStatusRead:
403- status = History::MessageStatusRead;
404- break;
405- case Tp::DeliveryStatusTemporarilyFailed:
406- status = History::MessageStatusTemporarilyFailed;
407- break;
408- case Tp::DeliveryStatusUnknown:
409- status = History::MessageStatusUnknown;
410- break;
411- }
412-
413- textEvent[History::FieldMessageStatus] = (int) status;
414+ textEvent[History::FieldMessageStatus] = (int) fromTelepathyDeliveryStatus(message.deliveryDetails().status());
415 if (!writeEvents(QList<QVariantMap>() << textEvent, properties)) {
416 qWarning() << "Failed to save the new message status!";
417 }
418@@ -1176,22 +1127,6 @@
419
420 }
421
422-void HistoryDaemon::onMessageRead(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message)
423-{
424- QVariantMap textEvent = getSingleEventFromTextChannel(textChannel, message.messageToken());
425- QVariantMap properties = propertiesFromChannel(textChannel);
426-
427- if (textEvent.isEmpty()) {
428- qWarning() << "Cound not find the original event to update with newEvent = false.";
429- return;
430- }
431-
432- textEvent[History::FieldNewEvent] = false;
433- if (!writeEvents(QList<QVariantMap>() << textEvent, properties)) {
434- qWarning() << "Failed to save the new message status!";
435- }
436-}
437-
438 void HistoryDaemon::onMessageSent(const Tp::TextChannelPtr textChannel, const Tp::Message &message, const QString &messageToken)
439 {
440 QVariantMap properties = propertiesFromChannel(textChannel);
441@@ -1383,3 +1318,33 @@
442 }
443 }
444 }
445+
446+History::MessageStatus HistoryDaemon::fromTelepathyDeliveryStatus(Tp::DeliveryStatus deliveryStatus)
447+{
448+ History::MessageStatus status;
449+ switch (deliveryStatus) {
450+ case Tp::DeliveryStatusAccepted:
451+ status = History::MessageStatusAccepted;
452+ break;
453+ case Tp::DeliveryStatusDeleted:
454+ status = History::MessageStatusDeleted;
455+ break;
456+ case Tp::DeliveryStatusDelivered:
457+ status = History::MessageStatusDelivered;
458+ break;
459+ case Tp::DeliveryStatusPermanentlyFailed:
460+ status = History::MessageStatusPermanentlyFailed;
461+ break;
462+ case Tp::DeliveryStatusRead:
463+ status = History::MessageStatusRead;
464+ break;
465+ case Tp::DeliveryStatusTemporarilyFailed:
466+ status = History::MessageStatusTemporarilyFailed;
467+ break;
468+ case Tp::DeliveryStatusUnknown:
469+ status = History::MessageStatusUnknown;
470+ break;
471+ }
472+
473+ return status;
474+}
475
476=== modified file 'daemon/historydaemon.h'
477--- daemon/historydaemon.h 2017-03-22 20:18:11 +0000
478+++ daemon/historydaemon.h 2017-03-22 20:18:11 +0000
479@@ -68,7 +68,6 @@
480 void onObserverCreated();
481 void onCallEnded(const Tp::CallChannelPtr &channel, bool missed);
482 void onMessageReceived(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message);
483- void onMessageRead(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message);
484 void onMessageSent(const Tp::TextChannelPtr textChannel, const Tp::Message &message, const QString &messageToken);
485 void onTextChannelAvailable(const Tp::TextChannelPtr channel);
486 void onTextChannelInvalidated(const Tp::TextChannelPtr channel);
487@@ -92,6 +91,8 @@
488 void writeRoomChangesInformationEvents(const QVariantMap &thread, const QVariantMap &interfaceProperties);
489 void writeRolesInformationEvents(const QVariantMap &thread, const Tp::ChannelPtr &channel, const RolesMap &rolesMap);
490 void writeRolesChangesInformationEvents(const QVariantMap &thread, const Tp::ChannelPtr &channel, const RolesMap &rolesMap);
491+
492+ static History::MessageStatus fromTelepathyDeliveryStatus(Tp::DeliveryStatus deliveryStatus);
493 private:
494 HistoryDaemon(QObject *parent = 0);
495
496
497=== modified file 'daemon/historyservicedbus.cpp'
498--- daemon/historyservicedbus.cpp 2017-03-22 20:18:11 +0000
499+++ daemon/historyservicedbus.cpp 2017-03-22 20:18:11 +0000
500@@ -27,7 +27,7 @@
501 Q_DECLARE_METATYPE(QList< QVariantMap >)
502
503 HistoryServiceDBus::HistoryServiceDBus(QObject *parent) :
504- QObject(parent), mAdaptor(0)
505+ QObject(parent), mAdaptor(0), mSignalsTimer(-1)
506 {
507 qDBusRegisterMetaType<QList<QVariantMap> >();
508 }
509@@ -47,32 +47,38 @@
510
511 void HistoryServiceDBus::notifyThreadsAdded(const QList<QVariantMap> &threads)
512 {
513- Q_EMIT ThreadsAdded(threads);
514+ mThreadsAdded << threads;
515+ triggerSignals();
516 }
517
518 void HistoryServiceDBus::notifyThreadsModified(const QList<QVariantMap> &threads)
519 {
520- Q_EMIT ThreadsModified(threads);
521+ mThreadsModified << threads;
522+ triggerSignals();
523 }
524
525 void HistoryServiceDBus::notifyThreadsRemoved(const QList<QVariantMap> &threads)
526 {
527- Q_EMIT ThreadsRemoved(threads);
528+ mThreadsRemoved << threads;
529+ triggerSignals();
530 }
531
532 void HistoryServiceDBus::notifyEventsAdded(const QList<QVariantMap> &events)
533 {
534- Q_EMIT EventsAdded(events);
535+ mEventsAdded << events;
536+ triggerSignals();
537 }
538
539 void HistoryServiceDBus::notifyEventsModified(const QList<QVariantMap> &events)
540 {
541- Q_EMIT EventsModified(events);
542+ mEventsModified << events;
543+ triggerSignals();
544 }
545
546 void HistoryServiceDBus::notifyEventsRemoved(const QList<QVariantMap> &events)
547 {
548- Q_EMIT EventsRemoved(events);
549+ mEventsRemoved << events;
550+ triggerSignals();
551 }
552
553 void HistoryServiceDBus::notifyThreadParticipantsChanged(const QVariantMap &thread,
554@@ -152,3 +158,73 @@
555 return HistoryDaemon::instance()->getSingleEvent(type, accountId, threadId, eventId);
556 }
557
558+void HistoryServiceDBus::timerEvent(QTimerEvent *event)
559+{
560+ if (event->timerId() == mSignalsTimer) {
561+ killTimer(mSignalsTimer);
562+ mSignalsTimer = -1;
563+ processSignals();
564+ }
565+}
566+
567+void HistoryServiceDBus::filterDuplicatesAndAdd(QList<QVariantMap> &targetList, const QList<QVariantMap> newItems, const QStringList &propertiesToCompare)
568+{
569+ Q_FOREACH (const QVariantMap &item, newItems) {
570+ Q_FOREACH(const QVariantMap &existing, targetList) {
571+ bool found = true;
572+ Q_FOREACH(const QString &prop, propertiesToCompare) {
573+ if (item[prop] != existing[prop]) {
574+ found = false;
575+ break;
576+ }
577+ }
578+
579+ if (!found) {
580+ targetList << item;
581+ }
582+ }
583+ }
584+}
585+
586+void HistoryServiceDBus::triggerSignals()
587+{
588+ if (mSignalsTimer >= 0) {
589+ killTimer(mSignalsTimer);
590+ }
591+
592+ mSignalsTimer = startTimer(100);
593+}
594+
595+void HistoryServiceDBus::processSignals()
596+{
597+ if (!mThreadsAdded.isEmpty()) {
598+ Q_EMIT ThreadsAdded(mThreadsAdded);
599+ mThreadsAdded.clear();
600+ }
601+
602+ if (!mThreadsModified.isEmpty()) {
603+ Q_EMIT ThreadsModified(mThreadsModified);
604+ mThreadsModified.clear();
605+ }
606+
607+ if (!mThreadsRemoved.isEmpty()) {
608+ Q_EMIT ThreadsRemoved(mThreadsRemoved);
609+ mThreadsRemoved.clear();
610+ }
611+
612+ if (!mEventsAdded.isEmpty()) {
613+ Q_EMIT EventsAdded(mEventsAdded);
614+ mEventsAdded.clear();
615+ }
616+
617+ if (!mEventsModified.isEmpty()) {
618+ Q_EMIT EventsModified(mEventsModified);
619+ mEventsModified.clear();
620+ }
621+
622+ if (!mEventsRemoved.isEmpty()) {
623+ Q_EMIT EventsRemoved(mEventsRemoved);
624+ mEventsRemoved.clear();
625+ }
626+}
627+
628
629=== modified file 'daemon/historyservicedbus.h'
630--- daemon/historyservicedbus.h 2017-03-22 20:18:11 +0000
631+++ daemon/historyservicedbus.h 2017-03-22 20:18:11 +0000
632@@ -84,8 +84,23 @@
633 void EventsModified(const QList<QVariantMap> &events);
634 void EventsRemoved(const QList<QVariantMap> &events);
635
636+protected:
637+ void timerEvent(QTimerEvent *event) override;
638+
639+protected Q_SLOTS:
640+ void filterDuplicatesAndAdd(QList<QVariantMap> &targetList, const QList<QVariantMap> newItems, const QStringList &propertiesToCompare);
641+ void triggerSignals();
642+ void processSignals();
643+
644 private:
645 HistoryServiceAdaptor *mAdaptor;
646+ QList<QVariantMap> mThreadsAdded;
647+ QList<QVariantMap> mThreadsModified;
648+ QList<QVariantMap> mThreadsRemoved;
649+ QList<QVariantMap> mEventsAdded;
650+ QList<QVariantMap> mEventsModified;
651+ QList<QVariantMap> mEventsRemoved;
652+ int mSignalsTimer;
653 };
654
655 #endif // HISTORYSERVICEDBUS_H
656
657=== modified file 'daemon/textchannelobserver.cpp'
658--- daemon/textchannelobserver.cpp 2017-03-22 20:18:11 +0000
659+++ daemon/textchannelobserver.cpp 2017-03-22 20:18:11 +0000
660@@ -39,10 +39,6 @@
661 connect(textChannel.data(),
662 SIGNAL(messageSent(Tp::Message,Tp::MessageSendingFlags,QString)),
663 SLOT(onMessageSent(Tp::Message,Tp::MessageSendingFlags,QString)));
664- connect(textChannel.data(),
665- SIGNAL(pendingMessageRemoved(const Tp::ReceivedMessage&)),
666- SLOT(onPendingMessageRemoved(const Tp::ReceivedMessage&)));
667-
668 Q_EMIT channelAvailable(textChannel);
669
670 // process the messages that are already pending in the channel
671@@ -83,13 +79,3 @@
672
673 Q_EMIT messageSent(textChannel, message, sentMessageToken);
674 }
675-
676-void TextChannelObserver::onPendingMessageRemoved(const Tp::ReceivedMessage &message)
677-{
678- Tp::TextChannelPtr textChannel(qobject_cast<Tp::TextChannel*>(sender()));
679- if (textChannel.isNull()) {
680- return;
681- }
682-
683- Q_EMIT messageRead(textChannel, message);
684-}
685
686=== modified file 'daemon/textchannelobserver.h'
687--- daemon/textchannelobserver.h 2017-03-22 20:18:11 +0000
688+++ daemon/textchannelobserver.h 2017-03-22 20:18:11 +0000
689@@ -39,7 +39,6 @@
690 void channelAvailable(const Tp::TextChannelPtr textChannel);
691 void textChannelInvalidated(const Tp::TextChannelPtr textChannel);
692 void messageReceived(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message);
693- void messageRead(const Tp::TextChannelPtr textChannel, const Tp::ReceivedMessage &message);
694 void messageSent(const Tp::TextChannelPtr textChannel, const Tp::Message &message, const QString &messageToken);
695
696 protected:
697@@ -50,7 +49,6 @@
698 void onTextChannelInvalidated();
699 void onMessageReceived(const Tp::ReceivedMessage &message);
700 void onMessageSent(const Tp::Message &message, Tp::MessageSendingFlags flags, const QString &sentMessageToken);
701- void onPendingMessageRemoved(const Tp::ReceivedMessage &message);
702
703 private:
704 QList<Tp::TextChannelPtr> mChannels;
705
706=== added file 'plugins/sqlite/schema/v18.sql'
707--- plugins/sqlite/schema/v18.sql 1970-01-01 00:00:00 +0000
708+++ plugins/sqlite/schema/v18.sql 2017-03-22 20:18:11 +0000
709@@ -0,0 +1,14 @@
710+CREATE TRIGGER text_threads_delete_trigger AFTER DELETE ON threads
711+FOR EACH ROW WHEN old.type=0
712+BEGIN
713+ DELETE FROM text_events WHERE
714+ accountId=old.accountId AND
715+ threadId=old.threadId;
716+END;
717+CREATE TRIGGER voice_threads_delete_trigger AFTER DELETE ON threads
718+FOR EACH ROW WHEN old.type=1
719+BEGIN
720+ DELETE FROM voice_events WHERE
721+ accountId=old.accountId AND
722+ threadId=old.threadId;
723+END;
724
725=== modified file 'plugins/sqlite/sqlitehistoryplugin.cpp'
726--- plugins/sqlite/sqlitehistoryplugin.cpp 2017-03-22 20:18:11 +0000
727+++ plugins/sqlite/sqlitehistoryplugin.cpp 2017-03-22 20:18:11 +0000
728@@ -315,7 +315,7 @@
729 return QVariantMap();
730 }
731
732- query.prepare("UPDATE text_events SET newEvent=:newEvent WHERE accountId=:accountId AND threadId=:threadId");
733+ query.prepare("UPDATE text_events SET newEvent=:newEvent WHERE accountId=:accountId AND threadId=:threadId AND newEvent=1");
734 query.bindValue(":accountId", thread[History::FieldAccountId].toString());
735 query.bindValue(":threadId", thread[History::FieldThreadId].toString());
736 query.bindValue(":newEvent", false);
737@@ -1337,7 +1337,7 @@
738 chatRoomInfo["SelfRoles"] = query1.value(20).toInt();
739
740 thread[History::FieldChatRoomInfo] = chatRoomInfo;
741- if (!History::Utils::shouldIncludeParticipants(thread)) {
742+ if (!History::Utils::shouldIncludeParticipants(History::Thread::fromProperties(thread))) {
743 thread.remove(History::FieldParticipants);
744 }
745 }
746
747=== modified file 'src/eventview.cpp'
748--- src/eventview.cpp 2015-10-01 19:44:45 +0000
749+++ src/eventview.cpp 2017-03-22 20:18:11 +0000
750@@ -1,5 +1,5 @@
751 /*
752- * Copyright (C) 2013 Canonical, Ltd.
753+ * Copyright (C) 2013-2017 Canonical, Ltd.
754 *
755 * Authors:
756 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
757@@ -128,6 +128,10 @@
758 connect(Manager::instance(),
759 SIGNAL(eventsRemoved(History::Events)),
760 SLOT(_d_eventsRemoved(History::Events)));
761+ // we don't filter thread signals
762+ connect(Manager::instance(),
763+ SIGNAL(threadsRemoved(History::Threads)),
764+ SIGNAL(threadsRemoved(History::Threads)));
765 }
766
767 EventView::~EventView()
768
769=== modified file 'src/eventview.h'
770--- src/eventview.h 2013-09-17 23:05:35 +0000
771+++ src/eventview.h 2017-03-22 20:18:11 +0000
772@@ -1,5 +1,5 @@
773 /*
774- * Copyright (C) 2013 Canonical, Ltd.
775+ * Copyright (C) 2013-2017 Canonical, Ltd.
776 *
777 * Authors:
778 * Gustavo Pichorim Boiko <gustavo.boiko@canonical.com>
779@@ -24,6 +24,7 @@
780
781 #include "types.h"
782 #include "event.h"
783+#include "thread.h"
784 #include "filter.h"
785 #include "sort.h"
786 #include <QObject>
787@@ -50,6 +51,7 @@
788 void eventsAdded(const History::Events &events);
789 void eventsModified(const History::Events &events);
790 void eventsRemoved(const History::Events &events);
791+ void threadsRemoved(const History::Threads &threads);
792 void invalidated();
793
794 private:
795
796=== modified file 'src/managerdbus.cpp'
797--- src/managerdbus.cpp 2017-03-22 20:18:11 +0000
798+++ src/managerdbus.cpp 2017-03-22 20:18:11 +0000
799@@ -124,11 +124,8 @@
800 return false;
801 }
802
803- QDBusReply<bool> reply = mInterface.call("RemoveThreads", QVariant::fromValue(threadMap));
804- if (!reply.isValid()) {
805- return false;
806- }
807- return reply.value();
808+ mInterface.asyncCall("RemoveThreads", QVariant::fromValue(threadMap));
809+ return true;
810 }
811
812 bool ManagerDBus::removeEvents(const Events &events)
813@@ -138,11 +135,7 @@
814 return false;
815 }
816
817- QDBusReply<bool> reply = mInterface.call("RemoveEvents", QVariant::fromValue(eventMap));
818- if (!reply.isValid()) {
819- return false;
820- }
821- return reply.value();
822+ mInterface.asyncCall("RemoveEvents", QVariant::fromValue(eventMap));
823 }
824
825 Thread ManagerDBus::getSingleThread(EventType type, const QString &accountId, const QString &threadId, const QVariantMap &properties)
826
827=== modified file 'tests/Ubuntu.History/HistoryEventModelTest.cpp'
828--- tests/Ubuntu.History/HistoryEventModelTest.cpp 2016-09-09 20:00:09 +0000
829+++ tests/Ubuntu.History/HistoryEventModelTest.cpp 2017-03-22 20:18:11 +0000
830@@ -1,5 +1,5 @@
831 /*
832- * Copyright (C) 2016 Canonical, Ltd.
833+ * Copyright (C) 2016-2017 Canonical, Ltd.
834 *
835 * This file is part of history-service.
836 *
837
838=== modified file 'tests/libhistoryservice/ManagerTest.cpp'
839--- tests/libhistoryservice/ManagerTest.cpp 2015-09-23 21:52:48 +0000
840+++ tests/libhistoryservice/ManagerTest.cpp 2017-03-22 20:18:11 +0000
841@@ -348,43 +348,11 @@
842 History::Threads threads;
843 threads << textThread << voiceThread;
844
845- // insert some text and voice events
846- History::Events events;
847- for (int i = 0; i < 50; ++i) {
848- History::TextEvent textEvent(textThread.accountId(),
849- textThread.threadId(),
850- QString("eventToBeRemoved%1").arg(i),
851- textThread.participants().first().identifier(),
852- QDateTime::currentDateTime(),
853- true,
854- QString("Hello world %1").arg(i),
855- History::MessageTypeText);
856- events.append(textEvent);
857-
858- History::VoiceEvent voiceEvent(voiceThread.accountId(),
859- voiceThread.threadId(),
860- QString("eventToBeRemoved%1").arg(i),
861- voiceThread.participants().first().identifier(),
862- QDateTime::currentDateTime(),
863- true,
864- true);
865- events.append(voiceEvent);
866- }
867-
868- QVERIFY(mManager->writeEvents(events));
869-
870- QSignalSpy eventsRemovedSpy(mManager, SIGNAL(eventsRemoved(History::Events)));
871 QSignalSpy threadsRemovedSpy(mManager, SIGNAL(threadsRemoved(History::Threads)));
872
873 QVERIFY(mManager->removeThreads(threads));
874- QTRY_COMPARE(eventsRemovedSpy.count(), 1);
875 QTRY_COMPARE(threadsRemovedSpy.count(), 1);
876
877- History::Events removedEvents = eventsRemovedSpy.first().first().value<History::Events>();
878- qSort(removedEvents);
879- qSort(events);
880- QCOMPARE(removedEvents, events);
881-
882 History::Threads removedThreads = threadsRemovedSpy.first().first().value<History::Threads>();
883 qSort(removedThreads);
884 qSort(threads);

Subscribers

People subscribed via source and target branches

to all changes: