From ea372dac8dda146255c7232922904e9f90a0d7f9 Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Mon, 1 Sep 2008 21:02:57 +0200 Subject: [PATCH] Introducing fast backlog replay! Thanks sph_ for the help! Known issues: - The scrollbar is a bit jumpy now when requesting further backlog --- src/client/clientbacklogmanager.cpp | 25 ++++- src/client/clientbacklogmanager.h | 7 ++ src/client/messagemodel.cpp | 138 +++++++++++++++++++++++++++- src/client/messagemodel.h | 8 +- src/common/message.h | 6 +- src/qtui/qtuimessageprocessor.cpp | 11 +++ 6 files changed, 185 insertions(+), 10 deletions(-) diff --git a/src/client/clientbacklogmanager.cpp b/src/client/clientbacklogmanager.cpp index ce22e337..519135a0 100644 --- a/src/client/clientbacklogmanager.cpp +++ b/src/client/clientbacklogmanager.cpp @@ -27,12 +27,12 @@ #include ClientBacklogManager::ClientBacklogManager(QObject *parent) - : BacklogManager(parent) + : BacklogManager(parent), + _buffer(true) { } void ClientBacklogManager::receiveBacklog(BufferId bufferId, int lastMsgs, int offset, QVariantList msgs) { - Q_UNUSED(bufferId) Q_UNUSED(lastMsgs) Q_UNUSED(offset) @@ -46,10 +46,29 @@ void ClientBacklogManager::receiveBacklog(BufferId bufferId, int lastMsgs, int o msg.setFlags(msg.flags() | Message::Backlog); msglist << msg; } - Client::messageProcessor()->process(msglist); + + if(_buffer) { + _messageBuffer << msglist; + _buffersWaiting.remove(bufferId); + if(_buffersWaiting.isEmpty()) { + _buffer = false; + qSort(_messageBuffer); + Client::messageProcessor()->process(_messageBuffer); + _messageBuffer.clear(); + } + } else { + Client::messageProcessor()->process(msglist); + } //qDebug() << "processed" << msgs.count() << "backlog lines in" << start.msecsTo(QTime::currentTime()); } +QVariantList ClientBacklogManager::requestBacklog(BufferId bufferId, int lastMsgs, int offset) { + if(_buffer) + _buffersWaiting << bufferId; + + return BacklogManager::requestBacklog(bufferId, lastMsgs, offset); +} + void ClientBacklogManager::requestInitialBacklog() { FixedBacklogRequester backlogRequester(this); backlogRequester.requestBacklog(); diff --git a/src/client/clientbacklogmanager.h b/src/client/clientbacklogmanager.h index d9171cfe..2f0fcf36 100644 --- a/src/client/clientbacklogmanager.h +++ b/src/client/clientbacklogmanager.h @@ -22,6 +22,7 @@ #define CLIENTBACKLOGMANAGER_H #include "backlogmanager.h" +#include "message.h" class ClientBacklogManager : public BacklogManager { Q_OBJECT @@ -33,7 +34,13 @@ public: public slots: virtual void receiveBacklog(BufferId bufferId, int lastMsgs, int offset, QVariantList msgs); + virtual QVariantList requestBacklog(BufferId bufferId, int lastMsgs = -1, int offset = -1); void requestInitialBacklog(); + +private: + bool _buffer; + QList _messageBuffer; + QSet _buffersWaiting; }; #endif // CLIENTBACKLOGMANAGER_H diff --git a/src/client/messagemodel.cpp b/src/client/messagemodel.cpp index 940dda20..245a7870 100644 --- a/src/client/messagemodel.cpp +++ b/src/client/messagemodel.cpp @@ -51,6 +51,8 @@ bool MessageModel::setData(const QModelIndex &index, const QVariant &value, int return false; } + + bool MessageModel::insertMessage(const Message &msg, bool fakeMsg) { MsgId id = msg.msgId(); int idx = indexForId(id); @@ -66,13 +68,123 @@ bool MessageModel::insertMessage(const Message &msg, bool fakeMsg) { return true; } -void MessageModel::insertMessages(const QList &msglist) { + +void MessageModel::insertMessageGroup(const QList &msglist) { if(msglist.isEmpty()) return; - // FIXME make this more efficient by grouping msgs - foreach(Message msg, msglist) - insertMessage(msg); + + int idx = indexForId(msglist.first().msgId()); + beginInsertRows(QModelIndex(), idx, idx+msglist.count()-1); + + foreach(Message msg, msglist) { + _messageList.insert(idx, createMessageModelItem(msg)); + idx++; + } + + endInsertRows(); } + +void MessageModel::insertMessages(const QList &msglist) { + if(msglist.isEmpty()) + return; + + if(_messageList.isEmpty()) { + insertMessageGroup(msglist); + return; + } + + bool inOrder = (msglist.first().msgId() < msglist.last().msgId()); + + // check if the whole bunch fits in at one position + if(indexForId(msglist.first().msgId()) == indexForId(msglist.last().msgId())) { + if(inOrder) { + insertMessageGroup(msglist); + } else { + QList messages = msglist; + qSort(messages); + insertMessageGroup(messages); + } + return; + } + + // depending on the order we have to traverse from the front to the back or vice versa + // for the sake of performance we have a little code duplication here + // if you need to do some changes here you'll probably need to change them at all + // places marked DUPE + + + // FIXME: keep scrollbars from jumping + // the somewhat bulk insert leads to a jumpy scrollbar when the user requests further backlog. + // it would probably be the best to stop processing each time we actually insert a messagegroup + // and give back controll to the eventloop (similar to what the QtUiMessageProcessor used to do) + QList grouplist; + MsgId id; + bool fastForward = false; + QList::const_iterator iter; + if(inOrder) { + iter = msglist.constEnd(); + iter--; // this op is safe as we've allready passed an empty check + } else { + iter = msglist.constBegin(); + } + + // DUPE (1 / 3) + int idx = indexForId((*iter).msgId()); + // we always compare to the previous entry... + // if there isn't, we can fastforward to the top + if(idx - 1 >= 0) // also safe as we've passed another empty check + id = _messageList[idx - 1]->msgId(); + else + fastForward = true; + grouplist << *iter; + + if(!inOrder) + iter++; + + if(inOrder) { + while(iter != msglist.constBegin()) { + iter--; + // DUPE (2 / 3) + if(!fastForward && (*iter).msgId() < id) { + insertMessageGroup(grouplist); + grouplist.clear(); + + // build new group + int idx = indexForId((*iter).msgId()); + if(idx - 1 >= 0) + id = _messageList[idx - 1]->msgId(); + else + fastForward = true; + } + grouplist.prepend(*iter); + } + } else { + while(iter != msglist.constEnd()) { + // DUPE (3 / 3) + if(!fastForward && (*iter).msgId() < id) { + insertMessageGroup(grouplist); + grouplist.clear(); + + // build new group + int idx = indexForId((*iter).msgId()); + if(idx - 1 >= 0) + id = _messageList[idx - 1]->msgId(); + else + fastForward = true; + } + grouplist.prepend(*iter); + iter++; + } + } + + if(!grouplist.isEmpty()) { + insertMessageGroup(grouplist); + } + + return; +} + + void MessageModel::clear() { beginRemoveRows(QModelIndex(), 0, rowCount() - 1); qDeleteAll(_messageList); @@ -80,6 +192,7 @@ void MessageModel::clear() { endRemoveRows(); } + // returns index of msg with given Id or of the next message after that (i.e., the index where we'd insert this msg) int MessageModel::indexForId(MsgId id) { if(_messageList.isEmpty() || id <= _messageList.value(0)->data(0, MsgIdRole).value()) return 0; @@ -119,3 +232,20 @@ QVariant MessageModelItem::data(int column, int role) const { } } + +// Stuff for later +bool MessageModelItem::lessThan(const MessageModelItem *m1, const MessageModelItem *m2){ + return (*m1) < (*m2); +} + +bool MessageModelItem::operator<(const MessageModelItem &other) const { + return _msgId < other._msgId; +} + +bool MessageModelItem::operator==(const MessageModelItem &other) const { + return _msgId == other._msgId; +} + +bool MessageModelItem::operator>(const MessageModelItem &other) const { + return _msgId > other._msgId; +} diff --git a/src/client/messagemodel.h b/src/client/messagemodel.h index cc61c4f6..62488cc4 100644 --- a/src/client/messagemodel.h +++ b/src/client/messagemodel.h @@ -72,8 +72,8 @@ protected: virtual MessageModelItem *createMessageModelItem(const Message &) = 0; private: + void insertMessageGroup(const QList &); QList _messageList; - int indexForId(MsgId); }; @@ -96,6 +96,12 @@ public: inline Message::Type msgType() const { return _type; } inline Message::Flags msgFlags() const { return _flags; } + // For sorting + bool operator<(const MessageModelItem &) const; + bool operator==(const MessageModelItem &) const; + bool operator>(const MessageModelItem &) const; + static bool lessThan(const MessageModelItem *m1, const MessageModelItem *m2); + private: QDateTime _timestamp; MsgId _msgId; diff --git a/src/common/message.h b/src/common/message.h index 56417942..482039f2 100644 --- a/src/common/message.h +++ b/src/common/message.h @@ -18,8 +18,8 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ -#ifndef _MESSAGE_H_ -#define _MESSAGE_H_ +#ifndef MESSAGE_H_ +#define MESSAGE_H_ #include #include @@ -75,6 +75,8 @@ public: void setFlags(Flags flags); + inline bool operator<(const Message &other) const { return _msgId < other._msgId; } + private: QDateTime _timestamp; MsgId _msgId; diff --git a/src/qtui/qtuimessageprocessor.cpp b/src/qtui/qtuimessageprocessor.cpp index 46a7f61d..9399d1f0 100644 --- a/src/qtui/qtuimessageprocessor.cpp +++ b/src/qtui/qtuimessageprocessor.cpp @@ -61,6 +61,17 @@ void QtUiMessageProcessor::process(Message &msg) { } void QtUiMessageProcessor::process(QList &msgs) { + QList::iterator msgIter = msgs.begin(); + QList::iterator msgIterEnd = msgs.end(); + while(msgIter != msgIterEnd) { + checkForHighlight(*msgIter); + postProcess(*msgIter); + msgIter++; + } + Client::messageModel()->insertMessages(msgs); + return; + + if(msgs.isEmpty()) return; _processQueue.append(msgs); _msgCount += msgs.count(); -- 2.20.1