os/persistentdata/persistentstorage/dbms/pcdbms/ustor/US_DBS.CPP
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include "US_STD.H"
    17 #include "U32STD_DBMS.H"
    18 
    19 // Class CDbStoreDatabase::CCompactor
    20 
    21 NONSHARABLE_CLASS(CDbStoreDatabase::CCompactor) : public CDbStoreDatabase::CStepper
    22 	{
    23 public:
    24 	static CCompactor* NewL(CDbDatabase::TUtility aType, CStreamStore& aStore,
    25                             TInt& aReclaim, TInt& aStep);
    26 	~CCompactor();
    27 private:
    28 	inline CCompactor(TInt& aReclaim);
    29 // from CStepper
    30 	TInt StepL(TInt aStep);
    31 private:
    32 	RStoreReclaim iReclaimer;
    33 	TInt& iReclaim;
    34 	};
    35 
    36 inline CDbStoreDatabase::CCompactor::CCompactor(TInt& aReclaim)
    37 	:iReclaim(aReclaim)
    38 	{
    39 	}
    40 
    41 CDbStoreDatabase::CCompactor* CDbStoreDatabase::CCompactor::NewL(CDbDatabase::TUtility aType,
    42 																 CStreamStore& aStore,
    43 																 TInt& aReclaim,TInt& aStep)
    44 	{
    45 	CCompactor* self=new(ELeave) CCompactor(aReclaim);
    46 	CleanupStack::PushL(self);
    47 	if (aType==CDbDatabase::ECompact)
    48 		self->iReclaimer.CompactL(aStore,aStep);
    49 	else
    50 		self->iReclaimer.OpenL(aStore,aStep);
    51 	CleanupStack::Pop();
    52 	return self;
    53 	}
    54 
    55 CDbStoreDatabase::CCompactor::~CCompactor()
    56 	{
    57 	iReclaimer.Close();
    58 	}
    59 
    60 //
    61 // Single step the compactor
    62 // We cannot deal with the "in use" scenario as we could end up locking out forever
    63 // that has to be left to clients using the RDbIncremental interface
    64 //
    65 TInt CDbStoreDatabase::CCompactor::StepL(TInt aStep)
    66 	{
    67 	iReclaimer.NextL(aStep);
    68 	if (aStep==0)
    69 		{
    70 		iReclaim=iReclaimer.Available();
    71 		iReclaimer.Close();
    72 		}
    73 	return aStep;
    74 	}
    75 
    76 
    77 // Class CDbStoreDatabase
    78 
    79 EXPORT_C CDbStoreDatabase::CDbStoreDatabase()
    80 	:iReclaim(KErrGeneral)
    81 	{
    82 	}
    83 
    84 //
    85 // Create a StoreDatabase object. This type shares the store
    86 //
    87 CDbStoreDatabase* CDbStoreDatabase::NewLC(CStreamStore* aStore)
    88 	{
    89 	__ASSERT(aStore);
    90 	CDbStoreDatabase* self=new(ELeave) CDbStoreDatabase;
    91 	CleanupStack::PushL(self);
    92 	self->iStore=aStore;
    93 	self->iSharedStore=1;
    94 	return self;
    95 	}
    96 
    97 
    98 //SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method.
    99 CDbDatabase* CDbStoreDatabase::CreateL(CStreamStore* aStore,TStreamId& aStreamId)
   100 	{
   101 	CDbStoreDatabase* self=NewLC(aStore);
   102 	aStreamId=self->ConstructL();
   103 	CDbDatabase* db=self->InterfaceL();
   104 	CleanupStack::Pop();			// self
   105 	return db;
   106 	}
   107 	
   108 // SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method.
   109 // Phase 2 construction for creating a new database
   110 // Initialise a new database object, creating the required persistent structure
   111 //
   112 EXPORT_C TStreamId CDbStoreDatabase::ConstructL()
   113 	{
   114 	__ASSERT(iStore);	// this must have been provided by now
   115 	iVersion=TUint8(EDbStoreVersion2);
   116 	InitPagePoolL();
   117 	iPagePool->Create(Store());
   118 	iTokenId=Store().ExtendL();
   119 	ReplaceTokenL(0);
   120 	iSchemaId=Store().ExtendL();
   121 	Schema().Loaded();
   122 	ReplaceSchemaL();
   123 	return iSchemaId;
   124 	}
   125 	
   126 // SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method.
   127 // Open phase #2: Authenticate the client
   128 //
   129 EXPORT_C void CDbStoreDatabase::AuthenticateL()
   130 	{
   131 	if (!iPagePool)
   132 		{
   133 		// first client to open the database, so complete initialisation now
   134 		InitPagePoolL();
   135 		SchemaL();
   136 		}
   137 	}
   138 
   139 // SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method.
   140 void CDbStoreDatabase::InitPagePoolL()
   141 	{
   142 	iPagePool = new(ELeave) RStorePagePool;
   143 	}
   144 	
   145 
   146 CDbSource* CDbStoreDatabase::OpenL(CStreamStore* aStore,TStreamId aStreamId)
   147 	{
   148 	CDbStoreDatabase* self=NewLC(aStore);
   149 	self->RestoreL(aStreamId);
   150 	CDbSource* src=self->SourceL();
   151 	CleanupStack::Pop();			// self
   152 	return src;
   153 	}
   154 
   155 //
   156 // Phase 2 construction for opening a database
   157 // Client must still authenticate before it can be used
   158 //
   159 EXPORT_C void CDbStoreDatabase::RestoreL(TStreamId aStreamId)
   160 	{
   161 	__ASSERT(iStore);	// this must have been provided by now
   162 	iSchemaId=aStreamId;
   163 // read the databse header for encryption information
   164 	RStoreReadStream strm;
   165 	strm.OpenLC(Store(),aStreamId);
   166 	ReadHeaderL(strm);
   167 	CleanupStack::PopAndDestroy();	// strm
   168 	}
   169 
   170 //
   171 // Load the root stream header (up to the security key)
   172 //
   173 void CDbStoreDatabase::ReadHeaderL(RReadStream& aStream)
   174 	{
   175 	TUid uid;
   176 	aStream>>uid;
   177 	if (uid!=KDbmsStoreDatabase)
   178 		__LEAVE(KErrArgument);
   179 	aStream>>iVersion;
   180 	switch (iVersion)
   181 		{
   182 	case EDbStoreCompressed:
   183 		aStream>>CompressionL();
   184 		break;
   185 	case EDbStoreVersion2:
   186 		break;
   187 	default:
   188 		__LEAVE(KErrNotSupported);
   189 		break;
   190 		}
   191 	}
   192 
   193 CDbStoreCompression& CDbStoreDatabase::CompressionL()
   194 	{
   195 	CDbStoreCompression* c=iCompression;
   196 	if (!c)
   197 		iFilter=iCompression=c=CDbStoreCompression::NewL();
   198 	return *c;
   199 	}
   200 
   201 EXPORT_C CDbStoreDatabase::~CDbStoreDatabase()
   202 	{
   203 	if (iPageCache)
   204 		{
   205 		iPagePool->Release();
   206 		delete iPageCache;
   207 		}
   208 	delete iClusterCache;
   209 	delete iPagePool;
   210 	delete iCompression;
   211 	if (!iSharedStore)
   212 		delete iStore;
   213 	}
   214 
   215 //
   216 // Validate the column set first
   217 //
   218 EXPORT_C CDbTableDef* CDbStoreDatabase::CreateTableL(const TDesC& aName,const CDbColSet& aColSet,const CDbKey* aPrimaryKey)
   219 	{
   220 	if (aPrimaryKey)
   221 		__LEAVE(KErrNotSupported);	// Store database does not support primary keys
   222 	CDbStoreDef* def=CDbStoreDef::NewLC(aName,aColSet);
   223 	def->SetTokenId(CDbStoreRecords::CreateL(ClusterCacheL()));
   224 	CleanupStack::Pop();
   225 	return def;
   226 	}
   227 
   228 EXPORT_C CDbTableIndexDef* CDbStoreDatabase::CreateIndexL(const CDbTableDef& aTable,const TDesC& aName,const CDbKey& aKey)
   229 	{
   230 	CDbStoreIndexDef* def=CDbStoreIndexDef::NewLC(aName,aKey,aTable.Columns());
   231 	def->SetTokenId(CDbStoreIndex::CreateL(*this,*def));
   232 	CleanupStack::Pop();			// IndexDef
   233 	return def;
   234 	}
   235 
   236 //
   237 // Destroy the entire database...
   238 //
   239 EXPORT_C void CDbStoreDatabase::DestroyL()
   240 	{
   241 	iPagePool->Discard();
   242 	iPagePool->ReclaimAllL();	// reclaim all page pool space
   243 	iStore->DeleteL(iSchemaId);
   244 	iStore->DeleteL(iTokenId);
   245 	iStore->CommitL();
   246 	}
   247 
   248 EXPORT_C CDbTable* CDbStoreDatabase::TableL(const CDbTableDef& aDef)
   249 	{
   250 	return new(ELeave) CDbStoreTable(*this,aDef);
   251 	}
   252 
   253 //
   254 // load the schema for the database
   255 //
   256 EXPORT_C void CDbStoreDatabase::LoadSchemaL()
   257 	{
   258 	RDbStoreReadStream strm(*this);
   259 	strm.OpenLC(Store(),iSchemaId);
   260 	ReadHeaderL(strm);
   261 	strm.FilterL(strm.EMixed,iSchemaId.Value());
   262 	strm>>iTokenId;
   263 	RDbTableSchema& schema=Schema();
   264 	TCardinality tables;
   265 	strm>>tables;
   266 	for (TInt ii=tables;ii>0;--ii)
   267 		schema.Add(CDbStoreDef::NewL(strm));
   268 	CleanupStack::PopAndDestroy();
   269 	strm.OpenLC(Store(),iTokenId);
   270 	strm>>iFlags>>iPoolToken;
   271 	iPagePool->Open(Store(),iPoolToken);
   272 	CleanupStack::PopAndDestroy();
   273 	}
   274 
   275 //
   276 // Re-write the schema stream
   277 //
   278 void CDbStoreDatabase::ReplaceSchemaL()
   279 	{
   280 	RDbStoreWriteStream out(*this);
   281 	out.ReplaceLC(Store(),iSchemaId);
   282 	out<<KDbmsStoreDatabase<<iVersion;
   283 	switch (iVersion)
   284 		{
   285 	case EDbStoreCompressed:
   286 		__ASSERT(iCompression);
   287 		out<<*iCompression;
   288 		break;
   289 	case EDbStoreVersion2:
   290 		break;
   291 	default:
   292 		__ASSERT(0);
   293 		}
   294 	out.FilterL(out.EMixed,iSchemaId.Value());
   295 	out<<iTokenId;
   296 	TSglQueIterC<CDbStoreDef> iter(Schema());
   297 	TInt count=0;
   298 	while (iter++)
   299 		++count;
   300 	out<<TCardinality(count);
   301 	iter.SetToFirst();
   302 	for (const CDbStoreDef* def;(def=iter++)!=0;)
   303 		out<<*def;
   304 	out.CommitL();
   305 	CleanupStack::PopAndDestroy();
   306 	}
   307 
   308 //
   309 // Re-write the token stream, removing the mark
   310 //
   311 void CDbStoreDatabase::ReplaceTokenL(TUint aFlags)
   312 	{
   313 	RStoreWriteStream out;
   314 	out.ReplaceLC(Store(),iTokenId);
   315 	out<<TUint8(aFlags&EDamaged)<<iPagePool->Token();
   316 	out.CommitL();
   317 	CleanupStack::PopAndDestroy();
   318 	}
   319 
   320 //
   321 // Return some database property
   322 //
   323 EXPORT_C TInt CDbStoreDatabase::Property(CDbDatabase::TProperty aProperty)
   324 	{
   325 	switch (aProperty)
   326 		{
   327 	case CDbDatabase::EIsDamaged:
   328 		return iFlags&EDamaged ? 1 : 0;
   329 	case CDbDatabase::ECompactable:
   330 		return 1;
   331 	default:
   332 		return CDbTableDatabase::Property(aProperty);
   333 		}
   334 	}
   335 
   336 //
   337 // mark the database as dirty
   338 //
   339 void CDbStoreDatabase::MarkL()
   340 	{
   341 	if (!(iFlags&EModified))
   342 		{
   343 		RStoreWriteStream out;
   344 		out.OpenLC(Store(),iTokenId);
   345 		out.WriteUint8L(EDamaged);		// mark as dirty
   346 		iPoolToken.Touch();
   347 		out<<iPoolToken;
   348 		out.CommitL();
   349 		CleanupStack::PopAndDestroy();
   350 		iFlags|=EModified;
   351 		}
   352 	}
   353 
   354 //
   355 // Reset all cache buffers
   356 //
   357 EXPORT_C void CDbStoreDatabase::Idle()
   358 	{
   359 	if (iPageCache)
   360 		{
   361 		iPagePool->Purge();
   362 		delete iPageCache;
   363 		iPageCache=NULL;
   364 		}
   365 	if (iClusterCache)
   366 		{
   367 		delete iClusterCache;
   368 		iClusterCache=NULL;
   369 		}
   370 	}
   371 
   372 //
   373 // Commit the store, and when all is well, clear the token
   374 //
   375 void CDbStoreDatabase::SynchStoreL(TDbLockType aLock)
   376 	{
   377 	if (iPageCache)
   378 		iPagePool->FlushL();
   379 	TUint newflags=iFlags&~EModified;
   380 	if (aLock==EDbRecoveryLock)
   381 		newflags&=~EDamaged;
   382 	if (aLock==EDbRecoveryLock || iFlags&EModified)
   383 		ReplaceTokenL(newflags);
   384 	if (aLock>=EDbWriteLock || iSharedStore)
   385 		{
   386 		iStore->CommitL();
   387 		iFlags=TUint8(newflags);
   388 		iPoolToken=iPagePool->Token();
   389 		}
   390 	}
   391 
   392 //
   393 // An index has been successfully recovered, commit it
   394 //
   395 void CDbStoreDatabase::IndexRecoveredL()
   396 	{
   397 	SynchStoreL(EDbSchemaLock);
   398 	}
   399 
   400 //
   401 // Ensure all data is in the store
   402 //
   403 EXPORT_C void CDbStoreDatabase::SynchL(TDbLockType aLock)
   404 	{
   405 	if (aLock==EDbSchemaLock)
   406 		ReplaceSchemaL();
   407 	if (iClusterCache)
   408 		iClusterCache->FlushL();
   409 	SynchStoreL(aLock);
   410 	}
   411 
   412 //
   413 // Unwind the store, throw out changes, etc
   414 //
   415 EXPORT_C void CDbStoreDatabase::Revert(TDbLockType aLock)
   416 	{
   417 	if (aLock>=EDbWriteLock)
   418 		{
   419 		if (iClusterCache)
   420 			iClusterCache->Discard();
   421 		if (iPageCache)
   422 			iPagePool->Purge();
   423 		if (iFlags&EModified)
   424 			iFlags|=EDamaged;
   425 		iPagePool->Open(Store(),iPoolToken);	// reset the page pool
   426 		}
   427 	else if (!iSharedStore)		// don't touch the store if not shared
   428 		return;
   429 	iStore->Revert();
   430 	}
   431 
   432 //
   433 // Ensure we have a cluster cache and return it
   434 //
   435 CClusterCache& CDbStoreDatabase::ClusterCacheL()
   436 	{
   437 	CClusterCache* cache=iClusterCache;
   438 	if (!cache)
   439 		iClusterCache=cache=CClusterCache::NewL(*this);
   440 	return *cache;
   441 	}
   442 
   443 //
   444 // Ensure we have a page cache and return the pool
   445 //
   446 MPagePool& CDbStoreDatabase::PagePoolL()
   447 	{
   448 	if (!iPageCache)
   449 		{
   450 		iPageCache=CPageCache::NewL(EPageCachePages);
   451 		iPagePool->Set(*iPageCache);
   452 		}
   453 	return *iPagePool;
   454 	}
   455 
   456 //
   457 // Create an incremental object that compacts the store
   458 //
   459 EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::UtilityL(CDbDatabase::TUtility aType,TInt& aStep)
   460 	{
   461 	switch (aType)
   462 		{
   463 	case CDbDatabase::EStats:
   464 	case CDbDatabase::ECompact:
   465 		return CCompactor::NewL(aType,Store(),iReclaim,aStep);
   466 	case CDbDatabase::ERecover:
   467 		return RecoverL(aStep);
   468 	default:
   469 		return CDbTableDatabase::UtilityL(aType,aStep);
   470 		}
   471 	}
   472 
   473 //
   474 // Create an incremental object to destroy a table
   475 //
   476 EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::RecordDiscarderL(const CDbTableDef& aTable,TInt& aStep)
   477 	{
   478 	CDbStoreTable::CDiscarder* discarder=new(ELeave) CDbStoreTable::CDiscarder;
   479 	CleanupStack::PushL(discarder);
   480 	aStep=discarder->OpenL((CDbStoreTable*)TableL(aTable));
   481 	CleanupStack::Pop();
   482 	return discarder;
   483 	}
   484 
   485 //
   486 // Create an incremental object to destroy an index
   487 //
   488 EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::IndexDiscarderL(const CDbTableDef& aTable,const CDbTableIndexDef& anIndex,TInt& aStep)
   489 	{
   490 	CDbStoreIndex::CDiscarder* discarder=new(ELeave) CDbStoreIndex::CDiscarder;
   491 	CleanupStack::PushL(discarder);
   492 	CDbStoreIndex* index=CDbStoreIndex::NewL(*this,(const CDbStoreIndexDef&)anIndex,aTable);
   493 	aStep=discarder->Open(index);
   494 	index->OpenL();
   495 	CleanupStack::Pop();
   496 	return discarder;
   497 	}
   498 
   499 //
   500 // Provide a stepper to alter the table data
   501 // if no data to alter, return 0
   502 //
   503 EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::TableAlterL(CDbTableDef& aTable,const HDbColumnSet& aNewSet,TInt& aStep)
   504 	{
   505 	CDbStoreDef& def=STATIC_CAST(CDbStoreDef&,aTable);
   506 //
   507 	aStep=CDbStoreRecords::CardinalityL(Store(),def);
   508 	if (!aStep)
   509 		return NULL; // no data to modify
   510 
   511 // check that all added columns are nullable
   512 	HDbColumnSet::TIteratorC col=aNewSet.Begin();
   513 	HDbColumnSet::TIteratorC end=aNewSet.End();
   514 	do
   515 		{
   516 		if (col->iFlags&TDbColumnDef::EAdded && col->iAttributes&TDbCol::ENotNull)
   517 			__LEAVE(KErrArgument);		// added column is not nullable
   518 		} while (++col<end);
   519 //
   520 // check to see if anything is being dropped or changed type
   521 	col=aTable.Columns().Begin();
   522 	end=aTable.Columns().End();
   523 	while (!(col->iFlags&(TDbColumnDef::EDropped|TDbColumnDef::EChangedType|TDbColumnDef::EChangedLen)))
   524 		{
   525 		if (++col==end)
   526 			{	// no changes which affect layout, so no work required
   527 			aStep=0;
   528 			return NULL;
   529 			}
   530 		}
   531 // work required
   532 	CDbStoreTable::CAlter* alter=new(ELeave) CDbStoreTable::CAlter;
   533 	CleanupStack::PushL(alter);
   534 	alter->OpenL((CDbStoreTable*)TableL(def),aNewSet);
   535 	CleanupStack::Pop();
   536 	return alter;
   537 	}
   538 
   539 EXPORT_C void CDbStoreDatabase::Reserved_1()
   540 	{
   541 	}
   542 
   543 EXPORT_C void CDbStoreDatabase::Reserved_2()
   544 	{
   545 	}
   546