loolwsd/MasterProcessSession.cpp | 27 +++++++++++++++++++++ loolwsd/MasterProcessSession.hpp | 1 loolwsd/TileCache.cpp | 50 +++++++++++++++++++++++++++++++++++++++ loolwsd/TileCache.hpp | 27 ++++++++++++++++++++- 4 files changed, 103 insertions(+), 2 deletions(-)
New commits: commit d5bb373447ea57029b6be846e93a15e99c7045fc Author: Tor Lillqvist <t...@collabora.com> Date: Fri Apr 15 18:24:00 2016 +0300 Improve efficiency when multiple clients of same doc ask for same tile(s) Keep track of tiles being rendered in TileCache, and when asked to render the same tile as is already being rendered, just "subscribe" to the existing ongoing rendering. When a tile has been rendered and is being sent out to clients, check if there are "subscriptions" and send it to them, too. One problem is that if the client that caused a tile rendering to be initiated goes away before the rendering has completed, it will never complete, and the subscribers are left without the tile. Change-Id: Icca237876a0f466c29eb5bf60ffd4da3d9d68600 Reviewed-on: https://gerrit.libreoffice.org/24228 Reviewed-by: Ashod Nakashian <ashnak...@gmail.com> Tested-by: Ashod Nakashian <ashnak...@gmail.com> diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp index c2d4856..ccdc6b0 100644 --- a/loolwsd/MasterProcessSession.cpp +++ b/loolwsd/MasterProcessSession.cpp @@ -181,6 +181,22 @@ bool MasterProcessSession::_handleInput(const char *buffer, int length) assert(firstLine.size() < static_cast<std::string::size_type>(length)); _docBroker->tileCache().saveTile(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight, buffer + firstLine.size() + 1, length - firstLine.size() - 1); + auto lock = _docBroker->tileCache().getTilesBeingRenderdLock(); + std::shared_ptr<TileBeingRendered> tileBeingRendered = _docBroker->tileCache().findTileBeingRendered(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight); + if (tileBeingRendered) + { + for (auto i: tileBeingRendered->getSubscribers()) + { + auto subscriber = i.lock(); + if (subscriber) + { + Log::debug("Sending tile also to subscriber " + subscriber->getName()); + subscriber->sendBinaryFrame(buffer, length); + } + } + _docBroker->tileCache().forgetTileBeingRendered(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight); + } + lock.unlock(); } else if (tokens[0] == "status:") { @@ -569,6 +585,17 @@ void MasterProcessSession::sendTile(const char *buffer, int length, StringTokeni return; } + auto lock = _docBroker->tileCache().getTilesBeingRenderdLock(); + std::shared_ptr<TileBeingRendered> tileBeingRendered = _docBroker->tileCache().findTileBeingRendered(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight); + if (tileBeingRendered) + { + Log::debug("Tile is already being rendered, subscribing"); + tileBeingRendered->subscribe(shared_from_this()); + return; + } + _docBroker->tileCache().rememberTileAsBeingRendered(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight); + lock.unlock(); + if (_peer.expired()) dispatchChild(); forwardToPeer(buffer, length); diff --git a/loolwsd/MasterProcessSession.hpp b/loolwsd/MasterProcessSession.hpp index c38b20f..beffa34 100644 --- a/loolwsd/MasterProcessSession.hpp +++ b/loolwsd/MasterProcessSession.hpp @@ -16,7 +16,6 @@ #include "LOOLSession.hpp" #include "MessageQueue.hpp" -#include "TileCache.hpp" class DocumentBroker; diff --git a/loolwsd/TileCache.cpp b/loolwsd/TileCache.cpp index 26f986a..409f316 100644 --- a/loolwsd/TileCache.cpp +++ b/loolwsd/TileCache.cpp @@ -18,6 +18,7 @@ #include <mutex> #include <sstream> #include <string> +#include <vector> #include <Poco/DigestEngine.h> #include <Poco/DirectoryIterator.h> @@ -43,6 +44,16 @@ using Poco::URI; using namespace LOOLProtocol; +void TileBeingRendered::subscribe(std::weak_ptr<MasterProcessSession> session) +{ + _subscribers.push_back(session); +} + +std::vector<std::weak_ptr<MasterProcessSession>> TileBeingRendered::getSubscribers() +{ + return _subscribers; +} + TileCache::TileCache(const std::string& docURL, const Timestamp& modifiedTime, const std::string& rootCacheDir) : @@ -78,6 +89,45 @@ TileCache::TileCache(const std::string& docURL, TileCache::~TileCache() { Log::info("~TileCache dtor for uri [" + _docURL + "]."); +#if 0 + auto lock = getTilesBeingRenderdLock(); + _tilesBeingRendered.clear(); +#endif +} + +std::unique_lock<std::mutex> TileCache::getTilesBeingRenderdLock() +{ + return std::unique_lock<std::mutex>(_tilesBeingRenderedMutex); +} + +void TileCache::rememberTileAsBeingRendered(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight) +{ + const std::string cachedName = cacheFileName(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight); + + assert(_tilesBeingRendered.find(cachedName) == _tilesBeingRendered.end()); + + _tilesBeingRendered[cachedName] = std::make_shared<TileBeingRendered>(); +} + +std::shared_ptr<TileBeingRendered> TileCache::findTileBeingRendered(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight) +{ + const std::string cachedName = cacheFileName(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight); + + auto tile = _tilesBeingRendered.find(cachedName); + + if (tile == _tilesBeingRendered.end()) + return nullptr; + + return tile->second; +} + +void TileCache::forgetTileBeingRendered(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight) +{ + const std::string cachedName = cacheFileName(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight); + + assert(_tilesBeingRendered.find(cachedName) != _tilesBeingRendered.end()); + + _tilesBeingRendered.erase(cachedName); } std::unique_ptr<std::fstream> TileCache::lookupTile(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight) diff --git a/loolwsd/TileCache.hpp b/loolwsd/TileCache.hpp index 163ab7b..54a462e 100644 --- a/loolwsd/TileCache.hpp +++ b/loolwsd/TileCache.hpp @@ -14,6 +14,7 @@ #include <memory> #include <set> #include <string> +#include <vector> #include <Poco/Timestamp.h> @@ -26,6 +27,18 @@ The cache consists of 2 cache directories: The editing cache is cleared on startup, and copied to the persistent on each save. */ + +class MasterProcessSession; + +class TileBeingRendered +{ + std::vector<std::weak_ptr<MasterProcessSession>> _subscribers; + +public: + void subscribe(std::weak_ptr<MasterProcessSession> session); + std::vector<std::weak_ptr<MasterProcessSession>> getSubscribers(); +}; + class TileCache { public: @@ -37,7 +50,16 @@ public: TileCache(const TileCache&) = delete; + std::unique_lock<std::mutex> getTilesBeingRenderdLock(); + + void rememberTileAsBeingRendered(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight); + + std::shared_ptr<TileBeingRendered> findTileBeingRendered(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight); + + void forgetTileBeingRendered(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight); + std::unique_ptr<std::fstream> lookupTile(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight); + void saveTile(int part, int width, int height, int tilePosX, int tilePosY, int tileWidth, int tileHeight, const char *data, size_t size); std::string getTextFile(std::string fileName); @@ -80,7 +102,6 @@ private: /// Store the timestamp to modtime.txt. void saveLastModified(const Poco::Timestamp& timestamp); -private: const std::string _docURL; const std::string _rootCacheDir; const std::string _persCacheDir; @@ -96,6 +117,10 @@ private: std::set<std::string> _toBeRemoved; std::mutex _cacheMutex; + + std::mutex _tilesBeingRenderedMutex; + + std::map<std::string, std::shared_ptr<TileBeingRendered>> _tilesBeingRendered; }; #endif _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits