1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/persistentstorage/store/UPAGE/UP_CACHE.CPP Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,335 @@
1.4 +// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "UP_STD.H"
1.20 +
1.21 +struct SCachePage
1.22 + {
1.23 + TCachePage iPage[1];
1.24 + TUint8 iData[KPoolPageSize];
1.25 + };
1.26 +
1.27 +EXPORT_C CPageCache* CPageCache::NewL(TInt aPages)
1.28 +/** Allocates and constructs a new page cache.
1.29 +
1.30 +@param aPages Number of pages in the cache
1.31 +@return New page cache object */
1.32 + {
1.33 + CPageCache* cache=CPageCache::NewLC(aPages);
1.34 + CleanupStack::Pop();
1.35 + return cache;
1.36 + }
1.37 +
1.38 +EXPORT_C CPageCache* CPageCache::NewLC(TInt aPages)
1.39 +/** Allocates and constructs a new page cache, and leaves it on the cleanup stack.
1.40 +
1.41 +@param aPages Number of pages in the cache
1.42 +@return New page cache object */
1.43 + {
1.44 + CPageCache* cache=new(ELeave) CPageCache;
1.45 + CleanupStack::PushL(cache);
1.46 + cache->ConstructL(aPages);
1.47 + return cache;
1.48 + }
1.49 +
1.50 +EXPORT_C CPageCache::CPageCache()
1.51 + : iFree(_FOFF(TCachePage,iLink)-_FOFF(SCachePage,iPage[1]))/*,iPages(NULL),iEnd(NULL)*/
1.52 +/** Default constructor. */
1.53 + {
1.54 +#if defined(__PAGE_CACHE_STATS)
1.55 +// iStats.Reset();
1.56 +#endif
1.57 + }
1.58 +
1.59 +EXPORT_C void CPageCache::ConstructL(TInt aPages)
1.60 +/** Second phase construction.
1.61 +
1.62 +@param aPages Number of pages in the cache */
1.63 + {
1.64 + SCachePage* page=new(ELeave) SCachePage[aPages];
1.65 + SCachePage* end=page+aPages;
1.66 + iPages=page;
1.67 + iEnd=end;
1.68 + for (;page<end;++page)
1.69 + {
1.70 + page->iPage[0].iOwner=NULL;
1.71 + page->iPage[0].iChange=EPageNoChange;
1.72 + iFree.AddFirst(page->iPage[1]);
1.73 + }
1.74 + }
1.75 +
1.76 +EXPORT_C CPageCache::~CPageCache()
1.77 +/** Destructor.
1.78 +
1.79 +All cache pages are deleted. */
1.80 + {
1.81 +#if defined (_DEBUG)
1.82 + for (SCachePage* page=iPages,*end=iEnd;page<end;++page)
1.83 + __ASSERT_DEBUG(page->iPage[0].iOwner==NULL,Panic(EPageCacheInUse));
1.84 +#endif
1.85 + delete[] iPages;
1.86 + }
1.87 +
1.88 +TCachePage* CPageCache::Find(TCachePagePool* aPool,TPageRef aRef)
1.89 +//
1.90 +// Find a page in the cache.
1.91 +//
1.92 + {
1.93 + for (SCachePage* page=iPages,*end=iEnd;page<end;++page)
1.94 + {
1.95 + if (page->iPage[0].iOwner!=aPool)
1.96 + {
1.97 + __ASSERT_DEBUG(page->iPage[1].IsQued(),User::Invariant());
1.98 + // no other page pool can have locked pages
1.99 + continue;
1.100 + }
1.101 +//
1.102 + if (page->iPage[0].iRef==aRef)
1.103 + {
1.104 +#if defined(__PAGE_CACHE_STATS)
1.105 + if (page->iPage[1].IsQued())
1.106 + iStats.Hit(); // finding a locked page is not a hit, I'm afraid
1.107 +#endif
1.108 + return &page->iPage[1];
1.109 + }
1.110 + }
1.111 +#if defined(__PAGE_CACHE_STATS)
1.112 + iStats.Miss();
1.113 +#endif
1.114 + return NULL;
1.115 + }
1.116 +
1.117 +EXPORT_C TPageAbandonFunction TCachePagePool::AcquireL()
1.118 +/** Returns a function that abandons all locked pages for this page pool.
1.119 +
1.120 +@return A function that abandons all locked pages for this page pool. */
1.121 + {
1.122 + return &DoAbandon;
1.123 + }
1.124 +
1.125 +EXPORT_C TAny* TCachePagePool::AllocL()
1.126 +/** Allocates an unassigned page.
1.127 +
1.128 +@return Newly allocated page. */
1.129 + {
1.130 + CPageCache& cache=*iCache;
1.131 + __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
1.132 + TCachePage* page=DoAllocL(cache);
1.133 + page[-1].iOwner=this;
1.134 + __ASSERT_DEBUG(page[-1].iChange==EPageNoChange,User::Invariant());
1.135 + page[-1].iRef=KNullPageRef;
1.136 + page->Deque();
1.137 + return page;
1.138 + }
1.139 +
1.140 +EXPORT_C TAny* TCachePagePool::LockL(TPageRef aRef)
1.141 +/** Locks a page and returns a pointer to it.
1.142 +
1.143 +@param aRef Reference to page to lock
1.144 +@return Locked page */
1.145 + {
1.146 + if (aRef==KNullPageRef)
1.147 + __LEAVE(KErrNotFound);
1.148 +//
1.149 + CPageCache& cache=*iCache;
1.150 + __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
1.151 + TCachePage* page=cache.Find(this,aRef);
1.152 + if (page==NULL)
1.153 + { // it's not in the cache, allocate a free page
1.154 + page=DoAllocL(cache);
1.155 + page[-1].iOwner=NULL;
1.156 + __ASSERT_DEBUG(page[-1].iChange==EPageNoChange,User::Invariant());
1.157 + ReadL(aRef,page);
1.158 + page[-1].iOwner=this;
1.159 + page[-1].iRef=aRef;
1.160 + }
1.161 + __ASSERT_DEBUG(page->IsQued(),Panic(EPageDoubleLock)); // it mustn't be locked already
1.162 + page->Deque();
1.163 + return page;
1.164 + }
1.165 +
1.166 +EXPORT_C TPageRef TCachePagePool::AssignL(const TAny* aPage,TPageReclamation aReclamation)
1.167 +/** Assigns a reference to a new page and unlocks it.
1.168 +
1.169 +@param aPage Page to assign
1.170 +@param aReclamation Flag for page reclaimation settings
1.171 +@return Reference to page */
1.172 + {
1.173 + TCachePage* page=(TCachePage*)aPage;
1.174 + __ASSERT_DEBUG(page!=NULL&&!page->IsQued(),Panic(EPageNotLocked));
1.175 + __ASSERT_DEBUG(page[-1].iOwner==this&&page[-1].iRef==KNullPageRef,User::Invariant());
1.176 + CPageCache& cache=*iCache;
1.177 + __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
1.178 + page[-1].iOwner=NULL;
1.179 + __ASSERT_DEBUG(page[-1].iChange==EPageNoChange,User::Invariant());
1.180 + cache.iFree.AddLast(*page);
1.181 + TPageRef ref=ExtendL(page,aReclamation);
1.182 + page[-1].iOwner=this;
1.183 + page[-1].iRef=ref;
1.184 + return ref;
1.185 + }
1.186 +
1.187 +EXPORT_C void TCachePagePool::UpdateL(const TAny* aPage)
1.188 +/** Updates a page.
1.189 +
1.190 +@param aPage Page to update */
1.191 + {
1.192 + TCachePage* page=(TCachePage*)aPage;
1.193 + __ASSERT_DEBUG(page!=NULL&&!page->IsQued(),Panic(EPageNotLocked));
1.194 + __ASSERT_DEBUG(page[-1].iOwner==this&&page[-1].iRef!=KNullPageRef,User::Invariant());
1.195 + CPageCache& cache=*iCache;
1.196 + __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
1.197 + page[-1].iOwner=NULL;
1.198 + page[-1].iChange=EPageNoChange;
1.199 + cache.iFree.AddLast(*page);
1.200 + WriteL(page[-1].iRef,page,EPageUpdate);
1.201 + page[-1].iOwner=this;
1.202 + }
1.203 +
1.204 +EXPORT_C void TCachePagePool::Unlock(const TAny* aPage,TPageChange aChange)
1.205 +//
1.206 +// Unlock a page, depending on aChange:
1.207 +// EPageNoChange: just unlock
1.208 +// EPageDirty: mark the page as dirty
1.209 +// EPageUpdate: mark the page as needing a safe update
1.210 +// EPageAbandon: discard the page
1.211 +//
1.212 +/** Unlocks a page.
1.213 +
1.214 +@param aPage Page to unlock
1.215 +@param aChange How the page should be treated once it is unlocked */
1.216 + {
1.217 + TCachePage* page=(TCachePage*)aPage;
1.218 + __ASSERT_DEBUG(page!=NULL&&!page->IsQued(),Panic(EPageNotLocked));
1.219 + __ASSERT_DEBUG(page[-1].iOwner==this&&page[-1].iRef!=KNullPageRef,User::Invariant());
1.220 + CPageCache& cache=*iCache;
1.221 + __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
1.222 + if (aChange>page[-1].iChange)
1.223 + page[-1].iChange=aChange;
1.224 + else if (aChange<EPageNoChange)
1.225 + {
1.226 + page[-1].iOwner=NULL;
1.227 + page[-1].iChange=EPageNoChange;
1.228 + }
1.229 + cache.iFree.AddLast(*page);
1.230 + }
1.231 +
1.232 +EXPORT_C TInt TCachePagePool::Flush()
1.233 +/** Flush all pages in this pool from the cache.
1.234 +
1.235 +It ensures that any dirty pages are written into persistent storage, but does
1.236 +not remove them from the cache.
1.237 +
1.238 +@return KErrNone if successful, otherwise another of the system-wide error
1.239 +codes. */
1.240 + {
1.241 + TRAPD(r,FlushL());
1.242 + return r;
1.243 + }
1.244 +
1.245 +EXPORT_C void TCachePagePool::FlushL()
1.246 +/** Flushes all pages in this pool from the cache, leaving with a system-wide error
1.247 +code if an error occurs. */
1.248 + {
1.249 + CPageCache& cache=*iCache;
1.250 + __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
1.251 + for (SCachePage* page=cache.iPages,*end=cache.iEnd;page<end;++page)
1.252 + {
1.253 + __ASSERT_DEBUG(page->iPage[1].IsQued(),User::Invariant()); // there mustn't be any locked pages
1.254 + if (page->iPage[0].iOwner!=this)
1.255 + continue;
1.256 +//
1.257 + TPageChange change=page->iPage[0].iChange;
1.258 + if (change>EPageNoChange)
1.259 + {
1.260 + WriteL(page->iPage[0].iRef,&page->iPage[1],change);
1.261 + page->iPage[0].iChange=EPageNoChange;
1.262 + }
1.263 + }
1.264 + }
1.265 +
1.266 +EXPORT_C void TCachePagePool::Purge()
1.267 +/** Purge all pages in this pool from the cache.
1.268 +
1.269 +This discards all pages from the cache, without saving dirty pages. */
1.270 + {
1.271 + CPageCache& cache=*iCache;
1.272 + __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
1.273 + for (SCachePage* page=cache.iPages,*end=cache.iEnd;page<end;++page)
1.274 + {
1.275 + __ASSERT_DEBUG(page->iPage[1].IsQued(),User::Invariant()); // there mustn't be any locked pages
1.276 + if (page->iPage[0].iOwner!=this)
1.277 + continue;
1.278 +//
1.279 + page->iPage[0].iOwner=NULL;
1.280 + page->iPage[0].iChange=EPageNoChange;
1.281 + page->iPage[1].Link().Deque();
1.282 + cache.iFree.AddFirst(page->iPage[1]);
1.283 + }
1.284 + }
1.285 +
1.286 +EXPORT_C void TCachePagePool::DoDeleteL(TPageRef aRef)
1.287 +//
1.288 +// Default implementation removing from cache.
1.289 +//
1.290 + {
1.291 + __ASSERT_DEBUG(aRef!=KNullPageRef,User::Invariant());
1.292 + CPageCache& cache=*iCache;
1.293 + __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
1.294 + TCachePage* page=cache.Find(this,aRef);
1.295 + if (page!=NULL)
1.296 + {
1.297 + page[-1].iOwner=NULL;
1.298 + page[-1].iChange=EPageNoChange;
1.299 + page->Link().Deque();
1.300 + cache.iFree.AddFirst(*page);
1.301 + }
1.302 + }
1.303 +
1.304 +void TCachePagePool::DoAbandon(MPagePool& aPool)
1.305 +//
1.306 +// Abandon all locked pages in this page pool.
1.307 +//
1.308 + {
1.309 + TCachePagePool& pool=STATIC_CAST(TCachePagePool&,aPool);
1.310 + CPageCache& cache=*pool.iCache;
1.311 + __ASSERT_DEBUG(pool.iCache!=NULL,Panic(EPageNotOpen));
1.312 + for (SCachePage* page=cache.iPages,*end=cache.iEnd;page<end;++page)
1.313 + {
1.314 + if (page->iPage[1].IsQued())
1.315 + continue;
1.316 +//
1.317 + __ASSERT_DEBUG(page->iPage[0].iOwner==&pool,User::Invariant());
1.318 + // no other page pool can have locked pages
1.319 + page->iPage[0].iOwner=NULL;
1.320 + page->iPage[0].iChange=EPageNoChange;
1.321 + cache.iFree.AddFirst(page->iPage[1]);
1.322 + }
1.323 + }
1.324 +
1.325 +TCachePage* TCachePagePool::DoAllocL(CPageCache& aCache)
1.326 + {
1.327 + __ASSERT_ALWAYS(!aCache.iFree.IsEmpty(),Panic(EPageCacheFull));
1.328 + // too small a cache or pages left locked unnecessarily
1.329 + TCachePage* page=aCache.iFree.First();
1.330 + TPageChange change=page[-1].iChange;
1.331 + if (change>EPageNoChange)
1.332 + {
1.333 + page[-1].iOwner->WriteL(page[-1].iRef,page,change);
1.334 + page[-1].iChange=EPageNoChange;
1.335 + }
1.336 + return page;
1.337 + }
1.338 +