--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/store/UPAGE/UP_CACHE.CPP Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,335 @@
+// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "UP_STD.H"
+
+struct SCachePage
+ {
+ TCachePage iPage[1];
+ TUint8 iData[KPoolPageSize];
+ };
+
+EXPORT_C CPageCache* CPageCache::NewL(TInt aPages)
+/** Allocates and constructs a new page cache.
+
+@param aPages Number of pages in the cache
+@return New page cache object */
+ {
+ CPageCache* cache=CPageCache::NewLC(aPages);
+ CleanupStack::Pop();
+ return cache;
+ }
+
+EXPORT_C CPageCache* CPageCache::NewLC(TInt aPages)
+/** Allocates and constructs a new page cache, and leaves it on the cleanup stack.
+
+@param aPages Number of pages in the cache
+@return New page cache object */
+ {
+ CPageCache* cache=new(ELeave) CPageCache;
+ CleanupStack::PushL(cache);
+ cache->ConstructL(aPages);
+ return cache;
+ }
+
+EXPORT_C CPageCache::CPageCache()
+ : iFree(_FOFF(TCachePage,iLink)-_FOFF(SCachePage,iPage[1]))/*,iPages(NULL),iEnd(NULL)*/
+/** Default constructor. */
+ {
+#if defined(__PAGE_CACHE_STATS)
+// iStats.Reset();
+#endif
+ }
+
+EXPORT_C void CPageCache::ConstructL(TInt aPages)
+/** Second phase construction.
+
+@param aPages Number of pages in the cache */
+ {
+ SCachePage* page=new(ELeave) SCachePage[aPages];
+ SCachePage* end=page+aPages;
+ iPages=page;
+ iEnd=end;
+ for (;page<end;++page)
+ {
+ page->iPage[0].iOwner=NULL;
+ page->iPage[0].iChange=EPageNoChange;
+ iFree.AddFirst(page->iPage[1]);
+ }
+ }
+
+EXPORT_C CPageCache::~CPageCache()
+/** Destructor.
+
+All cache pages are deleted. */
+ {
+#if defined (_DEBUG)
+ for (SCachePage* page=iPages,*end=iEnd;page<end;++page)
+ __ASSERT_DEBUG(page->iPage[0].iOwner==NULL,Panic(EPageCacheInUse));
+#endif
+ delete[] iPages;
+ }
+
+TCachePage* CPageCache::Find(TCachePagePool* aPool,TPageRef aRef)
+//
+// Find a page in the cache.
+//
+ {
+ for (SCachePage* page=iPages,*end=iEnd;page<end;++page)
+ {
+ if (page->iPage[0].iOwner!=aPool)
+ {
+ __ASSERT_DEBUG(page->iPage[1].IsQued(),User::Invariant());
+ // no other page pool can have locked pages
+ continue;
+ }
+//
+ if (page->iPage[0].iRef==aRef)
+ {
+#if defined(__PAGE_CACHE_STATS)
+ if (page->iPage[1].IsQued())
+ iStats.Hit(); // finding a locked page is not a hit, I'm afraid
+#endif
+ return &page->iPage[1];
+ }
+ }
+#if defined(__PAGE_CACHE_STATS)
+ iStats.Miss();
+#endif
+ return NULL;
+ }
+
+EXPORT_C TPageAbandonFunction TCachePagePool::AcquireL()
+/** Returns a function that abandons all locked pages for this page pool.
+
+@return A function that abandons all locked pages for this page pool. */
+ {
+ return &DoAbandon;
+ }
+
+EXPORT_C TAny* TCachePagePool::AllocL()
+/** Allocates an unassigned page.
+
+@return Newly allocated page. */
+ {
+ CPageCache& cache=*iCache;
+ __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
+ TCachePage* page=DoAllocL(cache);
+ page[-1].iOwner=this;
+ __ASSERT_DEBUG(page[-1].iChange==EPageNoChange,User::Invariant());
+ page[-1].iRef=KNullPageRef;
+ page->Deque();
+ return page;
+ }
+
+EXPORT_C TAny* TCachePagePool::LockL(TPageRef aRef)
+/** Locks a page and returns a pointer to it.
+
+@param aRef Reference to page to lock
+@return Locked page */
+ {
+ if (aRef==KNullPageRef)
+ __LEAVE(KErrNotFound);
+//
+ CPageCache& cache=*iCache;
+ __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
+ TCachePage* page=cache.Find(this,aRef);
+ if (page==NULL)
+ { // it's not in the cache, allocate a free page
+ page=DoAllocL(cache);
+ page[-1].iOwner=NULL;
+ __ASSERT_DEBUG(page[-1].iChange==EPageNoChange,User::Invariant());
+ ReadL(aRef,page);
+ page[-1].iOwner=this;
+ page[-1].iRef=aRef;
+ }
+ __ASSERT_DEBUG(page->IsQued(),Panic(EPageDoubleLock)); // it mustn't be locked already
+ page->Deque();
+ return page;
+ }
+
+EXPORT_C TPageRef TCachePagePool::AssignL(const TAny* aPage,TPageReclamation aReclamation)
+/** Assigns a reference to a new page and unlocks it.
+
+@param aPage Page to assign
+@param aReclamation Flag for page reclaimation settings
+@return Reference to page */
+ {
+ TCachePage* page=(TCachePage*)aPage;
+ __ASSERT_DEBUG(page!=NULL&&!page->IsQued(),Panic(EPageNotLocked));
+ __ASSERT_DEBUG(page[-1].iOwner==this&&page[-1].iRef==KNullPageRef,User::Invariant());
+ CPageCache& cache=*iCache;
+ __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
+ page[-1].iOwner=NULL;
+ __ASSERT_DEBUG(page[-1].iChange==EPageNoChange,User::Invariant());
+ cache.iFree.AddLast(*page);
+ TPageRef ref=ExtendL(page,aReclamation);
+ page[-1].iOwner=this;
+ page[-1].iRef=ref;
+ return ref;
+ }
+
+EXPORT_C void TCachePagePool::UpdateL(const TAny* aPage)
+/** Updates a page.
+
+@param aPage Page to update */
+ {
+ TCachePage* page=(TCachePage*)aPage;
+ __ASSERT_DEBUG(page!=NULL&&!page->IsQued(),Panic(EPageNotLocked));
+ __ASSERT_DEBUG(page[-1].iOwner==this&&page[-1].iRef!=KNullPageRef,User::Invariant());
+ CPageCache& cache=*iCache;
+ __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
+ page[-1].iOwner=NULL;
+ page[-1].iChange=EPageNoChange;
+ cache.iFree.AddLast(*page);
+ WriteL(page[-1].iRef,page,EPageUpdate);
+ page[-1].iOwner=this;
+ }
+
+EXPORT_C void TCachePagePool::Unlock(const TAny* aPage,TPageChange aChange)
+//
+// Unlock a page, depending on aChange:
+// EPageNoChange: just unlock
+// EPageDirty: mark the page as dirty
+// EPageUpdate: mark the page as needing a safe update
+// EPageAbandon: discard the page
+//
+/** Unlocks a page.
+
+@param aPage Page to unlock
+@param aChange How the page should be treated once it is unlocked */
+ {
+ TCachePage* page=(TCachePage*)aPage;
+ __ASSERT_DEBUG(page!=NULL&&!page->IsQued(),Panic(EPageNotLocked));
+ __ASSERT_DEBUG(page[-1].iOwner==this&&page[-1].iRef!=KNullPageRef,User::Invariant());
+ CPageCache& cache=*iCache;
+ __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
+ if (aChange>page[-1].iChange)
+ page[-1].iChange=aChange;
+ else if (aChange<EPageNoChange)
+ {
+ page[-1].iOwner=NULL;
+ page[-1].iChange=EPageNoChange;
+ }
+ cache.iFree.AddLast(*page);
+ }
+
+EXPORT_C TInt TCachePagePool::Flush()
+/** Flush all pages in this pool from the cache.
+
+It ensures that any dirty pages are written into persistent storage, but does
+not remove them from the cache.
+
+@return KErrNone if successful, otherwise another of the system-wide error
+codes. */
+ {
+ TRAPD(r,FlushL());
+ return r;
+ }
+
+EXPORT_C void TCachePagePool::FlushL()
+/** Flushes all pages in this pool from the cache, leaving with a system-wide error
+code if an error occurs. */
+ {
+ CPageCache& cache=*iCache;
+ __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
+ for (SCachePage* page=cache.iPages,*end=cache.iEnd;page<end;++page)
+ {
+ __ASSERT_DEBUG(page->iPage[1].IsQued(),User::Invariant()); // there mustn't be any locked pages
+ if (page->iPage[0].iOwner!=this)
+ continue;
+//
+ TPageChange change=page->iPage[0].iChange;
+ if (change>EPageNoChange)
+ {
+ WriteL(page->iPage[0].iRef,&page->iPage[1],change);
+ page->iPage[0].iChange=EPageNoChange;
+ }
+ }
+ }
+
+EXPORT_C void TCachePagePool::Purge()
+/** Purge all pages in this pool from the cache.
+
+This discards all pages from the cache, without saving dirty pages. */
+ {
+ CPageCache& cache=*iCache;
+ __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
+ for (SCachePage* page=cache.iPages,*end=cache.iEnd;page<end;++page)
+ {
+ __ASSERT_DEBUG(page->iPage[1].IsQued(),User::Invariant()); // there mustn't be any locked pages
+ if (page->iPage[0].iOwner!=this)
+ continue;
+//
+ page->iPage[0].iOwner=NULL;
+ page->iPage[0].iChange=EPageNoChange;
+ page->iPage[1].Link().Deque();
+ cache.iFree.AddFirst(page->iPage[1]);
+ }
+ }
+
+EXPORT_C void TCachePagePool::DoDeleteL(TPageRef aRef)
+//
+// Default implementation removing from cache.
+//
+ {
+ __ASSERT_DEBUG(aRef!=KNullPageRef,User::Invariant());
+ CPageCache& cache=*iCache;
+ __ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
+ TCachePage* page=cache.Find(this,aRef);
+ if (page!=NULL)
+ {
+ page[-1].iOwner=NULL;
+ page[-1].iChange=EPageNoChange;
+ page->Link().Deque();
+ cache.iFree.AddFirst(*page);
+ }
+ }
+
+void TCachePagePool::DoAbandon(MPagePool& aPool)
+//
+// Abandon all locked pages in this page pool.
+//
+ {
+ TCachePagePool& pool=STATIC_CAST(TCachePagePool&,aPool);
+ CPageCache& cache=*pool.iCache;
+ __ASSERT_DEBUG(pool.iCache!=NULL,Panic(EPageNotOpen));
+ for (SCachePage* page=cache.iPages,*end=cache.iEnd;page<end;++page)
+ {
+ if (page->iPage[1].IsQued())
+ continue;
+//
+ __ASSERT_DEBUG(page->iPage[0].iOwner==&pool,User::Invariant());
+ // no other page pool can have locked pages
+ page->iPage[0].iOwner=NULL;
+ page->iPage[0].iChange=EPageNoChange;
+ cache.iFree.AddFirst(page->iPage[1]);
+ }
+ }
+
+TCachePage* TCachePagePool::DoAllocL(CPageCache& aCache)
+ {
+ __ASSERT_ALWAYS(!aCache.iFree.IsEmpty(),Panic(EPageCacheFull));
+ // too small a cache or pages left locked unnecessarily
+ TCachePage* page=aCache.iFree.First();
+ TPageChange change=page[-1].iChange;
+ if (change>EPageNoChange)
+ {
+ page[-1].iOwner->WriteL(page[-1].iRef,page,change);
+ page[-1].iChange=EPageNoChange;
+ }
+ return page;
+ }
+