25 |
25 |
26 /** |
26 /** |
27 The static cache page creation function. |
27 The static cache page creation function. |
28 Cache page objects are not supposed to be created on the stack, so this factory function is required. |
28 Cache page objects are not supposed to be created on the stack, so this factory function is required. |
29 */ |
29 */ |
30 TDynamicDirCachePage* TDynamicDirCachePage::NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr) |
30 TDynamicDirCachePage* TDynamicDirCachePage::CreateCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr) |
31 { |
31 { |
32 return new(ELeave) TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr); |
32 return new TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr); |
33 } |
33 } |
34 |
34 |
35 /** |
35 /** |
36 Cache page constructor. |
36 Cache page constructor. |
37 @param aOwnerCache pointer of the cache that owns this page |
37 @param aOwnerCache pointer of the cache that owns this page |
156 } |
156 } |
157 |
157 |
158 |
158 |
159 // 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 |
160 // otherwise DoMakePageMRU() won't work properly with only one thread |
160 // otherwise DoMakePageMRU() won't work properly with only one thread |
161 //-- 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) |
162 const TUint KThreadCount = 1; |
162 const TUint KThreadCount = 1; |
163 iPermanentlyAllocatedPageCount = KThreadCount + 1; |
163 iPermanentlyAllocatedPageCount = KThreadCount + 1; |
164 |
164 |
165 if (iPermanentlyAllocatedPageCount > iMinSizeInPages) |
165 if (iPermanentlyAllocatedPageCount > iMinSizeInPages) |
166 iMinSizeInPages = iPermanentlyAllocatedPageCount; |
166 iMinSizeInPages = iPermanentlyAllocatedPageCount; |
167 |
167 |
168 for (TUint n=0; n<iPermanentlyAllocatedPageCount; n++) |
168 for (TUint n=0; n<iPermanentlyAllocatedPageCount; n++) |
169 { |
169 { |
170 TDynamicDirCachePage* pPage = AllocateAndLockNewPageL(0); |
170 TDynamicDirCachePage* pPage = AllocateAndLockNewPage(0); |
|
171 ASSERT(pPage); |
|
172 if (!pPage) |
|
173 User::Leave(KErrNoMemory); |
171 AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked); |
174 AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked); |
172 LookupTblAdd(pPage); |
175 LookupTblAdd(pPage); |
173 } |
176 } |
174 |
177 |
175 } |
178 } |
692 return; |
695 return; |
693 } |
696 } |
694 } |
697 } |
695 |
698 |
696 TDynamicDirCachePage* pPage = FindPageByPos(aPos); |
699 TDynamicDirCachePage* pPage = FindPageByPos(aPos); |
697 if (pPage) |
700 if (pPage) |
698 { |
701 { |
699 ASSERT(pPage->IsValid()); |
702 ASSERT(pPage->IsValid()); |
700 // lock page before make it MRU |
703 // lock page before make it MRU |
701 if (pPage->PageType() == TDynamicDirCachePage::EUnlocked) |
704 if (pPage->PageType() == TDynamicDirCachePage::EUnlocked) |
702 { |
705 { |
703 ASSERT(!pPage->IsLocked()); |
706 ASSERT(!pPage->IsLocked()); |
704 if (LockPage(pPage) == NULL) |
707 if (LockPage(pPage) == NULL) |
705 { |
708 { |
706 DeQueue(pPage); |
709 DeQueue(pPage); |
707 LookupTblRemove(pPage->StartPos()); |
710 LookupTblRemove(pPage->StartPos()); |
708 DecommitPage(pPage); |
711 DecommitPage(pPage); |
709 delete pPage; |
712 delete pPage; |
710 pPage = NULL; |
713 pPage = NULL; |
711 } |
714 } |
712 } |
715 } |
713 else |
716 else |
714 { |
717 { |
715 // error checking: page should either be locked or active |
718 // error checking: page should either be locked or active |
716 ASSERT(LockPage(pPage) != NULL); |
719 ASSERT(LockPage(pPage) != NULL); |
717 } |
720 } |
718 } |
721 } |
719 |
722 |
720 // if page not found or page data not valid anymore, use active page to read data |
723 // if page not found or page data not valid anymore, use active page to read data |
721 if (!pPage) |
724 if (!pPage) |
722 { |
725 { |
723 TRAPD(err, pPage = UpdateActivePageL(aPos)); |
726 TRAPD(err, pPage = UpdateActivePageL(aPos)); |
724 if (err != KErrNone) |
727 if (err != KErrNone) |
725 { |
728 { |
726 // problem occurred reading active page, return immediately. |
729 // problem occurred reading active page, return immediately. |
727 return; |
730 return; |
728 } |
731 } |
729 } |
732 } |
730 |
733 |
731 // by now, the page is either locked or active page |
734 // by now, the page is either locked or active page |
732 ASSERT(pPage && pPage->IsValid() && pPage->IsLocked()); |
735 ASSERT(pPage && pPage->IsValid() && pPage->IsLocked()); |
733 |
736 |
734 |
737 |
735 |
738 // if we used the active page (last on the queue), try to grow the cache. |
736 TBool allocateNewPage = pPage == iLockedQ.Last() && !CacheIsFull(); |
739 TBool growCache = pPage == iLockedQ.Last(); |
737 |
|
738 |
740 |
739 switch (pPage->PageType()) |
741 switch (pPage->PageType()) |
740 { |
742 { |
741 case TDynamicDirCachePage::EUnlocked: |
743 case TDynamicDirCachePage::EUnlocked: |
742 { |
744 { |
760 } |
762 } |
761 default: |
763 default: |
762 ASSERT(0); |
764 ASSERT(0); |
763 } |
765 } |
764 |
766 |
765 if (allocateNewPage) |
767 if (CacheIsFull() || !growCache) |
766 { |
768 return; |
767 TDynamicDirCachePage* nPage = NULL; |
769 |
768 TRAPD(err, nPage = AllocateAndLockNewPageL(0)); |
770 // attempt to grow the cache by appending a clean, new page at the end of the LRU list. |
769 if (err == KErrNone) |
771 // This can fail when out of memory; the LRU mechanism then makes sure the oldest page will be re-used. |
770 { |
772 TDynamicDirCachePage* nPage = AllocateAndLockNewPage(0); |
771 |
773 if (!nPage) |
772 // about to add a page to end of locked queue, so lie about iLockedQCount |
774 return; |
773 iLockedQCount++; |
775 |
774 CheckThresholds(); |
776 // about to add a page to end of locked queue, so lie about iLockedQCount |
775 iLockedQCount--; |
777 iLockedQCount++; |
776 |
778 CheckThresholds(); |
777 iLockedQ.AddLast(*nPage); |
779 iLockedQCount--; |
778 nPage->SetPageType(TDynamicDirCachePage::ELocked); |
780 |
779 ++iLockedQCount; |
781 iLockedQ.AddLast(*nPage); |
780 LookupTblAdd(nPage); |
782 nPage->SetPageType(TDynamicDirCachePage::ELocked); |
781 } |
783 ++iLockedQCount; |
782 } |
784 LookupTblAdd(nPage); |
783 } |
785 } |
784 |
786 |
785 /** |
787 /** |
786 Implementation of pure virtual function. |
788 Implementation of pure virtual function. |
787 @see MDiskSpecialAccessor::MakePageMRU() |
789 @see MDiskSpecialAccessor::MakePageMRU() |
896 when creating iActive page or making a page MRU (which might result in page evictions). |
898 when creating iActive page or making a page MRU (which might result in page evictions). |
897 @return the pointer of the newly created page, or NULL if allocation failed. |
899 @return the pointer of the newly created page, or NULL if allocation failed. |
898 @param aStartMedPos the starting media address of the page to be created. |
900 @param aStartMedPos the starting media address of the page to be created. |
899 @pre aStartMedPos should not already be existing in the cache. |
901 @pre aStartMedPos should not already be existing in the cache. |
900 */ |
902 */ |
901 TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos) |
903 TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPage(TInt64 aStartMedPos) |
902 { |
904 { |
903 __PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos); |
905 __PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPage(aStartMedPos=%lx)"), aStartMedPos); |
904 |
906 |
905 TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs()); |
907 TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs()); |
906 if (startRamAddr) |
908 |
907 { |
909 if (!startRamAddr) |
908 // create new page and return |
910 return NULL; |
909 TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr); |
911 |
910 pPage->SetLocked(ETrue); |
912 TDynamicDirCachePage* pPage = TDynamicDirCachePage::CreateCachePage(this, aStartMedPos, startRamAddr); |
911 pPage->SetValid(EFalse); |
913 |
912 return pPage; |
914 // Failure would mean the cache chunk was able to grow but we've run out of heap. |
913 } |
915 // This seems extremely unlikely, but decommit the now-unmanageable cache segment just in case. |
914 |
916 if (!pPage) |
915 return NULL; |
917 { |
|
918 iCacheMemoryClient->DecommitSegments(startRamAddr, PageSizeInSegs()); |
|
919 return NULL; |
|
920 } |
|
921 |
|
922 pPage->SetLocked(ETrue); |
|
923 pPage->SetValid(EFalse); |
|
924 return pPage; |
916 } |
925 } |
917 |
926 |
918 #ifdef _DEBUG |
927 #ifdef _DEBUG |
919 /** |
928 /** |
920 Dump cache information, only enabled in debug mode. |
929 Dump cache information, only enabled in debug mode. |