diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2020-06-04 18:39:54 +0200 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2020-06-09 09:49:19 +0200 |
commit | a97539174fd7f76713291dd4e8138adb1f776c91 (patch) | |
tree | 77c60c0297f42b8ce25c8be50a7094eb5db56ca2 /sc | |
parent | 49df367a5da14b31729e2f4f5dd6bf4e249df8d3 (diff) |
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@collabora.com>
Diffstat (limited to 'sc')
-rw-r--r-- | sc/inc/document.hxx | 14 | ||||
-rw-r--r-- | sc/inc/scopetools.hxx | 13 | ||||
-rw-r--r-- | sc/source/core/data/column.cxx | 4 | ||||
-rw-r--r-- | sc/source/core/data/column3.cxx | 10 | ||||
-rw-r--r-- | sc/source/core/data/documen2.cxx | 3 | ||||
-rw-r--r-- | sc/source/core/data/document10.cxx | 48 | ||||
-rw-r--r-- | sc/source/core/tool/scopetools.cxx | 22 |
7 files changed, 112 insertions, 2 deletions
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: */ |