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 // if page not found or page data not valid anymore, use active page to read data |
720 // if page not found or page data not valid anymore, use active page to read data |
723 if (!pPage) |
721 if (!pPage) |
724 { |
722 { |
725 TRAPD(err, pPage = UpdateActivePageL(aPos)); |
723 TRAPD(err, pPage = UpdateActivePageL(aPos)); |
726 if (err != KErrNone) |
724 if (err != KErrNone) |
727 { |
725 { |
728 // problem occurred reading active page, return immediately. |
726 // problem occurred reading active page, return immediately. |
729 return; |
727 return; |
730 } |
728 } |
731 } |
729 } |
732 |
730 |
733 // by now, the page is either locked or active page |
731 // by now, the page is either locked or active page |
|
732 ASSERT(pPage && pPage->IsValid() && pPage->IsLocked()); |
734 ASSERT(pPage && pPage->IsValid() && pPage->IsLocked()); |
733 |
735 |
734 |
736 |
735 |
737 // if we used the active page (last on the queue), try to grow the cache. |
736 TBool allocateNewPage = pPage == iLockedQ.Last() && !CacheIsFull(); |
738 TBool growCache = pPage == iLockedQ.Last(); |
737 |
|
738 |
739 |
739 switch (pPage->PageType()) |
740 switch (pPage->PageType()) |
740 { |
741 { |
741 case TDynamicDirCachePage::EUnlocked: |
742 case TDynamicDirCachePage::EUnlocked: |
742 { |
743 { |
760 } |
761 } |
761 default: |
762 default: |
762 ASSERT(0); |
763 ASSERT(0); |
763 } |
764 } |
764 |
765 |
765 if (allocateNewPage) |
766 if (CacheIsFull() || !growCache) |
766 { |
767 return; |
767 TDynamicDirCachePage* nPage = NULL; |
768 |
768 TRAPD(err, nPage = AllocateAndLockNewPageL(0)); |
769 // attempt to grow the cache by appending a clean, new page at the end of the LRU list. |
769 if (err == KErrNone) |
770 // This can fail when out of memory; the LRU mechanism then makes sure the oldest page will be re-used. |
770 { |
771 TDynamicDirCachePage* nPage = AllocateAndLockNewPage(0); |
771 |
772 if (!nPage) |
772 // about to add a page to end of locked queue, so lie about iLockedQCount |
773 return; |
773 iLockedQCount++; |
774 |
774 CheckThresholds(); |
775 // about to add a page to end of locked queue, so lie about iLockedQCount |
775 iLockedQCount--; |
776 iLockedQCount++; |
776 |
777 CheckThresholds(); |
777 iLockedQ.AddLast(*nPage); |
778 iLockedQCount--; |
778 nPage->SetPageType(TDynamicDirCachePage::ELocked); |
779 |
779 ++iLockedQCount; |
780 iLockedQ.AddLast(*nPage); |
780 LookupTblAdd(nPage); |
781 nPage->SetPageType(TDynamicDirCachePage::ELocked); |
781 } |
782 ++iLockedQCount; |
782 } |
783 LookupTblAdd(nPage); |
783 } |
784 } |
784 |
785 |
785 /** |
786 /** |
786 Implementation of pure virtual function. |
787 Implementation of pure virtual function. |
787 @see MDiskSpecialAccessor::MakePageMRU() |
788 @see MDiskSpecialAccessor::MakePageMRU() |
819 if (activePage->StartPos() == pageStartMedPos && activePage->IsValid()) |
820 if (activePage->StartPos() == pageStartMedPos && activePage->IsValid()) |
820 { |
821 { |
821 return activePage; |
822 return activePage; |
822 } |
823 } |
823 |
824 |
824 __PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, activePage->StartPos()); |
825 //__PRINT2(_L("CDynamicDirCache::UpdateActivePageL(aPos=%lx, active=%lx)"), aPos, activePage->StartPos()); |
825 |
826 |
826 activePage->Deque(); |
827 activePage->Deque(); |
827 LookupTblRemove(activePage->StartPos()); |
828 LookupTblRemove(activePage->StartPos()); |
828 |
829 |
829 // set start med pos value, no other effects, only available to active page |
830 // set start med pos value, no other effects, only available to active page |
896 when creating iActive page or making a page MRU (which might result in page evictions). |
897 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. |
898 @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. |
899 @param aStartMedPos the starting media address of the page to be created. |
899 @pre aStartMedPos should not already be existing in the cache. |
900 @pre aStartMedPos should not already be existing in the cache. |
900 */ |
901 */ |
901 TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos) |
902 TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPage(TInt64 aStartMedPos) |
902 { |
903 { |
903 __PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos); |
904 __PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPage(aStartMedPos=%lx)"), aStartMedPos); |
904 |
905 |
905 TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs()); |
906 TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs()); |
906 if (startRamAddr) |
907 |
907 { |
908 if (!startRamAddr) |
908 // create new page and return |
909 return NULL; |
909 TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr); |
910 |
910 pPage->SetLocked(ETrue); |
911 TDynamicDirCachePage* pPage = TDynamicDirCachePage::CreateCachePage(this, aStartMedPos, startRamAddr); |
911 pPage->SetValid(EFalse); |
912 |
912 return pPage; |
913 // Failure would mean the cache chunk was able to grow but we've run out of heap. |
913 } |
914 // This seems extremely unlikely, but decommit the now-unmanageable cache segment just in case. |
914 |
915 if (!pPage) |
915 return NULL; |
916 { |
916 } |
917 iCacheMemoryClient->DecommitSegments(startRamAddr, PageSizeInSegs()); |
|
918 return NULL; |
|
919 } |
|
920 |
|
921 pPage->SetLocked(ETrue); |
|
922 pPage->SetValid(EFalse); |
|
923 return pPage; |
|
924 } |
|
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. |
921 @see CDynamicDirCache::Control() |
930 @see CDynamicDirCache::Control() |