37 @param aOwnerCache pointer of the cache that owns this page |
37 @param aOwnerCache pointer of the cache that owns this page |
38 @param aStartMedPos the start address on the media that this page caches |
38 @param aStartMedPos the start address on the media that this page caches |
39 @param aStartRamAddr the start address in the ram that this page content lives |
39 @param aStartRamAddr the start address in the ram that this page content lives |
40 */ |
40 */ |
41 TDynamicDirCachePage::TDynamicDirCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr) |
41 TDynamicDirCachePage::TDynamicDirCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr) |
42 :iStartMedPos(aStartMedPos), |
42 :iStartMedPos(aStartMedPos), |
43 iStartRamAddr(aStartRamAddr), |
43 iStartRamAddr(aStartRamAddr), |
44 iOwnerCache(aOwnerCache), |
44 iOwnerCache(aOwnerCache), |
45 iValid(EFalse), |
45 iValid(EFalse), |
46 iLocked(EFalse) |
46 iLocked(EFalse) |
47 { |
47 { |
48 //__PRINT3(_L("TDynamicDirCachePage::TDynamicDirCachePage(aStartMedPos=%lx, aStartRamAddr=0x%X, aPageSize=%u)"), aStartMedPos, aStartRamAddr, PageSizeInBytes()); |
48 //__PRINT3(_L("TDynamicDirCachePage::TDynamicDirCachePage(aStartMedPos=%lx, aStartRamAddr=0x%X, aPageSize=%u)"), aStartMedPos, aStartRamAddr, PageSizeInBytes()); |
49 iType = EUnknown; |
49 iType = EUnknown; |
50 } |
50 } |
51 |
51 |
102 /** |
102 /** |
103 Constructor of CDynamicDirCache. |
103 Constructor of CDynamicDirCache. |
104 @param aDrive local drive interface to read/write media |
104 @param aDrive local drive interface to read/write media |
105 @param aMinPageNum the minimum page number for the cache, includes iActive page and locked pages. |
105 @param aMinPageNum the minimum page number for the cache, includes iActive page and locked pages. |
106 @param aMaxPageNum the maximum page number for the cache, includes iActive page, locked pages and unlocked pages. |
106 @param aMaxPageNum the maximum page number for the cache, includes iActive page, locked pages and unlocked pages. |
107 @param aPageSizeInBytesLog2 the log2 value of page size in bytes, assumes page size is always a power of two |
107 @param aPageSizeInBytesLog2 Log2 of the page size in bytes, this is the cache read granularity |
108 */ |
108 @param aWrGranularityLog2 Log2(cache write granularity) |
109 CDynamicDirCache::CDynamicDirCache(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeInBytesLog2) |
109 */ |
110 :iPageSizeLog2(aPageSizeInBytesLog2), |
110 CDynamicDirCache::CDynamicDirCache(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeInBytesLog2, TUint32 aWrGranularityLog2) |
111 iMinSizeInPages(aMinPageNum), |
111 :iPageSizeLog2(aPageSizeInBytesLog2), |
112 iMaxSizeInPages(aMaxPageNum), |
112 iWrGranularityLog2(aWrGranularityLog2), |
113 iDrive(aDrive), |
113 iMinSizeInPages(aMinPageNum), |
114 iLockedQ(_FOFF(TDynamicDirCachePage, iLink)), |
114 iMaxSizeInPages(aMaxPageNum), |
115 iUnlockedQ(_FOFF(TDynamicDirCachePage, iLink)), |
115 iDrive(aDrive), |
116 iLockedQCount(0), |
116 iLockedQ(_FOFF(TDynamicDirCachePage, iLink)), |
117 iUnlockedQCount(0), |
117 iUnlockedQ(_FOFF(TDynamicDirCachePage, iLink)), |
118 iHashFunction(HashFunction), |
118 iLockedQCount(0), |
119 iIdentityFunction(IdentityFunction), |
119 iUnlockedQCount(0), |
120 iLookupTable(iHashFunction, iIdentityFunction) |
120 iHashFunction(HashFunction), |
|
121 iIdentityFunction(IdentityFunction), |
|
122 iLookupTable(iHashFunction, iIdentityFunction) |
121 { |
123 { |
122 iPageSizeInBytes = 1 << aPageSizeInBytesLog2; |
124 iPageSizeInBytes = 1 << aPageSizeInBytesLog2; |
123 iCacheDisabled = EFalse; |
125 iCacheDisabled = EFalse; |
124 iMinCacheSizeInBytes = aMinPageNum << aPageSizeInBytesLog2; |
126 iMinCacheSizeInBytes = aMinPageNum << aPageSizeInBytesLog2; |
125 iMaxCacheSizeInBytes = aMaxPageNum << aPageSizeInBytesLog2; |
127 iMaxCacheSizeInBytes = aMaxPageNum << aPageSizeInBytesLog2; |
155 |
157 |
156 |
158 |
157 // allocate as many permanently locked pages as there are threads - plus one |
159 // allocate as many permanently locked pages as there are threads - plus one |
158 // otherwise DoMakePageMRU() won't work properly with only one thread |
160 // otherwise DoMakePageMRU() won't work properly with only one thread |
159 //-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool) |
161 //-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool) |
160 iPermanentlyAllocatedPageCount = 1; |
162 const TUint KThreadCount = 1; |
|
163 iPermanentlyAllocatedPageCount = KThreadCount + 1; |
161 |
164 |
162 if (iPermanentlyAllocatedPageCount > iMinSizeInPages) |
165 if (iPermanentlyAllocatedPageCount > iMinSizeInPages) |
163 iMinSizeInPages = iPermanentlyAllocatedPageCount; |
166 iMinSizeInPages = iPermanentlyAllocatedPageCount; |
164 |
167 |
165 for (TUint n=0; n<iPermanentlyAllocatedPageCount; n++) |
168 for (TUint n=0; n<iPermanentlyAllocatedPageCount; n++) |
172 } |
175 } |
173 |
176 |
174 /** |
177 /** |
175 Static factory function of CDynamicDirCache |
178 Static factory function of CDynamicDirCache |
176 */ |
179 */ |
177 CDynamicDirCache* CDynamicDirCache::NewL(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeLog2, const TDesC& aClientName) |
180 CDynamicDirCache* CDynamicDirCache::NewL(TDriveInterface& aDrive, TUint32 aMinPageNum, TUint32 aMaxPageNum, TUint32 aPageSizeLog2, TUint32 aWrGranularityLog2, const TDesC& aClientName) |
178 { |
181 { |
179 __PRINT3(_L("CDynamicDirCache::NewL(MinPageNum=%u, MaxPageNum=%u, page=%u)"), aMinPageNum, aMaxPageNum, 1<<aPageSizeLog2); |
182 __PRINT3(_L("CDynamicDirCache::NewL(MinPageNum=%u, MaxPageNum=%u, page=%u)"), aMinPageNum, aMaxPageNum, 1<<aPageSizeLog2); |
180 CDynamicDirCache* pSelf = new (ELeave) CDynamicDirCache(aDrive, aMinPageNum, aMaxPageNum, aPageSizeLog2); |
183 CDynamicDirCache* pSelf = new (ELeave) CDynamicDirCache(aDrive, aMinPageNum, aMaxPageNum, aPageSizeLog2, aWrGranularityLog2); |
181 CleanupStack::PushL(pSelf); |
184 CleanupStack::PushL(pSelf); |
182 pSelf->ConstructL(aClientName); |
185 pSelf->ConstructL(aClientName); |
183 CleanupStack::Pop(); |
186 CleanupStack::Pop(); |
184 return pSelf; |
187 return pSelf; |
185 } |
188 } |
336 @param aPos the starting position of the media address to be write. |
339 @param aPos the starting position of the media address to be write. |
337 @param aData the starting address that the writing content lives in the ram. |
340 @param aData the starting address that the writing content lives in the ram. |
338 @param aDataLen the length of the content to be written. |
341 @param aDataLen the length of the content to be written. |
339 @pre aDataLen should be no more than page size. |
342 @pre aDataLen should be no more than page size. |
340 */ |
343 */ |
341 void CDynamicDirCache::WriteDataOntoSinglePageL(TInt64 aPos, const TUint8* aData, TUint32 aDataLen) |
344 TDynamicDirCachePage* CDynamicDirCache::WriteDataOntoSinglePageL(TInt64 aPos, const TUint8* aData, TUint32 aDataLen) |
342 { |
345 { |
343 ASSERT(aDataLen <= iPageSizeInBytes); |
346 ASSERT(aDataLen <= iPageSizeInBytes); |
344 //-- the data section is in the cache page entirely, take data directly from the cache |
347 //-- the data section is in the cache page entirely, take data directly from the cache |
345 TDynamicDirCachePage* pPage = FindPageByPos(aPos); |
348 TDynamicDirCachePage* pPage = FindPageByPos(aPos); |
346 if (pPage) |
349 if (pPage) |
405 TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos); |
409 TUint32 bytesToPageEnd = (TUint32)(pageStartMedPos + PageSz - aPos); |
406 |
410 |
407 // __PRINT5(_L("CDynamicDirCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pageStartMedPos, PageSz, bytesToPageEnd); |
411 // __PRINT5(_L("CDynamicDirCache::WriteL: aPos=%lx, aLength=%x, page:%lx, pageSz:%x, bytesToPageEnd=%x"), aPos, dataLen, pageStartMedPos, PageSz, bytesToPageEnd); |
408 |
412 |
409 if(dataLen <= bytesToPageEnd) |
413 if(dataLen <= bytesToPageEnd) |
410 { |
414 {//-- make small write a multiple of a write granularity size (if it is used at all) |
411 WriteDataOntoSinglePageL(aPos, pData, dataLen); |
415 //-- this is not the best way to use write granularity, but we would need to refactor cache pages code to make it normal |
|
416 |
|
417 TDynamicDirCachePage* pPage = WriteDataOntoSinglePageL(aPos, pData, dataLen); |
|
418 TPtrC8 desBlock(aDes); |
|
419 |
|
420 if(iWrGranularityLog2) |
|
421 {//-- write granularity is used |
|
422 const TInt64 newPos = (aPos >> iWrGranularityLog2) << iWrGranularityLog2; //-- round position down to the granularity unit size |
|
423 TUint32 newLen = (TUint32)(aPos - newPos)+dataLen; |
|
424 newLen = RoundUp(newLen, iWrGranularityLog2); |
|
425 |
|
426 const TUint8* pd = pPage->PtrInPage(newPos); |
|
427 desBlock.Set(pd, newLen); |
|
428 aPos = newPos; |
|
429 |
|
430 } |
|
431 |
|
432 //-- write data to the media |
|
433 const TInt nErr = iDrive.WriteCritical(aPos, desBlock); |
|
434 if(nErr != KErrNone) |
|
435 {//-- some serious problem occured during writing, invalidate cache. |
|
436 InvalidateCache(); |
|
437 User::Leave(nErr); |
|
438 } |
|
439 |
|
440 |
412 } |
441 } |
413 else |
442 else |
414 { |
443 {//-- Data to be written cross cache page boundary or probably we have more than 1 page to write |
|
444 //-- this is a very rare case. |
415 __PRINT(_L("CDynamicDirCache::WriteL() CROSS PAGE!")); |
445 __PRINT(_L("CDynamicDirCache::WriteL() CROSS PAGE!")); |
416 |
446 |
417 //-- Data to be written cross cache page boundary or probably we have more than 1 page to write |
447 //-- Data to be written cross cache page boundary or probably we have more than 1 page to write |
418 TInt64 currMediaPos(aPos); |
448 TInt64 currMediaPos(aPos); |
419 |
449 |
437 //-- 3. write the rest of the data |
467 //-- 3. write the rest of the data |
438 if(dataLen > 0) |
468 if(dataLen > 0) |
439 { |
469 { |
440 WriteDataOntoSinglePageL(currMediaPos, pData, dataLen); |
470 WriteDataOntoSinglePageL(currMediaPos, pData, dataLen); |
441 } |
471 } |
442 }// else(dataLen <= bytesToPageEnd) |
|
443 |
|
444 |
472 |
445 //-- write data to the media |
473 //-- write data to the media |
446 const TInt nErr = iDrive.WriteCritical(aPos,aDes); |
474 const TInt nErr = iDrive.WriteCritical(aPos,aDes); |
447 if(nErr != KErrNone) |
475 if(nErr != KErrNone) |
448 {//-- some serious problem occured during writing, invalidate cache. |
476 {//-- some serious problem occured during writing, invalidate cache. |
449 InvalidateCache(); |
477 InvalidateCache(); |
450 User::Leave(nErr); |
478 User::Leave(nErr); |
451 } |
479 } |
|
480 |
|
481 |
|
482 }// else(dataLen <= bytesToPageEnd) |
|
483 |
|
484 |
452 } |
485 } |
453 |
486 |
454 /** |
487 /** |
455 Invalidate the cache |
488 Invalidate the cache |
456 @see MWTCacheInterface::InvalidateCache() |
489 @see MWTCacheInterface::InvalidateCache() |
647 |
678 |
648 void CDynamicDirCache::DoMakePageMRU(TInt64 aPos) |
679 void CDynamicDirCache::DoMakePageMRU(TInt64 aPos) |
649 { |
680 { |
650 // __PRINT1(_L("MakePageMRU (%lx)"), aPos); |
681 // __PRINT1(_L("MakePageMRU (%lx)"), aPos); |
651 // __PRINT4(_L("Current Cache State: iLockedQCount=%d, iUnlockedQCount=%d, iLookupTbl=%d, iMaxSizeInPages=%d"), iLockedQCount, iUnlockedQCount, iLookupTable.Count(), iMaxSizeInPages); |
682 // __PRINT4(_L("Current Cache State: iLockedQCount=%d, iUnlockedQCount=%d, iLookupTbl=%d, iMaxSizeInPages=%d"), iLockedQCount, iUnlockedQCount, iLookupTable.Count(), iMaxSizeInPages); |
|
683 // check there are at least two locked pages |
|
684 ASSERT(iLockedQCount > 1); |
|
685 |
652 // check the MRU page first, if it is already the MRU page, we can return immediately |
686 // check the MRU page first, if it is already the MRU page, we can return immediately |
653 TInt64 pageStartMedPos = CalcPageStartPos(aPos); |
687 TInt64 pageStartMedPos = CalcPageStartPos(aPos); |
654 if (!iLockedQ.IsEmpty()) |
688 if (!iLockedQ.IsEmpty()) |
655 { |
689 { |
656 if (iLockedQ.First()->StartPos() == pageStartMedPos) |
690 if (iLockedQ.First()->StartPos() == pageStartMedPos) |
917 /** |
951 /** |
918 Dump cache content, only enabled in debug mode. |
952 Dump cache content, only enabled in debug mode. |
919 @see CDynamicDirCache::Control() |
953 @see CDynamicDirCache::Control() |
920 */ |
954 */ |
921 void CDynamicDirCache::Dump() |
955 void CDynamicDirCache::Dump() |
922 { |
956 { |
923 __PRINT(_L("======== CDynamicDirCache::Dump =========")); |
957 __PRINT(_L("======== CDynamicDirCache::Dump =========")); |
924 if (!iLockedQ.IsEmpty()) |
958 if (!iLockedQ.IsEmpty()) |
925 { |
959 { |
926 TDblQueIter<TDynamicDirCachePage> q(iLockedQ); |
960 TDblQueIter<TDynamicDirCachePage> q(iLockedQ); |
927 q.SetToFirst(); |
961 q.SetToFirst(); |
928 TInt i = 0; |
962 TInt i = 0; |
929 while((TDynamicDirCachePage*)q) |
963 while((TDynamicDirCachePage*)q) |
930 { |
964 { |
931 TDynamicDirCachePage* pP = q++; |
965 TDynamicDirCachePage* pP = q++; |
932 __PRINT5(_L("=== CDynamicDirCache::iLockedQ\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); |
966 __PRINT5(_L("=== CDynamicDirCache::iLockedQ [%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); |
933 } |
967 } |
934 } |
968 } |
935 if (!iUnlockedQ.IsEmpty()) |
969 __PRINT(_L("=== CDynamicDirCache:: --------------------")); |
936 { |
970 |
937 TDblQueIter<TDynamicDirCachePage> q(iUnlockedQ); |
971 if (!iUnlockedQ.IsEmpty()) |
938 q.SetToFirst(); |
972 { |
939 TInt i = 0; |
973 TDblQueIter<TDynamicDirCachePage> q(iUnlockedQ); |
940 while((TDynamicDirCachePage*)q) |
974 q.SetToFirst(); |
941 { |
975 TInt i = 0; |
942 TDynamicDirCachePage* pP = q++; |
976 while((TDynamicDirCachePage*)q) |
943 __PRINT5(_L("=== CDynamicDirCache::iUnlockedQ\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); |
977 { |
944 } |
978 TDynamicDirCachePage* pP = q++; |
945 } |
979 __PRINT5(_L("=== CDynamicDirCache::iUnlockedQ [%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); |
946 |
980 } |
947 if (iLookupTable.Count()) |
981 } |
948 { |
982 __PRINT(_L("=== CDynamicDirCache:: --------------------")); |
949 TInt i = 0; |
983 |
950 THashSetIter<TLookupEntry> iter(iLookupTable); |
984 if (iLookupTable.Count()) |
951 TLookupEntry* pEntry; |
985 { |
952 pEntry = (TLookupEntry*) iter.Next(); |
986 TInt i = 0; |
953 while(pEntry) |
987 THashSetIter<TLookupEntry> iter(iLookupTable); |
954 { |
988 TLookupEntry* pEntry; |
955 TDynamicDirCachePage* pP = pEntry->iPage; |
989 pEntry = (TLookupEntry*) iter.Next(); |
956 __PRINT5(_L("=== CDynamicDirCache::iLookupTable\t[%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); |
990 while(pEntry) |
957 pEntry = (TLookupEntry*) iter.Next(); |
991 { |
958 }; |
992 TDynamicDirCachePage* pP = pEntry->iPage; |
959 } |
993 __PRINT5(_L("=== CDynamicDirCache::iLookupTable [%4d](pos=%lx, locked=%d, valid=%d, size=%u)"), i++, pP->StartPos(), pP->IsLocked(), pP->IsValid(), pP->PageSizeInBytes()); |
960 __PRINT(_L("===========================================\n")); |
994 pEntry = (TLookupEntry*) iter.Next(); |
961 } |
995 }; |
|
996 } |
|
997 __PRINT(_L("===========================================\n")); |
|
998 } |
962 #endif //_DEBUG |
999 #endif //_DEBUG |
963 |
1000 |
964 /** |
1001 /** |
965 Lock an unlocked page, or do nothing if the page is already locked. |
1002 Lock an unlocked page, or do nothing if the page is already locked. |
966 @return TUint8* pointer of the page to be locked, if locking is successful, otherwise return NULL. |
1003 @return TUint8* pointer of the page to be locked, if locking is successful, otherwise return NULL. |