Merge pull request #188 from Nheko-Reborn/optimize-cpu-usage

Optimize cpu usage
This commit is contained in:
DeepBlueV7.X 2020-05-01 00:21:13 +02:00 committed by GitHub
commit 00c4d2629a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 57 additions and 214 deletions

View file

@ -17,6 +17,10 @@ Page {
palette: colors palette: colors
FontMetrics {
id: fontMetrics
}
Settings { Settings {
id: settings id: settings
category: "user" category: "user"
@ -256,7 +260,7 @@ Page {
Rectangle { Rectangle {
id: chatFooter id: chatFooter
height: Math.max(16, footerContent.height) height: Math.max(fontMetrics.height * 1.2, footerContent.height)
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
@ -326,8 +330,4 @@ Page {
} }
} }
} }
FontMetrics {
id: fontMetrics
}
} }

View file

@ -62,6 +62,7 @@ constexpr auto SYNC_STATE_DB("sync_state");
//! Read receipts per room/event. //! Read receipts per room/event.
constexpr auto READ_RECEIPTS_DB("read_receipts"); constexpr auto READ_RECEIPTS_DB("read_receipts");
constexpr auto NOTIFICATIONS_DB("sent_notifications"); constexpr auto NOTIFICATIONS_DB("sent_notifications");
//! TODO: delete pending_receipts database on old cache versions
//! Encryption related databases. //! Encryption related databases.
@ -703,70 +704,6 @@ Cache::setCurrentFormat()
txn.commit(); txn.commit();
} }
std::vector<QString>
Cache::pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id)
{
auto db = getPendingReceiptsDb(txn);
std::string key, unused;
std::vector<QString> pending;
auto cursor = lmdb::cursor::open(txn, db);
while (cursor.get(key, unused, MDB_NEXT)) {
ReadReceiptKey receipt;
try {
receipt = json::parse(key);
} catch (const nlohmann::json::exception &e) {
nhlog::db()->warn("pendingReceiptsEvents: {}", e.what());
continue;
}
if (receipt.room_id == room_id)
pending.emplace_back(QString::fromStdString(receipt.event_id));
}
cursor.close();
return pending;
}
void
Cache::removePendingReceipt(lmdb::txn &txn, const std::string &room_id, const std::string &event_id)
{
auto db = getPendingReceiptsDb(txn);
ReadReceiptKey receipt_key{event_id, room_id};
auto key = json(receipt_key).dump();
try {
lmdb::dbi_del(txn, db, lmdb::val(key.data(), key.size()), nullptr);
} catch (const lmdb::error &e) {
nhlog::db()->critical("removePendingReceipt: {}", e.what());
}
}
void
Cache::addPendingReceipt(const QString &room_id, const QString &event_id)
{
auto txn = lmdb::txn::begin(env_);
auto db = getPendingReceiptsDb(txn);
ReadReceiptKey receipt_key{event_id.toStdString(), room_id.toStdString()};
auto key = json(receipt_key).dump();
std::string empty;
try {
lmdb::dbi_put(txn,
db,
lmdb::val(key.data(), key.size()),
lmdb::val(empty.data(), empty.size()));
} catch (const lmdb::error &e) {
nhlog::db()->critical("addPendingReceipt: {}", e.what());
}
txn.commit();
}
CachedReceipts CachedReceipts
Cache::readReceipts(const QString &event_id, const QString &room_id) Cache::readReceipts(const QString &event_id, const QString &room_id)
{ {
@ -802,30 +739,6 @@ Cache::readReceipts(const QString &event_id, const QString &room_id)
return receipts; return receipts;
} }
std::vector<QString>
Cache::filterReadEvents(const QString &room_id,
const std::vector<QString> &event_ids,
const std::string &excluded_user)
{
std::vector<QString> read_events;
for (const auto &event : event_ids) {
auto receipts = readReceipts(event, room_id);
if (receipts.size() == 0)
continue;
if (receipts.size() == 1) {
if (receipts.begin()->second == excluded_user)
continue;
}
read_events.emplace_back(event);
}
return read_events;
}
void void
Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Receipts &receipts) Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Receipts &receipts)
{ {
@ -881,27 +794,6 @@ Cache::updateReadReceipt(lmdb::txn &txn, const std::string &room_id, const Recei
} }
} }
void
Cache::notifyForReadReceipts(const std::string &room_id)
{
auto txn = lmdb::txn::begin(env_);
QSettings settings;
auto local_user = settings.value("auth/user_id").toString();
auto matches = filterReadEvents(QString::fromStdString(room_id),
pendingReceiptsEvents(txn, room_id),
local_user.toStdString());
for (const auto &m : matches)
removePendingReceipt(txn, room_id, m.toStdString());
if (!matches.empty())
emit newReadReceipts(QString::fromStdString(room_id), matches);
txn.commit();
}
void void
Cache::calculateRoomReadStatus() Cache::calculateRoomReadStatus()
{ {
@ -1019,7 +911,12 @@ Cache::saveState(const mtx::responses::Sync &res)
std::map<QString, bool> readStatus; std::map<QString, bool> readStatus;
for (const auto &room : res.rooms.join) { for (const auto &room : res.rooms.join) {
notifyForReadReceipts(room.first); if (!room.second.ephemeral.receipts.empty()) {
std::vector<QString> receipts;
for (const auto &receipt : room.second.ephemeral.receipts)
receipts.push_back(QString::fromStdString(receipt.first));
emit newReadReceipts(QString::fromStdString(room.first), receipts);
}
readStatus.emplace(QString::fromStdString(room.first), readStatus.emplace(QString::fromStdString(room.first),
calculateRoomReadStatus(room.first)); calculateRoomReadStatus(room.first));
} }
@ -2634,36 +2531,6 @@ readReceipts(const QString &event_id, const QString &room_id)
return instance_->readReceipts(event_id, room_id); return instance_->readReceipts(event_id, room_id);
} }
//! Filter the events that have at least one read receipt.
std::vector<QString>
filterReadEvents(const QString &room_id,
const std::vector<QString> &event_ids,
const std::string &excluded_user)
{
return instance_->filterReadEvents(room_id, event_ids, excluded_user);
}
//! Add event for which we are expecting some read receipts.
void
addPendingReceipt(const QString &room_id, const QString &event_id)
{
instance_->addPendingReceipt(room_id, event_id);
}
void
removePendingReceipt(lmdb::txn &txn, const std::string &room_id, const std::string &event_id)
{
instance_->removePendingReceipt(txn, room_id, event_id);
}
void
notifyForReadReceipts(const std::string &room_id)
{
instance_->notifyForReadReceipts(room_id);
}
std::vector<QString>
pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id)
{
return instance_->pendingReceiptsEvents(txn, room_id);
}
QByteArray QByteArray
image(const QString &url) image(const QString &url)
{ {

View file

@ -154,21 +154,6 @@ using UserReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>
UserReceipts UserReceipts
readReceipts(const QString &event_id, const QString &room_id); readReceipts(const QString &event_id, const QString &room_id);
//! Filter the events that have at least one read receipt.
std::vector<QString>
filterReadEvents(const QString &room_id,
const std::vector<QString> &event_ids,
const std::string &excluded_user);
//! Add event for which we are expecting some read receipts.
void
addPendingReceipt(const QString &room_id, const QString &event_id);
void
removePendingReceipt(lmdb::txn &txn, const std::string &room_id, const std::string &event_id);
void
notifyForReadReceipts(const std::string &room_id);
std::vector<QString>
pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id);
QByteArray QByteArray
image(const QString &url); image(const QString &url);
QByteArray QByteArray

View file

@ -39,7 +39,8 @@ struct DescInfo
QString event_id; QString event_id;
QString userid; QString userid;
QString body; QString body;
QString timestamp; QString descriptiveTime;
uint64_t timestamp;
QDateTime datetime; QDateTime datetime;
}; };

View file

@ -137,18 +137,6 @@ public:
using UserReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>>; using UserReceipts = std::multimap<uint64_t, std::string, std::greater<uint64_t>>;
UserReceipts readReceipts(const QString &event_id, const QString &room_id); UserReceipts readReceipts(const QString &event_id, const QString &room_id);
//! Filter the events that have at least one read receipt.
std::vector<QString> filterReadEvents(const QString &room_id,
const std::vector<QString> &event_ids,
const std::string &excluded_user);
//! Add event for which we are expecting some read receipts.
void addPendingReceipt(const QString &room_id, const QString &event_id);
void removePendingReceipt(lmdb::txn &txn,
const std::string &room_id,
const std::string &event_id);
void notifyForReadReceipts(const std::string &room_id);
std::vector<QString> pendingReceiptsEvents(lmdb::txn &txn, const std::string &room_id);
QByteArray image(const QString &url) const; QByteArray image(const QString &url) const;
QByteArray image(lmdb::txn &txn, const std::string &url) const; QByteArray image(lmdb::txn &txn, const std::string &url) const;
void saveImage(const std::string &url, const std::string &data); void saveImage(const std::string &url, const std::string &data);

View file

@ -187,10 +187,11 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
QFont tsFont; QFont tsFont;
tsFont.setPointSizeF(tsFont.pointSizeF() * 0.9); tsFont.setPointSizeF(tsFont.pointSizeF() * 0.9);
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
const int msgStampWidth = QFontMetrics(tsFont).width(lastMsgInfo_.timestamp) + 4; const int msgStampWidth =
QFontMetrics(tsFont).width(lastMsgInfo_.descriptiveTime) + 4;
#else #else
const int msgStampWidth = const int msgStampWidth =
QFontMetrics(tsFont).horizontalAdvance(lastMsgInfo_.timestamp) + 4; QFontMetrics(tsFont).horizontalAdvance(lastMsgInfo_.descriptiveTime) + 4;
#endif #endif
// We use the full width of the widget if there is no unread msg bubble. // We use the full width of the widget if there is no unread msg bubble.
const int bottomLineWidthLimit = (unreadMsgCount_ > 0) ? msgStampWidth : 0; const int bottomLineWidthLimit = (unreadMsgCount_ > 0) ? msgStampWidth : 0;
@ -227,7 +228,7 @@ RoomInfoListItem::paintEvent(QPaintEvent *event)
p.setFont(tsFont); p.setFont(tsFont);
p.drawText(QPoint(width() - wm.padding - msgStampWidth, top_y), p.drawText(QPoint(width() - wm.padding - msgStampWidth, top_y),
lastMsgInfo_.timestamp); lastMsgInfo_.descriptiveTime);
p.restore(); p.restore();
} else { } else {
int btnWidth = (width() - wm.iconSize - 6 * wm.padding) / 2; int btnWidth = (width() - wm.iconSize - 6 * wm.padding) / 2;

View file

@ -82,7 +82,9 @@ RoomList::addRoom(const QString &room_id, const RoomInfo &info)
MainWindow::instance()->openLeaveRoomDialog(room_id); MainWindow::instance()->openLeaveRoomDialog(room_id);
}); });
rooms_.emplace(room_id, QSharedPointer<RoomInfoListItem>(room_item)); QSharedPointer<RoomInfoListItem> roomWidget(room_item);
rooms_.emplace(room_id, roomWidget);
rooms_sort_cache_.push_back(roomWidget);
if (!info.avatar_url.empty()) if (!info.avatar_url.empty())
updateAvatar(room_id, QString::fromStdString(info.avatar_url)); updateAvatar(room_id, QString::fromStdString(info.avatar_url));
@ -100,6 +102,14 @@ RoomList::updateAvatar(const QString &room_id, const QString &url)
void void
RoomList::removeRoom(const QString &room_id, bool reset) RoomList::removeRoom(const QString &room_id, bool reset)
{ {
auto roomIt = rooms_.find(room_id);
for (auto roomSortIt = rooms_sort_cache_.begin(); roomSortIt != rooms_sort_cache_.end();
++roomSortIt) {
if (roomIt->second == *roomSortIt) {
rooms_sort_cache_.erase(roomSortIt);
break;
}
}
rooms_.erase(room_id); rooms_.erase(room_id);
if (rooms_.empty() || !reset) if (rooms_.empty() || !reset)
@ -336,7 +346,8 @@ RoomList::updateRoomDescription(const QString &roomid, const DescInfo &info)
struct room_sort struct room_sort
{ {
bool operator()(const RoomInfoListItem *a, const RoomInfoListItem *b) const bool operator()(const QSharedPointer<RoomInfoListItem> a,
const QSharedPointer<RoomInfoListItem> b) const
{ {
// Sort by "importance" (i.e. invites before mentions before // Sort by "importance" (i.e. invites before mentions before
// notifs before new events before old events), then secondly // notifs before new events before old events), then secondly
@ -351,12 +362,10 @@ struct room_sort
// Now sort by recency // Now sort by recency
// Zero if empty, otherwise the time that the event occured // Zero if empty, otherwise the time that the event occured
const uint64_t a_recency = a->lastMessageInfo().userid.isEmpty() const uint64_t a_recency =
? 0 a->lastMessageInfo().userid.isEmpty() ? 0 : a->lastMessageInfo().timestamp;
: a->lastMessageInfo().datetime.toMSecsSinceEpoch(); const uint64_t b_recency =
const uint64_t b_recency = b->lastMessageInfo().userid.isEmpty() b->lastMessageInfo().userid.isEmpty() ? 0 : b->lastMessageInfo().timestamp;
? 0
: b->lastMessageInfo().datetime.toMSecsSinceEpoch();
return a_recency > b_recency; return a_recency > b_recency;
} }
}; };
@ -366,27 +375,17 @@ RoomList::sortRoomsByLastMessage()
{ {
isSortPending_ = false; isSortPending_ = false;
std::multiset<RoomInfoListItem *, room_sort> times; std::sort(begin(rooms_sort_cache_), end(rooms_sort_cache_), room_sort{});
for (int ii = 0; ii < contentsLayout_->count(); ++ii) { int newIndex = 0;
auto room = qobject_cast<RoomInfoListItem *>(contentsLayout_->itemAt(ii)->widget()); for (const auto &roomWidget : rooms_sort_cache_) {
const auto currentIndex = contentsLayout_->indexOf(roomWidget.get());
if (!room) if (currentIndex != newIndex) {
continue; contentsLayout_->removeWidget(roomWidget.get());
else contentsLayout_->insertWidget(newIndex, roomWidget.get());
times.insert(room);
} }
newIndex++;
for (auto it = times.cbegin(); it != times.cend(); ++it) {
const auto roomWidget = *it;
const auto currentIndex = contentsLayout_->indexOf(roomWidget);
const auto newIndex = std::distance(times.cbegin(), it);
if (currentIndex == newIndex)
continue;
contentsLayout_->removeWidget(roomWidget);
contentsLayout_->insertWidget(newIndex, roomWidget);
} }
} }
@ -500,7 +499,9 @@ RoomList::addInvitedRoom(const QString &room_id, const RoomInfo &info)
connect(room_item, &RoomInfoListItem::acceptInvite, this, &RoomList::acceptInvite); connect(room_item, &RoomInfoListItem::acceptInvite, this, &RoomList::acceptInvite);
connect(room_item, &RoomInfoListItem::declineInvite, this, &RoomList::declineInvite); connect(room_item, &RoomInfoListItem::declineInvite, this, &RoomList::declineInvite);
rooms_.emplace(room_id, QSharedPointer<RoomInfoListItem>(room_item)); QSharedPointer<RoomInfoListItem> roomWidget(room_item);
rooms_.emplace(room_id, roomWidget);
rooms_sort_cache_.push_back(roomWidget);
updateAvatar(room_id, QString::fromStdString(info.avatar_url)); updateAvatar(room_id, QString::fromStdString(info.avatar_url));

View file

@ -100,6 +100,7 @@ private:
OverlayModal *joinRoomModal_; OverlayModal *joinRoomModal_;
std::map<QString, QSharedPointer<RoomInfoListItem>> rooms_; std::map<QString, QSharedPointer<RoomInfoListItem>> rooms_;
std::vector<QSharedPointer<RoomInfoListItem>> rooms_sort_cache_;
QString selectedRoom_; QString selectedRoom_;
bool isSortPending_ = false; bool isSortPending_ = false;

View file

@ -41,6 +41,7 @@ createDescriptionInfo(const Event &event, const QString &localUser, const QStrin
utils::messageDescription<T>( utils::messageDescription<T>(
username, QString::fromStdString(msg.content.body).trimmed(), sender == localUser), username, QString::fromStdString(msg.content.body).trimmed(), sender == localUser),
utils::descriptiveTime(ts), utils::descriptiveTime(ts),
msg.origin_server_ts,
ts}; ts};
} }
@ -184,7 +185,8 @@ utils::getMessageDescription(const TimelineEvent &event,
info.userid = sender; info.userid = sender;
info.body = QString(" %1").arg( info.body = QString(" %1").arg(
messageDescription<Encrypted>(username, "", sender == localUser)); messageDescription<Encrypted>(username, "", sender == localUser));
info.timestamp = utils::descriptiveTime(ts); info.timestamp = msg->origin_server_ts;
info.descriptiveTime = utils::descriptiveTime(ts);
info.event_id = QString::fromStdString(msg->event_id); info.event_id = QString::fromStdString(msg->event_id);
info.datetime = ts; info.datetime = ts;

View file

@ -173,9 +173,6 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
// mark our messages as read // mark our messages as read
readEvent(event_id.toStdString()); readEvent(event_id.toStdString());
// ask to be notified for read receipts
cache::addPendingReceipt(room_id_, event_id);
emit dataChanged(index(idx, 0), index(idx, 0)); emit dataChanged(index(idx, 0), index(idx, 0));
if (pending.size() > 0) if (pending.size() > 0)