common/Common.hpp       |    2 +
 test/TileCacheTests.cpp |   62 ++++++++++++++++++++++++++++++++++++++++++++++++
 wsd/ClientSession.cpp   |   18 +++++++++++--
 wsd/ClientSession.hpp   |    3 +-
 wsd/DocumentBroker.cpp  |   16 +++++++++++-
 5 files changed, 96 insertions(+), 5 deletions(-)

New commits:
commit ea871566685f64949080735d430c7f767c63f582
Author:     Tamás Zolnai <tamas.zol...@collabora.com>
AuthorDate: Fri Sep 28 19:30:57 2018 +0200
Commit:     Jan Holesovsky <ke...@collabora.com>
CommitDate: Mon Oct 1 13:16:54 2018 +0200

    Upper limit of sent out versions of the same tile
    
    We try to decrease the network usage with avoiding sending out
    to much tiles to the client. When we already sent out two versions
    of the same tile without having the tileprocessed message from the
    client we delay sending out the next version to avoid spamming tiles
    on the network.
    
    Change-Id: Ia47cd7c0d3fb829f6777f0c3265970433591df19
    (cherry picked from commit ac2cd92d25815cd476008c6cd8035e989d0c8826)
    Reviewed-on: https://gerrit.libreoffice.org/61129
    Reviewed-by: Jan Holesovsky <ke...@collabora.com>
    Tested-by: Jan Holesovsky <ke...@collabora.com>

diff --git a/common/Common.hpp b/common/Common.hpp
index 978ef2c18..29008fd24 100644
--- a/common/Common.hpp
+++ b/common/Common.hpp
@@ -20,6 +20,8 @@ constexpr int CHILD_REBALANCE_INTERVAL_MS = CHILD_TIMEOUT_MS 
/ 10;
 constexpr int POLL_TIMEOUT_MS = COMMAND_TIMEOUT_MS / 10;
 constexpr int WS_SEND_TIMEOUT_MS = 1000;
 
+constexpr int TILE_ROUNDTRIP_TIMEOUT_MS = 5000;
+
 /// Pipe and Socket read buffer size.
 /// Should be large enough for ethernet packets
 /// which can be 1500 bytes long.
diff --git a/test/TileCacheTests.cpp b/test/TileCacheTests.cpp
index 535bafc30..f8eefa278 100644
--- a/test/TileCacheTests.cpp
+++ b/test/TileCacheTests.cpp
@@ -81,6 +81,7 @@ class TileCacheTests : public CPPUNIT_NS::TestFixture
     //CPPUNIT_TEST(testTileInvalidatePartImpress);
     CPPUNIT_TEST(testTileBeingRenderedHandling);
     CPPUNIT_TEST(testWireIDFilteringOnWSDSide);
+    CPPUNIT_TEST(testLimitTileVersionsOnFly);
 
     CPPUNIT_TEST_SUITE_END();
 
@@ -106,6 +107,7 @@ class TileCacheTests : public CPPUNIT_NS::TestFixture
     void testTileInvalidatePartImpress();
     void testTileBeingRenderedHandling();
     void testWireIDFilteringOnWSDSide();
+    void testLimitTileVersionsOnFly();
 
     void checkTiles(std::shared_ptr<LOOLWebSocket>& socket,
                     const std::string& type,
@@ -1282,6 +1284,66 @@ void TileCacheTests::testWireIDFilteringOnWSDSide()
     CPPUNIT_ASSERT_MESSAGE("Not expected tile message arrived!", tile.empty());
 }
 
+void TileCacheTests::testLimitTileVersionsOnFly()
+{
+    // We have an upper limit (2) for the versions of the same tile wsd send 
out
+    // without getting the tileprocessed message for the first tile message.
+    const char* testname = "testLimitTileVersionsOnFly ";
+
+    std::string documentPath, documentURL;
+    getDocumentPathAndURL("empty.odt", documentPath, documentURL, testname);
+    std::shared_ptr<LOOLWebSocket> socket = loadDocAndGetSocket(_uri, 
documentURL, testname);
+
+    // Set the client visible area
+    sendTextFrame(socket, "clientvisiblearea x=-2662 y=0 width=16000 
height=9875");
+    sendTextFrame(socket, "clientzoom tilepixelwidth=256 tilepixelheight=256 
tiletwipwidth=3200 tiletwipheight=3200");
+
+    // Type one character to trigger sending tiles
+    sendChar(socket, 'x', skNone, testname);
+
+    // Handle all tiles send by wsd
+    bool getTileResp = false;
+    do
+    {
+        std::string tile = getResponseString(socket, "tile:", testname, 1000);
+        getTileResp = !tile.empty();
+    } while(getTileResp);
+
+    // Type an other character to trigger sending tiles
+    sendChar(socket, 'x', skNone, testname);
+
+    // Handle all tiles sent by wsd
+    getTileResp = false;
+    do
+    {
+        std::string tile = getResponseString(socket, "tile:", testname, 1000);
+        getTileResp = !tile.empty();
+    } while(getTileResp);
+
+    // For the third invalidation wsd does not send the new tile since
+    // two versions of the same tile were already sent.
+    sendChar(socket, 'x', skNone, testname);
+
+    std::vector<char> tile1 = getResponseMessage(socket, "tile:", testname, 
1000);
+    CPPUNIT_ASSERT_MESSAGE("Not expected tile message arrived!", 
tile1.empty());
+
+    // When the next tileprocessed message arrive with correct tileID
+    // wsd sends the delayed tile
+    sendTextFrame(socket, "tileprocessed tile=0:0:0:3200:3200");
+
+    int arrivedTiles = 0;
+    bool gotTile = false;
+    do
+    {
+        std::vector<char> tile = getResponseMessage(socket, "tile:", testname, 
1000);
+        gotTile = !tile.empty();
+        if(gotTile)
+            ++arrivedTiles;
+    } while(gotTile);
+
+    CPPUNIT_ASSERT_EQUAL(1, arrivedTiles);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(TileCacheTests);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/wsd/ClientSession.cpp b/wsd/ClientSession.cpp
index 8a4bb18cd..d28915ec8 100644
--- a/wsd/ClientSession.cpp
+++ b/wsd/ClientSession.cpp
@@ -1100,7 +1100,7 @@ void ClientSession::removeOutdatedTilesOnFly()
     {
         auto tileIter = _tilesOnFly.begin();
         double elapsedTimeMs = 
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now()
 - tileIter->second).count();
-        if(elapsedTimeMs > 5000.0)
+        if(elapsedTimeMs > TILE_ROUNDTRIP_TIMEOUT_MS)
         {
             LOG_WRN("Tracker tileID was dropped because of time out. 
Tileprocessed message did not arrive");
             _tilesOnFly.erase(tileIter);
@@ -1110,6 +1110,18 @@ void ClientSession::removeOutdatedTilesOnFly()
     }
 }
 
+size_t ClientSession::countIdenticalTilesOnFly(const TileDesc& tile) const
+{
+    size_t count = 0;
+    std::string tileID = generateTileID(tile);
+    for(auto& tileItem : _tilesOnFly)
+    {
+        if(tileItem.first == tileID)
+            ++count;
+    }
+    return count;
+}
+
 Util::Rectangle ClientSession::getNormalizedVisibleArea() const
 {
     Util::Rectangle normalizedVisArea;
@@ -1242,7 +1254,7 @@ void ClientSession::handleTileInvalidation(const 
std::string& message,
                 Util::Rectangle tileRect (j * _tileWidthTwips, i * 
_tileHeightTwips, _tileWidthTwips, _tileHeightTwips);
                 if(invalidateRect.intersects(tileRect))
                 {
-                    invalidTiles.emplace_back(TileDesc(part, _tileWidthPixel, 
_tileHeightPixel, j * _tileWidthTwips, i * _tileHeightTwips, _tileWidthTwips, 
_tileHeightTwips, -1, 0, -1, false));
+                    invalidTiles.emplace_back(part, _tileWidthPixel, 
_tileHeightPixel, j * _tileWidthTwips, i * _tileHeightTwips, _tileWidthTwips, 
_tileHeightTwips, -1, 0, -1, false);
 
                     TileWireId oldWireId = 0;
                     auto iter = 
_oldWireIds.find(generateTileID(invalidTiles.back()));
@@ -1329,7 +1341,7 @@ void ClientSession::clearTileSubscription()
     _tilesBeingRendered.clear();
 }
 
-std::string ClientSession::generateTileID(const TileDesc& tile)
+std::string ClientSession::generateTileID(const TileDesc& tile) const
 {
     std::ostringstream tileID;
     tileID << tile.getPart() << ":" << tile.getTilePosX() << ":" << 
tile.getTilePosY() << ":"
diff --git a/wsd/ClientSession.hpp b/wsd/ClientSession.hpp
index 38da74801..eb0440046 100644
--- a/wsd/ClientSession.hpp
+++ b/wsd/ClientSession.hpp
@@ -110,6 +110,7 @@ public:
     void clearTilesOnFly();
     size_t getTilesOnFlyCount() const { return _tilesOnFly.size(); }
     void removeOutdatedTilesOnFly();
+    size_t countIdenticalTilesOnFly(const TileDesc& tile) const;
 
     Util::Rectangle getVisibleArea() const { return _clientVisibleArea; }
     /// Visible area can have negative value as position, but we have tiles 
only in the positive range
@@ -174,7 +175,7 @@ private:
                                 const std::shared_ptr<DocumentBroker>& 
docBroker);
 
     /// Generate a unique id for a tile
-    std::string generateTileID(const TileDesc& tile);
+    std::string generateTileID(const TileDesc& tile) const;
 
 private:
     std::weak_ptr<DocumentBroker> _docBroker;
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index c6b589899..02b112a95 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -1424,12 +1424,26 @@ void DocumentBroker::sendRequestedTiles(const 
std::shared_ptr<ClientSession>& se
     std::deque<TileDesc>& requestedTiles = session->getRequestedTiles();
     if (!requestedTiles.empty())
     {
+        size_t delayedTiles = 0;
         std::vector<TileDesc> tilesNeedsRendering;
         while(session->getTilesOnFlyCount() + 
session->getTilesBeingRenderedCount() < tilesOnFlyUpperLimit &&
-              !requestedTiles.empty())
+              !requestedTiles.empty() &&
+              // If we delayed all tiles we don't send any tile (we will when 
next tileprocessed message arrives)
+              delayedTiles < requestedTiles.size())
         {
             TileDesc& tile = *(requestedTiles.begin());
 
+            // We already sent out two versions of the same tile, let's not 
send the third one
+            // until we get a tileprocessed message for this specific tile.
+            if (session->countIdenticalTilesOnFly(tile) >= 2)
+            {
+                requestedTiles.push_back(requestedTiles.front());
+                requestedTiles.pop_front();
+                delayedTiles += 1;
+                LOG_INF("Requested tile was delayed!");
+                continue;
+            }
+
             // Satisfy as many tiles from the cache.
             std::unique_ptr<std::fstream> cachedTile = 
_tileCache->lookupTile(tile);
             if (cachedTile)
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to