persistentstorage/dbms/ustor/US_DBS.CPP
changeset 0 08ec8eefde2f
child 55 44f437012c90
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/persistentstorage/dbms/ustor/US_DBS.CPP	Fri Jan 22 11:06:30 2010 +0200
@@ -0,0 +1,545 @@
+// 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 "US_STD.H"
+
+// Class CDbStoreDatabase::CCompactor
+
+NONSHARABLE_CLASS(CDbStoreDatabase::CCompactor) : public CDbStoreDatabase::CStepper
+	{
+public:
+	static CCompactor* NewL(CDbDatabase::TUtility aType, CStreamStore& aStore,
+                            TInt& aReclaim, TInt& aStep);
+	~CCompactor();
+private:
+	inline CCompactor(TInt& aReclaim);
+// from CStepper
+	TInt StepL(TInt aStep);
+private:
+	RStoreReclaim iReclaimer;
+	TInt& iReclaim;
+	};
+
+inline CDbStoreDatabase::CCompactor::CCompactor(TInt& aReclaim)
+	:iReclaim(aReclaim)
+	{
+	}
+
+CDbStoreDatabase::CCompactor* CDbStoreDatabase::CCompactor::NewL(CDbDatabase::TUtility aType,
+																 CStreamStore& aStore,
+																 TInt& aReclaim,TInt& aStep)
+	{
+	CCompactor* self=new(ELeave) CCompactor(aReclaim);
+	CleanupStack::PushL(self);
+	if (aType==CDbDatabase::ECompact)
+		self->iReclaimer.CompactL(aStore,aStep);
+	else
+		self->iReclaimer.OpenL(aStore,aStep);
+	CleanupStack::Pop();
+	return self;
+	}
+
+CDbStoreDatabase::CCompactor::~CCompactor()
+	{
+	iReclaimer.Close();
+	}
+
+//
+// Single step the compactor
+// We cannot deal with the "in use" scenario as we could end up locking out forever
+// that has to be left to clients using the RDbIncremental interface
+//
+TInt CDbStoreDatabase::CCompactor::StepL(TInt aStep)
+	{
+	iReclaimer.NextL(aStep);
+	if (aStep==0)
+		{
+		iReclaim=iReclaimer.Available();
+		iReclaimer.Close();
+		}
+	return aStep;
+	}
+
+
+// Class CDbStoreDatabase
+
+EXPORT_C CDbStoreDatabase::CDbStoreDatabase()
+	:iReclaim(KErrGeneral)
+	{
+	}
+
+//
+// Create a StoreDatabase object. This type shares the store
+//
+CDbStoreDatabase* CDbStoreDatabase::NewLC(CStreamStore* aStore)
+	{
+	__ASSERT(aStore);
+	CDbStoreDatabase* self=new(ELeave) CDbStoreDatabase;
+	CleanupStack::PushL(self);
+	self->iStore=aStore;
+	self->iSharedStore=1;
+	return self;
+	}
+
+
+//SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method.
+CDbDatabase* CDbStoreDatabase::CreateL(CStreamStore* aStore,TStreamId& aStreamId)
+	{
+	CDbStoreDatabase* self=NewLC(aStore);
+	aStreamId=self->ConstructL();
+	CDbDatabase* db=self->InterfaceL();
+	CleanupStack::Pop();			// self
+	return db;
+	}
+	
+// SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method.
+// Phase 2 construction for creating a new database
+// Initialise a new database object, creating the required persistent structure
+//
+EXPORT_C TStreamId CDbStoreDatabase::ConstructL()
+	{
+	__ASSERT(iStore);	// this must have been provided by now
+	iVersion=TUint8(EDbStoreVersion2);
+	InitPagePoolL();
+	iPagePool->Create(Store());
+	iTokenId=Store().ExtendL();
+	ReplaceTokenL(0);
+	iSchemaId=Store().ExtendL();
+	Schema().Loaded();
+	ReplaceSchemaL();
+	return iSchemaId;
+	}
+	
+// SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method.
+// Open phase #2: Authenticate the client
+//
+EXPORT_C void CDbStoreDatabase::AuthenticateL()
+	{
+	if (!iPagePool)
+		{
+		// first client to open the database, so complete initialisation now
+		InitPagePoolL();
+		SchemaL();
+		}
+	}
+
+// SYMBIAN_REMOVE_TRIVIAL_ENCRYPTION version of the method.
+void CDbStoreDatabase::InitPagePoolL()
+	{
+	iPagePool = new(ELeave) RStorePagePool;
+	}
+	
+
+CDbSource* CDbStoreDatabase::OpenL(CStreamStore* aStore,TStreamId aStreamId)
+	{
+	CDbStoreDatabase* self=NewLC(aStore);
+	self->RestoreL(aStreamId);
+	CDbSource* src=self->SourceL();
+	CleanupStack::Pop();			// self
+	return src;
+	}
+
+//
+// Phase 2 construction for opening a database
+// Client must still authenticate before it can be used
+//
+EXPORT_C void CDbStoreDatabase::RestoreL(TStreamId aStreamId)
+	{
+	__ASSERT(iStore);	// this must have been provided by now
+	iSchemaId=aStreamId;
+// read the databse header for encryption information
+	RStoreReadStream strm;
+	strm.OpenLC(Store(),aStreamId);
+	ReadHeaderL(strm);
+	CleanupStack::PopAndDestroy();	// strm
+	}
+
+//
+// Load the root stream header (up to the security key)
+//
+void CDbStoreDatabase::ReadHeaderL(RReadStream& aStream)
+	{
+	TUid uid;
+	aStream>>uid;
+	if (uid!=KDbmsStoreDatabase)
+		__LEAVE(KErrArgument);
+	aStream>>iVersion;
+	switch (iVersion)
+		{
+	case EDbStoreCompressed:
+		aStream>>CompressionL();
+		break;
+	case EDbStoreVersion2:
+		break;
+	default:
+		__LEAVE(KErrNotSupported);
+		break;
+		}
+	}
+
+CDbStoreCompression& CDbStoreDatabase::CompressionL()
+	{
+	CDbStoreCompression* c=iCompression;
+	if (!c)
+		iFilter=iCompression=c=CDbStoreCompression::NewL();
+	return *c;
+	}
+
+EXPORT_C CDbStoreDatabase::~CDbStoreDatabase()
+	{
+	if (iPageCache)
+		{
+		iPagePool->Release();
+		delete iPageCache;
+		}
+	delete iClusterCache;
+	delete iPagePool;
+	delete iCompression;
+	if (!iSharedStore)
+		delete iStore;
+	}
+
+//
+// Validate the column set first
+//
+EXPORT_C CDbTableDef* CDbStoreDatabase::CreateTableL(const TDesC& aName,const CDbColSet& aColSet,const CDbKey* aPrimaryKey)
+	{
+	if (aPrimaryKey)
+		__LEAVE(KErrNotSupported);	// Store database does not support primary keys
+	CDbStoreDef* def=CDbStoreDef::NewLC(aName,aColSet);
+	def->SetTokenId(CDbStoreRecords::CreateL(ClusterCacheL()));
+	CleanupStack::Pop();
+	return def;
+	}
+
+EXPORT_C CDbTableIndexDef* CDbStoreDatabase::CreateIndexL(const CDbTableDef& aTable,const TDesC& aName,const CDbKey& aKey)
+	{
+	CDbStoreIndexDef* def=CDbStoreIndexDef::NewLC(aName,aKey,aTable.Columns());
+	def->SetTokenId(CDbStoreIndex::CreateL(*this,*def));
+	CleanupStack::Pop();			// IndexDef
+	return def;
+	}
+
+//
+// Destroy the entire database...
+//
+EXPORT_C void CDbStoreDatabase::DestroyL()
+	{
+	iPagePool->Discard();
+	iPagePool->ReclaimAllL();	// reclaim all page pool space
+	iStore->DeleteL(iSchemaId);
+	iStore->DeleteL(iTokenId);
+	iStore->CommitL();
+	}
+
+EXPORT_C CDbTable* CDbStoreDatabase::TableL(const CDbTableDef& aDef)
+	{
+	return new(ELeave) CDbStoreTable(*this,aDef);
+	}
+
+//
+// load the schema for the database
+//
+EXPORT_C void CDbStoreDatabase::LoadSchemaL()
+	{
+	RDbStoreReadStream strm(*this);
+	strm.OpenLC(Store(),iSchemaId);
+	ReadHeaderL(strm);
+	strm.FilterL(strm.EMixed,iSchemaId.Value());
+	strm>>iTokenId;
+	RDbTableSchema& schema=Schema();
+	TCardinality tables;
+	strm>>tables;
+	for (TInt ii=tables;ii>0;--ii)
+		schema.Add(CDbStoreDef::NewL(strm));
+	CleanupStack::PopAndDestroy();
+	strm.OpenLC(Store(),iTokenId);
+	strm>>iFlags>>iPoolToken;
+	iPagePool->Open(Store(),iPoolToken);
+	CleanupStack::PopAndDestroy();
+	}
+
+//
+// Re-write the schema stream
+//
+void CDbStoreDatabase::ReplaceSchemaL()
+	{
+	RDbStoreWriteStream out(*this);
+	out.ReplaceLC(Store(),iSchemaId);
+	out<<KDbmsStoreDatabase<<iVersion;
+	switch (iVersion)
+		{
+	case EDbStoreCompressed:
+		__ASSERT(iCompression);
+		out<<*iCompression;
+		break;
+	case EDbStoreVersion2:
+		break;
+	default:
+		__ASSERT(0);
+		}
+	out.FilterL(out.EMixed,iSchemaId.Value());
+	out<<iTokenId;
+	TSglQueIterC<CDbStoreDef> iter(Schema());
+	TInt count=0;
+	while (iter++)
+		++count;
+	out<<TCardinality(count);
+	iter.SetToFirst();
+	for (const CDbStoreDef* def;(def=iter++)!=0;)
+		out<<*def;
+	out.CommitL();
+	CleanupStack::PopAndDestroy();
+	}
+
+//
+// Re-write the token stream, removing the mark
+//
+void CDbStoreDatabase::ReplaceTokenL(TUint aFlags)
+	{
+	RStoreWriteStream out;
+	out.ReplaceLC(Store(),iTokenId);
+	out<<TUint8(aFlags&EDamaged)<<iPagePool->Token();
+	out.CommitL();
+	CleanupStack::PopAndDestroy();
+	}
+
+//
+// Return some database property
+//
+EXPORT_C TInt CDbStoreDatabase::Property(CDbDatabase::TProperty aProperty)
+	{
+	switch (aProperty)
+		{
+	case CDbDatabase::EIsDamaged:
+		return iFlags&EDamaged ? 1 : 0;
+	case CDbDatabase::ECompactable:
+		return 1;
+	default:
+		return CDbTableDatabase::Property(aProperty);
+		}
+	}
+
+//
+// mark the database as dirty
+//
+void CDbStoreDatabase::MarkL()
+	{
+	if (!(iFlags&EModified))
+		{
+		RStoreWriteStream out;
+		out.OpenLC(Store(),iTokenId);
+		out.WriteUint8L(EDamaged);		// mark as dirty
+		iPoolToken.Touch();
+		out<<iPoolToken;
+		out.CommitL();
+		CleanupStack::PopAndDestroy();
+		iFlags|=EModified;
+		}
+	}
+
+//
+// Reset all cache buffers
+//
+EXPORT_C void CDbStoreDatabase::Idle()
+	{
+	if (iPageCache)
+		{
+		iPagePool->Purge();
+		delete iPageCache;
+		iPageCache=NULL;
+		}
+	if (iClusterCache)
+		{
+		delete iClusterCache;
+		iClusterCache=NULL;
+		}
+	}
+
+//
+// Commit the store, and when all is well, clear the token
+//
+void CDbStoreDatabase::SynchStoreL(TDbLockType aLock)
+	{
+	if (iPageCache)
+		iPagePool->FlushL();
+	TUint newflags=iFlags&~EModified;
+	if (aLock==EDbRecoveryLock)
+		newflags&=~EDamaged;
+	if (aLock==EDbRecoveryLock || iFlags&EModified)
+		ReplaceTokenL(newflags);
+	if (aLock>=EDbWriteLock || iSharedStore)
+		{
+		iStore->CommitL();
+		iFlags=TUint8(newflags);
+		iPoolToken=iPagePool->Token();
+		}
+	}
+
+//
+// An index has been successfully recovered, commit it
+//
+void CDbStoreDatabase::IndexRecoveredL()
+	{
+	SynchStoreL(EDbSchemaLock);
+	}
+
+//
+// Ensure all data is in the store
+//
+EXPORT_C void CDbStoreDatabase::SynchL(TDbLockType aLock)
+	{
+	if (aLock==EDbSchemaLock)
+		ReplaceSchemaL();
+	if (iClusterCache)
+		iClusterCache->FlushL();
+	SynchStoreL(aLock);
+	}
+
+//
+// Unwind the store, throw out changes, etc
+//
+EXPORT_C void CDbStoreDatabase::Revert(TDbLockType aLock)
+	{
+	if (aLock>=EDbWriteLock)
+		{
+		if (iClusterCache)
+			iClusterCache->Discard();
+		if (iPageCache)
+			iPagePool->Purge();
+		if (iFlags&EModified)
+			iFlags|=EDamaged;
+		iPagePool->Open(Store(),iPoolToken);	// reset the page pool
+		}
+	else if (!iSharedStore)		// don't touch the store if not shared
+		return;
+	iStore->Revert();
+	}
+
+//
+// Ensure we have a cluster cache and return it
+//
+CClusterCache& CDbStoreDatabase::ClusterCacheL()
+	{
+	CClusterCache* cache=iClusterCache;
+	if (!cache)
+		iClusterCache=cache=CClusterCache::NewL(*this);
+	return *cache;
+	}
+
+//
+// Ensure we have a page cache and return the pool
+//
+MPagePool& CDbStoreDatabase::PagePoolL()
+	{
+	if (!iPageCache)
+		{
+		iPageCache=CPageCache::NewL(EPageCachePages);
+		iPagePool->Set(*iPageCache);
+		}
+	return *iPagePool;
+	}
+
+//
+// Create an incremental object that compacts the store
+//
+EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::UtilityL(CDbDatabase::TUtility aType,TInt& aStep)
+	{
+	switch (aType)
+		{
+	case CDbDatabase::EStats:
+	case CDbDatabase::ECompact:
+		return CCompactor::NewL(aType,Store(),iReclaim,aStep);
+	case CDbDatabase::ERecover:
+		return RecoverL(aStep);
+	default:
+		return CDbTableDatabase::UtilityL(aType,aStep);
+		}
+	}
+
+//
+// Create an incremental object to destroy a table
+//
+EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::RecordDiscarderL(const CDbTableDef& aTable,TInt& aStep)
+	{
+	CDbStoreTable::CDiscarder* discarder=new(ELeave) CDbStoreTable::CDiscarder;
+	CleanupStack::PushL(discarder);
+	aStep=discarder->OpenL((CDbStoreTable*)TableL(aTable));
+	CleanupStack::Pop();
+	return discarder;
+	}
+
+//
+// Create an incremental object to destroy an index
+//
+EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::IndexDiscarderL(const CDbTableDef& aTable,const CDbTableIndexDef& anIndex,TInt& aStep)
+	{
+	CDbStoreIndex::CDiscarder* discarder=new(ELeave) CDbStoreIndex::CDiscarder;
+	CleanupStack::PushL(discarder);
+	CDbStoreIndex* index=CDbStoreIndex::NewL(*this,(const CDbStoreIndexDef&)anIndex,aTable);
+	aStep=discarder->Open(index);
+	index->OpenL();
+	CleanupStack::Pop();
+	return discarder;
+	}
+
+//
+// Provide a stepper to alter the table data
+// if no data to alter, return 0
+//
+EXPORT_C CDbTableDatabase::CStepper* CDbStoreDatabase::TableAlterL(CDbTableDef& aTable,const HDbColumnSet& aNewSet,TInt& aStep)
+	{
+	CDbStoreDef& def=STATIC_CAST(CDbStoreDef&,aTable);
+//
+	aStep=CDbStoreRecords::CardinalityL(Store(),def);
+	if (!aStep)
+		return NULL; // no data to modify
+
+// check that all added columns are nullable
+	HDbColumnSet::TIteratorC col=aNewSet.Begin();
+	HDbColumnSet::TIteratorC end=aNewSet.End();
+	do
+		{
+		if (col->iFlags&TDbColumnDef::EAdded && col->iAttributes&TDbCol::ENotNull)
+			__LEAVE(KErrArgument);		// added column is not nullable
+		} while (++col<end);
+//
+// check to see if anything is being dropped or changed type
+	col=aTable.Columns().Begin();
+	end=aTable.Columns().End();
+	while (!(col->iFlags&(TDbColumnDef::EDropped|TDbColumnDef::EChangedType|TDbColumnDef::EChangedLen)))
+		{
+		if (++col==end)
+			{	// no changes which affect layout, so no work required
+			aStep=0;
+			return NULL;
+			}
+		}
+// work required
+	CDbStoreTable::CAlter* alter=new(ELeave) CDbStoreTable::CAlter;
+	CleanupStack::PushL(alter);
+	alter->OpenL((CDbStoreTable*)TableL(def),aNewSet);
+	CleanupStack::Pop();
+	return alter;
+	}
+
+EXPORT_C void CDbStoreDatabase::Reserved_1()
+	{
+	}
+
+EXPORT_C void CDbStoreDatabase::Reserved_2()
+	{
+	}
+