summaryrefslogtreecommitdiffstats
path: root/desktop
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2021-10-15 08:43:23 +0200
committerLuboš Luňák <l.lunak@collabora.com>2021-10-24 01:40:45 +0200
commit273a25c796fca9afa0dfadac57dc3f336831221c (patch)
tree3efb1e505e27164bcdb2c164c59a48c814221ffe /desktop
parentUse std::transform instead of loop (diff)
downloadcore-273a25c796fca9afa0dfadac57dc3f336831221c.tar.gz
core-273a25c796fca9afa0dfadac57dc3f336831221c.zip
change some LOK internal updates to be pull model instead of push
Some LOK messages may get called very often, such as updates about cursor position. And since only the last one matters, they get generated every time, which costs some time, and then later except for one they get all discard again from CallbackFlushHandler queue, which again costs time. Change the model to instead only set an 'updated' flag, and CallbackFlushHandler will request the actual message payload only before flushing. This commit changes LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR and LOK_CALLBACK_INVALIDATE_VIEW_CURSOR to work this way. Change-Id: I376be63176c0b4b5cb492fbf529c21ed01b35481 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/124083 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
Diffstat (limited to 'desktop')
-rw-r--r--desktop/inc/lib/init.hxx23
-rw-r--r--desktop/source/lib/init.cxx144
2 files changed, 167 insertions, 0 deletions
diff --git a/desktop/inc/lib/init.hxx b/desktop/inc/lib/init.hxx
index bc090fc208a9..01620a4f02ac 100644
--- a/desktop/inc/lib/init.hxx
+++ b/desktop/inc/lib/init.hxx
@@ -104,6 +104,8 @@ namespace desktop {
virtual void libreOfficeKitViewCallback(int nType, const char* pPayload) override;
virtual void libreOfficeKitViewCallbackWithViewId(int nType, const char* pPayload, int nViewId) override;
virtual void libreOfficeKitViewInvalidateTilesCallback(const tools::Rectangle* pRect, int nPart) override;
+ virtual void libreOfficeKitViewUpdatedCallback(int nType) override;
+ virtual void libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId) override;
private:
struct CallbackData
@@ -171,6 +173,8 @@ namespace desktop {
queue_type2::iterator toQueue2(queue_type1::iterator);
queue_type2::reverse_iterator toQueue2(queue_type1::reverse_iterator);
void queue(const int type, CallbackData& data);
+ void enqueueUpdatedTypes();
+ void enqueueUpdatedType( int type, SfxViewShell* sourceViewShell, int viewId );
/** we frequently want to scan the queue, and mostly when we do so, we only care about the element type
so we split the queue in 2 to make the scanning cache friendly. */
@@ -178,6 +182,25 @@ namespace desktop {
queue_type2 m_queue2;
std::map<int, std::string> m_states;
std::unordered_map<int, std::unordered_map<int, std::string>> m_viewStates;
+
+ // For some types only the last message matters (see isUpdatedType()) or only the last message
+ // per each viewId value matters (see isUpdatedTypePerViewId()), so instead of using push model
+ // where we'd get flooded by repeated messages (which might be costly to generate and process),
+ // the preferred way is that libreOfficeKitViewUpdatedCallback()
+ // or libreOfficeKitViewUpdatedCallbackPerViewId() get called to notify about such a message being
+ // needed, and we'll set a flag here to fetch the actual message before flushing.
+ void setUpdatedType( int nType, bool value );
+ void setUpdatedTypePerViewId( int nType, int nViewId, int nSourceViewId, bool value );
+ void resetUpdatedType( int nType);
+ void resetUpdatedTypePerViewId( int nType, int nViewId );
+ std::vector<bool> m_updatedTypes; // index is type, value is if set
+ struct PerViewIdData
+ {
+ bool set; // value is if set
+ int sourceViewId;
+ };
+ std::unordered_map<int, std::vector<PerViewIdData>> m_updatedTypesPerViewId; // key is view, index is type
+
LibreOfficeKitDocument* m_pDocument;
int m_viewId = -1; // view id of the associated SfxViewShell
LibreOfficeKitCallback m_pCallback;
diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index ba3315306464..c38a6dd8d754 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -698,6 +698,23 @@ static bool lcl_isViewCallbackType(const int type)
}
}
+static bool isUpdatedType(int /*type*/)
+{
+ return false;
+}
+
+static bool isUpdatedTypePerViewId(int type)
+{
+ switch (type)
+ {
+ case LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR:
+ case LOK_CALLBACK_INVALIDATE_VIEW_CURSOR:
+ return true;
+ default:
+ return false;
+ }
+}
+
static int lcl_getViewId(const std::string& payload)
{
// this is a cheap way how to get the viewId from a JSON message; proper
@@ -1455,6 +1472,48 @@ CallbackFlushHandler::queue_type2::reverse_iterator CallbackFlushHandler::toQueu
return m_queue2.rbegin() + delta;
}
+void CallbackFlushHandler::setUpdatedType( int nType, bool value )
+{
+ assert(isUpdatedType(nType));
+ if( m_updatedTypes.size() <= o3tl::make_unsigned( nType ))
+ m_updatedTypes.resize( nType + 1 ); // new are default-constructed, i.e. false
+ m_updatedTypes[ nType ] = value;
+}
+
+void CallbackFlushHandler::resetUpdatedType( int nType )
+{
+ setUpdatedType( nType, false );
+}
+
+void CallbackFlushHandler::setUpdatedTypePerViewId( int nType, int nViewId, int nSourceViewId, bool value )
+{
+ assert(isUpdatedTypePerViewId(nType));
+ std::vector<PerViewIdData>& types = m_updatedTypesPerViewId[ nViewId ];
+ if( types.size() <= o3tl::make_unsigned( nType ))
+ types.resize( nType + 1 ); // new are default-constructed, i.e. false
+ types[ nType ] = PerViewIdData{ value, nSourceViewId };
+}
+
+void CallbackFlushHandler::resetUpdatedTypePerViewId( int nType, int nViewId )
+{
+ assert(isUpdatedTypePerViewId(nType));
+ bool allViewIds = false;
+ // Handle specially messages that do not have viewId for backwards compatibility.
+ if( nType == LOK_CALLBACK_INVALIDATE_VISIBLE_CURSOR && !comphelper::LibreOfficeKit::isViewIdForVisCursorInvalidation())
+ allViewIds = true;
+ if( !allViewIds )
+ {
+ setUpdatedTypePerViewId( nType, nViewId, -1, false );
+ return;
+ }
+ for( auto& it : m_updatedTypesPerViewId )
+ {
+ std::vector<PerViewIdData>& types = it.second;
+ if( types.size() >= o3tl::make_unsigned( nType ))
+ types[ nType ].set = false;
+ }
+}
+
void CallbackFlushHandler::libreOfficeKitViewCallback(int nType, const char* pPayload)
{
CallbackData callbackData(pPayload);
@@ -1473,6 +1532,22 @@ void CallbackFlushHandler::libreOfficeKitViewInvalidateTilesCallback(const tools
queue(LOK_CALLBACK_INVALIDATE_TILES, callbackData);
}
+void CallbackFlushHandler::libreOfficeKitViewUpdatedCallback(int nType)
+{
+ assert(isUpdatedType( nType ));
+ std::unique_lock<std::mutex> lock(m_mutex);
+ SAL_INFO("lok", "Updated: [" << nType << "]");
+ setUpdatedType(nType, true);
+}
+
+void CallbackFlushHandler::libreOfficeKitViewUpdatedCallbackPerViewId(int nType, int nViewId, int nSourceViewId)
+{
+ assert(isUpdatedTypePerViewId( nType ));
+ std::unique_lock<std::mutex> lock(m_mutex);
+ SAL_INFO("lok", "Updated: [" << nType << "]");
+ setUpdatedTypePerViewId(nType, nViewId, nSourceViewId, true);
+}
+
void CallbackFlushHandler::queue(const int type, const char* data)
{
CallbackData callbackData(data);
@@ -1536,6 +1611,20 @@ void CallbackFlushHandler::queue(const int type, CallbackData& aCallbackData)
std::unique_lock<std::mutex> lock(m_mutex);
+ // Update types should be received via the updated callbacks for performance,
+ // getting them as normal callbacks is technically not wrong, but probably should be avoided.
+ // Reset the updated flag if we get a normal message.
+ if(isUpdatedType(type))
+ {
+ SAL_INFO("lok", "Received event with updated type [" << type << "] as normal callback");
+ resetUpdatedType(type);
+ }
+ if(isUpdatedTypePerViewId(type))
+ {
+ SAL_INFO("lok", "Received event with updated type [" << type << "] as normal callback");
+ resetUpdatedTypePerViewId(type, aCallbackData.getViewId());
+ }
+
// drop duplicate callbacks for the listed types
switch (type)
{
@@ -2028,6 +2117,58 @@ bool CallbackFlushHandler::processWindowEvent(int type, CallbackData& aCallbackD
return false;
}
+void CallbackFlushHandler::enqueueUpdatedTypes()
+{
+ if( m_updatedTypes.empty() && m_updatedTypesPerViewId.empty())
+ return;
+ SfxViewShell* viewShell = SfxViewShell::GetFirst( false,
+ [this](const SfxViewShell* shell) { return shell->GetViewShellId().get() == m_viewId; } );
+ assert(viewShell != nullptr);
+ for( size_t type = 0; type < m_updatedTypes.size(); ++type )
+ {
+ if(m_updatedTypes[ type ])
+ {
+ assert(isUpdatedType( type ));
+ enqueueUpdatedType( type, viewShell, m_viewId );
+ }
+ }
+ for( const auto& it : m_updatedTypesPerViewId )
+ {
+ int viewId = it.first;
+ const std::vector<PerViewIdData>& types = it.second;
+ for( size_t type = 0; type < types.size(); ++type )
+ {
+ if(types[ type ].set)
+ {
+ assert(isUpdatedTypePerViewId( type ));
+ SfxViewShell* sourceViewShell = viewShell;
+ const int sourceViewId = types[ type ].sourceViewId;
+ if( sourceViewId != m_viewId )
+ sourceViewShell = SfxViewShell::GetFirst( false,
+ [sourceViewId](const SfxViewShell* shell) { return shell->GetViewShellId().get() == sourceViewId; } );
+ if(sourceViewShell == nullptr)
+ {
+ SAL_INFO("lok", "View #" << sourceViewId << " no longer found for updated event [" << type << "]");
+ continue; // View removed, probably cleaning up.
+ }
+ enqueueUpdatedType( type, sourceViewShell, viewId );
+ }
+ }
+ }
+ m_updatedTypes.clear();
+ m_updatedTypesPerViewId.clear();
+}
+
+void CallbackFlushHandler::enqueueUpdatedType( int type, SfxViewShell* viewShell, int viewId )
+{
+ OString payload = viewShell->getLOKPayload( type, viewId );
+ CallbackData callbackData(payload.getStr(), viewId);
+ m_queue1.emplace_back(type);
+ m_queue2.emplace_back(callbackData);
+ SAL_INFO("lok", "Queued updated [" << type << "]: [" << callbackData.getPayload()
+ << "] to have " << m_queue1.size() << " entries.");
+}
+
void CallbackFlushHandler::Invoke()
{
comphelper::ProfileZone aZone("CallbackFlushHandler::Invoke");
@@ -2045,6 +2186,9 @@ void CallbackFlushHandler::Invoke()
std::scoped_lock<std::mutex> lock(m_mutex);
+ // Append messages for updated types, fetch them only now.
+ enqueueUpdatedTypes();
+
SAL_INFO("lok", "Flushing " << m_queue1.size() << " elements.");
auto it1 = m_queue1.begin();
auto it2 = m_queue2.begin();