diff -r 000000000000 -r 08ec8eefde2f loggingservices/eventlogger/LogServ/src/LogServCacheStrings.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loggingservices/eventlogger/LogServ/src/LogServCacheStrings.cpp Fri Jan 22 11:06:30 2010 +0200 @@ -0,0 +1,256 @@ +// Copyright (c) 2002-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 "LogServCacheStrings.h" +#include "LogServDatabaseTransactionInterface.h" +#include "logservpanic.h" +#include "LogServSqlStrings.h" + +/** +Strings array granularity. +@internalComponent +*/ +const TInt KLogNumberOfInitialStrings = 16; + +///////////////////////////////////////////////////////////////////////////////////////// +// -----> CLogServCacheStrings (source) +///////////////////////////////////////////////////////////////////////////////////////// + +CLogServCacheStrings::CLogServCacheStrings(MLogServDatabaseTransactionInterface& aDatabase) : + iDatabase(aDatabase), + iStrings(KLogNumberOfInitialStrings) + { + } + +CLogServCacheStrings::~CLogServCacheStrings() + { + DestroyCache(); + } + +void CLogServCacheStrings::DestroyCache() + { + for(TInt i=iStrings.Count()-1;i>=0;--i) + { + TLogServCacheStringEntry::DeleteEntry(iStrings[i]); + } + iStrings.Close(); + } + +void CLogServCacheStrings::ConstructL() + { + ReadStringsFromDatabaseL(); + } + +CLogServCacheStrings* CLogServCacheStrings::NewL(MLogServDatabaseTransactionInterface& aDatabase) + { + CLogServCacheStrings* self = new(ELeave) CLogServCacheStrings(aDatabase); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +/** +Find the descriptor corresponding to a given string id. KNullDesC if the id is not found. +*/ +const TPtrC CLogServCacheStrings::FindString(TLogStringId aId) const + { + if(aId != KLogNullStringId) + { + for(TInt i=iStrings.Count()-1;i>=0;--i) + { + if(iStrings[i]->iId == aId) + { + return iStrings[i]->String(); + } + } + } + return KNullDesC(); + } + + +/** +Find the id of a given string. KLogNullStringId if no string is found. +*/ +TLogStringId CLogServCacheStrings::FindId(const TDesC& aString) + { + if(aString.Length() == 0) + { + return KLogNullStringId; + } + TInt position = iStrings.FindInOrder(aString, &CLogServCacheStrings::Compare1); + return position >= 0 ? iStrings[position]->iId : KLogNullStringId; + } + +/** +Find the id of a given string. Add the string to the cache if the string is not there. +If the aString length is 0, then do not search the cache, do not add the string, just return KLogNullStringId. +If the string has to be added - the string will be added to the cache and +a new record will be inserted into the database. +If the database is in transaction, the string in the cache will have its "dirty" flag set. During the rollback +(if a rollback occurs) all strings with "dirty" flag set will be removed from the cache. +The idea is to keep the cache content consistent with the database content. +*/ +TLogStringId CLogServCacheStrings::GetIdL(const TDesC& aString) + { + if(aString.Length() == 0) + { + return KLogNullStringId; + } + TLogStringId id = FindId(aString); + if(id == KLogNullStringId) + { + id = DoAddStringL(aString); + } + return id; + } + +/** +Clears the dirty flag of the cache entries that have been added during the last transaction. +*/ +void CLogServCacheStrings::Commit() + { + if(iDirty) + { + for(TInt i=iStrings.Count()-1;i>=0;--i) + { + iStrings[i]->iDirty = EFalse; + } + iDirty = EFalse; + } + } + + +/** +Removes any strings added to the cache of strings since the beginning of last transaction (with iDirty flag set). +*/ +void CLogServCacheStrings::Rollback() + { + if(iDirty) + { + for(TInt i=iStrings.Count()-1;i>=0;--i) + { + if(iStrings[i]->iDirty) + { + TLogServCacheStringEntry::DeleteEntry(iStrings[i]); + iStrings.Remove(i); + } + } + iDirty = EFalse; + } + } + +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////// + +void CLogServCacheStrings::ReadStringsFromDatabaseL() + { + DestroyCache(); + RDbTable tbl; + CleanupClosePushL(tbl); + User::LeaveIfError(tbl.Open(iDatabase.DTIDatabase(), KLogNameStringString, RDbRowSet::EReadOnly)); + if(tbl.FirstL()) + { + InitializeColNumsL(tbl); + iStrings.ReserveL(tbl.CountL()); + do + { + tbl.GetL(); + const TLogStringId id = tbl.ColInt16(iIdColNo); + const TPtrC pString(tbl.ColDes(iStringColNo)); + TLinearOrder orderer(&CLogServCacheStrings::Compare2); + TLogServCacheStringEntry* entry = TLogServCacheStringEntry::NewEntryL(id, pString); + TInt err = iStrings.InsertInOrder(entry, orderer); + __ASSERT_ALWAYS(err == KErrNone, Panic(ELogStringsCacheReserved)); + } + while(tbl.NextL()); + } + CleanupStack::PopAndDestroy(&tbl); + } + +//Atomic "add string to cache" operation. +TLogStringId CLogServCacheStrings::DoAddStringL(const TDesC& aString) + { + //Reserve space for the new string in the cache + iStrings.ReserveL(iStrings.Count() + 1); + //Open the database table and push it on the cleanup stack. + //If the InitializeColNumsL() operation leaves then the table will be closed automatically. + RDbTable tbl; + CleanupClosePushL(tbl); + User::LeaveIfError(tbl.Open(iDatabase.DTIDatabase(), KLogNameStringString)); + InitializeColNumsL(tbl); + //Allocate space for the new record in the table. Push the Cancel() function on the cleanup stack. + //If some of the next calls leaves, the insert operation will be automatically cancelled. + tbl.InsertL(); + const TLogStringId id = tbl.ColInt16(iIdColNo); + tbl.SetColL(iStringColNo, aString); + //Create new cache entry and push it on the cleanup stack. + TLogServCacheStringEntry* entry = TLogServCacheStringEntry::NewEntryLC(id, aString, iDatabase.DTIInTransaction()); + //Finish the "insert record" operation. If PutL() leaves, then: + // - the new cache entry is deleted + // - the insert operation is cancelled + // - the table is closed + tbl.PutL(); + //Pop the entry and the Cancel() from the cleanup stack. Close the table. + CleanupStack::Pop();//TLogServCacheStringEntry + CleanupStack::PopAndDestroy(&tbl); + //The next operation is guaranteed to be a non-failing "add entry" operation. + TLinearOrder orderer(&CLogServCacheStrings::Compare2); + TInt err = iStrings.InsertInOrder(entry, orderer); + __ASSERT_ALWAYS(err == KErrNone, Panic(ELogStringsCacheReserved)); + //Mark the cache as dirty. Later if there was an outstanding transaction and that transaction failed, + //The database rollback operation will restore the original state of the table. + //The CLogServCacheStrings::RollbackAddStringsL() will remove from the cache all "dirty" strings. + iDirty = ETrue; + return id; + } + +TInt CLogServCacheStrings::Compare1(const TDesC* aString, TLogServCacheStringEntry* const& aRight) + { + __ASSERT_DEBUG(aString != NULL, Panic(ELogStringsCacheNullArg1)); + __ASSERT_DEBUG(aRight != NULL, Panic(ELogStringsCacheNullArg1)); + return aString->Compare(aRight->String()); + } + +TInt CLogServCacheStrings::Compare2(TLogServCacheStringEntry* const& aLeft, TLogServCacheStringEntry* const& aRight) + { + __ASSERT_DEBUG(aLeft != NULL, Panic(ELogStringsCacheNullArg2)); + __ASSERT_DEBUG(aRight != NULL, Panic(ELogStringsCacheNullArg2)); + return aLeft->String().Compare(aRight->String()); + } + +void CLogServCacheStrings::InitializeColNumsL(RDbRowSet& aRowSet) + { + if(iIdColNo == 0) + { + CDbColSet* colset = aRowSet.ColSetL(); + iIdColNo = colset->ColNo(KLogFieldStringIdString); + iStringColNo = colset->ColNo(KLogFieldStringTextString); + delete colset; + } + __ASSERT_DEBUG(iIdColNo > 0, Panic(ELogInvalidStringColNo)); + __ASSERT_DEBUG(iStringColNo > 0, Panic(ELogInvalidStringColNo)); + } + +void CLogServCacheStrings::TLogServCacheStringEntry::CleanupEntry(TAny* aEntry) + { + TLogServCacheStringEntry* entry = reinterpret_cast (aEntry); + CLogServCacheStrings::TLogServCacheStringEntry::DeleteEntry(entry); + }