Introducing fast backlog replay! Thanks sph_ for the help!
authorMarcus Eggenberger <egs@quassel-irc.org>
Mon, 1 Sep 2008 19:02:57 +0000 (21:02 +0200)
committerMarcus Eggenberger <egs@quassel-irc.org>
Mon, 1 Sep 2008 19:02:57 +0000 (21:02 +0200)
Known issues:
 - The scrollbar is a bit jumpy now when requesting further backlog

src/client/clientbacklogmanager.cpp
src/client/clientbacklogmanager.h
src/client/messagemodel.cpp
src/client/messagemodel.h
src/common/message.h
src/qtui/qtuimessageprocessor.cpp

index ce22e33..519135a 100644 (file)
 #include <QDebug>
 
 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();
index d9171cf..2f0fcf3 100644 (file)
@@ -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<Message> _messageBuffer;
+  QSet<BufferId> _buffersWaiting;
 };
 
 #endif // CLIENTBACKLOGMANAGER_H
index 940dda2..245a787 100644 (file)
@@ -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<Message> &msglist) {
+
+void MessageModel::insertMessageGroup(const QList<Message> &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<Message> &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<Message> 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<Message> grouplist;
+  MsgId id;
+  bool fastForward = false;
+  QList<Message>::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<MsgId>()) 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;
+}
index cc61c4f..62488cc 100644 (file)
@@ -72,8 +72,8 @@ protected:
   virtual MessageModelItem *createMessageModelItem(const Message &) = 0;
 
 private:
+  void insertMessageGroup(const QList<Message> &);
   QList<MessageModelItem *> _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;
index 5641794..482039f 100644 (file)
@@ -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 <QString>
 #include <QDateTime>
@@ -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;
index 46a7f61..9399d1f 100644 (file)
@@ -61,6 +61,17 @@ void QtUiMessageProcessor::process(Message &msg) {
 }
 
 void QtUiMessageProcessor::process(QList<Message> &msgs) {
+  QList<Message>::iterator msgIter = msgs.begin();
+  QList<Message>::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();