From 9a1453bbd56fb7912c73845fc8580ce79e694286 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Sun, 9 Dec 2018 19:55:14 +0900 Subject: Room: track more changes; fix cache smashing upon restart Commit fd52459 introduced a regression rendering the cache unusable after a client restart (an empty state overwrites whatever state was in the cache). This commit contains the fix, along with more room change tracking. # Conflicts: # lib/room.h --- lib/room.cpp | 59 +++++++++++++++++++++++++++++++++++------------------------ lib/room.h | 7 ++++--- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/lib/room.cpp b/lib/room.cpp index 8b81bfb2..cdc7572a 100644 --- a/lib/room.cpp +++ b/lib/room.cpp @@ -212,12 +212,12 @@ class Room::Private */ void dropDuplicateEvents(RoomEvents& events) const; - void setLastReadEvent(User* u, QString eventId); + Changes setLastReadEvent(User* u, QString eventId); void updateUnreadCount(rev_iter_t from, rev_iter_t to); - void promoteReadMarker(User* u, rev_iter_t newMarker, - bool force = false); + Changes promoteReadMarker(User* u, rev_iter_t newMarker, + bool force = false); - void markMessagesAsRead(rev_iter_t upToMarker); + Changes markMessagesAsRead(rev_iter_t upToMarker); QString sendEvent(RoomEventPtr&& event); @@ -386,11 +386,11 @@ void Room::setJoinState(JoinState state) emit joinStateChanged(oldState, state); } -void Room::Private::setLastReadEvent(User* u, QString eventId) +Room::Changes Room::Private::setLastReadEvent(User* u, QString eventId) { auto& storedId = lastReadEventIds[u]; if (storedId == eventId) - return; + return Change::NoChange; eventIdReadUsers.remove(storedId, u); eventIdReadUsers.insert(eventId, u); swap(storedId, eventId); @@ -401,8 +401,9 @@ void Room::Private::setLastReadEvent(User* u, QString eventId) if (storedId != serverReadMarker) connection->callApi(id, storedId); emit q->readMarkerMoved(eventId, storedId); - connection->saveRoomState(q); + return Change::ReadMarkerChange; } + return Change::NoChange; } void Room::Private::updateUnreadCount(rev_iter_t from, rev_iter_t to) @@ -445,14 +446,15 @@ void Room::Private::updateUnreadCount(rev_iter_t from, rev_iter_t to) } } -void Room::Private::promoteReadMarker(User* u, rev_iter_t newMarker, bool force) +Room::Changes Room::Private::promoteReadMarker(User* u, rev_iter_t newMarker, + bool force) { Q_ASSERT_X(u, __FUNCTION__, "User* should not be nullptr"); Q_ASSERT(newMarker >= timeline.crbegin() && newMarker <= timeline.crend()); const auto prevMarker = q->readMarker(u); if (!force && prevMarker <= newMarker) // Remember, we deal with reverse iterators - return; + return Change::NoChange; Q_ASSERT(newMarker < timeline.crend()); @@ -461,7 +463,7 @@ void Room::Private::promoteReadMarker(User* u, rev_iter_t newMarker, bool force) auto eagerMarker = find_if(newMarker.base(), timeline.cend(), [=](const TimelineItem& ti) { return ti->senderId() != u->id(); }); - setLastReadEvent(u, (*(eagerMarker - 1))->id()); + auto changes = setLastReadEvent(u, (*(eagerMarker - 1))->id()); if (isLocalUser(u)) { const auto oldUnreadCount = unreadMessages; @@ -485,14 +487,16 @@ void Room::Private::promoteReadMarker(User* u, rev_iter_t newMarker, bool force) qCDebug(MAIN) << "Room" << displayname << "still has" << unreadMessages << "unread message(s)"; emit q->unreadMessagesChanged(q); + changes |= Change::UnreadNotifsChange; } } + return changes; } -void Room::Private::markMessagesAsRead(rev_iter_t upToMarker) +Room::Changes Room::Private::markMessagesAsRead(rev_iter_t upToMarker) { const auto prevMarker = q->readMarker(); - promoteReadMarker(q->localUser(), upToMarker); + auto changes = promoteReadMarker(q->localUser(), upToMarker); if (prevMarker != upToMarker) qCDebug(MAIN) << "Marked messages as read until" << *q->readMarker(); @@ -508,6 +512,7 @@ void Room::Private::markMessagesAsRead(rev_iter_t upToMarker) break; } } + return changes; } void Room::markMessagesAsRead(QString uptoEventId) @@ -1151,7 +1156,7 @@ void Room::updateData(SyncRoomData&& data, bool fromCache) d->updateDisplayname(); for( auto&& ephemeralEvent: data.ephemeral ) - processEphemeralEvent(move(ephemeralEvent)); + roomChanges |= processEphemeralEvent(move(ephemeralEvent)); // See https://github.com/QMatrixClient/libqmatrixclient/wiki/unread_count if (data.unreadCount != -2 && data.unreadCount != d->unreadMessages) @@ -1716,9 +1721,9 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events) // clients historically expect. This may eventually change though if we // postulate that the current state is only current between syncs but not // within a sync. - Changes stateChanges = Change::NoChange; + Changes roomChanges = Change::NoChange; for (const auto& eptr: events) - stateChanges |= q->processStateEvent(*eptr); + roomChanges |= q->processStateEvent(*eptr); auto timelineSize = timeline.size(); auto totalInserted = 0; @@ -1778,16 +1783,17 @@ Room::Changes Room::Private::addNewMessageEvents(RoomEvents&& events) auto firstWriter = q->user((*from)->senderId()); if (q->readMarker(firstWriter) != timeline.crend()) { - promoteReadMarker(firstWriter, rev_iter_t(from) - 1); + roomChanges |= promoteReadMarker(firstWriter, rev_iter_t(from) - 1); qCDebug(MAIN) << "Auto-promoted read marker for" << firstWriter->id() << "to" << *q->readMarker(firstWriter); } updateUnreadCount(timeline.crbegin(), rev_iter_t(from)); + roomChanges |= Change::UnreadNotifsChange; } Q_ASSERT(timeline.size() == timelineSize + totalInserted); - return stateChanges; + return roomChanges; } void Room::Private::addHistoricalMessageEvents(RoomEvents&& events) @@ -1906,8 +1912,9 @@ Room::Changes Room::processStateEvent(const RoomEvent& e) ); } -void Room::processEphemeralEvent(EventPtr&& event) +Room::Changes Room::processEphemeralEvent(EventPtr&& event) { + Changes changes = NoChange; QElapsedTimer et; et.start(); if (auto* evt = eventCast(event)) { @@ -1946,7 +1953,7 @@ void Room::processEphemeralEvent(EventPtr&& event) continue; // FIXME, #185 auto u = user(r.userId); if (memberJoinState(u) == JoinState::Join) - d->promoteReadMarker(u, newMarker); + changes |= d->promoteReadMarker(u, newMarker); } } else { @@ -1963,7 +1970,7 @@ void Room::processEphemeralEvent(EventPtr&& event) auto u = user(r.userId); if (memberJoinState(u) == JoinState::Join && readMarker(u) == timelineEdge()) - d->setLastReadEvent(u, p.evtId); + changes |= d->setLastReadEvent(u, p.evtId); } } } @@ -1973,12 +1980,17 @@ void Room::processEphemeralEvent(EventPtr&& event) << evt->eventsWithReceipts().size() << "event(s) with" << totalReceipts << "receipt(s)," << et; } + return changes; } Room::Changes Room::processAccountDataEvent(EventPtr&& event) { + Changes changes = NoChange; if (auto* evt = eventCast(event)) + { d->setTags(evt->tags()); + changes |= Change::TagsChange; + } if (auto* evt = eventCast(event)) { @@ -1986,10 +1998,9 @@ Room::Changes Room::processAccountDataEvent(EventPtr&& event) qCDebug(MAIN) << "Server-side read marker at" << readEventId; d->serverReadMarker = readEventId; const auto newMarker = findInTimeline(readEventId); - if (newMarker != timelineEdge()) - d->markMessagesAsRead(newMarker); - else - d->setLastReadEvent(localUser(), readEventId); + changes |= newMarker != timelineEdge() + ? d->markMessagesAsRead(newMarker) + : d->setLastReadEvent(localUser(), readEventId); } // For all account data events auto& currentData = d->accountData[event->matrixType()]; diff --git a/lib/room.h b/lib/room.h index 9d4561e5..7533c599 100644 --- a/lib/room.h +++ b/lib/room.h @@ -116,8 +116,9 @@ namespace QMatrixClient MembersChange = 0x80, EncryptionOn = 0x100, AccountDataChange = 0x200, - OtherChange = 0x1000, - AnyChange = 0x1FFF + ReadMarkerChange = 0x800, + OtherChange = 0x8000, + AnyChange = 0xFFFF }; Q_DECLARE_FLAGS(Changes, Change) Q_FLAG(Changes) @@ -459,7 +460,7 @@ namespace QMatrixClient protected: /// Returns true if any of room names/aliases has changed virtual Changes processStateEvent(const RoomEvent& e); - virtual void processEphemeralEvent(EventPtr&& event); + virtual Changes processEphemeralEvent(EventPtr&& event); virtual Changes processAccountDataEvent(EventPtr&& event); virtual void onAddNewTimelineEvents(timeline_iter_t /*from*/) { } virtual void onAddHistoricalTimelineEvents(rev_iter_t /*from*/) { } -- cgit v1.2.3 From 8f39d870759de362d5ac911d6554347fb3b46759 Mon Sep 17 00:00:00 2001 From: Kitsune Ral Date: Mon, 10 Dec 2018 07:07:15 +0900 Subject: Suppress a function_traits<> test with lambdas on MSVC2015 Assigning a lambda to a static variable causes it to fail with 'auto must always deduce to the same type' error. --- lib/util.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/util.cpp b/lib/util.cpp index 5e7644a1..e22a1df5 100644 --- a/lib/util.cpp +++ b/lib/util.cpp @@ -112,10 +112,12 @@ static_assert(is_callable_v, "Test is_callable<> with function object 1"); static_assert(std::is_same, int>(), "Test fn_arg_t defaulting to first argument"); +#if (!defined(_MSC_VER) || _MSC_VER >= 1910) static auto l = [] { return 1; }; static_assert(is_callable_v, "Test is_callable_v<> with lambda"); static_assert(std::is_same, int>::value, "Test fn_return_t<> with lambda"); +#endif template struct fn_object -- cgit v1.2.3