loolwsd/ChildProcessSession.cpp | 11 ++++++++++- loolwsd/Connect.cpp | 34 ++++++++++++++++++++++++++++------ loolwsd/LOOLProtocol.cpp | 30 ++++++++++++++++++++++++++++++ loolwsd/LOOLProtocol.hpp | 6 ++++++ loolwsd/MasterProcessSession.cpp | 28 ++++++++++++++++++++-------- loolwsd/Util.cpp | 12 +++++++++--- loolwsd/Util.hpp | 3 +++ loolwsd/protocol.txt | 9 +++++++-- 8 files changed, 113 insertions(+), 20 deletions(-)
New commits: commit 5a509f9211a5b24dc0a8c0008d3c24e0448e41d0 Author: Tor Lillqvist <[email protected]> Date: Wed Apr 20 18:44:25 2016 +0300 In a debug build, say in the tile: reponse also whether it was found in cache Also, do the construction of the response string in MasterProcessSession::sendTile() only when it is actually going to be used. diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp index 0320de1..0dee495 100644 --- a/loolwsd/MasterProcessSession.cpp +++ b/loolwsd/MasterProcessSession.cpp @@ -7,6 +7,8 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "config.h" + #include <Poco/FileStream.h> #include <Poco/JSON/Object.h> #include <Poco/JSON/Parser.h> @@ -572,16 +574,22 @@ void MasterProcessSession::sendTile(const char *buffer, int length, StringTokeni return; } - const std::string response = "tile: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()) + "\n"; - - std::vector<char> output; - output.reserve(4 * width * height); - output.resize(response.size()); - std::memcpy(output.data(), response.data(), response.size()); - std::unique_ptr<std::fstream> cachedTile = _docBroker->tileCache().lookupTile(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight); + if (cachedTile) { + std::string response = "tile: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()); + +#if ENABLE_DEBUG + response += " renderid=cached"; +#endif + response += "\n"; + + std::vector<char> output; + output.reserve(4 * width * height); + output.resize(response.size()); + std::memcpy(output.data(), response.data(), response.size()); + assert(cachedTile->is_open()); cachedTile->seekg(0, std::ios_base::end); size_t pos = output.size(); @@ -691,6 +699,10 @@ void MasterProcessSession::sendCombinedTiles(const char* /*buffer*/, int /*lengt oss << " timestamp=" << reqTimestamp; } +#if ENABLE_DEBUG + oss << " renderid=cached"; +#endif + oss << "\n"; const std::string response = oss.str(); diff --git a/loolwsd/protocol.txt b/loolwsd/protocol.txt index 2c79445..1d2324d 100644 --- a/loolwsd/protocol.txt +++ b/loolwsd/protocol.txt @@ -237,9 +237,10 @@ tile: part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=< The parameters from the corresponding 'tile' command. - Additionally, in a debug build, the renderid is a unique + Additionally, in a debug build, the renderid is either a unique identifier, different for each actual call to LibreOfficeKit to - render a tile. + render a tile, or the string 'cached' if the tile was found in the + cache. Each LOK_CALLBACK_FOO_BAR callback causes a corresponding message to the client, consisting of the FOO_BAR part in lowercase, without commit 842525c25cb74bfd1fc62b5e4a65cacf811b590b Author: Tor Lillqvist <[email protected]> Date: Wed Apr 20 18:31:16 2016 +0300 Guard against mixing up cout output from separate threads diff --git a/loolwsd/Connect.cpp b/loolwsd/Connect.cpp index 8f64ff3..8c10f27 100644 --- a/loolwsd/Connect.cpp +++ b/loolwsd/Connect.cpp @@ -13,6 +13,7 @@ #include <cstring> #include <fstream> #include <iostream> +#include <mutex> #include <Poco/Version.h> #include <Poco/Net/AcceptCertificateHandler.h> @@ -68,6 +69,7 @@ using Poco::URI; using Poco::Util::Application; static bool closeExpected = false; +static std::mutex coutMutex; class Output: public Runnable { @@ -89,7 +91,10 @@ public: n = _ws.receiveFrame(buffer, sizeof(buffer), flags); if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE) { - std::cout << "Got " << n << " bytes: " << getAbbreviatedMessage(buffer, n) << std::endl; + { + std::unique_lock<std::mutex> lock(coutMutex); + std::cout << "Got " << n << " bytes: " << getAbbreviatedMessage(buffer, n) << std::endl; + } std::string firstLine = getFirstLine(buffer, n); StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); @@ -109,12 +114,17 @@ public: } } while (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE); - std::cout << "CLOSE frame received" << std::endl; + + { + std::unique_lock<std::mutex> lock(coutMutex); + std::cout << "CLOSE frame received" << std::endl; + } if (!closeExpected) std::_Exit(Application::EXIT_SOFTWARE); } catch (WebSocketException& exc) { + std::unique_lock<std::mutex> lock(coutMutex); std::cout << "Got exception " << exc.message() << std::endl; } } @@ -184,7 +194,10 @@ protected: { // Accept an input line "sleep <n>" that makes us sleep a number of seconds. long sleepTime = std::stol(line.substr(std::string("sleep").length())); - std::cout << "Sleeping " << sleepTime << " seconds" << std::endl; + { + std::unique_lock<std::mutex> lock(coutMutex); + std::cout << "Sleeping " << sleepTime << " seconds" << std::endl; + } Thread::sleep(sleepTime * 1000); } else if (line == "exit") @@ -192,7 +205,10 @@ protected: // While hacking on LOOL and editing input files for this program back and forth it // is a good idea to be able to add an enforced exit in the middle of the input // file. - std::cout << "Exiting" << std::endl; + { + std::unique_lock<std::mutex> lock(coutMutex); + std::cout << "Exiting" << std::endl; + } break; } else if (line.find("#") == 0) @@ -201,12 +217,18 @@ protected: } else { - std::cout << "Sending: '" << line << "'" << std::endl; + { + std::unique_lock<std::mutex> lock(coutMutex); + std::cout << "Sending: '" << line << "'" << std::endl; + } ws.sendFrame(line.c_str(), line.size()); } } - std::cout << "Shutting down websocket" << std::endl; + { + std::unique_lock<std::mutex> lock(coutMutex); + std::cout << "Shutting down websocket" << std::endl; + } closeExpected = true; ws.shutdown(); thread.join(); commit 77a91c4b2e1fe1ea74f8a1e60c45cd3f4e1fd5c2 Author: Tor Lillqvist <[email protected]> Date: Wed Apr 20 17:06:08 2016 +0300 In debug builds append a renderid=<unique-id> token to tile: responses Will be used in unit test to verify that several clients of the same document asking for the same tile simultaneously indeed do cause just one tile rendering to take place. diff --git a/loolwsd/ChildProcessSession.cpp b/loolwsd/ChildProcessSession.cpp index 0bdf33e..7fbebcf 100644 --- a/loolwsd/ChildProcessSession.cpp +++ b/loolwsd/ChildProcessSession.cpp @@ -700,7 +700,12 @@ void ChildProcessSession::sendTile(const char* /*buffer*/, int /*length*/, Strin if (_multiView) _loKitDocument->pClass->setView(_loKitDocument, _viewId); - const std::string response = "tile: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()) + "\n"; + std::string response = "tile: " + Poco::cat(std::string(" "), tokens.begin() + 1, tokens.end()); + +#if ENABLE_DEBUG + response += " renderid=" + Util::UniqueId(); +#endif + response += "\n"; std::vector<char> output; output.reserve(response.size() + (4 * width * height)); @@ -853,6 +858,10 @@ void ChildProcessSession::sendCombinedTiles(const char* /*buffer*/, int /*length if (reqTimestamp != "") response += " timestamp=" + reqTimestamp; +#if ENABLE_DEBUG + response += " renderid=" + Util::UniqueId(); +#endif + response += "\n"; std::vector<char> output; diff --git a/loolwsd/protocol.txt b/loolwsd/protocol.txt index 989dc13..2c79445 100644 --- a/loolwsd/protocol.txt +++ b/loolwsd/protocol.txt @@ -232,11 +232,15 @@ textselectioncontent: <content> Current selection's content -tile: part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<ypos> tilewidth=<tileWidth> tileheight=<tileHeight> [timestamp=<time>] +tile: part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<ypos> tilewidth=<tileWidth> tileheight=<tileHeight> [timestamp=<time>] [renderid=<id>] <binaryPngImage> The parameters from the corresponding 'tile' command. + Additionally, in a debug build, the renderid is a unique + identifier, different for each actual call to LibreOfficeKit to + render a tile. + Each LOK_CALLBACK_FOO_BAR callback causes a corresponding message to the client, consisting of the FOO_BAR part in lowercase, without underscore, followed by a colon, space and the callback payload. For commit 7b47548020ee23b5f8191e464ec72ed6dd39b2a9 Author: Tor Lillqvist <[email protected]> Date: Wed Apr 20 16:44:12 2016 +0300 Add getToken* variants that iterate over a StringTokenizer If any of the tokens in the string matches name=<value> for the name in question, store that value and return true. Otherwise return false. diff --git a/loolwsd/LOOLProtocol.cpp b/loolwsd/LOOLProtocol.cpp index ab87c22..eac5c71 100644 --- a/loolwsd/LOOLProtocol.cpp +++ b/loolwsd/LOOLProtocol.cpp @@ -117,6 +117,36 @@ namespace LOOLProtocol return true; } + bool getTokenInteger(const Poco::StringTokenizer& tokens, const std::string& name, int& value) + { + for (int i = 0; i < tokens.count(); i++) + { + if (getTokenInteger(tokens[i], name, value)) + return true; + } + return false; + } + + bool getTokenString(const Poco::StringTokenizer& tokens, const std::string& name, std::string& value) + { + for (int i = 0; i < tokens.count(); i++) + { + if (getTokenString(tokens[i], name, value)) + return true; + } + return false; + } + + bool getTokenKeyword(const Poco::StringTokenizer& tokens, const std::string& name, const std::map<std::string, int>& map, int& value) + { + for (int i = 0; i < tokens.count(); i++) + { + if (getTokenKeyword(tokens[i], name, map, value)) + return true; + } + return false; + } + bool parseStatus(const std::string& message, LibreOfficeKitDocumentType& type, int& nParts, int& currentPart, int& width, int& height) { StringTokenizer tokens(message, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM); diff --git a/loolwsd/LOOLProtocol.hpp b/loolwsd/LOOLProtocol.hpp index 0ed166a..673e75f 100644 --- a/loolwsd/LOOLProtocol.hpp +++ b/loolwsd/LOOLProtocol.hpp @@ -13,6 +13,8 @@ #include <map> #include <string> +#include <Poco/StringTokenizer.h> + #define LOK_USE_UNSTABLE_API #include <LibreOfficeKit/LibreOfficeKitEnums.h> @@ -40,6 +42,10 @@ namespace LOOLProtocol 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); + bool getTokenInteger(const Poco::StringTokenizer& tokens, const std::string& name, int& value); + bool getTokenString(const Poco::StringTokenizer& tokens, const std::string& name, std::string& value); + bool getTokenKeyword(const Poco::StringTokenizer& tokens, const std::string& name, const std::map<std::string, int>& map, int& value); + // Functions that parse messages. All return false if parsing fails bool parseStatus(const std::string& message, LibreOfficeKitDocumentType& type, int& nParts, int& currentPart, int& width, int& height); commit d423f7c2fdd2a21f7c2d32b110ba4613173d7ac7 Author: Tor Lillqvist <[email protected]> Date: Wed Apr 20 16:43:00 2016 +0300 Add Util::UniqueId() to get a string id that is unique across processes and calls diff --git a/loolwsd/Util.cpp b/loolwsd/Util.cpp index d30b31a..aef31fe 100644 --- a/loolwsd/Util.cpp +++ b/loolwsd/Util.cpp @@ -10,10 +10,13 @@ #include "config.h" #include <execinfo.h> +#include <signal.h> #include <sys/poll.h> #include <sys/prctl.h> #include <sys/uio.h> +#include <unistd.h> +#include <atomic> #include <cassert> #include <cstdlib> #include <cstring> @@ -23,12 +26,9 @@ #include <random> #include <sstream> #include <string> -#include <unistd.h> #include <png.h> -#include <signal.h> - #include <Poco/ConsoleChannel.h> #include <Poco/Exception.h> #include <Poco/Format.h> @@ -437,6 +437,12 @@ namespace Util hash.resize(std::min(8, (int)hash.length())); std::cout << app << " " << LOOLWSD_VERSION << " - " << hash << std::endl; } + + std::string UniqueId() + { + static std::atomic_int counter(0); + return std::to_string(Poco::Process::id()) + "/" + std::to_string(counter++); + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/loolwsd/Util.hpp b/loolwsd/Util.hpp index f2b0ffb..4647865 100644 --- a/loolwsd/Util.hpp +++ b/loolwsd/Util.hpp @@ -120,6 +120,9 @@ namespace Util /// Display version information void displayVersionInfo(const char *app); + /// Return a string that is unique across processes and calls. + std::string UniqueId(); + /// Given one or more patterns to allow, and one or more to deny, /// the match member will return true if, and only if, the subject /// matches the allowed list, but not the deny. commit e94e8344adcdf8c2cd24288792c22b8894d49f1a Author: Tor Lillqvist <[email protected]> Date: Wed Apr 20 16:35:36 2016 +0300 IIUC, the 'tile' and 'tile:' messages have an optional timestamp parameter diff --git a/loolwsd/protocol.txt b/loolwsd/protocol.txt index 2b4d80f..989dc13 100644 --- a/loolwsd/protocol.txt +++ b/loolwsd/protocol.txt @@ -105,7 +105,7 @@ status styles -tile part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<ypos> tilewidth=<tileWidth> tileheight=<tileHeight> +tile part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<ypos> tilewidth=<tileWidth> tileheight=<tileHeight> [timestamp=<time>] All parameters are numbers. @@ -232,7 +232,7 @@ textselectioncontent: <content> Current selection's content -tile: part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<ypos> tilewidth=<tileWidth> tileheight=<tileHeight> +tile: part=<partNumber> width=<width> height=<height> tileposx=<xpos> tileposy=<ypos> tilewidth=<tileWidth> tileheight=<tileHeight> [timestamp=<time>] <binaryPngImage> The parameters from the corresponding 'tile' command. commit 949907170780f9da1da78f4cd07515ed82a450e8 Author: Tor Lillqvist <[email protected]> Date: Wed Apr 20 16:10:39 2016 +0300 Change comment to make sense diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp index 54962b9..0320de1 100644 --- a/loolwsd/MasterProcessSession.cpp +++ b/loolwsd/MasterProcessSession.cpp @@ -196,7 +196,7 @@ bool MasterProcessSession::_handleInput(const char *buffer, int length) queue = subscriber->getQueue(); // re-emit the tile command in the other thread // to re-check and hit the cache. NB. it needs to be - // 'tile' and not 'tile' + // 'tile' and not 'tile:' if (queue) { std::string noColon = firstLine + "\n"; _______________________________________________ Libreoffice-commits mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
