Wait tileprocessed message from client to send new bunch of tiles
We always one bunch of tiles (e.g. all tiles invalidated) and we are waiting until client send tileprocessed message back for all tiles before sending the new tiles. By canceltiles message we drop every previously requested tiles and make wsd ready to send new tiles, which will be requested by the client in theory. Change-Id: I9901420ada549e962ffaf5e6bd58e52b86bd129d
This commit is contained in:
parent
57cdd68fcf
commit
15afe2c0fb
6 changed files with 137 additions and 31 deletions
|
@ -1436,6 +1436,9 @@ L.TileLayer = L.GridLayer.extend({
|
|||
tile.el.src = img;
|
||||
}
|
||||
L.Log.log(textMsg, L.INCOMING, key);
|
||||
|
||||
// Send acknowledgment, that the tile message arrived
|
||||
this._map._socket.sendMessage('tileprocessed tile= ' + key);
|
||||
},
|
||||
|
||||
_tileOnLoad: function (done, tile) {
|
||||
|
|
|
@ -54,7 +54,8 @@ ClientSession::ClientSession(const std::string& id,
|
|||
_tileWidthPixel(0),
|
||||
_tileHeightPixel(0),
|
||||
_tileWidthTwips(0),
|
||||
_tileHeightTwips(0)
|
||||
_tileHeightTwips(0),
|
||||
_tilesOnFly(0)
|
||||
{
|
||||
assert(!creatingPngThumbnail || thumbnailFile != "");
|
||||
const size_t curConnections = ++LOOLWSD::NumConnections;
|
||||
|
@ -138,6 +139,7 @@ bool ClientSession::_handleInput(const char *buffer, int length)
|
|||
return loadDocument(buffer, length, tokens, docBroker);
|
||||
}
|
||||
else if (tokens[0] != "canceltiles" &&
|
||||
tokens[0] != "tileprocessed" &&
|
||||
tokens[0] != "clientzoom" &&
|
||||
tokens[0] != "clientvisiblearea" &&
|
||||
tokens[0] != "outlinestate" &&
|
||||
|
@ -329,6 +331,13 @@ bool ClientSession::_handleInput(const char *buffer, int length)
|
|||
return forwardToChild(std::string(buffer, length), docBroker);
|
||||
}
|
||||
}
|
||||
else if (tokens[0] == "tileprocessed")
|
||||
{
|
||||
if(_tilesOnFly > 0) // canceltiles message can zero this value
|
||||
--_tilesOnFly;
|
||||
docBroker->sendRequestedTiles(shared_from_this());
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tokens[0] == "key")
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
#include "DocumentBroker.hpp"
|
||||
#include <Poco/URI.h>
|
||||
#include <Rectangle.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
class DocumentBroker;
|
||||
|
||||
|
||||
/// Represents a session to a LOOL client, in the WSD process.
|
||||
class ClientSession final : public Session, public std::enable_shared_from_this<ClientSession>
|
||||
{
|
||||
|
@ -107,6 +109,12 @@ public:
|
|||
/// Set WOPI fileinfo object
|
||||
void setWopiFileInfo(std::unique_ptr<WopiStorage::WOPIFileInfo>& wopiFileInfo) { _wopiFileInfo = std::move(wopiFileInfo); }
|
||||
|
||||
boost::optional<TileCombined>& getRequestedTiles() { return _requestedTiles; }
|
||||
|
||||
int getTilesOnFly() const { return _tilesOnFly; }
|
||||
void setTilesOnFly(int tilesOnFly) { _tilesOnFly = tilesOnFly; }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/// SocketHandler: disconnection event.
|
||||
|
@ -195,8 +203,13 @@ private:
|
|||
|
||||
// Type of the docuemnt, extracter from status message
|
||||
std::string _docType;
|
||||
|
||||
int _tilesOnFly;
|
||||
|
||||
boost::optional<TileCombined> _requestedTiles;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
|
|
@ -1290,61 +1290,136 @@ void DocumentBroker::handleTileCombinedRequest(TileCombined& tileCombined,
|
|||
|
||||
LOG_TRC("TileCombined request for " << tileCombined.serialize());
|
||||
|
||||
// Satisfy as many tiles from the cache.
|
||||
std::vector<TileDesc> tiles;
|
||||
// Check which newly requested tiles needs rendering.
|
||||
std::vector<TileDesc> tilesNeedsRendering;
|
||||
for (auto& tile : tileCombined.getTiles())
|
||||
{
|
||||
std::unique_ptr<std::fstream> cachedTile = _tileCache->lookupTile(tile);
|
||||
if (cachedTile)
|
||||
{
|
||||
//TODO: Combine the response to reduce latency.
|
||||
#if ENABLE_DEBUG
|
||||
const std::string response = tile.serialize("tile:") + " renderid=cached\n";
|
||||
#else
|
||||
const std::string response = tile.serialize("tile:") + "\n";
|
||||
#endif
|
||||
|
||||
std::vector<char> output;
|
||||
output.reserve(static_cast<size_t>(4) * tile.getWidth() * tile.getHeight());
|
||||
output.resize(response.size());
|
||||
std::memcpy(output.data(), response.data(), response.size());
|
||||
|
||||
assert(cachedTile->is_open());
|
||||
cachedTile->seekg(0, std::ios_base::end);
|
||||
const size_t pos = output.size();
|
||||
std::streamsize size = cachedTile->tellg();
|
||||
output.resize(pos + size);
|
||||
cachedTile->seekg(0, std::ios_base::beg);
|
||||
cachedTile->read(output.data() + pos, size);
|
||||
if(cachedTile)
|
||||
cachedTile->close();
|
||||
|
||||
session->sendBinaryFrame(output.data(), output.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not cached, needs rendering.
|
||||
tile.setVersion(++_tileVersion);
|
||||
tileCache().subscribeToTileRendering(tile, session);
|
||||
tiles.push_back(tile);
|
||||
tilesNeedsRendering.push_back(tile);
|
||||
_debugRenderedTileCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tiles.empty())
|
||||
// Send rendering request
|
||||
if (!tilesNeedsRendering.empty())
|
||||
{
|
||||
TileCombined newTileCombined = TileCombined::create(tiles);
|
||||
TileCombined newTileCombined = TileCombined::create(tilesNeedsRendering);
|
||||
|
||||
// Forward to child to render.
|
||||
const std::string req = newTileCombined.serialize("tilecombine");
|
||||
LOG_DBG("Sending residual tilecombine: " << req);
|
||||
_childProcess->sendTextFrame(req);
|
||||
}
|
||||
|
||||
// Accumulate tiles
|
||||
boost::optional<TileCombined>& requestedTiles = session->getRequestedTiles();
|
||||
if(requestedTiles == boost::none)
|
||||
{
|
||||
requestedTiles = TileCombined::create(tileCombined.getTiles());
|
||||
}
|
||||
// Drop duplicated tiles, but use newer version number
|
||||
else
|
||||
{
|
||||
for (const auto& newTile : tileCombined.getTiles())
|
||||
{
|
||||
const TileDesc& firstOldTile = requestedTiles.get().getTiles()[0];
|
||||
if(newTile.getPart() != firstOldTile.getPart() ||
|
||||
newTile.getWidth() != firstOldTile.getWidth() ||
|
||||
newTile.getHeight() != firstOldTile.getHeight() ||
|
||||
newTile.getTileWidth() != firstOldTile.getTileWidth() ||
|
||||
newTile.getTileHeight() != firstOldTile.getTileHeight() )
|
||||
{
|
||||
LOG_WRN("Different visible area information in tile requests");
|
||||
}
|
||||
|
||||
bool tileFound = false;
|
||||
for (auto& oldTile : requestedTiles.get().getTiles())
|
||||
{
|
||||
if(oldTile.getTilePosX() == newTile.getTilePosX() &&
|
||||
oldTile.getTilePosY() == newTile.getTilePosY() )
|
||||
{
|
||||
oldTile.setVersion(newTile.getVersion());
|
||||
oldTile.setOldWireId(newTile.getOldWireId());
|
||||
oldTile.setWireId(newTile.getWireId());
|
||||
tileFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!tileFound)
|
||||
requestedTiles.get().getTiles().push_back(newTile);
|
||||
}
|
||||
}
|
||||
|
||||
lock.unlock();
|
||||
lock.release();
|
||||
sendRequestedTiles(session);
|
||||
}
|
||||
|
||||
void DocumentBroker::sendRequestedTiles(const std::shared_ptr<ClientSession>& session)
|
||||
{
|
||||
assert(session->getTilesOnFly() >= 0);
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
|
||||
// All tiles were processed on client side what we sent last time, so we can send a new banch of tiles
|
||||
// which was invalidated / requested in the meantime
|
||||
boost::optional<TileCombined>& requestedTiles = session->getRequestedTiles();
|
||||
if(session->getTilesOnFly() == 0 && requestedTiles != boost::none && !requestedTiles.get().getTiles().empty())
|
||||
{
|
||||
session->setTilesOnFly(requestedTiles.get().getTiles().size());
|
||||
|
||||
// Satisfy as many tiles from the cache.
|
||||
for (auto& tile : requestedTiles.get().getTiles())
|
||||
{
|
||||
std::unique_ptr<std::fstream> cachedTile = _tileCache->lookupTile(tile);
|
||||
if (cachedTile)
|
||||
{
|
||||
//TODO: Combine the response to reduce latency.
|
||||
#if ENABLE_DEBUG
|
||||
const std::string response = tile.serialize("tile:") + " renderid=cached\n";
|
||||
#else
|
||||
const std::string response = tile.serialize("tile:") + "\n";
|
||||
#endif
|
||||
|
||||
std::vector<char> output;
|
||||
output.reserve(static_cast<size_t>(4) * tile.getWidth() * tile.getHeight());
|
||||
output.resize(response.size());
|
||||
std::memcpy(output.data(), response.data(), response.size());
|
||||
|
||||
assert(cachedTile->is_open());
|
||||
cachedTile->seekg(0, std::ios_base::end);
|
||||
const auto pos = output.size();
|
||||
std::streamsize size = cachedTile->tellg();
|
||||
output.resize(pos + size);
|
||||
cachedTile->seekg(0, std::ios_base::beg);
|
||||
cachedTile->read(output.data() + pos, size);
|
||||
cachedTile->close();
|
||||
|
||||
session->sendBinaryFrame(output.data(), output.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not cached, needs rendering. Rendering request was already sent
|
||||
tileCache().subscribeToTileRendering(tile, session);
|
||||
}
|
||||
}
|
||||
requestedTiles = boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentBroker::cancelTileRequests(const std::shared_ptr<ClientSession>& session)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
|
||||
// Clear tile requests
|
||||
session->setTilesOnFly(0);
|
||||
session->getRequestedTiles() = boost::none;
|
||||
|
||||
const std::string canceltiles = tileCache().cancelTiles(session);
|
||||
if (!canceltiles.empty())
|
||||
{
|
||||
|
|
|
@ -301,6 +301,7 @@ public:
|
|||
void handleDialogRequest(const std::string& dialogCmd);
|
||||
void handleTileCombinedRequest(TileCombined& tileCombined,
|
||||
const std::shared_ptr<ClientSession>& session);
|
||||
void sendRequestedTiles(const std::shared_ptr<ClientSession>& session);
|
||||
void cancelTileRequests(const std::shared_ptr<ClientSession>& session);
|
||||
void handleTileResponse(const std::vector<char>& payload);
|
||||
void handleDialogPaintResponse(const std::vector<char>& payload, bool child);
|
||||
|
|
|
@ -31,6 +31,11 @@ canceltiles
|
|||
parameter. There is no guarantee of exactly which tile: messages
|
||||
might still be sent back to the client.
|
||||
|
||||
tileprocessed tile=<tileid>
|
||||
|
||||
Previously sent tile (server -> client) arrived and processed by the client.
|
||||
Tileid has the next stucture : <tile x coord>:<tile y coord>:<zoom level>:<selected part>
|
||||
|
||||
downloadas name=<fileName> id=<id> format=<document format> options=<SkipImages, etc>
|
||||
|
||||
Exports the current document to the desired format and returns a download URL
|
||||
|
|
Loading…
Reference in a new issue