os/persistentdata/persistentstorage/store/UPAGE/UP_CACHE.CPP
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
//
sl@0
    15
sl@0
    16
#include "UP_STD.H"
sl@0
    17
sl@0
    18
struct SCachePage
sl@0
    19
	{
sl@0
    20
	TCachePage iPage[1];
sl@0
    21
	TUint8 iData[KPoolPageSize];
sl@0
    22
	};
sl@0
    23
sl@0
    24
EXPORT_C CPageCache* CPageCache::NewL(TInt aPages)
sl@0
    25
/** Allocates and constructs a new page cache.
sl@0
    26
sl@0
    27
@param aPages Number of pages in the cache
sl@0
    28
@return New page cache object */
sl@0
    29
	{
sl@0
    30
	CPageCache* cache=CPageCache::NewLC(aPages);
sl@0
    31
	CleanupStack::Pop();
sl@0
    32
	return cache;
sl@0
    33
	}
sl@0
    34
sl@0
    35
EXPORT_C CPageCache* CPageCache::NewLC(TInt aPages)
sl@0
    36
/** Allocates and constructs a new page cache, and leaves it on the cleanup stack.
sl@0
    37
sl@0
    38
@param aPages Number of pages in the cache
sl@0
    39
@return New page cache object */
sl@0
    40
	{
sl@0
    41
	CPageCache* cache=new(ELeave) CPageCache;
sl@0
    42
	CleanupStack::PushL(cache);
sl@0
    43
	cache->ConstructL(aPages);
sl@0
    44
	return cache;
sl@0
    45
	}
sl@0
    46
sl@0
    47
EXPORT_C CPageCache::CPageCache()
sl@0
    48
	: iFree(_FOFF(TCachePage,iLink)-_FOFF(SCachePage,iPage[1]))/*,iPages(NULL),iEnd(NULL)*/
sl@0
    49
/** Default constructor. */
sl@0
    50
	{
sl@0
    51
#if defined(__PAGE_CACHE_STATS)
sl@0
    52
//	iStats.Reset();
sl@0
    53
#endif
sl@0
    54
	}
sl@0
    55
sl@0
    56
EXPORT_C void CPageCache::ConstructL(TInt aPages)
sl@0
    57
/** Second phase construction.
sl@0
    58
sl@0
    59
@param aPages Number of pages in the cache */
sl@0
    60
	{
sl@0
    61
	SCachePage* page=new(ELeave) SCachePage[aPages];
sl@0
    62
	SCachePage* end=page+aPages;
sl@0
    63
	iPages=page;
sl@0
    64
	iEnd=end;
sl@0
    65
	for (;page<end;++page)
sl@0
    66
		{
sl@0
    67
		page->iPage[0].iOwner=NULL;
sl@0
    68
		page->iPage[0].iChange=EPageNoChange;
sl@0
    69
		iFree.AddFirst(page->iPage[1]);
sl@0
    70
		}
sl@0
    71
	}
sl@0
    72
sl@0
    73
EXPORT_C CPageCache::~CPageCache()
sl@0
    74
/** Destructor.
sl@0
    75
sl@0
    76
All cache pages are deleted. */
sl@0
    77
	{
sl@0
    78
#if defined (_DEBUG)
sl@0
    79
	for (SCachePage* page=iPages,*end=iEnd;page<end;++page)
sl@0
    80
		__ASSERT_DEBUG(page->iPage[0].iOwner==NULL,Panic(EPageCacheInUse));
sl@0
    81
#endif
sl@0
    82
	delete[] iPages;
sl@0
    83
	}
sl@0
    84
sl@0
    85
TCachePage* CPageCache::Find(TCachePagePool* aPool,TPageRef aRef)
sl@0
    86
//
sl@0
    87
// Find a page in the cache.
sl@0
    88
//
sl@0
    89
	{
sl@0
    90
	for (SCachePage* page=iPages,*end=iEnd;page<end;++page)
sl@0
    91
		{
sl@0
    92
		if (page->iPage[0].iOwner!=aPool)
sl@0
    93
			{
sl@0
    94
			__ASSERT_DEBUG(page->iPage[1].IsQued(),User::Invariant());
sl@0
    95
				// no other page pool can have locked pages
sl@0
    96
			continue;
sl@0
    97
			}
sl@0
    98
//
sl@0
    99
		if (page->iPage[0].iRef==aRef)
sl@0
   100
			{
sl@0
   101
#if defined(__PAGE_CACHE_STATS)
sl@0
   102
			if (page->iPage[1].IsQued())
sl@0
   103
				iStats.Hit(); // finding a locked page is not a hit, I'm afraid
sl@0
   104
#endif
sl@0
   105
			return &page->iPage[1];
sl@0
   106
			}
sl@0
   107
		}
sl@0
   108
#if defined(__PAGE_CACHE_STATS)
sl@0
   109
	iStats.Miss();
sl@0
   110
#endif
sl@0
   111
	return NULL;
sl@0
   112
	}
sl@0
   113
sl@0
   114
EXPORT_C TPageAbandonFunction TCachePagePool::AcquireL()
sl@0
   115
/** Returns a function that abandons all locked pages for this page pool. 
sl@0
   116
sl@0
   117
@return A function that abandons all locked pages for this page pool. */
sl@0
   118
	{
sl@0
   119
	return &DoAbandon;
sl@0
   120
	}
sl@0
   121
sl@0
   122
EXPORT_C TAny* TCachePagePool::AllocL()
sl@0
   123
/** Allocates an unassigned page. 
sl@0
   124
sl@0
   125
@return Newly allocated page. */
sl@0
   126
	{
sl@0
   127
	CPageCache& cache=*iCache;
sl@0
   128
	__ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
sl@0
   129
	TCachePage* page=DoAllocL(cache);
sl@0
   130
	page[-1].iOwner=this;
sl@0
   131
	__ASSERT_DEBUG(page[-1].iChange==EPageNoChange,User::Invariant());
sl@0
   132
	page[-1].iRef=KNullPageRef;
sl@0
   133
	page->Deque();
sl@0
   134
	return page;
sl@0
   135
	}
sl@0
   136
sl@0
   137
EXPORT_C TAny* TCachePagePool::LockL(TPageRef aRef)
sl@0
   138
/** Locks a page and returns a pointer to it.
sl@0
   139
sl@0
   140
@param aRef Reference to page to lock
sl@0
   141
@return Locked page */
sl@0
   142
	{
sl@0
   143
	if (aRef==KNullPageRef)
sl@0
   144
		__LEAVE(KErrNotFound);
sl@0
   145
//
sl@0
   146
	CPageCache& cache=*iCache;
sl@0
   147
	__ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
sl@0
   148
	TCachePage* page=cache.Find(this,aRef);
sl@0
   149
	if (page==NULL)
sl@0
   150
		{ // it's not in the cache, allocate a free page
sl@0
   151
		page=DoAllocL(cache);
sl@0
   152
		page[-1].iOwner=NULL;
sl@0
   153
		__ASSERT_DEBUG(page[-1].iChange==EPageNoChange,User::Invariant());
sl@0
   154
		ReadL(aRef,page);
sl@0
   155
		page[-1].iOwner=this;
sl@0
   156
		page[-1].iRef=aRef;
sl@0
   157
		}
sl@0
   158
	__ASSERT_DEBUG(page->IsQued(),Panic(EPageDoubleLock)); // it mustn't be locked already
sl@0
   159
	page->Deque();
sl@0
   160
	return page;
sl@0
   161
	}
sl@0
   162
sl@0
   163
EXPORT_C TPageRef TCachePagePool::AssignL(const TAny* aPage,TPageReclamation aReclamation)
sl@0
   164
/** Assigns a reference to a new page and unlocks it. 
sl@0
   165
sl@0
   166
@param aPage Page to assign
sl@0
   167
@param aReclamation Flag for page reclaimation settings
sl@0
   168
@return Reference to page */
sl@0
   169
	{
sl@0
   170
	TCachePage* page=(TCachePage*)aPage;
sl@0
   171
	__ASSERT_DEBUG(page!=NULL&&!page->IsQued(),Panic(EPageNotLocked));
sl@0
   172
	__ASSERT_DEBUG(page[-1].iOwner==this&&page[-1].iRef==KNullPageRef,User::Invariant());
sl@0
   173
	CPageCache& cache=*iCache;
sl@0
   174
	__ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
sl@0
   175
	page[-1].iOwner=NULL;
sl@0
   176
	__ASSERT_DEBUG(page[-1].iChange==EPageNoChange,User::Invariant());
sl@0
   177
	cache.iFree.AddLast(*page);
sl@0
   178
	TPageRef ref=ExtendL(page,aReclamation);
sl@0
   179
	page[-1].iOwner=this;
sl@0
   180
	page[-1].iRef=ref;
sl@0
   181
	return ref;
sl@0
   182
	}
sl@0
   183
sl@0
   184
EXPORT_C void TCachePagePool::UpdateL(const TAny* aPage)
sl@0
   185
/** Updates a page. 
sl@0
   186
sl@0
   187
@param aPage Page to update */
sl@0
   188
	{
sl@0
   189
	TCachePage* page=(TCachePage*)aPage;
sl@0
   190
	__ASSERT_DEBUG(page!=NULL&&!page->IsQued(),Panic(EPageNotLocked));
sl@0
   191
	__ASSERT_DEBUG(page[-1].iOwner==this&&page[-1].iRef!=KNullPageRef,User::Invariant());
sl@0
   192
	CPageCache& cache=*iCache;
sl@0
   193
	__ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
sl@0
   194
	page[-1].iOwner=NULL;
sl@0
   195
	page[-1].iChange=EPageNoChange;
sl@0
   196
	cache.iFree.AddLast(*page);
sl@0
   197
	WriteL(page[-1].iRef,page,EPageUpdate);
sl@0
   198
	page[-1].iOwner=this;
sl@0
   199
	}
sl@0
   200
sl@0
   201
EXPORT_C void TCachePagePool::Unlock(const TAny* aPage,TPageChange aChange)
sl@0
   202
//
sl@0
   203
// Unlock a page, depending on aChange:
sl@0
   204
//		EPageNoChange: just unlock
sl@0
   205
//		EPageDirty: mark the page as dirty
sl@0
   206
//		EPageUpdate: mark the page as needing a safe update
sl@0
   207
//		EPageAbandon: discard the page
sl@0
   208
//
sl@0
   209
/** Unlocks a page.
sl@0
   210
sl@0
   211
@param aPage Page to unlock
sl@0
   212
@param aChange How the page should be treated once it is unlocked */
sl@0
   213
	{
sl@0
   214
	TCachePage* page=(TCachePage*)aPage;
sl@0
   215
	__ASSERT_DEBUG(page!=NULL&&!page->IsQued(),Panic(EPageNotLocked));
sl@0
   216
	__ASSERT_DEBUG(page[-1].iOwner==this&&page[-1].iRef!=KNullPageRef,User::Invariant());
sl@0
   217
	CPageCache& cache=*iCache;
sl@0
   218
	__ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
sl@0
   219
	if (aChange>page[-1].iChange)
sl@0
   220
		page[-1].iChange=aChange;
sl@0
   221
	else if (aChange<EPageNoChange)
sl@0
   222
		{
sl@0
   223
		page[-1].iOwner=NULL;
sl@0
   224
		page[-1].iChange=EPageNoChange;
sl@0
   225
		}
sl@0
   226
	cache.iFree.AddLast(*page);
sl@0
   227
	}
sl@0
   228
sl@0
   229
EXPORT_C TInt TCachePagePool::Flush()
sl@0
   230
/** Flush all pages in this pool from the cache.
sl@0
   231
sl@0
   232
It ensures that any dirty pages are written into persistent storage, but does 
sl@0
   233
not remove them from the cache.
sl@0
   234
sl@0
   235
@return KErrNone if successful, otherwise another of the system-wide error 
sl@0
   236
codes. */
sl@0
   237
	{
sl@0
   238
	TRAPD(r,FlushL());
sl@0
   239
	return r;
sl@0
   240
	}
sl@0
   241
sl@0
   242
EXPORT_C void TCachePagePool::FlushL()
sl@0
   243
/** Flushes all pages in this pool from the cache, leaving with a system-wide error 
sl@0
   244
code if an error occurs. */
sl@0
   245
	{
sl@0
   246
	CPageCache& cache=*iCache;
sl@0
   247
	__ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
sl@0
   248
	for (SCachePage* page=cache.iPages,*end=cache.iEnd;page<end;++page)
sl@0
   249
		{
sl@0
   250
		__ASSERT_DEBUG(page->iPage[1].IsQued(),User::Invariant()); // there mustn't be any locked pages
sl@0
   251
		if (page->iPage[0].iOwner!=this)
sl@0
   252
			continue;
sl@0
   253
//
sl@0
   254
		TPageChange change=page->iPage[0].iChange;
sl@0
   255
		if (change>EPageNoChange)
sl@0
   256
			{
sl@0
   257
			WriteL(page->iPage[0].iRef,&page->iPage[1],change);
sl@0
   258
			page->iPage[0].iChange=EPageNoChange;
sl@0
   259
			}
sl@0
   260
		}
sl@0
   261
	}
sl@0
   262
sl@0
   263
EXPORT_C void TCachePagePool::Purge()
sl@0
   264
/** Purge all pages in this pool from the cache.
sl@0
   265
sl@0
   266
This discards all pages from the cache, without saving dirty pages. */
sl@0
   267
	{
sl@0
   268
	CPageCache& cache=*iCache;
sl@0
   269
	__ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
sl@0
   270
	for (SCachePage* page=cache.iPages,*end=cache.iEnd;page<end;++page)
sl@0
   271
		{
sl@0
   272
		__ASSERT_DEBUG(page->iPage[1].IsQued(),User::Invariant()); // there mustn't be any locked pages
sl@0
   273
		if (page->iPage[0].iOwner!=this)
sl@0
   274
			continue;
sl@0
   275
//
sl@0
   276
		page->iPage[0].iOwner=NULL;
sl@0
   277
		page->iPage[0].iChange=EPageNoChange;
sl@0
   278
		page->iPage[1].Link().Deque();
sl@0
   279
		cache.iFree.AddFirst(page->iPage[1]);
sl@0
   280
		}
sl@0
   281
	}
sl@0
   282
sl@0
   283
EXPORT_C void TCachePagePool::DoDeleteL(TPageRef aRef)
sl@0
   284
//
sl@0
   285
// Default implementation removing from cache.
sl@0
   286
//
sl@0
   287
	{
sl@0
   288
	__ASSERT_DEBUG(aRef!=KNullPageRef,User::Invariant());
sl@0
   289
	CPageCache& cache=*iCache;
sl@0
   290
	__ASSERT_DEBUG(iCache!=NULL,Panic(EPageNotOpen));
sl@0
   291
	TCachePage* page=cache.Find(this,aRef);
sl@0
   292
	if (page!=NULL)
sl@0
   293
		{
sl@0
   294
		page[-1].iOwner=NULL;
sl@0
   295
		page[-1].iChange=EPageNoChange;
sl@0
   296
		page->Link().Deque();
sl@0
   297
		cache.iFree.AddFirst(*page);
sl@0
   298
		}
sl@0
   299
	}
sl@0
   300
sl@0
   301
void TCachePagePool::DoAbandon(MPagePool& aPool)
sl@0
   302
//
sl@0
   303
// Abandon all locked pages in this page pool.
sl@0
   304
//
sl@0
   305
	{
sl@0
   306
	TCachePagePool& pool=STATIC_CAST(TCachePagePool&,aPool);
sl@0
   307
	CPageCache& cache=*pool.iCache;
sl@0
   308
	__ASSERT_DEBUG(pool.iCache!=NULL,Panic(EPageNotOpen));
sl@0
   309
	for (SCachePage* page=cache.iPages,*end=cache.iEnd;page<end;++page)
sl@0
   310
		{
sl@0
   311
		if (page->iPage[1].IsQued())
sl@0
   312
			continue;
sl@0
   313
//
sl@0
   314
		__ASSERT_DEBUG(page->iPage[0].iOwner==&pool,User::Invariant());
sl@0
   315
			// no other page pool can have locked pages
sl@0
   316
		page->iPage[0].iOwner=NULL;
sl@0
   317
		page->iPage[0].iChange=EPageNoChange;
sl@0
   318
		cache.iFree.AddFirst(page->iPage[1]);
sl@0
   319
		}
sl@0
   320
	}
sl@0
   321
sl@0
   322
TCachePage* TCachePagePool::DoAllocL(CPageCache& aCache)
sl@0
   323
	{
sl@0
   324
	__ASSERT_ALWAYS(!aCache.iFree.IsEmpty(),Panic(EPageCacheFull));
sl@0
   325
		// too small a cache or pages left locked unnecessarily
sl@0
   326
	TCachePage* page=aCache.iFree.First();
sl@0
   327
	TPageChange change=page[-1].iChange;
sl@0
   328
	if (change>EPageNoChange)
sl@0
   329
		{
sl@0
   330
		page[-1].iOwner->WriteL(page[-1].iRef,page,change);
sl@0
   331
		page[-1].iChange=EPageNoChange;
sl@0
   332
		}
sl@0
   333
	return page;
sl@0
   334
	}
sl@0
   335