sl@0: // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: #include "LogServCacheStrings.h" sl@0: #include "LogServDatabaseTransactionInterface.h" sl@0: #include "logservpanic.h" sl@0: #include "LogServSqlStrings.h" sl@0: sl@0: /** sl@0: Strings array granularity. sl@0: @internalComponent sl@0: */ sl@0: const TInt KLogNumberOfInitialStrings = 16; sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: // -----> CLogServCacheStrings (source) sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: CLogServCacheStrings::CLogServCacheStrings(MLogServDatabaseTransactionInterface& aDatabase) : sl@0: iDatabase(aDatabase), sl@0: iStrings(KLogNumberOfInitialStrings) sl@0: { sl@0: } sl@0: sl@0: CLogServCacheStrings::~CLogServCacheStrings() sl@0: { sl@0: DestroyCache(); sl@0: } sl@0: sl@0: void CLogServCacheStrings::DestroyCache() sl@0: { sl@0: for(TInt i=iStrings.Count()-1;i>=0;--i) sl@0: { sl@0: TLogServCacheStringEntry::DeleteEntry(iStrings[i]); sl@0: } sl@0: iStrings.Close(); sl@0: } sl@0: sl@0: void CLogServCacheStrings::ConstructL() sl@0: { sl@0: ReadStringsFromDatabaseL(); sl@0: } sl@0: sl@0: CLogServCacheStrings* CLogServCacheStrings::NewL(MLogServDatabaseTransactionInterface& aDatabase) sl@0: { sl@0: CLogServCacheStrings* self = new(ELeave) CLogServCacheStrings(aDatabase); sl@0: CleanupStack::PushL(self); sl@0: self->ConstructL(); sl@0: CleanupStack::Pop(self); sl@0: return self; sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** sl@0: Find the descriptor corresponding to a given string id. KNullDesC if the id is not found. sl@0: */ sl@0: const TPtrC CLogServCacheStrings::FindString(TLogStringId aId) const sl@0: { sl@0: if(aId != KLogNullStringId) sl@0: { sl@0: for(TInt i=iStrings.Count()-1;i>=0;--i) sl@0: { sl@0: if(iStrings[i]->iId == aId) sl@0: { sl@0: return iStrings[i]->String(); sl@0: } sl@0: } sl@0: } sl@0: return KNullDesC(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Find the id of a given string. KLogNullStringId if no string is found. sl@0: */ sl@0: TLogStringId CLogServCacheStrings::FindId(const TDesC& aString) sl@0: { sl@0: if(aString.Length() == 0) sl@0: { sl@0: return KLogNullStringId; sl@0: } sl@0: TInt position = iStrings.FindInOrder(aString, &CLogServCacheStrings::Compare1); sl@0: return position >= 0 ? iStrings[position]->iId : KLogNullStringId; sl@0: } sl@0: sl@0: /** sl@0: Find the id of a given string. Add the string to the cache if the string is not there. sl@0: If the aString length is 0, then do not search the cache, do not add the string, just return KLogNullStringId. sl@0: If the string has to be added - the string will be added to the cache and sl@0: a new record will be inserted into the database. sl@0: If the database is in transaction, the string in the cache will have its "dirty" flag set. During the rollback sl@0: (if a rollback occurs) all strings with "dirty" flag set will be removed from the cache. sl@0: The idea is to keep the cache content consistent with the database content. sl@0: */ sl@0: TLogStringId CLogServCacheStrings::GetIdL(const TDesC& aString) sl@0: { sl@0: if(aString.Length() == 0) sl@0: { sl@0: return KLogNullStringId; sl@0: } sl@0: TLogStringId id = FindId(aString); sl@0: if(id == KLogNullStringId) sl@0: { sl@0: id = DoAddStringL(aString); sl@0: } sl@0: return id; sl@0: } sl@0: sl@0: /** sl@0: Clears the dirty flag of the cache entries that have been added during the last transaction. sl@0: */ sl@0: void CLogServCacheStrings::Commit() sl@0: { sl@0: if(iDirty) sl@0: { sl@0: for(TInt i=iStrings.Count()-1;i>=0;--i) sl@0: { sl@0: iStrings[i]->iDirty = EFalse; sl@0: } sl@0: iDirty = EFalse; sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: Removes any strings added to the cache of strings since the beginning of last transaction (with iDirty flag set). sl@0: */ sl@0: void CLogServCacheStrings::Rollback() sl@0: { sl@0: if(iDirty) sl@0: { sl@0: for(TInt i=iStrings.Count()-1;i>=0;--i) sl@0: { sl@0: if(iStrings[i]->iDirty) sl@0: { sl@0: TLogServCacheStringEntry::DeleteEntry(iStrings[i]); sl@0: iStrings.Remove(i); sl@0: } sl@0: } sl@0: iDirty = EFalse; sl@0: } sl@0: } sl@0: sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: ///////////////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: void CLogServCacheStrings::ReadStringsFromDatabaseL() sl@0: { sl@0: DestroyCache(); sl@0: RDbTable tbl; sl@0: CleanupClosePushL(tbl); sl@0: User::LeaveIfError(tbl.Open(iDatabase.DTIDatabase(), KLogNameStringString, RDbRowSet::EReadOnly)); sl@0: if(tbl.FirstL()) sl@0: { sl@0: InitializeColNumsL(tbl); sl@0: iStrings.ReserveL(tbl.CountL()); sl@0: do sl@0: { sl@0: tbl.GetL(); sl@0: const TLogStringId id = tbl.ColInt16(iIdColNo); sl@0: const TPtrC pString(tbl.ColDes(iStringColNo)); sl@0: TLinearOrder orderer(&CLogServCacheStrings::Compare2); sl@0: TLogServCacheStringEntry* entry = TLogServCacheStringEntry::NewEntryL(id, pString); sl@0: TInt err = iStrings.InsertInOrder(entry, orderer); sl@0: __ASSERT_ALWAYS(err == KErrNone, Panic(ELogStringsCacheReserved)); sl@0: } sl@0: while(tbl.NextL()); sl@0: } sl@0: CleanupStack::PopAndDestroy(&tbl); sl@0: } sl@0: sl@0: //Atomic "add string to cache" operation. sl@0: TLogStringId CLogServCacheStrings::DoAddStringL(const TDesC& aString) sl@0: { sl@0: //Reserve space for the new string in the cache sl@0: iStrings.ReserveL(iStrings.Count() + 1); sl@0: //Open the database table and push it on the cleanup stack. sl@0: //If the InitializeColNumsL() operation leaves then the table will be closed automatically. sl@0: RDbTable tbl; sl@0: CleanupClosePushL(tbl); sl@0: User::LeaveIfError(tbl.Open(iDatabase.DTIDatabase(), KLogNameStringString)); sl@0: InitializeColNumsL(tbl); sl@0: //Allocate space for the new record in the table. Push the Cancel() function on the cleanup stack. sl@0: //If some of the next calls leaves, the insert operation will be automatically cancelled. sl@0: tbl.InsertL(); sl@0: const TLogStringId id = tbl.ColInt16(iIdColNo); sl@0: tbl.SetColL(iStringColNo, aString); sl@0: //Create new cache entry and push it on the cleanup stack. sl@0: TLogServCacheStringEntry* entry = TLogServCacheStringEntry::NewEntryLC(id, aString, iDatabase.DTIInTransaction()); sl@0: //Finish the "insert record" operation. If PutL() leaves, then: sl@0: // - the new cache entry is deleted sl@0: // - the insert operation is cancelled sl@0: // - the table is closed sl@0: tbl.PutL(); sl@0: //Pop the entry and the Cancel() from the cleanup stack. Close the table. sl@0: CleanupStack::Pop();//TLogServCacheStringEntry sl@0: CleanupStack::PopAndDestroy(&tbl); sl@0: //The next operation is guaranteed to be a non-failing "add entry" operation. sl@0: TLinearOrder orderer(&CLogServCacheStrings::Compare2); sl@0: TInt err = iStrings.InsertInOrder(entry, orderer); sl@0: __ASSERT_ALWAYS(err == KErrNone, Panic(ELogStringsCacheReserved)); sl@0: //Mark the cache as dirty. Later if there was an outstanding transaction and that transaction failed, sl@0: //The database rollback operation will restore the original state of the table. sl@0: //The CLogServCacheStrings::RollbackAddStringsL() will remove from the cache all "dirty" strings. sl@0: iDirty = ETrue; sl@0: return id; sl@0: } sl@0: sl@0: TInt CLogServCacheStrings::Compare1(const TDesC* aString, TLogServCacheStringEntry* const& aRight) sl@0: { sl@0: __ASSERT_DEBUG(aString != NULL, Panic(ELogStringsCacheNullArg1)); sl@0: __ASSERT_DEBUG(aRight != NULL, Panic(ELogStringsCacheNullArg1)); sl@0: return aString->Compare(aRight->String()); sl@0: } sl@0: sl@0: TInt CLogServCacheStrings::Compare2(TLogServCacheStringEntry* const& aLeft, TLogServCacheStringEntry* const& aRight) sl@0: { sl@0: __ASSERT_DEBUG(aLeft != NULL, Panic(ELogStringsCacheNullArg2)); sl@0: __ASSERT_DEBUG(aRight != NULL, Panic(ELogStringsCacheNullArg2)); sl@0: return aLeft->String().Compare(aRight->String()); sl@0: } sl@0: sl@0: void CLogServCacheStrings::InitializeColNumsL(RDbRowSet& aRowSet) sl@0: { sl@0: if(iIdColNo == 0) sl@0: { sl@0: CDbColSet* colset = aRowSet.ColSetL(); sl@0: iIdColNo = colset->ColNo(KLogFieldStringIdString); sl@0: iStringColNo = colset->ColNo(KLogFieldStringTextString); sl@0: delete colset; sl@0: } sl@0: __ASSERT_DEBUG(iIdColNo > 0, Panic(ELogInvalidStringColNo)); sl@0: __ASSERT_DEBUG(iStringColNo > 0, Panic(ELogInvalidStringColNo)); sl@0: } sl@0: sl@0: void CLogServCacheStrings::TLogServCacheStringEntry::CleanupEntry(TAny* aEntry) sl@0: { sl@0: TLogServCacheStringEntry* entry = reinterpret_cast (aEntry); sl@0: CLogServCacheStrings::TLogServCacheStringEntry::DeleteEntry(entry); sl@0: }