[Libreoffice-commits] core.git: sc/inc sc/source

Luboš Luňák (via logerrit) logerrit at kemper.freedesktop.org
Tue Jun 9 07:49:51 UTC 2020


 sc/inc/document.hxx                |   14 ++++++++++
 sc/inc/scopetools.hxx              |   13 ++++++++++
 sc/source/core/data/column.cxx     |    4 +++
 sc/source/core/data/column3.cxx    |   10 ++++++-
 sc/source/core/data/documen2.cxx   |    3 ++
 sc/source/core/data/document10.cxx |   48 +++++++++++++++++++++++++++++++++++++
 sc/source/core/tool/scopetools.cxx |   22 ++++++++++++++++
 7 files changed, 112 insertions(+), 2 deletions(-)

New commits:
commit a97539174fd7f76713291dd4e8138adb1f776c91
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Thu Jun 4 18:39:54 2020 +0200
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Jun 9 09:49:19 2020 +0200

    delay and batch calls to StartListeningFormulaCells() (tdf#133302)
    
    In the testcase ScColumn::StartListeningUnshared() gets called
    repeatedly with almost the same cells range (just extending),
    so this gets quadratic. Delaying and doing it once on the whole
    range at the end avoids this.
    
    Change-Id: I3e92817d434cf7e4be0ea658f9adc0a24ceda260
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95531
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>

diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index 03ea2b9d4336..0f7415ac846f 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -49,6 +49,7 @@
 #include <memory>
 #include <map>
 #include <set>
+#include <unordered_map>
 #include <vector>
 
 #include "markdata.hxx"
@@ -129,6 +130,7 @@ class ScBroadcastAreaSlotMachine;
 class ScChangeViewSettings;
 class ScChartListenerCollection;
 class ScClipOptions;
+class ScColumn;
 class ScConditionalFormat;
 class ScConditionalFormatList;
 class ScDBCollection;
@@ -519,6 +521,10 @@ private:
     // If the pointer is set, formula cells will not be automatically grouped into shared formula groups,
     // instead the range will be extended to contain all such cells.
     std::unique_ptr< ScRange > pDelayedFormulaGrouping;
+    // If non-empty, ScColumn::StartListeningFormulaCells() calls may be delayed using this,
+    // avoiding repeated calling for the same cells in the given range. The function will be called once
+    // later for all the cells in the range.
+    std::unordered_map< ScColumn*, std::pair<SCROW, SCROW>> pDelayedStartListeningFormulaCells;
 
     bool                bLinkFormulaNeedingCheck; // valid only after loading, for ocDde and ocWebservice
 
@@ -1360,6 +1366,14 @@ public:
     bool            IsDelayedFormulaGrouping() const { return bool(pDelayedFormulaGrouping); }
     /// To be used only by SharedFormulaUtil::joinFormulaCells().
     void            AddDelayedFormulaGroupingCell( const ScFormulaCell* cell );
+    /// If set, ScColumn::StartListeningFormulaCells() calls may be delayed using
+    /// CanDelayStartListeningFormulaCells() until reset again, at which point the function will
+    /// be called as necessary.
+    void            EnableDelayStartListeningFormulaCells( ScColumn* column, bool delay );
+    bool            IsEnabledDelayStartListeningFormulaCells( ScColumn* column ) const;
+    /// If true is returned, ScColumn::StartListeningFormulaCells() for the given cells will be performed
+    /// later. If false is returned, it needs to be done explicitly.
+    bool            CanDelayStartListeningFormulaCells( ScColumn* column, SCROW row1, SCROW row2 );
 
     FormulaError    GetErrCode( const ScAddress& ) const;
 
diff --git a/sc/inc/scopetools.hxx b/sc/inc/scopetools.hxx
index ac78fb428060..dd060615db67 100644
--- a/sc/inc/scopetools.hxx
+++ b/sc/inc/scopetools.hxx
@@ -13,6 +13,7 @@
 #include "scdllapi.h"
 
 class ScDocument;
+class ScColumn;
 namespace vcl { class Window; }
 
 namespace sc {
@@ -73,6 +74,18 @@ public:
     void reset();
 };
 
+/// Wrapper for ScDocument::EnableDelayStartListeningFormulaCells()
+class DelayStartListeningFormulaCells
+{
+    ScColumn& mColumn;
+    bool const mbOldValue;
+public:
+    DelayStartListeningFormulaCells(ScColumn& column, bool delay);
+    DelayStartListeningFormulaCells(ScColumn& column);
+    ~DelayStartListeningFormulaCells();
+    void set();
+};
+
 }
 
 #endif
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index a223352b8dd3..61011da9aeae 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -1661,6 +1661,7 @@ public:
                 sc::formula_block::const_iterator itEnd = it;
                 std::advance(itEnd, nDataSize);
 
+                sc::DelayStartListeningFormulaCells startDelay(mrDestCol); // disabled
                 if(nDataSize > 1024 && (mnCopyFlags & InsertDeleteFlags::FORMULA) != InsertDeleteFlags::NONE)
                 {
                     // If the column to be replaced contains a long formula group (tdf#102364), there can
@@ -1668,6 +1669,9 @@ public:
                     // the first element becomes very high. Optimize this by removing them in one go.
                     sc::EndListeningContext context(*mrDestCol.GetDoc());
                     mrDestCol.EndListeningFormulaCells( context, nRow, nRow + nDataSize - 1, nullptr, nullptr );
+                    // There can be a similar problem with starting to listen to cells repeatedly (tdf#133302).
+                    // Delay it.
+                    startDelay.set();
                 }
 
                 for (; it != itEnd; ++it, ++nRow)
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 88ed96df0f3c..0f4f3d8e76ab 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -349,9 +349,15 @@ void ScColumn::StartListeningUnshared( const std::vector<SCROW>& rNewSharedRows
         sc::StartListeningContext aStartCxt(*pDoc, pPosSet);
         sc::EndListeningContext aEndCxt(*pDoc, pPosSet);
         if (rNewSharedRows.size() >= 2)
-            StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[0], rNewSharedRows[1]);
+        {
+            if(!pDoc->CanDelayStartListeningFormulaCells( this, rNewSharedRows[0], rNewSharedRows[1]))
+                StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[0], rNewSharedRows[1]);
+        }
         if (rNewSharedRows.size() >= 4)
-            StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[2], rNewSharedRows[3]);
+        {
+            if(!pDoc->CanDelayStartListeningFormulaCells( this, rNewSharedRows[2], rNewSharedRows[3]))
+                StartListeningFormulaCells(aStartCxt, aEndCxt, rNewSharedRows[2], rNewSharedRows[3]);
+        }
     }
 }
 
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
index afacfecc4640..d80e15dd1c34 100644
--- a/sc/source/core/data/documen2.cxx
+++ b/sc/source/core/data/documen2.cxx
@@ -398,6 +398,9 @@ ScDocument::~ScDocument()
     if(mpCellStringPool.use_count() > 1)
         mpCellStringPool->purge();
     mpCellStringPool.reset();
+
+    assert( pDelayedFormulaGrouping == nullptr );
+    assert( pDelayedStartListeningFormulaCells.empty());
 }
 
 void ScDocument::InitClipPtrs( ScDocument* pSourceDoc )
diff --git a/sc/source/core/data/document10.cxx b/sc/source/core/data/document10.cxx
index 59f0787591f1..0aac4ce29025 100644
--- a/sc/source/core/data/document10.cxx
+++ b/sc/source/core/data/document10.cxx
@@ -395,6 +395,54 @@ void ScDocument::AddDelayedFormulaGroupingCell( const ScFormulaCell* cell )
         pDelayedFormulaGrouping->ExtendTo( cell->aPos );
 }
 
+void ScDocument::EnableDelayStartListeningFormulaCells( ScColumn* column, bool delay )
+{
+    if( delay )
+    {
+        if( pDelayedStartListeningFormulaCells.find( column ) == pDelayedStartListeningFormulaCells.end())
+            pDelayedStartListeningFormulaCells[ column ] = std::pair<SCROW, SCROW>( -1, -1 );
+    }
+    else
+    {
+        auto it = pDelayedStartListeningFormulaCells.find( column );
+        if( it != pDelayedStartListeningFormulaCells.end())
+        {
+            if( it->second.first != -1 )
+            {
+                auto pPosSet = std::make_shared<sc::ColumnBlockPositionSet>(*this);
+                sc::StartListeningContext aStartCxt(*this, pPosSet);
+                sc::EndListeningContext aEndCxt(*this, pPosSet);
+                column->StartListeningFormulaCells(aStartCxt, aEndCxt, it->second.first, it->second.second);
+            }
+            pDelayedStartListeningFormulaCells.erase( it );
+        }
+    }
+}
+
+bool ScDocument::IsEnabledDelayStartListeningFormulaCells( ScColumn* column ) const
+{
+    return pDelayedStartListeningFormulaCells.find( column ) != pDelayedStartListeningFormulaCells.end();
+}
+
+bool ScDocument::CanDelayStartListeningFormulaCells( ScColumn* column, SCROW row1, SCROW row2 )
+{
+    auto it = pDelayedStartListeningFormulaCells.find( column );
+    if( it == pDelayedStartListeningFormulaCells.end())
+        return false; // not enabled
+    if( it->second.first == -1 && it->second.second == -1 ) // uninitialized
+        pDelayedStartListeningFormulaCells[ column ] = std::make_pair( row1, row2 );
+    else
+    {
+        if( row1 > it->second.second + 1 || row2 < it->second.first - 1 )
+        { // two non-adjacent ranges, just bail out
+            return false;
+        }
+        it->second.first = std::min( it->second.first, row1 );
+        it->second.second = std::max( it->second.second, row2 );
+    }
+    return true;
+}
+
 bool ScDocument::HasFormulaCell( const ScRange& rRange ) const
 {
     if (!rRange.IsValid())
diff --git a/sc/source/core/tool/scopetools.cxx b/sc/source/core/tool/scopetools.cxx
index 71a4cf15eb1d..6416e3c2ea89 100644
--- a/sc/source/core/tool/scopetools.cxx
+++ b/sc/source/core/tool/scopetools.cxx
@@ -9,6 +9,7 @@
 
 #include <scopetools.hxx>
 #include <document.hxx>
+#include <column.hxx>
 #include <vcl/window.hxx>
 
 namespace sc {
@@ -73,6 +74,27 @@ void DelayFormulaGroupingSwitch::reset()
     mrDoc.DelayFormulaGrouping(mbOldValue);
 }
 
+DelayStartListeningFormulaCells::DelayStartListeningFormulaCells(ScColumn& column, bool delay)
+    : mColumn(column), mbOldValue(column.GetDoc()->IsEnabledDelayStartListeningFormulaCells(&column))
+{
+    column.GetDoc()->EnableDelayStartListeningFormulaCells(&column, delay);
+}
+
+DelayStartListeningFormulaCells::DelayStartListeningFormulaCells(ScColumn& column)
+    : mColumn(column), mbOldValue(column.GetDoc()->IsEnabledDelayStartListeningFormulaCells(&column))
+{
+}
+
+DelayStartListeningFormulaCells::~DelayStartListeningFormulaCells()
+{
+    mColumn.GetDoc()->EnableDelayStartListeningFormulaCells(&mColumn, mbOldValue);
+}
+
+void DelayStartListeningFormulaCells::set()
+{
+    mColumn.GetDoc()->EnableDelayStartListeningFormulaCells(&mColumn, true);
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */


More information about the Libreoffice-commits mailing list