common/Protocol.cpp | 32 ++++++ common/Protocol.hpp | 2 kit/Kit.cpp | 133 ++++++++++++++++++--------- loleaflet/src/core/Socket.js | 4 loleaflet/src/layer/tile/CalcTileLayer.js | 14 +- loleaflet/src/layer/tile/ImpressTileLayer.js | 14 +- loleaflet/src/layer/tile/TileLayer.js | 4 loleaflet/src/layer/tile/WriterTileLayer.js | 14 +- test/Makefile.am | 2 test/TileQueueTests.cpp | 28 ++--- test/httpwstest.cpp | 2 wsd/TileDesc.hpp | 85 ++++++++--------- wsd/protocol.txt | 16 +-- 13 files changed, 219 insertions(+), 131 deletions(-)
New commits: commit 73a87493f0d35629d5a16a6be7c720ec2fd726c2 Author: Michael Meeks <michael.me...@collabora.com> Date: Wed Jun 14 17:28:07 2017 +0100 Use WireIds instead of long hashes to identify tiles efficiently. Changes protocol to use 'wid' instead of 'hash' everywhere. Wire-ids are monotonically increasing integers that can be mapped to hash values for all of the hash values and tiles we cache internally. Change-Id: Ibcb25817bab0f453e93d52a6f99d3ff65059e47d diff --git a/common/Protocol.cpp b/common/Protocol.cpp index be1a0b4c..b5e04665 100644 --- a/common/Protocol.cpp +++ b/common/Protocol.cpp @@ -59,6 +59,20 @@ namespace LOOLProtocol return true; } + bool stringToUInt32(const std::string& input, uint32_t& value) + { + try + { + value = std::stoul(input); + } + catch (std::invalid_argument&) + { + return false; + } + + return true; + } + bool stringToUInt64(const std::string& input, uint64_t& value) { try @@ -103,6 +117,21 @@ namespace LOOLProtocol return false; } + bool getTokenUInt32(const std::string& token, const std::string& name, uint32_t& value) + { + if (token.size() > (name.size() + 1) && + token.compare(0, name.size(), name) == 0 && + token[name.size()] == '=') + { + const char* str = token.data() + name.size() + 1; + char* endptr = nullptr; + value = strtoul(str, &endptr, 10); + return (endptr > str); + } + + return false; + } + bool getTokenString(const std::string& token, const std::string& name, std::string& value) { if (token.size() > (name.size() + 1) && diff --git a/common/Protocol.hpp b/common/Protocol.hpp index e26703d5..1e2158a9 100644 --- a/common/Protocol.hpp +++ b/common/Protocol.hpp @@ -42,6 +42,7 @@ namespace LOOLProtocol std::tuple<int, int, std::string> ParseVersion(const std::string& version); bool stringToInteger(const std::string& input, int& value); + bool stringToUInt32(const std::string& input, uint32_t& value); bool stringToUInt64(const std::string& input, uint64_t& value); inline @@ -66,6 +67,7 @@ namespace LOOLProtocol } bool getTokenInteger(const std::string& token, const std::string& name, int& value); + bool getTokenUInt32(const std::string& token, const std::string& name, uint32_t& value); bool getTokenUInt64(const std::string& token, const std::string& name, uint64_t& value); bool getTokenString(const std::string& token, const std::string& name, std::string& value); bool getTokenKeyword(const std::string& token, const std::string& name, const std::map<std::string, int>& map, int& value); diff --git a/kit/Kit.cpp b/kit/Kit.cpp index edf4942f..be07bbb8 100644 --- a/kit/Kit.cpp +++ b/kit/Kit.cpp @@ -284,11 +284,14 @@ namespace class PngCache { typedef std::shared_ptr< std::vector< char > > CacheData; + struct CacheEntry { size_t _hitCount; + TileWireId _wireId; CacheData _data; - CacheEntry(size_t defaultSize) : + CacheEntry(size_t defaultSize, TileWireId id) : _hitCount(1), // Every entry is used at least once; prevent removal at birth. + _wireId(id), _data( new std::vector< char >() ) { _data->reserve( defaultSize ); @@ -299,7 +302,32 @@ class PngCache static const size_t CacheSizeHardLimit = CacheSizeSoftLimit * 2; size_t _cacheHits; size_t _cacheTests; - std::map< uint64_t, CacheEntry > _cache; + TileWireId _nextId; + + std::map< TileBinaryHash, CacheEntry > _cache; + std::map< TileWireId, TileBinaryHash > _wireToHash; + + void clearCache(bool logStats = false) + { + if (logStats) + LOG_DBG("cache clear " << _cache.size() << " items total size " << + _cacheSize << " current hits " << _cacheHits); + _cache.clear(); + _cacheSize = 0; + _cacheHits = 0; + _cacheTests = 0; + _nextId = 1; + } + + // Keep these ids small and wrap them. + TileWireId createNewWireId() + { + TileWireId id = ++_nextId; + // FIXME: if we wrap - we should flush the clients too really ... + if (id < 1) + clearCache(true); + return id; + } void balanceCache() { @@ -324,6 +352,11 @@ class PngCache // Shrink cache when we exceed the size to maximize // the chance of hitting these entries in the future. _cacheSize -= it->second._data->size(); + + auto wIt = _wireToHash.find(it->second._wireId); + assert(wIt != _wireToHash.end()); + _wireToHash.erase(wIt); + it = _cache.erase(it); } else @@ -366,10 +399,10 @@ class PngCache int width, int height, int bufferWidth, int bufferHeight, std::vector<char>& output, LibreOfficeKitTileMode mode, - const uint64_t hash) + TileBinaryHash hash, TileWireId wid) { LOG_DBG("PNG cache with hash " << hash << " missed."); - CacheEntry newEntry(bufferWidth * bufferHeight * 1); + CacheEntry newEntry(bufferWidth * bufferHeight * 1, wid); if (Png::encodeSubBufferToPNG(pixmap, startX, startY, width, height, bufferWidth, bufferHeight, *newEntry._data, mode)) @@ -392,39 +425,51 @@ class PngCache } public: - PngCache() : - _cacheSize(0), - _cacheHits(0), - _cacheTests(0) + PngCache() + { + clearCache(); + } + + TileWireId hashToWireId(TileBinaryHash id) { + TileWireId wid; + if (id == 0) + return 0; + auto it = _cache.find(id); + if (it != _cache.end()) + wid = it->second._wireId; + else + { + wid = createNewWireId(); + _wireToHash.emplace(wid, id); + } + return wid; } bool encodeBufferToPNG(unsigned char* pixmap, int width, int height, std::vector<char>& output, LibreOfficeKitTileMode mode, - uint64_t hash) + TileBinaryHash hash, TileWireId wid) { if (cacheTest(hash, output)) - { return true; - } return cacheEncodeSubBufferToPNG(pixmap, 0, 0, width, height, - width, height, output, mode, hash); + width, height, output, mode, + hash, wid); } bool encodeSubBufferToPNG(unsigned char* pixmap, size_t startX, size_t startY, int width, int height, int bufferWidth, int bufferHeight, std::vector<char>& output, LibreOfficeKitTileMode mode, - uint64_t hash) + TileBinaryHash hash, TileWireId wid) { if (cacheTest(hash, output)) - { return true; - } return cacheEncodeSubBufferToPNG(pixmap, startX, startY, width, height, - bufferWidth, bufferHeight, output, mode, hash); + bufferWidth, bufferHeight, output, mode, + hash, wid); } }; @@ -606,21 +651,9 @@ public: assert(ws && "Expected a non-null websocket."); auto tile = TileDesc::parse(tokens); - // Send back the request with all optional parameters given in the request. - const auto tileMsg = tile.serialize("tile:"); -#if ENABLE_DEBUG - const std::string response = tileMsg + " renderid=" + Util::UniqueId() + "\n"; -#else - const std::string response = tileMsg + "\n"; -#endif - - std::vector<char> output; - output.reserve(response.size() + (4 * tile.getWidth() * tile.getHeight())); - output.resize(response.size()); - std::memcpy(output.data(), response.data(), response.size()); - + size_t pixmapDataSize = 4 * tile.getWidth() * tile.getHeight(); std::vector<unsigned char> pixmap; - pixmap.resize(output.capacity()); + pixmap.resize(pixmapDataSize); std::unique_lock<std::mutex> lock(_documentMutex); if (!_loKitDocument) @@ -647,18 +680,36 @@ public: " ms (" << area / elapsed << " MP/s)."); const auto mode = static_cast<LibreOfficeKitTileMode>(_loKitDocument->getTileMode()); - const uint64_t hash = Png::hashBuffer(pixmap.data(), tile.getWidth(), tile.getHeight()); - if (hash != 0 && tile.getOldHash() == hash) + const TileBinaryHash hash = Png::hashBuffer(pixmap.data(), tile.getWidth(), tile.getHeight()); + TileWireId wid = _pngCache.hashToWireId(hash); + + tile.setWireId(wid); + + // Send back the request with all optional parameters given in the request. + const auto tileMsg = tile.serialize("tile:"); +#if ENABLE_DEBUG + const std::string response = tileMsg + " renderid=" + Util::UniqueId() + "\n"; +#else + const std::string response = tileMsg + "\n"; +#endif + + std::vector<char> output; + output.reserve(response.size() + pixmapDataSize); + output.resize(response.size()); + std::memcpy(output.data(), response.data(), response.size()); + + if (hash != 0 && tile.getOldWireId() == wid) { // The tile content is identical to what the client already has, so skip it - LOG_TRC("Match oldhash==hash (" << hash << "), skipping"); + LOG_TRC("Match oldWireId==wid (" << wid << " for hash " << hash << "), skipping"); return; } - if (!_pngCache.encodeBufferToPNG(pixmap.data(), tile.getWidth(), tile.getHeight(), output, mode, hash)) + if (!_pngCache.encodeBufferToPNG(pixmap.data(), tile.getWidth(), tile.getHeight(), output, mode, hash, wid)) { //FIXME: Return error. //sendTextFrame("error: cmd=tile kind=failure"); + LOG_ERR("Failed to encode tile into PNG."); return; } @@ -742,17 +793,19 @@ public: const uint64_t hash = Png::hashSubBuffer(pixmap.data(), positionX * pixelWidth, positionY * pixelHeight, pixelWidth, pixelHeight, pixmapWidth, pixmapHeight); - if (hash != 0 && tiles[tileIndex].getOldHash() == hash) + TileWireId wireId = _pngCache.hashToWireId(hash); + if (hash != 0 && tiles[tileIndex].getOldWireId() == wireId) { // The tile content is identical to what the client already has, so skip it LOG_TRC("Match for tile #" << tileIndex << " at (" << positionX << "," << - positionY << ") oldhash==hash (" << hash << "), skipping"); + positionY << ") oldhash==hash (" << hash << "), wireId: " << wireId << " skipping"); tiles.erase(tiles.begin() + tileIndex); continue; } if (!_pngCache.encodeSubBufferToPNG(pixmap.data(), positionX * pixelWidth, positionY * pixelHeight, - pixelWidth, pixelHeight, pixmapWidth, pixmapHeight, output, mode, hash)) + pixelWidth, pixelHeight, pixmapWidth, pixmapHeight, output, mode, + hash, wireId)) { //FIXME: Return error. //sendTextFrame("error: cmd=tile kind=failure"); @@ -761,9 +814,9 @@ public: } const auto imgSize = output.size() - oldSize; - LOG_TRC("Encoded tile #" << tileIndex << " at (" << positionX << "," << positionY << ") with oldhash=" << - tiles[tileIndex].getOldHash() << ", hash=" << hash << " in " << imgSize << " bytes."); - tiles[tileIndex].setHash(hash); + LOG_TRC("Encoded tile #" << tileIndex << " at (" << positionX << "," << positionY << ") with oldWireId=" << + tiles[tileIndex].getOldWireId() << ", hash=" << hash << " wireId: " << wireId << " in " << imgSize << " bytes."); + tiles[tileIndex].setWireId(wireId); tiles[tileIndex].setImgSize(imgSize); tileIndex++; } diff --git a/loleaflet/src/core/Socket.js b/loleaflet/src/core/Socket.js index 433c0318..235a5948 100644 --- a/loleaflet/src/core/Socket.js +++ b/loleaflet/src/core/Socket.js @@ -760,8 +760,8 @@ L.Socket = L.Class.extend({ else if (tokens[i].substring(0, 12) === 'rendercount=') { command.rendercount = parseInt(tokens[i].substring(12)); } - else if (tokens[i].startsWith('hash=')) { - command.hash = this.getParameterValue(tokens[i]); + else if (tokens[i].startsWith('wid=')) { + command.wireId = this.getParameterValue(tokens[i]); } } if (command.tileWidth && command.tileHeight && this._map._docLayer) { diff --git a/loleaflet/src/layer/tile/CalcTileLayer.js b/loleaflet/src/layer/tile/CalcTileLayer.js index f0a39644..a863e4a1 100644 --- a/loleaflet/src/layer/tile/CalcTileLayer.js +++ b/loleaflet/src/layer/tile/CalcTileLayer.js @@ -244,7 +244,7 @@ L.CalcTileLayer = L.TileLayer.extend({ var tilePositionsX = ''; var tilePositionsY = ''; - var oldHashes = ''; + var oldWireIds = ''; var needsNewTiles = false; for (var key in this._tiles) { @@ -268,14 +268,14 @@ L.CalcTileLayer = L.TileLayer.extend({ tilePositionsY += ','; } tilePositionsY += tileTopLeft.y; - if (oldHashes !== '') { - oldHashes += ','; + if (oldWireIds !== '') { + oldWireIds += ','; } - if (this._tiles[key].oldhash === undefined) { - oldHashes += '0'; + if (this._tiles[key].oldWireId === undefined) { + oldWireIds += '0'; } else { - oldHashes += this._tiles[key].oldhash; + oldWireIds += this._tiles[key].oldWireId; } needsNewTiles = true; if (this._debug) { @@ -300,7 +300,7 @@ L.CalcTileLayer = L.TileLayer.extend({ 'tileposy=' + tilePositionsY + ' ' + 'tilewidth=' + this._tileWidthTwips + ' ' + 'tileheight=' + this._tileHeightTwips + ' ' + - 'oldhash=' + oldHashes; + 'oldwid=' + oldWireIds; this._map._socket.sendMessage(message, ''); if (this._debug) { diff --git a/loleaflet/src/layer/tile/ImpressTileLayer.js b/loleaflet/src/layer/tile/ImpressTileLayer.js index 209232d8..d2392d1c 100644 --- a/loleaflet/src/layer/tile/ImpressTileLayer.js +++ b/loleaflet/src/layer/tile/ImpressTileLayer.js @@ -351,7 +351,7 @@ L.ImpressTileLayer = L.TileLayer.extend({ var tilePositionsX = ''; var tilePositionsY = ''; - var oldHashes = ''; + var oldWireIds = ''; var needsNewTiles = false; for (var key in this._tiles) { @@ -375,14 +375,14 @@ L.ImpressTileLayer = L.TileLayer.extend({ tilePositionsY += ','; } tilePositionsY += tileTopLeft.y; - if (oldHashes !== '') { - oldHashes += ','; + if (oldWireIds !== '') { + oldWireIds += ','; } - if (this._tiles[key].oldhash === undefined) { - oldHashes += '0'; + if (this._tiles[key].oldWireId === undefined) { + oldWireIds += '0'; } else { - oldHashes += this._tiles[key].oldhash; + oldWireIds += this._tiles[key].oldWireId; } needsNewTiles = true; if (this._debug) { @@ -407,7 +407,7 @@ L.ImpressTileLayer = L.TileLayer.extend({ 'tileposy=' + tilePositionsY + ' ' + 'tilewidth=' + this._tileWidthTwips + ' ' + 'tileheight=' + this._tileHeightTwips + ' ' + - 'oldhash=' + oldHashes; + 'oldwid=' + oldWireIds; this._map._socket.sendMessage(message, ''); if (this._debug) { diff --git a/loleaflet/src/layer/tile/TileLayer.js b/loleaflet/src/layer/tile/TileLayer.js index 109569ce..986a2ca0 100644 --- a/loleaflet/src/layer/tile/TileLayer.js +++ b/loleaflet/src/layer/tile/TileLayer.js @@ -1175,8 +1175,8 @@ L.TileLayer = L.GridLayer.extend({ }); } else if (tile) { - if (command.hash != undefined) { - tile.oldhash = command.hash; + if (command.wireId != undefined) { + tile.oldWireId = command.wireId; } if (this._tiles[key]._invalidCount > 0) { this._tiles[key]._invalidCount -= 1; diff --git a/loleaflet/src/layer/tile/WriterTileLayer.js b/loleaflet/src/layer/tile/WriterTileLayer.js index 5610d010..0b1f1487 100644 --- a/loleaflet/src/layer/tile/WriterTileLayer.js +++ b/loleaflet/src/layer/tile/WriterTileLayer.js @@ -100,7 +100,7 @@ L.WriterTileLayer = L.TileLayer.extend({ var visibleArea = new L.Bounds(visibleTopLeft, visibleBottomRight); var tilePositionsX = ''; var tilePositionsY = ''; - var oldHashes = ''; + var oldWireIds = ''; var needsNewTiles = false; for (var key in this._tiles) { var coords = this._tiles[key].coords; @@ -123,14 +123,14 @@ L.WriterTileLayer = L.TileLayer.extend({ tilePositionsY += ','; } tilePositionsY += tileTopLeft.y; - if (oldHashes !== '') { - oldHashes += ','; + if (oldWireIds !== '') { + oldWireIds += ','; } - if (this._tiles[key].oldhash === undefined) { - oldHashes += '0'; + if (this._tiles[key].oldWireId === undefined) { + oldWireIds += '0'; } else { - oldHashes += this._tiles[key].oldhash; + oldWireIds += this._tiles[key].oldWireId; } needsNewTiles = true; if (this._debug) { @@ -158,7 +158,7 @@ L.WriterTileLayer = L.TileLayer.extend({ 'tileposy=' + tilePositionsY + ' ' + 'tilewidth=' + this._tileWidthTwips + ' ' + 'tileheight=' + this._tileHeightTwips + ' ' + - 'oldhash=' + oldHashes; + 'oldwid=' + oldWireIds; this._map._socket.sendMessage(message, ''); diff --git a/test/Makefile.am b/test/Makefile.am index 50629277..f7f4c090 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -75,7 +75,7 @@ check-local: ./run_unit.sh --log-file test.log --trs-file test.trs # FIXME 2: unit-oob.la fails with symbol undefined: # UnitWSD::testHandleRequest(UnitWSD::TestRequest, UnitHTTPServerRequest&, UnitHTTPServerResponse&) , -TESTS = unit-prefork.la unit-tilecache.la unit-timeout.la # unit-client.la - enable to run unit-tests in wsd ... +TESTS = unit-prefork.la unit-tilecache.la unit-timeout.la # unit-client.la # - enable to run unit-tests in wsd ... else TESTS = ${top_builddir}/test/test endif diff --git a/test/TileQueueTests.cpp b/test/TileQueueTests.cpp index 2bf8e7a7..72f263eb 100644 --- a/test/TileQueueTests.cpp +++ b/test/TileQueueTests.cpp @@ -70,11 +70,11 @@ class TileQueueTests : public CPPUNIT_NS::TestFixture void TileQueueTests::testTileQueuePriority() { - const std::string reqHigh = "tile part=0 width=256 height=256 tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 oldhash=0 hash=0"; - const std::string resHigh = "tile part=0 width=256 height=256 tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 oldhash=0 hash=0 ver=-1"; + const std::string reqHigh = "tile part=0 width=256 height=256 tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 oldwid=0 wid=0"; + const std::string resHigh = "tile part=0 width=256 height=256 tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1"; const TileQueue::Payload payloadHigh(resHigh.data(), resHigh.data() + resHigh.size()); - const std::string reqLow = "tile part=0 width=256 height=256 tileposx=0 tileposy=253440 tilewidth=3840 tileheight=3840 oldhash=0 hash=0"; - const std::string resLow = "tile part=0 width=256 height=256 tileposx=0 tileposy=253440 tilewidth=3840 tileheight=3840 oldhash=0 hash=0 ver=-1"; + const std::string reqLow = "tile part=0 width=256 height=256 tileposx=0 tileposy=253440 tilewidth=3840 tileheight=3840 oldwid=0 wid=0"; + const std::string resLow = "tile part=0 width=256 height=256 tileposx=0 tileposy=253440 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1"; const TileQueue::Payload payloadLow(resLow.data(), resLow.data() + resLow.size()); TileQueue queue; @@ -121,11 +121,11 @@ void TileQueueTests::testTileCombinedRendering() const std::string req3 = "tile part=0 width=256 height=256 tileposx=0 tileposy=3840 tilewidth=3840 tileheight=3840"; const std::string req4 = "tile part=0 width=256 height=256 tileposx=3840 tileposy=3840 tilewidth=3840 tileheight=3840"; - const std::string resHor = "tilecombine part=0 width=256 height=256 tileposx=0,3840 tileposy=0,0 imgsize=0,0 tilewidth=3840 tileheight=3840 ver=-1,-1 oldhash=0,0 hash=0,0"; + const std::string resHor = "tilecombine part=0 width=256 height=256 tileposx=0,3840 tileposy=0,0 imgsize=0,0 tilewidth=3840 tileheight=3840 ver=-1,-1 oldwid=0,0 wid=0,0"; const TileQueue::Payload payloadHor(resHor.data(), resHor.data() + resHor.size()); - const std::string resVer = "tilecombine part=0 width=256 height=256 tileposx=0,0 tileposy=0,3840 imgsize=0,0 tilewidth=3840 tileheight=3840 ver=-1,-1 oldhash=0,0 hash=0,0"; + const std::string resVer = "tilecombine part=0 width=256 height=256 tileposx=0,0 tileposy=0,3840 imgsize=0,0 tilewidth=3840 tileheight=3840 ver=-1,-1 oldwid=0,0 wid=0,0"; const TileQueue::Payload payloadVer(resVer.data(), resVer.data() + resVer.size()); - const std::string resFull = "tilecombine part=0 width=256 height=256 tileposx=0,3840,0 tileposy=0,0,3840 imgsize=0,0,0 tilewidth=3840 tileheight=3840 ver=-1,-1,-1 oldhash=0,0,0 hash=0,0,0"; + const std::string resFull = "tilecombine part=0 width=256 height=256 tileposx=0,3840,0 tileposy=0,0,3840 imgsize=0,0,0 tilewidth=3840 tileheight=3840 ver=-1,-1,-1 oldwid=0,0,0 wid=0,0,0"; const TileQueue::Payload payloadFull(resFull.data(), resFull.data() + resFull.size()); TileQueue queue; @@ -169,7 +169,7 @@ void TileQueueTests::testTileRecombining() // but when we later extract that, it is just one "tilecombine" message std::string message(payloadAsString(queue.get())); - CPPUNIT_ASSERT_EQUAL(std::string("tilecombine part=0 width=256 height=256 tileposx=7680,0,3840 tileposy=0,0,0 imgsize=0,0,0 tilewidth=3840 tileheight=3840 ver=-1,-1,-1 oldhash=0,0,0 hash=0,0,0"), message); + CPPUNIT_ASSERT_EQUAL(std::string("tilecombine part=0 width=256 height=256 tileposx=7680,0,3840 tileposy=0,0,0 imgsize=0,0,0 tilewidth=3840 tileheight=3840 ver=-1,-1,-1 oldwid=0,0,0 wid=0,0,0"), message); // and nothing remains in the queue CPPUNIT_ASSERT_EQUAL(0, static_cast<int>(queue._queue.size())); @@ -189,10 +189,10 @@ void TileQueueTests::testViewOrder() const std::vector<std::string> tiles = { - "tile part=0 width=256 height=256 tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 oldhash=0 hash=0 ver=-1", - "tile part=0 width=256 height=256 tileposx=0 tileposy=7680 tilewidth=3840 tileheight=3840 oldhash=0 hash=0 ver=-1", - "tile part=0 width=256 height=256 tileposx=0 tileposy=15360 tilewidth=3840 tileheight=3840 oldhash=0 hash=0 ver=-1", - "tile part=0 width=256 height=256 tileposx=0 tileposy=23040 tilewidth=3840 tileheight=3840 oldhash=0 hash=0 ver=-1" + "tile part=0 width=256 height=256 tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1", + "tile part=0 width=256 height=256 tileposx=0 tileposy=7680 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1", + "tile part=0 width=256 height=256 tileposx=0 tileposy=15360 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1", + "tile part=0 width=256 height=256 tileposx=0 tileposy=23040 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1" }; for (auto &tile : tiles) @@ -237,8 +237,8 @@ void TileQueueTests::testPreviewsDeprioritization() // the previews const std::vector<std::string> tiles = { - "tile part=0 width=256 height=256 tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 oldhash=0 hash=0 ver=-1", - "tile part=0 width=256 height=256 tileposx=0 tileposy=7680 tilewidth=3840 tileheight=3840 oldhash=0 hash=0 ver=-1" + "tile part=0 width=256 height=256 tileposx=0 tileposy=0 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1", + "tile part=0 width=256 height=256 tileposx=0 tileposy=7680 tilewidth=3840 tileheight=3840 oldwid=0 wid=0 ver=-1" }; for (auto &preview : previews) diff --git a/test/httpwstest.cpp b/test/httpwstest.cpp index 79c64fa4..c207b5ea 100644 --- a/test/httpwstest.cpp +++ b/test/httpwstest.cpp @@ -1876,7 +1876,7 @@ void HTTPWSTest::testCalcRenderAfterNewView53() sendTextFrame(socket, "key type=input char=0 key=1031", testname); // Get tile. - const auto req = "tilecombine part=0 width=256 height=256 tileposx=0 tileposy=291840 tilewidth=3840 tileheight=3840 oldhash=0"; + const auto req = "tilecombine part=0 width=256 height=256 tileposx=0 tileposy=291840 tilewidth=3840 tileheight=3840 oldwid=0"; const std::vector<char> tile1 = getTileAndSave(socket, req, "/tmp/calc_render_53_orig.png", testname); diff --git a/wsd/TileDesc.hpp b/wsd/TileDesc.hpp index 0004c1e7..a4c61636 100644 --- a/wsd/TileDesc.hpp +++ b/wsd/TileDesc.hpp @@ -20,6 +20,9 @@ #include "Exceptions.hpp" #include "Protocol.hpp" +typedef uint32_t TileWireId; +typedef uint64_t TileBinaryHash; + /// Tile Descriptor /// Represents a tile's coordinates and dimensions. class TileDesc @@ -37,8 +40,8 @@ public: _imgSize(imgSize), _id(id), _broadcast(broadcast), - _oldHash(0), - _hash(0) + _oldWireId(0), + _wireId(0) { if (_part < 0 || _width <= 0 || @@ -66,10 +69,10 @@ public: void setImgSize(const int imgSize) { _imgSize = imgSize; } int getId() const { return _id; } bool getBroadcast() const { return _broadcast; } - void setOldHash(uint64_t hash) { _oldHash = hash; } - uint64_t getOldHash() const { return _oldHash; } - void setHash(uint64_t hash) { _hash = hash; } - uint64_t getHash() const { return _hash; } + void setOldWireId(TileWireId id) { _oldWireId = id; } + TileWireId getOldWireId() const { return _oldWireId; } + void setWireId(TileWireId id) { _wireId = id; } + TileWireId getWireId() const { return _wireId; } bool operator==(const TileDesc& other) const { @@ -145,8 +148,8 @@ public: << " tileposy=" << _tilePosY << " tilewidth=" << _tileWidth << " tileheight=" << _tileHeight - << " oldhash=" << _oldHash - << " hash=" << _hash; + << " oldwid=" << _oldWireId + << " wid=" << _wireId; // Anything after ver is optional. oss << " ver=" << _ver; @@ -181,13 +184,13 @@ public: pairs["imgsize"] = 0; pairs["id"] = -1; - uint64_t oldHash = 0; - uint64_t hash = 0; + TileWireId oldWireId = 0; + TileWireId wireId = 0; for (size_t i = 0; i < tokens.size(); ++i) { - if (LOOLProtocol::getTokenUInt64(tokens[i], "oldhash", oldHash)) + if (LOOLProtocol::getTokenUInt32(tokens[i], "oldwid", oldWireId)) ; - else if (LOOLProtocol::getTokenUInt64(tokens[i], "hash", hash)) + else if (LOOLProtocol::getTokenUInt32(tokens[i], "wid", wireId)) ; else { @@ -209,8 +212,8 @@ public: pairs["tilewidth"], pairs["tileheight"], pairs["ver"], pairs["imgsize"], pairs["id"], broadcast); - result.setOldHash(oldHash); - result.setHash(hash); + result.setOldWireId(oldWireId); + result.setWireId(wireId); return result; } @@ -233,8 +236,8 @@ private: int _imgSize; //< Used for responses. int _id; bool _broadcast; - uint64_t _oldHash; - uint64_t _hash; + TileWireId _oldWireId; + TileWireId _wireId; }; /// One or more tile header. @@ -247,8 +250,8 @@ private: const std::string& tilePositionsX, const std::string& tilePositionsY, int tileWidth, int tileHeight, const std::string& vers, const std::string& imgSizes, int id, - const std::string& oldHashes, - const std::string& hashes) : + const std::string& oldWireIds, + const std::string& wireIds) : _part(part), _width(width), _height(height), @@ -269,8 +272,8 @@ private: Poco::StringTokenizer positionYtokens(tilePositionsY, ",", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM); Poco::StringTokenizer imgSizeTokens(imgSizes, ",", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM); Poco::StringTokenizer verTokens(vers, ",", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM); - Poco::StringTokenizer oldHashTokens(oldHashes, ",", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM); - Poco::StringTokenizer hashTokens(hashes, ",", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM); + Poco::StringTokenizer oldWireIdTokens(oldWireIds, ",", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM); + Poco::StringTokenizer wireIdTokens(wireIds, ",", Poco::StringTokenizer::TOK_IGNORE_EMPTY | Poco::StringTokenizer::TOK_TRIM); const auto numberOfPositions = positionXtokens.count(); @@ -278,8 +281,8 @@ private: if (numberOfPositions != positionYtokens.count() || (!imgSizes.empty() && numberOfPositions != imgSizeTokens.count()) || (!vers.empty() && numberOfPositions != verTokens.count()) || - (!oldHashes.empty() && numberOfPositions != oldHashTokens.count()) || - (!hashes.empty() && numberOfPositions != hashTokens.count())) + (!oldWireIds.empty() && numberOfPositions != oldWireIdTokens.count()) || + (!wireIds.empty() && numberOfPositions != wireIdTokens.count())) { throw BadArgumentException("Invalid tilecombine descriptor. Unequal number of tiles in parameters."); } @@ -310,21 +313,21 @@ private: throw BadArgumentException("Invalid 'ver' in tilecombine descriptor."); } - uint64_t oldHash = 0; - if (oldHashTokens.count() && !LOOLProtocol::stringToUInt64(oldHashTokens[i], oldHash)) + TileWireId oldWireId = 0; + if (oldWireIdTokens.count() && !LOOLProtocol::stringToUInt32(oldWireIdTokens[i], oldWireId)) { throw BadArgumentException("Invalid tilecombine descriptor."); } - uint64_t hash = 0; - if (hashTokens.count() && !LOOLProtocol::stringToUInt64(hashTokens[i], hash)) + TileWireId wireId = 0; + if (wireIdTokens.count() && !LOOLProtocol::stringToUInt32(wireIdTokens[i], wireId)) { throw BadArgumentException("Invalid tilecombine descriptor."); } _tiles.emplace_back(_part, _width, _height, x, y, _tileWidth, _tileHeight, ver, imgSize, id, false); - _tiles.back().setOldHash(oldHash); - _tiles.back().setHash(hash); + _tiles.back().setOldWireId(oldWireId); + _tiles.back().setWireId(wireId); } } @@ -378,17 +381,17 @@ public: } oss.seekp(-1, std::ios_base::cur); // Ditto. - oss << " oldhash="; + oss << " oldwid="; for (const auto& tile : _tiles) { - oss << tile.getOldHash() << ','; + oss << tile.getOldWireId() << ','; } oss.seekp(-1, std::ios_base::cur); // Ditto - oss << " hash="; + oss << " wid="; for (const auto& tile : _tiles) { - oss << tile.getHash() << ','; + oss << tile.getWireId() << ','; } oss.seekp(-1, std::ios_base::cur); // See beow. @@ -416,8 +419,8 @@ public: std::string tilePositionsY; std::string imgSizes; std::string versions; - std::string oldhashes; - std::string hashes; + std::string oldwireIds; + std::string wireIds; for (const auto& token : tokens) { @@ -441,13 +444,13 @@ public: { versions = value; } - else if (name == "oldhash") + else if (name == "oldwid") { - oldhashes = value; + oldwireIds = value; } - else if (name == "hash") + else if (name == "wid") { - hashes = value; + wireIds = value; } else { @@ -464,7 +467,7 @@ public: tilePositionsX, tilePositionsY, pairs["tilewidth"], pairs["tileheight"], versions, - imgSizes, pairs["id"], oldhashes, hashes); + imgSizes, pairs["id"], oldwireIds, wireIds); } /// Deserialize a TileDesc from a string format. @@ -488,8 +491,8 @@ public: xs << tile.getTilePosX() << ','; ys << tile.getTilePosY() << ','; vers << tile.getVersion() << ','; - oldhs << tile.getOldHash() << ','; - hs << tile.getHash() << ','; + oldhs << tile.getOldWireId() << ','; + hs << tile.getWireId() << ','; } vers.seekp(-1, std::ios_base::cur); // Remove last comma. diff --git a/wsd/protocol.txt b/wsd/protocol.txt index eaa30727..281aa257 100644 --- a/wsd/protocol.txt +++ b/wsd/protocol.txt @@ -129,11 +129,10 @@ status styles -tile part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<ypos> tilewidth=<tileWidth> tileheight=<tileHeight> [timestamp=<time>] [id=<id> broadcast=<yesOrNo>] [oldhash=<hash>] +tile part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<ypos> tilewidth=<tileWidth> tileheight=<tileHeight> [timestamp=<time>] [id=<id> broadcast=<yesOrNo>] [oldwid=<wireId>] Parameters are numbers except broadcast which is 'yes' or 'no' and - hash which is a 64-bit hash. (There is no need for the client to - parse it into a number, it can be treated as an opaque string.) + wireId which is an opaque string identifier unique to this tile. Note: id must be echoed back in the response verbatim. It and the following parameter, broadcast, are used when rendering slide @@ -144,7 +143,7 @@ tile part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<y tilecombine <parameters> Accepts same parameters as the 'tile' message except that - parameters 'tileposx', 'tileposy' and 'oldhash' are + parameters 'tileposx', 'tileposy' and 'oldwid are comma-separated lists, and the number of elements in each must be same. @@ -323,16 +322,17 @@ textselectioncontent: <content> Current selection's content -tile: part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<ypos> tilewidth=<tileWidth> tileheight=<tileHeight> [timestamp=<time>] [renderid=<id>] [hash=<hash>] +tile: part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<ypos> tilewidth=<tileWidth> tileheight=<tileHeight> [timestamp=<time>] [renderid=<id>] [wid=<wireId>] <binaryPngImage> The parameters from the corresponding 'tile' command. In a debug build, the renderid is either a unique identifier, different for each actual call to LibreOfficeKit to render a tile, - or the string 'cached' if the tile was found in the cache. hash is - a hash of the tile contents, and can be included by the client in - the next 'tile' message requesting the same tile. + or the string 'cached' if the tile was found in the cache. WireId + is a unique reference to a hashed tile on the server, and can + be included by the client in the next 'tile' message requesting + the same tile. commandresult: <payload> This is used to acknowledge the commands from the client. commit 8fb48811eccbf8f6d77919ce91c3cd918de15f56 Author: Michael Meeks <michael.me...@collabora.com> Date: Tue Jun 20 21:49:02 2017 +0100 Protocol - only match complete token names. Change-Id: I027e29da8cc6c48a0d896fa41516934a3ff71b43 diff --git a/common/Protocol.cpp b/common/Protocol.cpp index 0aa50c47..be1a0b4c 100644 --- a/common/Protocol.cpp +++ b/common/Protocol.cpp @@ -188,8 +188,9 @@ namespace LOOLProtocol auto pos = message.find(name); while (pos != std::string::npos) { + bool spaceBefore = pos == 0 || message[pos-1] == ' '; const auto beg = pos + name.size(); - if (message[beg] == '=') + if (spaceBefore && message[beg] == '=') { const auto end = message.find_first_of(" \n", beg); value = message.substr(beg + 1, end - beg - 1); _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits