sw/inc/doc.hxx                    |    3 ++-
 sw/source/core/docnode/ndtbl.cxx  |    7 +++++--
 sw/source/core/unocore/unotbl.cxx |   33 ++++++++++++++++++---------------
 sw/source/filter/xml/xmlimp.cxx   |    3 ++-
 sw/source/filter/xml/xmlimp.hxx   |    7 +++++++
 sw/source/filter/xml/xmltbli.cxx  |   19 ++++++++++++++++---
 6 files changed, 50 insertions(+), 22 deletions(-)

New commits:
commit b398c4b9f2e360a712884d69232228c8048a23b4
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Fri Mar 31 17:38:42 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Mar 31 20:00:50 2023 +0200

    tdf#154486: Use known name when inserting the table into the document
    
    ... instead of assinging a unique name at insertion time, then changing
    to the final value.
    
    As discussed in commit 1dd71d79e15bd8098e7c17c8fcea3748592a902f (tdf#154486:
    use importer-local map to deduplicate table names, 2023-03-31), the lookup
    for a unique table name has an O(n^2) complexity, and can make loading of
    thousands tables impossible.
    
    This changes import time from 23 s to ~2.5 s, and the time now depends on 
the
    number of tables linearly (e.g., 200 000 tables load in ~45 s).
    
    Change-Id: I0f2b5e37db2d370bccbc8c3430f895c864d9a4c2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149840
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    (cherry picked from commit 18e4c95a59809f4109f13934f2f072aee1cea000)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149874
    Tested-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx
index 4a399b839896..428e64bcd9c7 100644
--- a/sw/inc/doc.hxx
+++ b/sw/inc/doc.hxx
@@ -1176,7 +1176,8 @@ public:
                                 const SwTableAutoFormat* pTAFormat = nullptr,
                                 const std::vector<sal_uInt16> *pColArr = 
nullptr,
                                 bool bCalledFromShell = false,
-                                bool bNewModel = true );
+                                bool bNewModel = true,
+                                const OUString& rTableName = {} );
 
     // If index is in a table, return TableNode, else 0.
     static SwTableNode* IsIdxInTable( const SwNodeIndex& rIdx );
diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx
index 77f7a4d3e97c..b4ea4cfe80d2 100644
--- a/sw/source/core/docnode/ndtbl.cxx
+++ b/sw/source/core/docnode/ndtbl.cxx
@@ -340,7 +340,8 @@ const SwTable* SwDoc::InsertTable( const 
SwInsertTableOptions& rInsTableOpts,
                                    const SwTableAutoFormat* pTAFormat,
                                    const std::vector<sal_uInt16> *pColArr,
                                    bool bCalledFromShell,
-                                   bool bNewModel )
+                                   bool bNewModel,
+                                   const OUString& rTableName )
 {
     assert(nRows && "Table without line?");
     assert(nCols && "Table without rows?");
@@ -357,7 +358,9 @@ const SwTable* SwDoc::InsertTable( const 
SwInsertTableOptions& rInsTableOpts,
             pColArr = nullptr;
     }
 
-    OUString aTableName = GetUniqueTableName();
+    OUString aTableName = rTableName;
+    if (aTableName.isEmpty() || FindTableFormatByName(aTableName) != nullptr)
+        aTableName = GetUniqueTableName();
 
     if( GetIDocumentUndoRedo().DoesUndo() )
     {
diff --git a/sw/source/core/unocore/unotbl.cxx 
b/sw/source/core/unocore/unotbl.cxx
index f1d697a36c81..76b439cd6d11 100644
--- a/sw/source/core/unocore/unotbl.cxx
+++ b/sw/source/core/unocore/unotbl.cxx
@@ -2121,11 +2121,28 @@ SwXTextTable::attach(const 
uno::Reference<text::XTextRange> & xTextRange)
             pDoc->getIDocumentContentOperations().DeleteAndJoin(aPam);
             aPam.DeleteMark();
         }
+
+        OUString tableName;
+        if (const::uno::Any* pName;
+            m_pImpl->m_pTableProps->GetProperty(FN_UNO_TABLE_NAME, 0, pName))
+        {
+            tableName = pName->get<OUString>();
+        }
+        else if (!m_pImpl->m_sTableName.isEmpty())
+        {
+            sal_uInt16 nIndex = 1;
+            tableName = m_pImpl->m_sTableName;
+            while (pDoc->FindTableFormatByName(tableName, true) && nIndex < 
USHRT_MAX)
+                tableName = m_pImpl->m_sTableName + OUString::number(nIndex++);
+        }
+
         pTable = pDoc->InsertTable(SwInsertTableOptions( 
SwInsertTableFlags::Headline | SwInsertTableFlags::DefaultBorder | 
SwInsertTableFlags::SplitLayout, 0 ),
                 *aPam.GetPoint(),
                 m_pImpl->m_nRows,
                 m_pImpl->m_nColumns,
-                text::HoriOrientation::FULL);
+                text::HoriOrientation::FULL,
+                nullptr, nullptr, false, true,
+                tableName);
         if(pTable)
         {
             // here, the properties of the descriptor need to be analyzed
@@ -2135,20 +2152,6 @@ SwXTextTable::attach(const 
uno::Reference<text::XTextRange> & xTextRange)
 
             m_pImpl->SetFrameFormat(*pTableFormat);
 
-            if (!m_pImpl->m_sTableName.isEmpty())
-            {
-                sal_uInt16 nIndex = 1;
-                OUString sTmpNameIndex(m_pImpl->m_sTableName);
-                while(pDoc->FindTableFormatByName(sTmpNameIndex, true) && 
nIndex < USHRT_MAX)
-                {
-                    sTmpNameIndex = m_pImpl->m_sTableName + 
OUString::number(nIndex++);
-                }
-                pDoc->SetTableName( *pTableFormat, sTmpNameIndex);
-            }
-
-            const::uno::Any* pName;
-            if (m_pImpl->m_pTableProps->GetProperty(FN_UNO_TABLE_NAME, 0, 
pName))
-                setName(pName->get<OUString>());
             m_pImpl->m_pTableProps.reset();
         }
         pDoc->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
diff --git a/sw/source/filter/xml/xmltbli.cxx b/sw/source/filter/xml/xmltbli.cxx
index fec24079defc..acc01482cda4 100644
--- a/sw/source/filter/xml/xmltbli.cxx
+++ b/sw/source/filter/xml/xmltbli.cxx
@@ -53,6 +53,7 @@
 #include <swtable.hxx>
 #include <swtblfmt.hxx>
 #include <pam.hxx>
+#include <unoprnms.hxx>
 #include <unotbl.hxx>
 #include <unotextrange.hxx>
 #include <cellatr.hxx>
@@ -1212,6 +1213,8 @@ SwXMLTableContext::SwXMLTableContext( SwXMLImport& 
rImport,
     if( xTable.is() )
     {
         xTable->initialize( 1, 1 );
+        if (css::uno::Reference<css::beans::XPropertySet> xPropSet{ xTable, 
css::uno::UNO_QUERY })
+            xPropSet->setPropertyValue(UNO_NAME_TABLE_NAME, 
css::uno::Any(sTableName));
 
         try
         {
@@ -1251,8 +1254,6 @@ SwXMLTableContext::SwXMLTableContext( SwXMLImport& 
rImport,
     m_pTableNode = pTable->GetTableNode();
     OSL_ENSURE( m_pTableNode, "table node missing" );
 
-    pTableFrameFormat->SetFormatName( sTableName );
-
     SwTableLine *pLine1 = m_pTableNode->GetTable().GetTabLines()[0U];
     m_pBox1 = pLine1->GetTabBoxes()[0U];
     m_pSttNd1 = m_pBox1->GetSttNd();
commit f75553b3f9071d8aa0deb4d9d4a5d4db431a8abd
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Fri Mar 31 10:51:32 2023 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Fri Mar 31 20:00:37 2023 +0200

    tdf#154486: use importer-local map to deduplicate table names
    
    ... instead of SwDoc::GetUniqueTableName. The latter is expensive with
    many tables, has O(n^2) complexity with rather large O, and in corner
    cases of thousands tables with no or duplicate names, is unacceptably
    slow.
    
    Changes the test case import time from 39 s to 23 s on my system.
    
    Change-Id: Ia461c860d56cbbfdcb25bacbb9cca4961ced885e
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149817
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    (cherry picked from commit 2548f3c65ceb2a1a341b52ecdbde6846decc0fdc)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149796
    Tested-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/source/filter/xml/xmlimp.cxx b/sw/source/filter/xml/xmlimp.cxx
index 2cb58cf2aa47..5ef66a1bf36f 100644
--- a/sw/source/filter/xml/xmlimp.cxx
+++ b/sw/source/filter/xml/xmlimp.cxx
@@ -324,7 +324,8 @@ SwXMLImport::SwXMLImport(
     m_bBlock( false ),
     m_bOrganizerMode( false ),
     m_bInititedXForms( false ),
-    m_pDoc( nullptr )
+    m_pDoc( nullptr ),
+    m_sDefTableName(SwResId(STR_TABLE_DEFNAME))
 {
     InitItemImport();
 }
diff --git a/sw/source/filter/xml/xmlimp.hxx b/sw/source/filter/xml/xmlimp.hxx
index 22f012c4dbfc..8791958fc69c 100644
--- a/sw/source/filter/xml/xmlimp.hxx
+++ b/sw/source/filter/xml/xmlimp.hxx
@@ -84,6 +84,10 @@ class SwXMLImport: public SvXMLImport
 
     SwDoc*      m_pDoc; // cached for getDoc()
 
+    // Optimization for new table name lookup
+    OUString m_sDefTableName; // See STR_TABLE_DEFNAME
+    std::map<OUString, sal_uInt32> m_aTableNameMap; // Last used indices for 
duplicating table names
+
     void                    InitItemImport();
     void                    FinitItemImport();
     void                    UpdateTextCollConditions( SwDoc *pDoc );
@@ -167,6 +171,9 @@ public:
 
     const SwDoc* getDoc() const;
     SwDoc* getDoc();
+
+    const OUString& GetDefTableName() { return m_sDefTableName; }
+    std::map<OUString, sal_uInt32>& GetTableNameMap() { return 
m_aTableNameMap; }
 };
 
 inline const SvXMLImportItemMapper& SwXMLImport::GetTableItemMapper() const
diff --git a/sw/source/filter/xml/xmltbli.cxx b/sw/source/filter/xml/xmltbli.cxx
index 44ae125d30b0..fec24079defc 100644
--- a/sw/source/filter/xml/xmltbli.cxx
+++ b/sw/source/filter/xml/xmltbli.cxx
@@ -1178,7 +1178,19 @@ SwXMLTableContext::SwXMLTableContext( SwXMLImport& 
rImport,
     }
     if( sTableName.isEmpty() )
     {
-        sTableName = pDoc->GetUniqueTableName();
+        // Optimization: use import's own map to create unique names, because
+        // SwDoc::GetUniqueTableName scans all the already present tables,
+        // builds a bitset using rather complex rules, and that has quadratic
+        // complexity. Try once, then fallback to SwDoc::GetUniqueTableName
+        auto& tableNameMap = rImport.GetTableNameMap();
+        sal_Int32 nextIx = ++tableNameMap[aName];
+        OUString test = aName.isEmpty()
+                                  ? OUString(rImport.GetDefTableName() + 
OUString::number(nextIx))
+                                  : OUString(aName + "_" + 
OUString::number(nextIx));
+        if (const SwTableFormat* pExisting = 
pDoc->FindTableFormatByName(test); !pExisting)
+            sTableName = test;
+        else
+            sTableName = pDoc->GetUniqueTableName();
         GetImport().GetTextImport()
             ->GetRenameMap().Add( XML_TEXT_RENAME_TYPE_TABLE, aName, 
sTableName );
     }

Reply via email to