loolwsd/LOOLSession.hpp | 4 - loolwsd/LOOLWSD.cpp | 41 +++--------------- loolwsd/Makefile.am | 5 -- loolwsd/MessageQueue.cpp | 107 +++++++++++++++++++++++++++++++++++++++++++++++ loolwsd/MessageQueue.hpp | 82 ++++++++++++++++++++++++++++++++++++ loolwsd/tsqueue.h | 75 -------------------------------- 6 files changed, 200 insertions(+), 114 deletions(-)
New commits: commit 6a1477d8a9ba70e01bfe494f5850ba7eae8ee8c1 Author: Jan Holesovsky <ke...@collabora.com> Date: Mon Nov 9 11:36:37 2015 +0100 loolwsd: Specialize the MessageQueue a bit. Introduce a bit of hierarchy there, at some stage we'll want to re-order the tile requests a bit so that it works better for collaborative editing; for the moment, removing the duplicate entries is enough. diff --git a/loolwsd/LOOLSession.hpp b/loolwsd/LOOLSession.hpp index e84b5d1..2bee3cd 100644 --- a/loolwsd/LOOLSession.hpp +++ b/loolwsd/LOOLSession.hpp @@ -29,8 +29,8 @@ #include <Poco/StringTokenizer.h> #include <Poco/Types.h> +#include "MessageQueue.hpp" #include "TileCache.hpp" -#include "tsqueue.h" // We have three kinds of Websocket sessions // 1) Between the master loolwsd server to the end-user LOOL client @@ -159,7 +159,7 @@ private: int _curPart; int _loadPart; /// Kind::ToClient instances store URLs of completed 'save as' documents. - tsqueue<std::string> _saveAsQueue; + MessageQueue _saveAsQueue; }; class ChildProcessSession final : public LOOLSession diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp index e1cf3d0..3626953 100644 --- a/loolwsd/LOOLWSD.cpp +++ b/loolwsd/LOOLWSD.cpp @@ -105,7 +105,7 @@ DEALINGS IN THE SOFTWARE. #include "LOOLProtocol.hpp" #include "LOOLSession.hpp" #include "LOOLWSD.hpp" -#include "tsqueue.h" +#include "MessageQueue.hpp" #include "Util.hpp" using namespace LOOLProtocol; @@ -149,7 +149,7 @@ using Poco::NamedMutex; class QueueHandler: public Runnable { public: - QueueHandler(tsqueue<std::string>& queue): + QueueHandler(MessageQueue& queue): _queue(queue) { } @@ -178,7 +178,7 @@ public: private: std::shared_ptr<LOOLSession> _session; - tsqueue<std::string>& _queue; + MessageQueue& _queue; }; /// Handles the filename part of the convert-to POST request payload. @@ -347,7 +347,7 @@ public: return; } - tsqueue<std::string> queue; + BasicTileQueue queue; Thread queueHandlerThread; QueueHandler handler(queue); @@ -392,22 +392,7 @@ public: if (kind == LOOLSession::Kind::ToClient && firstLine.size() == static_cast<std::string::size_type>(n)) { - // Check if it is a "canceltiles" and in that case remove outstanding - // "tile" messages from the queue. - if (tokens.count() == 1 && tokens[0] == "canceltiles") - { - queue.remove_if([](std::string& x) { - return (x.find("tile ") == 0 && x.find("id=") == std::string::npos); - }); - - // Also forward the "canceltiles" to the child process, if any - session->handleInput(buffer, n); - } - // Filter out duplicated tile messages. - else if ((firstLine.compare(0, 5, "tile ") != 0) || !queue.alreadyInQueue(firstLine)) - { - queue.put(firstLine); - } + queue.put(firstLine); } else { @@ -928,7 +913,7 @@ void LOOLWSD::componentMain() std::string hello("child " + std::to_string(_childId) + " " + std::to_string(Process::id())); session->sendTextFrame(hello); - tsqueue<std::string> queue; + TileQueue queue; Thread queueHandlerThread; QueueHandler handler(queue); @@ -950,19 +935,7 @@ void LOOLWSD::componentMain() // The only kind of messages a child process receives are the single-line ones (?) assert(firstLine.size() == static_cast<std::string::size_type>(n)); - // Check if it is a "canceltiles" and in that case remove outstanding - // "tile" messages from the queue. - if (tokens.count() == 1 && tokens[0] == "canceltiles") - { - queue.remove_if([](std::string& x) { - return (x.find("tile ") == 0 && x.find("id=") == std::string::npos); - }); - } - // Filter out duplicated tile messages. - else if ((firstLine.compare(0, 5, "tile ") != 0) || !queue.alreadyInQueue(firstLine)) - { - queue.put(firstLine); - } + queue.put(firstLine); } } while (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE); diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am index c86f449..be1bcb4 100644 --- a/loolwsd/Makefile.am +++ b/loolwsd/Makefile.am @@ -4,7 +4,7 @@ bin_PROGRAMS = loolwsd dist_bin_SCRIPTS = loolwsd-systemplate-setup -loolwsd_SOURCES = LOOLWSD.cpp LOOLSession.cpp TileCache.cpp Util.cpp LOOLProtocol.cpp +loolwsd_SOURCES = LOOLWSD.cpp LOOLSession.cpp MessageQueue.cpp TileCache.cpp Util.cpp LOOLProtocol.cpp noinst_PROGRAMS = loadtest connect lokitclient @@ -14,8 +14,7 @@ connect_SOURCES = Connect.cpp Util.cpp LOOLProtocol.cpp lokitclient_SOURCES = LOKitClient.cpp Util.cpp -noinst_HEADERS = LOKitHelper.hpp LOOLProtocol.hpp LOOLSession.hpp LOOLWSD.hpp LoadTest.hpp TileCache.hpp Util.hpp \ - tsqueue.h \ +noinst_HEADERS = LOKitHelper.hpp LOOLProtocol.hpp LOOLSession.hpp LOOLWSD.hpp LoadTest.hpp MessageQueue.hpp TileCache.hpp Util.hpp \ bundled/include/LibreOfficeKit/LibreOfficeKit.h bundled/include/LibreOfficeKit/LibreOfficeKitEnums.h \ bundled/include/LibreOfficeKit/LibreOfficeKitInit.h bundled/include/LibreOfficeKit/LibreOfficeKitTypes.h diff --git a/loolwsd/MessageQueue.cpp b/loolwsd/MessageQueue.cpp new file mode 100644 index 0000000..f37c5b8 --- /dev/null +++ b/loolwsd/MessageQueue.cpp @@ -0,0 +1,107 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "MessageQueue.hpp" + +#include <algorithm> + +MessageQueue::~MessageQueue() +{ + clear(); +} + +void MessageQueue::put(const std::string& value) +{ + std::unique_lock<std::mutex> lock(_mutex); + put_impl(value); + lock.unlock(); + _cv.notify_one(); +} + +std::string MessageQueue::get() +{ + std::unique_lock<std::mutex> lock(_mutex); + _cv.wait(lock, [this] { return wait_impl(); }); + return get_impl(); +} + +void MessageQueue::clear() +{ + std::unique_lock<std::mutex> lock(_mutex); + _queue.clear(); +} + +void MessageQueue::put_impl(const std::string& value) +{ + _queue.push_back(value); +} + +bool MessageQueue::wait_impl() const +{ + return _queue.size() > 0; +} + +std::string MessageQueue::get_impl() +{ + std::string result = _queue.front(); + _queue.pop_front(); + return result; +} + +void MessageQueue::clear_impl() +{ + _queue.clear(); +} + +void BasicTileQueue::put_impl(const std::string& value) +{ + if (value == "canceltiles") + { + // remove all the existing tiles from the queue + _queue.erase(std::remove_if(_queue.begin(), _queue.end(), + [](const std::string& v) { + // must not remove the tiles with 'id=', they are special, used + // eg. for previews etc. + return (v.compare(0, 5, "tile ") == 0) && (v.find("id=") == std::string::npos); + } + ), + _queue.end()); + + // put the "canceltiles" in front of other messages + _queue.push_front(value); + } + else + MessageQueue::put_impl(value); +} + +void TileQueue::put_impl(const std::string& value) +{ + if (value.compare(0, 5, "tile ") == 0) + { + // TODO: implement a real re-ordering here, so that the tiles closest to + // the cursor are returned first. + // * we will want to put just a general "tile" message to the queue + // * add a std::set that handles the tiles + // * change the get_impl() to decide which tile is the correct one to + // be returned + // * we will also need to be informed about the position of the cursor + // so that get_impl() returns optimal results + // + // For now: just don't put duplicates into the queue + for (auto it = _queue.cbegin(); it != _queue.cend(); ++it) + { + if (value == *it) + return; + } + } + + BasicTileQueue::put_impl(value); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/loolwsd/MessageQueue.hpp b/loolwsd/MessageQueue.hpp new file mode 100644 index 0000000..f1b8996 --- /dev/null +++ b/loolwsd/MessageQueue.hpp @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_MESSAGEQUEUE_HPP +#define INCLUDED_MESSAGEQUEUE_HPP + +#include "config.h" + +#include <condition_variable> +#include <mutex> +#include <deque> + +/** Thread-safe message queue (FIFO). +*/ +class MessageQueue +{ +public: + MessageQueue() {} + virtual ~MessageQueue(); + + MessageQueue(const MessageQueue&) = delete; + MessageQueue& operator=(const MessageQueue&) = delete; + + /// Thread safe insert the message. + void put(const std::string& value); + + /// Thread safe obtaining of the message. + std::string get(); + + /// Thread safe removal of all the pending messages. + void clear(); + +private: + std::mutex _mutex; + std::condition_variable _cv; + +protected: + virtual void put_impl(const std::string& value); + + virtual bool wait_impl() const; + + virtual std::string get_impl(); + + virtual void clear_impl(); + + std::deque<std::string> _queue; +}; + +/** MessageQueue specialized for handling of tiles. + +Used for basic handling of incoming requests, only can remove tiles when it +gets a "canceltiles" command. +*/ +class BasicTileQueue : public MessageQueue +{ +protected: + virtual void put_impl(const std::string& value); +}; + +/** MessageQueue specialized for priority handling of tiles. + +This class builds on BasicTileQueuee, and additonaly provides de-duplication +of tile requests. + +TODO: we'll need to add reordering of the tiles at some stage here too - so +that the ones closest to the cursor position are returned first. +*/ +class TileQueue : public BasicTileQueue +{ +protected: + virtual void put_impl(const std::string& value); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/loolwsd/tsqueue.h b/loolwsd/tsqueue.h deleted file mode 100644 index 94a36cd..0000000 --- a/loolwsd/tsqueue.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - */ - -#ifndef INCLUDED_TSQUEUE_H -#define INCLUDED_TSQUEUE_H - -#include "config.h" - -#include <condition_variable> -#include <mutex> -#include <deque> - -// Thread-safe queue - -template <class T> -class tsqueue -{ -public: - void put(const T& value) - { - std::unique_lock<std::mutex> lock(_mutex); - _queue.push_back(value); - lock.unlock(); - _cv.notify_one(); - } - - T get() - { - std::unique_lock<std::mutex> lock(_mutex); - _cv.wait(lock, [this] { return _queue.size() > 0; }); - T result = _queue.front(); - _queue.pop_front(); - return result; - } - - void clear() - { - std::unique_lock<std::mutex> lock(_mutex); - while (_queue.size()) - _queue.pop_front(); - } - - template<class UnaryPredicate> - void remove_if(UnaryPredicate p) - { - std::unique_lock<std::mutex> lock(_mutex); - _queue.erase(std::remove_if(_queue.begin(), _queue.end(), p), - _queue.end()); - } - - bool alreadyInQueue(std::string cmd) { - std::unique_lock<std::mutex> lock(_mutex); - for (auto it = _queue.cbegin(); it != _queue.cend(); ++it) { - if (cmd == *it) { - return true; - } - } - return false; - } - -private: - std::mutex _mutex; - std::condition_variable _cv; - std::deque<T> _queue; -}; - -#endif - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits