xref: /AOO41X/main/sw/source/core/bastyp/swcache.cxx (revision efeef26f81c84063fb0a91bde3856d4a51172d90)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 #include <tools/debug.hxx>
29 #include <errhdl.hxx>
30 #include <swcache.hxx>
31 
32 SV_IMPL_PTRARR(SwCacheObjArr,SwCacheObj*);
33 
34 #ifndef DBG_UTIL
35 #define INCREMENT( nVar )
36 #else
37 #define INCREMENT( nVar )   ++nVar
38 #endif
39 
40 /*************************************************************************
41 |*
42 |*  SwCache::Check()
43 |*
44 |*  Ersterstellung      MA 23. Mar. 94
45 |*  Letzte Aenderung    MA 23. Mar. 94
46 |*
47 |*************************************************************************/
48 
49 #ifdef DBG_UTIL
50 
Check()51 void SwCache::Check()
52 {
53     if ( !pRealFirst )
54         return;
55 
56     //Konsistenspruefung.
57     ASSERT( !pLast->GetNext(), "Last but not last." );
58     ASSERT( !pRealFirst->GetPrev(), "First but not first." );
59     sal_uInt16 nCnt = 0;
60     sal_Bool bFirstFound = sal_False;
61     SwCacheObj *pObj = pRealFirst;
62     SwCacheObj *pRekursive = pObj;
63     while ( pObj )
64     {
65         //Das Objekt muss auch auf dem Rueckwaertsweg gefunden werden.
66         SwCacheObj *pTmp = pLast;
67         while ( pTmp && pTmp != pObj )
68             pTmp = pTmp->GetPrev();
69         ASSERT( pTmp, "Objekt not found." );
70 
71         ++nCnt;
72         if ( pObj == pFirst )
73             bFirstFound = sal_True;
74         if ( !pObj->GetNext() )
75             ASSERT( pObj == pLast, "Last not Found." );
76         pObj = pObj->GetNext();
77         ASSERT( pObj != pRekursive, "Recursion in SwCache." );
78     }
79     ASSERT( bFirstFound, "First not Found." );
80     ASSERT( (nCnt + aFreePositions.Count()) == Count(), "Lost Chain." );
81     if ( Count() == nCurMax )
82         ASSERT( (nCurMax - nCnt) == aFreePositions.Count(), "Lost FreePositions." );
83 }
84 #endif
85 
86 #if defined(DBG_UTIL) && defined(MADEBUG)
87 #define CHECK Check();
88 #else
89 #define CHECK
90 #endif
91 
92 /*************************************************************************
93 |*
94 |*  SwCache::SwCache(), ~SwCache()
95 |*
96 |*  Ersterstellung      MA 15. Mar. 94
97 |*  Letzte Aenderung    MA 15. Mar. 94
98 |*
99 |*************************************************************************/
100 
101 
SwCache(const sal_uInt16 nInitSize,const sal_uInt16 nGrowSize,const ByteString & rNm)102 SwCache::SwCache( const sal_uInt16 nInitSize, const sal_uInt16 nGrowSize
103 #ifdef DBG_UTIL
104     , const ByteString &rNm
105 #endif
106     ) :
107     SwCacheObjArr( (sal_uInt8)nInitSize, (sal_uInt8)nGrowSize ),
108     aFreePositions( 5, 5 ),
109     pRealFirst( 0 ),
110     pFirst( 0 ),
111     pLast( 0 ),
112     nMax( nInitSize ),
113     nCurMax( nInitSize )
114 #ifdef DBG_UTIL
115     , aName( rNm ),
116     nAppend( 0 ),
117     nInsertFree( 0 ),
118     nReplace( 0 ),
119     nGetSuccess( 0 ),
120     nGetFail( 0 ),
121     nToTop( 0 ),
122     nDelete( 0 ),
123     nGetSeek( 0 ),
124     nAverageSeekCnt( 0 ),
125     nFlushCnt( 0 ),
126     nFlushedObjects( 0 ),
127     nIncreaseMax( 0 ),
128     nDecreaseMax( 0 )
129 #endif
130 {
131 }
132 
133 #ifdef DBG_UTIL
134 
135 
~SwCache()136 SwCache::~SwCache()
137 {
138 #if OSL_DEBUG_LEVEL > 1
139     {
140         ByteString sOut( aName ); sOut += '\n';
141         (( sOut += "Anzahl neuer Eintraege:             " )
142                     += ByteString::CreateFromInt32( nAppend ))+= '\n';
143         (( sOut += "Anzahl Insert auf freie Plaetze:    " )
144                     += ByteString::CreateFromInt32( nInsertFree ))+= '\n';
145         (( sOut += "Anzahl Ersetzungen:                 " )
146                     += ByteString::CreateFromInt32( nReplace ))+= '\n';
147         (( sOut += "Anzahl Erfolgreicher Get's:         " )
148                     += ByteString::CreateFromInt32( nGetSuccess ))+= '\n';
149         (( sOut += "Anzahl Fehlgeschlagener Get's:      " )
150                     += ByteString::CreateFromInt32( nGetFail ))+= '\n';
151         (( sOut += "Anzahl Umsortierungen (LRU):        " )
152                     += ByteString::CreateFromInt32( nToTop ))+= '\n';
153         (( sOut += "Anzahl Loeschungen:                 " )
154                     += ByteString::CreateFromInt32( nDelete ))+= '\n';
155         (( sOut += "Anzahl Get's ohne Index:            " )
156                     += ByteString::CreateFromInt32( nGetSeek ))+= '\n';
157         (( sOut += "Anzahl Seek fuer Get ohne Index:    " )
158                     += ByteString::CreateFromInt32( nAverageSeekCnt ))+= '\n';
159         (( sOut += "Anzahl Flush-Aufrufe:               " )
160                     += ByteString::CreateFromInt32( nFlushCnt ))+= '\n';
161         (( sOut += "Anzahl geflush'ter Objekte:         " )
162                     += ByteString::CreateFromInt32( nFlushedObjects ))+= '\n';
163         (( sOut += "Anzahl Cache-Erweiterungen:         " )
164                     += ByteString::CreateFromInt32( nIncreaseMax ))+= '\n';
165         (( sOut += "Anzahl Cache-Verkleinerungen:       " )
166                     += ByteString::CreateFromInt32( nDecreaseMax ))+= '\n';
167 
168         DBG_ERROR( sOut.GetBuffer() );
169     }
170     Check();
171 #endif
172 }
173 #endif
174 
175 /*************************************************************************
176 |*
177 |*  SwCache::Flush()
178 |*
179 |*  Ersterstellung      MA 15. Mar. 94
180 |*  Letzte Aenderung    MA 15. Mar. 94
181 |*
182 |*************************************************************************/
183 
184 
Flush(const sal_uInt8)185 void SwCache::Flush( const sal_uInt8 )
186 {
187     INCREMENT( nFlushCnt );
188     SwCacheObj *pObj = pRealFirst;
189     pRealFirst = pFirst = pLast = 0;
190     SwCacheObj *pTmp;
191     while ( pObj )
192     {
193 #ifdef DBG_UTIL
194         if ( pObj->IsLocked() )
195         {
196             ASSERT( sal_True, "Flushing locked objects." );
197             if ( !pRealFirst )
198             {
199                 pRealFirst = pFirst = pLast = pObj;
200                 pTmp = pObj->GetNext();
201                 pObj->SetNext( 0 ); pObj->SetPrev( 0 );
202                 pObj = pTmp;
203             }
204             else
205             {   pLast->SetNext( pObj );
206                 pObj->SetPrev( pLast );
207                 pLast = pObj;
208                 pTmp = pObj->GetNext();
209                 pObj->SetNext( 0 );
210                 pObj = pTmp;
211             }
212         }
213         else
214 #endif
215         {
216             pTmp = (SwCacheObj*)pObj;
217             pObj = pTmp->GetNext();
218             aFreePositions.Insert( pTmp->GetCachePos(), aFreePositions.Count() );
219             *(pData + pTmp->GetCachePos()) = (void*)0;
220             delete pTmp;
221             INCREMENT( nFlushedObjects );
222         }
223     }
224 }
225 
226 /*************************************************************************
227 |*
228 |*  SwCache::ToTop()
229 |*
230 |*  Ersterstellung      MA 15. Mar. 94
231 |*  Letzte Aenderung    MA 24. Apr. 95
232 |*
233 |*************************************************************************/
234 
235 
ToTop(SwCacheObj * pObj)236 void SwCache::ToTop( SwCacheObj *pObj )
237 {
238     INCREMENT( nToTop );
239 
240     //Objekt aus der LRU-Kette ausschneiden und am Anfang einfuegen.
241     if ( pRealFirst == pObj )   //pFirst wurde vom Aufrufer geprueft!
242     {   CHECK;
243         return;
244     }
245 
246     if ( !pRealFirst )
247     {   //Der erste wird eingetragen.
248         ASSERT( !pFirst && !pLast, "First not first." );
249         pRealFirst = pFirst = pLast = pObj;
250         CHECK;
251         return;
252     }
253 
254     //Ausschneiden.
255     if ( pObj == pLast )
256     {
257         ASSERT( pObj->GetPrev(), "Last but no Prev." );
258         pLast = pObj->GetPrev();
259         pLast->SetNext( 0 );
260     }
261     else
262     {
263         if ( pObj->GetNext() )
264             pObj->GetNext()->SetPrev( pObj->GetPrev() );
265         if ( pObj->GetPrev() )
266             pObj->GetPrev()->SetNext( pObj->GetNext() );
267     }
268 
269     //Am (virtuellen) Anfang einfuegen.
270     if ( pRealFirst == pFirst )
271     {
272         pRealFirst->SetPrev( pObj );
273         pObj->SetNext( pRealFirst );
274         pObj->SetPrev( 0 );
275         pRealFirst = pFirst = pObj;
276         CHECK;
277     }
278     else
279     {
280         ASSERT( pFirst, "ToTop, First ist not RealFirst an Empty." );
281 
282         if ( pFirst->GetPrev() )
283         {
284             pFirst->GetPrev()->SetNext( pObj );
285             pObj->SetPrev( pFirst->GetPrev() );
286         }
287         else
288             pObj->SetPrev( 0 );
289         pFirst->SetPrev( pObj );
290         pObj->SetNext( pFirst );
291         pFirst = pObj;
292         CHECK;
293     }
294 }
295 
296 /*************************************************************************
297 |*
298 |*  SwCache::Get()
299 |*
300 |*  Ersterstellung      MA 15. Mar. 94
301 |*  Letzte Aenderung    MA 22. Aug. 94
302 |*
303 |*************************************************************************/
304 
305 
Get(const void * pOwner,const sal_uInt16 nIndex,const sal_Bool bToTop)306 SwCacheObj *SwCache::Get( const void *pOwner, const sal_uInt16 nIndex,
307                           const sal_Bool bToTop )
308 {
309     SwCacheObj *pRet;
310     if ( 0 != (pRet = nIndex < Count() ? operator[]( nIndex ) : 0) )
311     {
312         if ( !pRet->IsOwner( pOwner ) )
313             pRet = 0;
314         else if ( bToTop && pRet != pFirst )
315             ToTop( pRet );
316     }
317 
318 #ifdef DBG_UTIL
319         if ( pRet )
320             ++nGetSuccess;
321         else
322             ++nGetFail;
323 #endif
324 
325     return pRet;
326 }
327 
328 
329 
Get(const void * pOwner,const sal_Bool bToTop)330 SwCacheObj *SwCache::Get( const void *pOwner, const sal_Bool bToTop )
331 {
332     SwCacheObj *pRet = pRealFirst;
333     while ( pRet && !pRet->IsOwner( pOwner ) )
334     {
335         INCREMENT( nAverageSeekCnt );
336         pRet = pRet->GetNext();
337     }
338 
339     if ( bToTop && pRet && pRet != pFirst )
340         ToTop( pRet );
341 
342 #ifdef DBG_UTIL
343     if ( pRet )
344         ++nGetSuccess;
345     else
346         ++nGetFail;
347     ++nGetSeek;
348 #endif
349     return pRet;
350 }
351 
352 /*************************************************************************
353 |*
354 |*  SwCache::Delete()
355 |*
356 |*  Ersterstellung      MA 15. Mar. 94
357 |*  Letzte Aenderung    MA 15. Mar. 94
358 |*
359 |*************************************************************************/
360 
361 
DeleteObj(SwCacheObj * pObj)362 void SwCache::DeleteObj( SwCacheObj *pObj )
363 {
364     CHECK;
365     ASSERT( !pObj->IsLocked(), "SwCache::Delete: Object ist Locked." );
366     if ( pObj->IsLocked() )
367         return;
368 
369     if ( pFirst == pObj )
370     {
371         if ( pFirst->GetNext() )
372             pFirst = pFirst->GetNext();
373         else
374             pFirst = pFirst->GetPrev();
375     }
376     if ( pRealFirst == pObj )
377         pRealFirst = pRealFirst->GetNext();
378     if ( pLast == pObj )
379         pLast = pLast->GetPrev();
380     if ( pObj->GetPrev() )
381         pObj->GetPrev()->SetNext( pObj->GetNext() );
382     if ( pObj->GetNext() )
383         pObj->GetNext()->SetPrev( pObj->GetPrev() );
384 
385     aFreePositions.Insert( pObj->GetCachePos(), aFreePositions.Count() );
386     *(pData + pObj->GetCachePos()) = (void*)0;
387     delete pObj;
388 
389     CHECK;
390     if ( Count() > nCurMax &&
391          (nCurMax <= (Count() - aFreePositions.Count())) )
392     {
393         //Falls moeglich wieder verkleinern, dazu muessen allerdings ausreichend
394         //Freie Positionen bereitstehen.
395         //Unangenehmer Nebeneffekt ist, das die Positionen verschoben werden
396         //muessen, und die Eigentuemer der Objekte diese wahrscheinlich nicht
397         //wiederfinden werden.
398         for ( sal_uInt16 i = 0; i < Count(); ++i )
399         {
400             SwCacheObj *pTmpObj = operator[](i);
401             if ( !pTmpObj )
402             {   SwCacheObjArr::Remove( i, 1 );
403                 --i;
404             }
405             else
406                 pTmpObj->SetCachePos( i );
407         }
408         aFreePositions.Remove( 0, aFreePositions.Count() );
409     }
410     CHECK;
411 }
412 
413 /*
414 
415 
416 void SwCache::Delete( const void *pOwner, const sal_uInt16 nIndex )
417 {
418     INCREMENT( nDelete );
419     SwCacheObj *pObj;
420     if ( 0 != (pObj = Get( pOwner, nIndex, sal_False )) )
421         DeleteObj( pObj );
422 }
423 */
424 
425 
426 
Delete(const void * pOwner)427 void SwCache::Delete( const void *pOwner )
428 {
429     INCREMENT( nDelete );
430     SwCacheObj *pObj;
431     if ( 0 != (pObj = Get( pOwner, sal_Bool(sal_False) )) )
432         DeleteObj( pObj );
433 }
434 
435 
436 /*************************************************************************
437 |*
438 |*  SwCache::Insert()
439 |*
440 |*  Ersterstellung      MA 15. Mar. 94
441 |*  Letzte Aenderung    MA 20. Sep. 94
442 |*
443 |*************************************************************************/
444 
445 
Insert(SwCacheObj * pNew)446 sal_Bool SwCache::Insert( SwCacheObj *pNew )
447 {
448     CHECK;
449     ASSERT( !pNew->GetPrev() && !pNew->GetNext(), "New but not new." );
450 
451     sal_uInt16 nPos;//Wird hinter den if's zum setzen am Obj benutzt.
452     if ( Count() < nCurMax )
453     {
454         //Es ist noch Platz frei, also einfach einfuegen.
455         INCREMENT( nAppend );
456         nPos = Count();
457         SwCacheObjArr::C40_INSERT( SwCacheObj, pNew, nPos );
458     }
459     else if ( aFreePositions.Count() )
460     {
461         //Es exitieren Platzhalter, also den letzten benutzen.
462         INCREMENT( nInsertFree );
463         const sal_uInt16 nFreePos = aFreePositions.Count() - 1;
464         nPos = aFreePositions[ nFreePos ];
465         *(pData + nPos) = pNew;
466         aFreePositions.Remove( nFreePos );
467     }
468     else
469     {
470         INCREMENT( nReplace );
471         //Der letzte des LRU fliegt raus.
472         SwCacheObj *pObj = pLast;
473 
474         while ( pObj && pObj->IsLocked() )
475             pObj = pObj->GetPrev();
476         if ( !pObj )
477         {
478             ASSERT( sal_False, "Cache overflow." );
479             return sal_False;
480         }
481 
482         nPos = pObj->GetCachePos();
483         if ( pObj == pLast )
484         {   ASSERT( pObj->GetPrev(), "Last but no Prev" );
485             pLast = pObj->GetPrev();
486             pLast->SetNext( 0 );
487         }
488         else
489         {
490             if ( pObj->GetPrev() )
491                 pObj->GetPrev()->SetNext( pObj->GetNext() );
492             if ( pObj->GetNext() )
493                 pObj->GetNext()->SetPrev( pObj->GetPrev() );
494         }
495         delete pObj;
496         *(pData + nPos) = pNew;
497     }
498     pNew->SetCachePos( nPos );
499 
500     //Anstelle von ToTop, einfach als pFirst einfuegen.
501 //  ToTop( nPos );
502     if ( pFirst )
503     {
504         if ( pFirst->GetPrev() )
505         {   pFirst->GetPrev()->SetNext( pNew );
506             pNew->SetPrev( pFirst->GetPrev() );
507         }
508         pFirst->SetPrev( pNew );
509         pNew->SetNext( pFirst );
510     }
511     else
512     {   ASSERT( !pLast, "Last but no First." );
513         pLast = pNew;
514     }
515     if ( pFirst == pRealFirst )
516         pRealFirst = pNew;
517     pFirst = pNew;
518 
519     CHECK;
520     return sal_True;
521 }
522 
523 /*************************************************************************
524 |*
525 |*  SwCache::SetLRUOfst()
526 |*
527 |*  Ersterstellung      MA 15. Mar. 94
528 |*  Letzte Aenderung    MA 15. Mar. 94
529 |*
530 |*************************************************************************/
531 
532 
SetLRUOfst(const sal_uInt16 nOfst)533 void SwCache::SetLRUOfst( const sal_uInt16 nOfst )
534 {
535     if ( !pRealFirst || ((Count() - aFreePositions.Count()) < nOfst) )
536         return;
537 
538     CHECK;
539     pFirst = pRealFirst;
540     for ( sal_uInt16 i = 0; i < Count() && i < nOfst; ++i )
541     {
542         if ( pFirst->GetNext() && pFirst->GetNext()->GetNext() )
543             pFirst = pFirst->GetNext();
544         else
545             break;
546     }
547     CHECK;
548 }
549 
550 /*************************************************************************
551 |*
552 |*  SwCacheObj::SwCacheObj()
553 |*
554 |*  Ersterstellung      MA 15. Mar. 94
555 |*  Letzte Aenderung    MA 24. Nov. 95
556 |*
557 |*************************************************************************/
558 
559 
SwCacheObj(const void * pOwn)560 SwCacheObj::SwCacheObj( const void *pOwn ) :
561     pNext( 0 ),
562     pPrev( 0 ),
563     nCachePos( USHRT_MAX ),
564     nLock( 0 ),
565     pOwner( pOwn )
566 {
567 }
568 
569 
570 
~SwCacheObj()571 SwCacheObj::~SwCacheObj()
572 {
573 }
574 
575 /*************************************************************************
576 |*
577 |*  SwCacheObj::SetLock(), Unlock()
578 |*
579 |*  Ersterstellung      MA 15. Mar. 94
580 |*  Letzte Aenderung    MA 15. Mar. 94
581 |*
582 |*************************************************************************/
583 
584 #ifdef DBG_UTIL
585 
586 
587 
Lock()588 void SwCacheObj::Lock()
589 {
590     ASSERT( nLock < UCHAR_MAX, "To many Locks for CacheObject." );
591     ++nLock;
592 }
593 
594 
595 
Unlock()596 void SwCacheObj::Unlock()
597 {
598     ASSERT( nLock, "No more Locks available." );
599     --nLock;
600 }
601 #endif
602 
603 
~SwCacheAccess()604 SwCacheAccess::~SwCacheAccess()
605 {
606     if ( pObj )
607         pObj->Unlock();
608 }
609 
610 /*************************************************************************
611 |*
612 |*  SwCacheAccess::Get()
613 |*
614 |*  Ersterstellung      MA 15. Mar. 94
615 |*  Letzte Aenderung    MA 04. Apr. 95
616 |*
617 |*************************************************************************/
618 
619 
_Get()620 void SwCacheAccess::_Get()
621 {
622     ASSERT( !pObj, "SwCacheAcces Obj already available." );
623 
624     pObj = NewObj();
625     if ( !rCache.Insert( pObj ) )
626     {
627         delete pObj;
628         pObj = 0;
629     }
630     else
631         pObj->Lock();
632 }
633 
634 /*************************************************************************
635 |*
636 |*  SwCacheAccess::IsAvailable()
637 |*
638 |*  Ersterstellung      MA 23. Mar. 94
639 |*  Letzte Aenderung    MA 23. Mar. 94
640 |*
641 |*************************************************************************/
642 
643 
IsAvailable() const644 sal_Bool SwCacheAccess::IsAvailable() const
645 {
646     return pObj != 0;
647 }
648 
649 
650 
651 
652 
653