xref: /trunk/main/sw/source/core/bastyp/swcache.cxx (revision 8f79cfd8)
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, "SwCacheAccess 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