os/persistentdata/persistentstorage/dbms/ustor/US_CLSTR.CPP
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/persistentdata/persistentstorage/dbms/ustor/US_CLSTR.CPP	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,656 @@
     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 "US_STD.H"
    1.20 +
    1.21 +// Class RClusterMap
    1.22 +
    1.23 +void RClusterMap::InsertL( TClusterId aCluster, TClusterId aPrevious )
    1.24 +//
    1.25 +// insert the entry into the map
    1.26 +//
    1.27 +	{
    1.28 +	TIdPair* map = iMap;
    1.29 +	if ( iEntries == iAlloc )
    1.30 +		{	// ensure there is space
    1.31 +		TInt size = iAlloc + EGranularity;
    1.32 +		iMap = map = ( TIdPair* )User::ReAllocL( map, size * sizeof( TIdPair ) );
    1.33 +		iAlloc = size;
    1.34 +		}
    1.35 +	TInt l = 0;
    1.36 +	TInt r = iEntries;
    1.37 +	while ( r > l )
    1.38 +		{
    1.39 +		TInt m = ( l + r ) >> 1;
    1.40 +		TClusterId id = map[ m ].iId;
    1.41 +		__ASSERT( aCluster != id );	// not already present
    1.42 +		if ( aCluster < id )
    1.43 +			r = m;
    1.44 +		else
    1.45 +			l = m + 1;
    1.46 +		}
    1.47 +	TIdPair* p = map + r;
    1.48 +	TIdPair* e = map + iEntries++;
    1.49 +	Mem::Move( p + 1, p, ( TUint8* )e - ( TUint8* )p );
    1.50 +	p->iId = aCluster;
    1.51 +	p->iPreviousId = aPrevious;
    1.52 +	}
    1.53 +
    1.54 +RClusterMap::TIdPair* RClusterMap::At( TClusterId aCluster )
    1.55 +	{
    1.56 +	TInt l = 0;
    1.57 +	TInt r = iEntries;
    1.58 +	while ( r > l )
    1.59 +		{
    1.60 +		TInt m = ( l + r ) >> 1;
    1.61 +		TClusterId id = iMap[ m ].iId;
    1.62 +		if ( aCluster < id )
    1.63 +			r = m;
    1.64 +		else if ( aCluster > id )
    1.65 +			l = m + 1;
    1.66 +		else
    1.67 +			return iMap + m;
    1.68 +		}
    1.69 +	return 0;
    1.70 +	}
    1.71 +
    1.72 +void RClusterMap::ResetL( TClusterId aHeadCluster )
    1.73 +	{
    1.74 +	iComplete = EFalse;
    1.75 +	iEntries = 0;
    1.76 +	InsertL( aHeadCluster, KNullClusterId );
    1.77 +	iLastMapped = iLastBound = aHeadCluster;
    1.78 +	iSkipped = ESeparation - 1;
    1.79 +	}
    1.80 +
    1.81 +TBool RClusterMap::At( TClusterId aCluster, TClusterId& aPreviousCluster )
    1.82 +	{
    1.83 +	TIdPair* p = At( aCluster );
    1.84 +	if ( p )
    1.85 +		aPreviousCluster = p->iPreviousId;
    1.86 +	else if ( aCluster == iLastBound )
    1.87 +		aPreviousCluster = iLastMapped;
    1.88 +	else
    1.89 +		return EFalse;
    1.90 +	return ETrue;
    1.91 +	}
    1.92 +
    1.93 +void RClusterMap::AddL( TClusterId aCluster )
    1.94 +	{
    1.95 +	__ASSERT( aCluster != KNullClusterId );
    1.96 +	if ( --iSkipped < 0 )
    1.97 +		{
    1.98 +		InsertL( aCluster, iLastMapped );
    1.99 +		iLastMapped = aCluster;
   1.100 +		iSkipped = ESeparation - 1;
   1.101 +		}
   1.102 +	iLastBound = aCluster;
   1.103 +	}
   1.104 +
   1.105 +void RClusterMap::DropL( TClusterId aCluster, TClusterId aNext )
   1.106 +//
   1.107 +// Cluster has been deleted, modify entry to contain the next cluster
   1.108 +// last cluster in table is never deleted
   1.109 +//
   1.110 +	{
   1.111 +	if ( aCluster == iLastBound )
   1.112 +		iLastBound = aNext;
   1.113 +	TIdPair* entry = At( aCluster );
   1.114 +	if ( !entry )
   1.115 +		return;		// not in the sparse map
   1.116 +// remove entry for cluster->prev
   1.117 +	TClusterId prev = entry->iPreviousId;
   1.118 +	Mem::Move( entry, entry + 1, ( TUint8* )( iMap + --iEntries ) - ( TUint8* )entry );
   1.119 +//
   1.120 +	if ( aCluster == iLastMapped )
   1.121 +		iLastMapped = aNext;
   1.122 +	else
   1.123 +		{	// find the referring entry next->cluster
   1.124 +		TIdPair* pnext = iMap;
   1.125 +		while ( pnext->iPreviousId != aCluster )
   1.126 +			{
   1.127 +			++pnext;
   1.128 +			__ASSERT( pnext < iMap + iEntries );
   1.129 +			}
   1.130 +		if ( pnext->iId == aNext )
   1.131 +			{	// referring entry is the next one => drop a link
   1.132 +			pnext->iPreviousId = prev;
   1.133 +			return;
   1.134 +			}
   1.135 +		// adjust next->new
   1.136 +		pnext->iPreviousId = aNext;
   1.137 +		}
   1.138 +	// add in new link to replace deleted one
   1.139 +	InsertL( aNext, prev );	// will not fail allocation as space available
   1.140 +	}
   1.141 +
   1.142 +// Class TClusterLinkCache
   1.143 +
   1.144 +void TClusterLinkCache::Add( TClusterId aCluster, RClusterMap& aMap )
   1.145 +//
   1.146 +// Add an entry to the cache
   1.147 +//
   1.148 +	{
   1.149 +	__ASSERT( iEnd != NULL );
   1.150 +	TClusterId id;
   1.151 +	__ASSERT( aMap.At( iMap[0], id ) );
   1.152 +//
   1.153 +	TClusterId* p = iEnd;
   1.154 +	if ( p == &iMap[ RClusterMap::ESeparation ] )
   1.155 +		{	// full, requires a shift down
   1.156 +		for ( ; !aMap.At( *p, id ); --p )
   1.157 +			{
   1.158 +			__ASSERT( p > iMap );
   1.159 +			}
   1.160 +		__ASSERT( p > iMap );
   1.161 +		__ASSERT( Has( id ) );
   1.162 +
   1.163 +		TClusterId* c = iMap;
   1.164 +		--c;
   1.165 +		while ( p <= iEnd )
   1.166 +			*++c = *p++;
   1.167 +		p = c;
   1.168 +		}
   1.169 +	*++p = aCluster;
   1.170 +	iEnd = p;
   1.171 +	}
   1.172 +
   1.173 +void TClusterLinkCache::Add( const TClusterId* aFirst, const TClusterId* aLast )
   1.174 +//
   1.175 +// Add several linked TClusterIds
   1.176 +//
   1.177 +	{
   1.178 +	__ASSERT( iEnd != NULL );
   1.179 +//
   1.180 +	TClusterId* p = iEnd;
   1.181 +	while ( aFirst < aLast && p < &iMap[ RClusterMap::ESeparation ] )
   1.182 +		*++p = *aFirst++;
   1.183 +	iEnd = p;
   1.184 +	}
   1.185 +
   1.186 +void TClusterLinkCache::Drop( TClusterId aCluster, TClusterId aNext )
   1.187 +//
   1.188 +// Drop the item if it is in the cache
   1.189 +//
   1.190 +	{
   1.191 +	TClusterId* p = iEnd;
   1.192 +	if ( !p )
   1.193 +		return;
   1.194 +	if ( *p == aCluster )
   1.195 +		{
   1.196 +		*p = aNext;
   1.197 +		return;
   1.198 +		}
   1.199 +	do
   1.200 +		{
   1.201 +		if ( p == iMap )
   1.202 +			return;
   1.203 +		} while ( *--p != aCluster );
   1.204 +	__ASSERT( *( p + 1 ) == aNext );
   1.205 +	for ( ; p < iEnd; ++p )
   1.206 +		*p = *( p + 1 );
   1.207 +	iEnd = p - 1;
   1.208 +	}
   1.209 +
   1.210 +TBool TClusterLinkCache::Has( TClusterId aCluster ) const
   1.211 +//
   1.212 +// Check if the cluster id is in the cache
   1.213 +// iEnd==0 is a valid state (empty cache)
   1.214 +//
   1.215 +	{
   1.216 +	for ( const TClusterId* p = iEnd; p >= iMap; )
   1.217 +		{
   1.218 +		if ( *p-- == aCluster )
   1.219 +			return ETrue;
   1.220 +		}
   1.221 +	return EFalse;
   1.222 +	}
   1.223 +
   1.224 +TBool TClusterLinkCache::At( TClusterId aCluster, TClusterId& aPrevious ) const
   1.225 +//
   1.226 +// If aCluster is in the cache, return the previous cluster in aPrevious
   1.227 +// iEnd==0 is a valid state (empty cache)
   1.228 +//
   1.229 +	{
   1.230 +	for ( const TClusterId* p = iEnd; p > iMap; )
   1.231 +		{
   1.232 +		if ( *p-- == aCluster )
   1.233 +			{
   1.234 +			aPrevious = *p;
   1.235 +			return ETrue;
   1.236 +			}
   1.237 +		}
   1.238 +	return EFalse;
   1.239 +	}
   1.240 +
   1.241 +// Class TClusterDes
   1.242 +
   1.243 +void TClusterDes::InternalizeL(RReadStream& aStream)
   1.244 +	{
   1.245 +	aStream>>iNext;
   1.246 +	iMembership=aStream.ReadUint16L();
   1.247 +	}
   1.248 +
   1.249 +void TClusterDes::ExternalizeL(RWriteStream& aStream) const
   1.250 +	{
   1.251 +	aStream<<iNext;
   1.252 +	aStream.WriteUint16L(iMembership);
   1.253 +	}
   1.254 +
   1.255 +
   1.256 +// Class CClusterCache
   1.257 +
   1.258 +inline CClusterCache::CClusterCache(CDbStoreDatabase& aDatabase)
   1.259 +	: iDatabase(aDatabase),iCache(_FOFF(CCluster,iLink))
   1.260 +	{}
   1.261 +
   1.262 +CClusterCache* CClusterCache::NewL(CDbStoreDatabase& aDatabase)
   1.263 +	{
   1.264 +	CClusterCache* self=new(ELeave) CClusterCache(aDatabase);
   1.265 +	CleanupStack::PushL(self);
   1.266 +	// Add the initial clusters
   1.267 +	for(TInt i=0;i<(EMaxClusters/2);++i)
   1.268 +		{
   1.269 +		self->AddClusterL();
   1.270 +		}
   1.271 +	CleanupStack::Pop();
   1.272 +	return self;
   1.273 +	}
   1.274 +
   1.275 +LOCAL_C void DeleteCluster(CCluster* aCluster)
   1.276 +//
   1.277 +// helper function which matches the Apply() prototype
   1.278 +//
   1.279 +	{
   1.280 +	delete aCluster;
   1.281 +	}
   1.282 +
   1.283 +CClusterCache::~CClusterCache()
   1.284 +	{
   1.285 +	Apply(DeleteCluster);
   1.286 +	}
   1.287 +
   1.288 +LOCAL_C void DiscardCluster(CCluster* aCluster)
   1.289 +//
   1.290 +// helper function which matches the Apply() prototype
   1.291 +//
   1.292 +	{
   1.293 +	aCluster->Discard();
   1.294 +	}
   1.295 +
   1.296 +void CClusterCache::Discard()
   1.297 +//
   1.298 +// discard the current changes in all clusters
   1.299 +//
   1.300 +	{
   1.301 +	Apply(DiscardCluster);
   1.302 +	}
   1.303 +
   1.304 +LOCAL_C void FlushClusterL(CCluster* aCluster)
   1.305 +//
   1.306 +// helper function which matches the Apply() prototype
   1.307 +//
   1.308 +	{
   1.309 +	aCluster->FlushL();
   1.310 +	}
   1.311 +
   1.312 +void CClusterCache::FlushL()
   1.313 +//
   1.314 +// Flush all the clusters in the cache
   1.315 +//
   1.316 +	{
   1.317 +	Apply(FlushClusterL);
   1.318 +	}
   1.319 +
   1.320 +CCluster* CClusterCache::Cluster(TClusterId aCluster)
   1.321 +//
   1.322 +// Look for a cluster in the cache
   1.323 +//
   1.324 +	{
   1.325 +	TDblQueIter<CCluster> iter(iCache);
   1.326 +	for (CCluster* cluster;(cluster=iter++)!=0;)
   1.327 +		{
   1.328 +		if (cluster->Id()==aCluster)
   1.329 +			return cluster;
   1.330 +		}
   1.331 +	return 0;
   1.332 +	}
   1.333 +
   1.334 +CCluster& CClusterCache::ClusterL(TClusterId aCluster)
   1.335 +//
   1.336 +// Get a cluster from the cache or store and move it to the top of the cache
   1.337 +// Track hits to the two clusters which most recently dropped out of the cache
   1.338 +//
   1.339 +	{
   1.340 +	CCluster* cluster=Cluster(aCluster);	// check if it is cached
   1.341 +	iFollowOnHits<<=2;
   1.342 +	if (!cluster)
   1.343 +		{		// get an empty cluster and read it
   1.344 +		if (aCluster==iCachePlus1)
   1.345 +			{	// the cluster has recently been discarded
   1.346 +			iCachePlus1=iCachePlus2;	// re-sequence the cache follow-on
   1.347 +			iFollowOnHits|=0x1;
   1.348 +			}
   1.349 +		else if (aCluster==iCachePlus2)
   1.350 +			iFollowOnHits|=0x2;	// the cluster has recently been discarded
   1.351 +		cluster=&NewClusterL();
   1.352 +		cluster->ReadL(aCluster);
   1.353 +		}
   1.354 +	return Touch(*cluster);
   1.355 +	}
   1.356 +
   1.357 +CCluster& CClusterCache::ClusterL()
   1.358 +//
   1.359 +// Get a new (empty) cluster from the cache and move it to the top
   1.360 +//
   1.361 +	{
   1.362 +	return Touch(NewClusterL());
   1.363 +	}
   1.364 +
   1.365 +CCluster& CClusterCache::Touch(CCluster& aCluster)
   1.366 +//
   1.367 +// Move a cluster to the top of the LRU list
   1.368 +//
   1.369 +	{
   1.370 +	aCluster.iLink.Deque();
   1.371 +	iCache.AddFirst(aCluster);
   1.372 +	return aCluster;
   1.373 +	}
   1.374 +
   1.375 +CCluster& CClusterCache::AddClusterL()
   1.376 +//
   1.377 +// Add a new cluster to the cache
   1.378 +//
   1.379 +	{
   1.380 +	__ASSERT(iClusters<EMaxClusters);
   1.381 +	CCluster& cluster=*CCluster::NewL(Database());
   1.382 +	iCache.AddLast(cluster);
   1.383 +	++iClusters;
   1.384 +	// move +2 hits into +1 zone and clear +1 hits
   1.385 +	iFollowOnHits=TUint8((TUint(iFollowOnHits)>>1)&0x55);
   1.386 +	return cluster;
   1.387 +	}
   1.388 +
   1.389 +CCluster& CClusterCache::NewClusterL()
   1.390 +//
   1.391 +// Get an empty cluster from the cache, but do not touch it
   1.392 +// If the hit detector has registered enough near-misses the cache is expanded
   1.393 +// by adding another cluster object
   1.394 +//
   1.395 +	{
   1.396 +	CCluster* cluster=Cluster(KNullClusterId);	// look for a discarded cluster first
   1.397 +	if (cluster)
   1.398 +		return *cluster;
   1.399 +// check for cache expansion
   1.400 +	TUint detected=iFollowOnHits;
   1.401 +	if ((detected&(detected-1))!=0 && iClusters<EMaxClusters)
   1.402 +		return AddClusterL();
   1.403 +// retire the last cache entry
   1.404 +	cluster=iCache.Last();
   1.405 +	cluster->FlushL();
   1.406 +	iCachePlus2=iCachePlus1;
   1.407 +	iCachePlus1=cluster->Id();
   1.408 +	return *cluster;
   1.409 +	}
   1.410 +
   1.411 +void CClusterCache::Apply(void (*aFunc)(CCluster*))
   1.412 +//
   1.413 +// Apply the function paramater to all clusters in the cache
   1.414 +// This function may leave <==> the parameter function may leave
   1.415 +//
   1.416 +	{
   1.417 +	TDblQueIter<CCluster> iter(iCache);
   1.418 +	for (CCluster* cluster;(cluster=iter++)!=0;)
   1.419 +		aFunc(cluster);
   1.420 +	}
   1.421 +
   1.422 +// Class CCluster
   1.423 +
   1.424 +CCluster* CCluster::NewL(CDbStoreDatabase& aDatabase)
   1.425 +	{
   1.426 +	return new(ELeave) CCluster(aDatabase);
   1.427 +	}
   1.428 +
   1.429 +CCluster::~CCluster()
   1.430 +	{
   1.431 +	User::Free(iMap[0]);
   1.432 +	}
   1.433 +
   1.434 +void CCluster::AdjustMap(TUint8** aMapEntry,TInt aAdjust)
   1.435 +//
   1.436 +// Adjust all map entries after aMapEntry
   1.437 +//
   1.438 +	{
   1.439 +	do *aMapEntry+=aAdjust; while (++aMapEntry<=&iMap[KMaxClustering]);
   1.440 +	}
   1.441 +
   1.442 +TInt CCluster::SetSizeL(TInt aSize)
   1.443 +//
   1.444 +// Set the minimum size for the cluster buffer
   1.445 +// Return the offset between the new and old cells
   1.446 +//
   1.447 +	{
   1.448 +	if (iSize>=aSize)
   1.449 +		return 0;
   1.450 +//
   1.451 +	aSize+=EGranularity-1;		// round to granularity
   1.452 +	aSize&=~(EGranularity-1);
   1.453 +	TUint8* base=iMap[0];
   1.454 +	TInt offset=(TUint8*)User::ReAllocL(base,aSize)-base;
   1.455 +	iSize=aSize;
   1.456 +	if (offset)
   1.457 +		AdjustMap(&iMap[0],offset);
   1.458 +	return offset;
   1.459 +	}
   1.460 +
   1.461 +void CCluster::Discard()
   1.462 +//
   1.463 +// discard the current changes
   1.464 +//
   1.465 +	{
   1.466 +	iCluster=KNullClusterId;
   1.467 +	iModified=EFalse;
   1.468 +	}
   1.469 +
   1.470 +void CCluster::Create(TClusterId aClusterId)
   1.471 +//
   1.472 +// Create a new cluster
   1.473 +//
   1.474 +	{
   1.475 +	__ASSERT(!iModified);
   1.476 +//
   1.477 +	iCluster=aClusterId;
   1.478 +	iDes.iNext=KNullClusterId;
   1.479 +	iDes.iMembership=0;
   1.480 +	TUint8* base=iMap[0];
   1.481 +	for (TUint8** ptr=&iMap[1];ptr<=&iMap[KMaxClustering];++ptr)
   1.482 +		*ptr=base;
   1.483 +	iModified=ETrue;
   1.484 +	}
   1.485 +
   1.486 +void CCluster::Relink(TClusterId aNextClusterId)
   1.487 +//
   1.488 +// Update the cluster to link to a different cluster
   1.489 +//
   1.490 +	{
   1.491 +	iDes.iNext=aNextClusterId;
   1.492 +	iModified=ETrue;
   1.493 +	}
   1.494 +
   1.495 +void CCluster::AlterL(MAlter& aAlterer)
   1.496 +//
   1.497 +// alter all records in the cluster
   1.498 +//
   1.499 +	{
   1.500 +	TUint members=iDes.iMembership;
   1.501 +	TUint8* wptr=iMap[0];
   1.502 +	TUint8* rptr=wptr;
   1.503 +	for (TUint8** map=&iMap[0];map<&iMap[KMaxClustering];members>>=1,++map)
   1.504 +		{
   1.505 +		if (members&1)
   1.506 +			{
   1.507 +			TInt size=map[1]-rptr;
   1.508 +			TInt expand=wptr-rptr+aAlterer.RecordExpansion(rptr,size);
   1.509 +			if (expand>0)
   1.510 +				{	// requires more space for alteration
   1.511 +				AdjustL(map,expand+EExpandBuffer,rptr);
   1.512 +				wptr=map[0];	// compensate for possible moving cache
   1.513 +				rptr=map[1]-size;	// record data is at end of this entry
   1.514 +				}
   1.515 +			wptr=aAlterer.AlterRecordL(wptr,rptr,size);
   1.516 +			rptr+=size;
   1.517 +			__ASSERT(wptr<=rptr);
   1.518 +			}
   1.519 +		else
   1.520 +			{
   1.521 +			__ASSERT(map[1]==rptr);
   1.522 +			}
   1.523 +		map[1]=wptr;
   1.524 +		}
   1.525 +	iModified=ETrue;
   1.526 +	}
   1.527 +
   1.528 +TPtrC8 CCluster::RecordL(TInt aIndex)
   1.529 +//
   1.530 +// Read the cluster and return the record data
   1.531 +//
   1.532 +	{
   1.533 +	if (!((iDes.iMembership>>aIndex)&1))
   1.534 +		__LEAVE(KErrNotFound);
   1.535 +	return TPtrC8(iMap[aIndex],iMap[aIndex+1]-iMap[aIndex]);
   1.536 +	}
   1.537 +
   1.538 +TUint8* CCluster::UpdateL(TInt aIndex,TInt aNewSize)
   1.539 +//
   1.540 +// read the cluster and return a writable descriptor over the new record data
   1.541 +//
   1.542 +	{
   1.543 +	SetRecordL(aIndex,aNewSize);
   1.544 +	iDes.iMembership|=(1<<aIndex);
   1.545 +	return iMap[aIndex];
   1.546 +	}
   1.547 +
   1.548 +TBool CCluster::DeleteL(TInt aIndex)
   1.549 +//
   1.550 +// return whether the cluster is empty or not
   1.551 +//
   1.552 +	{
   1.553 +	SetRecordL(aIndex,0);
   1.554 +	iDes.iMembership&=~(1<<aIndex);
   1.555 +	return iDes.iMembership;
   1.556 +	}
   1.557 +
   1.558 +void CCluster::FlushL()
   1.559 +	{
   1.560 +	if (iModified)
   1.561 +		{	// Externalize the cluster
   1.562 +		RDbStoreWriteStream cluster(iDatabase);
   1.563 +		cluster.ReplaceLC(iDatabase.Store(),iCluster);
   1.564 +		cluster<<iDes;
   1.565 +		TUint8** map=&iMap[0];
   1.566 +		TUint8* base=*map;
   1.567 +		TUint8* ptr=base;
   1.568 +		for (TUint members=iDes.iMembership;members!=0;members>>=1)
   1.569 +			{
   1.570 +			++map;
   1.571 +			if (members&1)
   1.572 +				{
   1.573 +				TUint8* end=*map;
   1.574 +				cluster << TCardinality(end-ptr);
   1.575 +				ptr=end;
   1.576 +				}
   1.577 +			else
   1.578 +				{
   1.579 +				__ASSERT(*map==ptr);
   1.580 +				}
   1.581 +			}
   1.582 +		cluster.FilterL(cluster.EMixed,iCluster);
   1.583 +		cluster.WriteL(base,ptr-base);
   1.584 +		cluster.CommitL();
   1.585 +		CleanupStack::PopAndDestroy();
   1.586 +		iModified=EFalse;
   1.587 +		}
   1.588 +	}
   1.589 +
   1.590 +void CCluster::ReadL(TClusterId aCluster)
   1.591 +//
   1.592 +// Internalize the cluster
   1.593 +//
   1.594 +	{
   1.595 +	__ASSERT(iCluster!=aCluster);
   1.596 +	__ASSERT(!iModified);
   1.597 +//
   1.598 +	iCluster=KNullClusterId;
   1.599 +	RDbStoreReadStream cluster(iDatabase);
   1.600 +	cluster.OpenLC(iDatabase.Store(),aCluster);
   1.601 +	cluster>>iDes;
   1.602 +	TUint8** map=&iMap[0];
   1.603 +	TUint8* base=*map;
   1.604 +	TUint8* ptr=base;
   1.605 +	for (TUint members=iDes.iMembership;members!=0;members>>=1)
   1.606 +		{
   1.607 +		if (members&1)
   1.608 +			{
   1.609 +			TCardinality card;
   1.610 +			cluster >> card;
   1.611 +			TInt size=card;
   1.612 +			if (size>KDbStoreMaxRecordLength)
   1.613 +				__LEAVE(KErrCorrupt);
   1.614 +			ptr+=size;
   1.615 +			}
   1.616 +		*++map=ptr;
   1.617 +		}
   1.618 +	while (map<&iMap[KMaxClustering])
   1.619 +		*++map=ptr;
   1.620 +	TInt len=ptr-base;
   1.621 +	base+=SetSizeL(len);
   1.622 +	cluster.FilterL(cluster.EMixed,aCluster);
   1.623 +	cluster.ReadL(base,len);
   1.624 +	CleanupStack::PopAndDestroy();
   1.625 +	iCluster=aCluster;
   1.626 +	}
   1.627 +
   1.628 +void CCluster::SetRecordL(TInt aIndex,TInt aNewSize)
   1.629 +	{
   1.630 +	AdjustL(&iMap[aIndex],iMap[aIndex]+aNewSize-iMap[aIndex+1],iMap[aIndex+1]);
   1.631 +	iModified=ETrue;
   1.632 +	}
   1.633 +
   1.634 +void CCluster::AdjustL(TUint8** aMapEntry,TInt aAdjust,TUint8* aData)
   1.635 +//
   1.636 +// Adjust the record at map entry by aAdjust bytes
   1.637 +// Move that entry data as well as the ones following for AlterCluster
   1.638 +//
   1.639 +	{
   1.640 +	if (!aAdjust)
   1.641 +		return;
   1.642 +//
   1.643 +	__ASSERT(aAdjust+aMapEntry[1]>=aMapEntry[0]);	// record cannot go -ve size
   1.644 +	__ASSERT(aData>=aMapEntry[0]);					// must not save data before this record
   1.645 +//
   1.646 +	aData+=SetSizeL(iMap[KMaxClustering]-iMap[0]+aAdjust);
   1.647 +	Mem::Copy(aData+aAdjust,aData,iMap[KMaxClustering]-aData);
   1.648 +	AdjustMap(aMapEntry+1,aAdjust);
   1.649 +	}
   1.650 +
   1.651 +// class CCluster::MAlter
   1.652 +
   1.653 +TInt CCluster::MAlter::RecordExpansion(const TUint8*,TInt)
   1.654 +//
   1.655 +// default to no expansion
   1.656 +//
   1.657 +	{
   1.658 +	return 0;
   1.659 +	}