diff -r cad71a31b7fc -r e36f3802f733 srsf/sisrscontrollerplugin/src/sidatabase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/srsf/sisrscontrollerplugin/src/sidatabase.cpp Wed Sep 01 12:29:17 2010 +0100 @@ -0,0 +1,514 @@ +/* +* Copyright (c) 2004-2006 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: This class implements the SI Controller Plugin database. +* +*/ + + +// INCLUDE FILES +#include "sidatabase.h" +#include "rubydebug.h" +#include "nssbackupobserver.h" + + +// CONSTANTS +// Estimate size in bytes for an empty database +// const TInt KSizeEstimateDb = 650; + +// Plugin database format string for secure DBMS +_LIT( KPluginDatabaseFormatString, "SECURE[10201AFF]" ); + +// Name of the DB lock mutex +_LIT( KLockMutex, "SIDATABASE" ); + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CSIDatabase::CSIDatabase +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CSIDatabase::CSIDatabase( TFileName aDatabaseFileName ) + : iOpenTransaction( EFalse ), + iDatabaseFileName( aDatabaseFileName ), + iDatabaseOpen( EFalse ) + { + // Nothing + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CSIDatabase::ConstructL() + { + RUBY_DEBUG_BLOCKL( "CSIDatabase::ConstructL" ); + // Checks to see if the Database already exists. If not, it creates one. + User::LeaveIfError( iDbSession.Connect() ); + CreateDatabaseL(); + OpenDatabaseL(); + + TInt err = iMutex.OpenGlobal( KLockMutex ); + if ( err != KErrNone ) + { + RUBY_DEBUG0( "CSIDatabase::ConstructL Creating new global mutex" ); + iMutex.CreateGlobal( KLockMutex ); + } + else + { + RUBY_DEBUG0( "CSIDatabase::ConstructL Using existing global mutex" ); + } + + iCriticalSection.CreateLocal(); + iBackupObserver = CNssBackupObserver::NewL( *this ); + + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CSIDatabase* CSIDatabase::NewL( TFileName aSDDatabaseFileName ) + { + RUBY_DEBUG_BLOCKL( "CSIDatabase::NewL" ); + + CSIDatabase* self = new( ELeave ) CSIDatabase( aSDDatabaseFileName ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + + return self; + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::Rollback +// Rollback all changes to the database. +// ----------------------------------------------------------------------------- +// +void CSIDatabase::Rollback() + { + RUBY_DEBUG0( "CSIDatabase::Rollback" ); + if ( iOpenTransaction ) + { + iDb.Rollback(); + // Try to recover the database, if it is damaged + if( iDb.IsDamaged() ) + { + iDb.Recover(); + } + iMutex.Signal(); + iCriticalSection.Signal(); + iOpenTransaction = EFalse; + } + + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::~CSIDatabase +// Destructor +// ----------------------------------------------------------------------------- +// +CSIDatabase::~CSIDatabase() + { + // Rollback if there are any changes not commited + if ( iOpenTransaction ) + { + iDb.Rollback(); + // Try to recover the database, if it is damaged + if( iDb.IsDamaged() ) + { + iDb.Recover(); + } + // Signal mutex if somebody happens to be waiting in BeginTransactionL() + iMutex.Signal(); + } + + delete iBackupObserver; + iCriticalSection.Close(); + + iDb.Close(); + iDbSession.Close(); + iDatabaseOpen = EFalse; + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::BeginTransactionL +// Begins a database transaction if not already. Waits until exclusive write lock +// has been gained. +// ----------------------------------------------------------------------------- +// +void CSIDatabase::BeginTransactionL() + { + + + if ( iOpenTransaction ) + { + // If we already have the lock, no need to take it again + RUBY_DEBUG0( "CSIDatabase::BeginTransactionL DB is already locked by current process" ); + return; + } + + // Take mutex to ensure that only one process tries to gain the lock + iMutex.Wait(); + iCriticalSection.Wait(); + + // Taking the global mutex makes it sure that this should succeed every time + TInt readLockErr = iDb.Begin(); + + if ( readLockErr == KErrNone ) + { + iOpenTransaction = ETrue; + } + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::CommitChangesL +// Commits all changes to the database. +// ----------------------------------------------------------------------------- +// +void CSIDatabase::CommitChangesL( TBool aCompact ) + { + if ( iOpenTransaction ) + { + TInt err = iDb.Commit(); + + RUBY_DEBUG1( "CSIDatabase::CommitChangesL iDb.Commit() [%d]", err ); + + if ( err != KErrNone ) + { + iDb.Rollback(); + // Try to recover the database, if it is damaged + if( iDb.IsDamaged() ) + { + iDb.Recover(); + } + + iMutex.Signal(); + iCriticalSection.Signal(); + iOpenTransaction = EFalse; + User::Leave( err ); + } + + if ( aCompact ) + { + RUBY_DEBUG0( "CSIDatabase::CommitChangesL compacting DB" ); + TInt error = iDb.Compact(); + if ( error != KErrNone ) + { + RUBY_DEBUG1( "CSIDatabase::CommitChangesL compact error: [%d]", error ); + } + } + + // Signal waiting BeginTransactionL() + iMutex.Signal(); + iCriticalSection.Signal(); + iOpenTransaction = EFalse; + + User::LeaveIfError( err ); + } + + + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::DoIDTablesExistL +// Checks to see if ID tables exist. +// ----------------------------------------------------------------------------- +// +TBool CSIDatabase::DoIDTablesExistL() + { + // Get db table names list + CDbTableNames* table_names = iDb.TableNamesL(); + TInt count = table_names->Count(); + delete table_names; + // 1 is for the lock table! + return ( count > 1 ); + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::DoesLockTableExistL +// Checks to see if lock table exists +// ----------------------------------------------------------------------------- +// +TBool CSIDatabase::DoesLockTableExistL() + { + // Get db table names list + CDbTableNames* table_names = iDb.TableNamesL(); + TInt count = table_names->Count(); + + for ( TInt counter = 0 ; counter < count ; counter++ ) + { + if ( (*table_names)[counter] == _L( "writelocktable" ) ) + { + delete table_names; + return ETrue; + } + } + + delete table_names; + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::DoesModelBankTableExistL +// Checks to see if model bank table exists +// ----------------------------------------------------------------------------- +// +TBool CSIDatabase::DoesModelBankTableExistL() + { + // Get db table names list + CDbTableNames* table_names = iDb.TableNamesL(); + TInt count = table_names->Count(); + + for ( TInt counter = 0 ; counter < count ; counter++ ) + { + if ( (*table_names)[counter] == _L( "siModelBankIdTable" ) ) + { + delete table_names; + return ETrue; + } + } + + delete table_names; + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::DoesLexiconTableExistL +// Checks if lexicon table exists +// ----------------------------------------------------------------------------- +// +TBool CSIDatabase::DoesLexiconTableExistL() + { + // Get db table names list + CDbTableNames* table_names = iDb.TableNamesL(); + TInt count = table_names->Count(); + + for ( TInt counter = 0 ; counter < count ; counter++ ) + { + if ( (*table_names)[counter] == _L( "siLexiconIdTable" ) ) + { + delete table_names; + return ETrue; + } + } + + delete table_names; + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::DoesGrammarTableExistL +// Checks if grammar table exists +// ----------------------------------------------------------------------------- +// +TBool CSIDatabase::DoesGrammarTableExistL() + { + // Get db table names list + CDbTableNames* table_names = iDb.TableNamesL(); + TInt count = table_names->Count(); + + for ( TInt counter = 0 ; counter < count ; counter++ ) + { + if ( (*table_names)[counter] == _L( "siGrammarIdTable" ) ) + { + delete table_names; + return ETrue; + } + } + + delete table_names; + return EFalse; + } + + +// ----------------------------------------------------------------------------- +// CSIDatabase::SIDatabase +// Returns a reference to the database. +// ----------------------------------------------------------------------------- +// +RDbNamedDatabase& CSIDatabase::SIDatabase() + { + return iDb; + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::CreateDatabaseL +// Creates a database file if one does not exist yet. +// ----------------------------------------------------------------------------- +// +void CSIDatabase::CreateDatabaseL() + { + RUBY_DEBUG_BLOCKL( "CSIDatabase::CreateDatabaseL" ); + + // Get the drive of the database file + iDatabaseDrive = EDriveC; + if ( iDatabaseFileName.Locate( 'c' ) == 0 || iDatabaseFileName.Locate( 'C' ) == 0 ) + { + iDatabaseDrive = EDriveC; + } + else if ( iDatabaseFileName.Locate( 'd' ) == 0 || iDatabaseFileName.Locate( 'D' ) == 0 ) + { + iDatabaseDrive = EDriveD; + } + else if ( iDatabaseFileName.Locate( 'z' ) == 0 || iDatabaseFileName.Locate( 'Z' ) == 0 ) + { + iDatabaseDrive = EDriveZ; + } + + else if ( iDatabaseFileName.Locate( 'e' ) == 0 || iDatabaseFileName.Locate( 'E' ) == 0 ) + { + iDatabaseDrive = EDriveE; + } + else + { + User::Leave( KErrPathNotFound ); + } + + RDbNamedDatabase database; + TInt ret = database.Create( iDbSession, iDatabaseFileName, KPluginDatabaseFormatString ); + if ( ret == KErrAlreadyExists ) + { + // Ignore KErrAlreadyExists, we will use the existing one if it is there + ret = KErrNone; + } + database.Close(); + User::LeaveIfError( ret ); + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::OpenDatabaseL +// Opens the database. +// ----------------------------------------------------------------------------- +// +void CSIDatabase::OpenDatabaseL() + { + if ( !iDatabaseOpen ) + { + + User::LeaveIfError( iDb.Open( iDbSession, iDatabaseFileName, KPluginDatabaseFormatString ) ); + + // Try to recover the database, if it is damaged + if( iDb.IsDamaged() ) + { + RUBY_DEBUG0( "CSIDatabase::OpenDatabaseL - Db is damaged. Attempt to recover." ); + + User::LeaveIfError( iDb.Recover() ); + } + + iDatabaseOpen = ETrue; + } + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::CloseDatabase +// Closes the database. +// ----------------------------------------------------------------------------- +// +TInt CSIDatabase::CloseDatabase() + { + RUBY_DEBUG0( "CSIDatabase::CloseDatabase" ); + + iDb.Close(); + iDatabaseOpen = EFalse; + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::DbSession +// Return reference to DB session. +// ----------------------------------------------------------------------------- +// +RDbs& CSIDatabase::DbSession() + { + return iDbSession; + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::DbDrive +// Returns a drive for DB file. +// ----------------------------------------------------------------------------- +// +TInt CSIDatabase::DbDrive() + { + return iDatabaseDrive; + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::CreateLockTableL +// Creates a dummy table to gain write-lock at the beginning of each transaction. +// ----------------------------------------------------------------------------- +// +void CSIDatabase::CreateLockTableL() + { + // Create writelocktable + // This table is accessed every time when transaction starts to gain + // exclusive locking of the DB + _LIT( KWriteLockTable, "writelocktable" ); + + _LIT( KCol1, "temporary" ); + + OpenDatabaseL(); + + // Create the rrd tables definition (columnset). + CDbColSet* columns = CDbColSet::NewLC(); + + // The tag id + TDbCol dbCol1( KCol1, EDbColUint32 ); + columns->AddL( dbCol1 ); + + User::LeaveIfError( iDb.CreateTable( KWriteLockTable, *columns ) ); + + // Cleanup columns + CleanupStack::PopAndDestroy( columns ); + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::LockTransactionsL +// Permit transactions and release database +// ----------------------------------------------------------------------------- +// +void CSIDatabase::LockTransactionsL() + { + // lock transactions + RUBY_DEBUG_BLOCK( "CSIDatabase::LockTransactionsL" ); + + iCriticalSection.Wait(); // wait until a possible transaction ends + + // release a database + CloseDatabase(); + } + +// ----------------------------------------------------------------------------- +// CSIDatabase::UnlockTransactionsL +// Allow transactions and reserve database +// ----------------------------------------------------------------------------- +// +void CSIDatabase::UnlockTransactionsL() + { + // unlock transactions + RUBY_DEBUG_BLOCK( "CSIDatabase::UnlockTransactionsL" ); + OpenDatabaseL(); // open database + + if ( iCriticalSection.IsBlocked() ) + { + iCriticalSection.Signal(); // allow to do transactions + } + } + +// End of File