From 1e88cd643a5959271f28eaaab3d14488374df11f Mon Sep 17 00:00:00 2001 From: Kohei Yoshida Date: Wed, 11 Jan 2012 15:24:52 -0500 Subject: fdo#44661: Properly update range keys for pivot cache. When the internal data source range gets modified, we should also update the affected range keys that are used to look up pivot caches. Otherwise we'll end up creating a brand new cache, without removing the old one that's no longer referenced. --- sc/inc/dpobject.hxx | 8 +++- sc/source/core/data/dpobject.cxx | 100 +++++++++++++++++++++++++++++++++++---- 2 files changed, 99 insertions(+), 9 deletions(-) (limited to 'sc') diff --git a/sc/inc/dpobject.hxx b/sc/inc/dpobject.hxx index cc73fcbee82a..db8ea9222f0f 100644 --- a/sc/inc/dpobject.hxx +++ b/sc/inc/dpobject.hxx @@ -259,12 +259,18 @@ public: class SheetCaches { friend class ScDPCollection; - typedef ::boost::ptr_map CachesType; + typedef boost::ptr_map CachesType; + typedef std::vector RangeIndexType; CachesType maCaches; + RangeIndexType maRanges; ScDocument* mpDoc; public: SheetCaches(ScDocument* pDoc); const ScDPCache* getCache(const ScRange& rRange); + + void updateReference( + UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz); + private: void removeCache(const ScRange& rRange); }; diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx index 51be02db8971..b0bbace516fa 100644 --- a/sc/source/core/data/dpobject.cxx +++ b/sc/source/core/data/dpobject.cxx @@ -2459,27 +2459,108 @@ uno::Reference ScDPObject::CreateSource( const ScDPS ScDPCollection::SheetCaches::SheetCaches(ScDocument* pDoc) : mpDoc(pDoc) {} +namespace { + +struct FindInvalidRange : public std::unary_function +{ + bool operator() (const ScRange& r) const + { + return !r.IsValid(); + } +}; + +} + const ScDPCache* ScDPCollection::SheetCaches::getCache(const ScRange& rRange) { - CachesType::const_iterator itr = maCaches.find(rRange); - if (itr != maCaches.end()) - // already cached. - return itr->second; + RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange); + if (it != maRanges.end()) + { + // Already cached. + size_t nIndex = std::distance(maRanges.begin(), it); + CachesType::iterator itCache = maCaches.find(nIndex); + if (itCache == maCaches.end()) + // cache pool and index pool out-of-sync !!! + return NULL; + return itCache->second; + } + + // Not cached. Create a new cache. SAL_WNODEPRECATED_DECLARATIONS_PUSH ::std::auto_ptr pCache(new ScDPCache(mpDoc)); SAL_WNODEPRECATED_DECLARATIONS_POP pCache->InitFromDoc(mpDoc, rRange); + + // Get the smallest available range index. + it = std::find_if(maRanges.begin(), maRanges.end(), FindInvalidRange()); + + size_t nIndex = maRanges.size(); + if (it == maRanges.end()) + { + // All range indices are valid. Append a new index. + maRanges.push_back(rRange); + } + else + { + // Slot with invalid range. Re-use this slot. + *it = rRange; + nIndex = std::distance(maRanges.begin(), it); + } + const ScDPCache* p = pCache.get(); - maCaches.insert(rRange, pCache); + maCaches.insert(nIndex, pCache); return p; } +void ScDPCollection::SheetCaches::updateReference( + UpdateRefMode eMode, const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz) +{ + if (maRanges.empty()) + // No caches. + return; + + RangeIndexType::iterator it = maRanges.begin(), itEnd = maRanges.end(); + for (; it != itEnd; ++it) + { + const ScRange& rKeyRange = *it; + SCCOL nCol1 = rKeyRange.aStart.Col(); + SCROW nRow1 = rKeyRange.aStart.Row(); + SCTAB nTab1 = rKeyRange.aStart.Tab(); + SCCOL nCol2 = rKeyRange.aEnd.Col(); + SCROW nRow2 = rKeyRange.aEnd.Row(); + SCTAB nTab2 = rKeyRange.aEnd.Tab(); + + ScRefUpdateRes eRes = ScRefUpdate::Update( + mpDoc, eMode, + r.aStart.Col(), r.aStart.Row(), r.aStart.Tab(), + r.aEnd.Col(), r.aEnd.Row(), r.aEnd.Tab(), nDx, nDy, nDz, + nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); + + if (eRes != UR_NOTHING) + { + // range updated. + ScRange aNew(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); + *it = aNew; + } + } +} + void ScDPCollection::SheetCaches::removeCache(const ScRange& rRange) { - CachesType::iterator itr = maCaches.find(rRange); - if (itr != maCaches.end()) - maCaches.erase(itr); + RangeIndexType::iterator it = std::find(maRanges.begin(), maRanges.end(), rRange); + if (it == maRanges.end()) + // Not cached. Nothing to do. + return; + + size_t nIndex = std::distance(maRanges.begin(), it); + CachesType::iterator itCache = maCaches.find(nIndex); + if (itCache == maCaches.end()) + // Cache pool and index pool out-of-sync !!! + return; + + it->SetInvalid(); // Make this slot available for future caches. + maCaches.erase(itCache); } ScDPCollection::NameCaches::NameCaches(ScDocument* pDoc) : mpDoc(pDoc) {} @@ -2687,6 +2768,9 @@ void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode, TablesType::iterator itr = maTables.begin(), itrEnd = maTables.end(); for (; itr != itrEnd; ++itr) itr->UpdateReference(eUpdateRefMode, r, nDx, nDy, nDz); + + // Update the source ranges of the caches. + maSheetCaches.updateReference(eUpdateRefMode, r, nDx, nDy, nDz); } bool ScDPCollection::RefsEqual( const ScDPCollection& r ) const -- cgit