os/persistentdata/loggingservices/eventlogger/LogServ/src/LogServCacheStrings.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/persistentdata/loggingservices/eventlogger/LogServ/src/LogServCacheStrings.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,256 @@
1.4 +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "LogServCacheStrings.h"
1.20 +#include "LogServDatabaseTransactionInterface.h"
1.21 +#include "logservpanic.h"
1.22 +#include "LogServSqlStrings.h"
1.23 +
1.24 +/**
1.25 +Strings array granularity.
1.26 +@internalComponent
1.27 +*/
1.28 +const TInt KLogNumberOfInitialStrings = 16;
1.29 +
1.30 +/////////////////////////////////////////////////////////////////////////////////////////
1.31 +// -----> CLogServCacheStrings (source)
1.32 +/////////////////////////////////////////////////////////////////////////////////////////
1.33 +
1.34 +CLogServCacheStrings::CLogServCacheStrings(MLogServDatabaseTransactionInterface& aDatabase) :
1.35 + iDatabase(aDatabase),
1.36 + iStrings(KLogNumberOfInitialStrings)
1.37 + {
1.38 + }
1.39 +
1.40 +CLogServCacheStrings::~CLogServCacheStrings()
1.41 + {
1.42 + DestroyCache();
1.43 + }
1.44 +
1.45 +void CLogServCacheStrings::DestroyCache()
1.46 + {
1.47 + for(TInt i=iStrings.Count()-1;i>=0;--i)
1.48 + {
1.49 + TLogServCacheStringEntry::DeleteEntry(iStrings[i]);
1.50 + }
1.51 + iStrings.Close();
1.52 + }
1.53 +
1.54 +void CLogServCacheStrings::ConstructL()
1.55 + {
1.56 + ReadStringsFromDatabaseL();
1.57 + }
1.58 +
1.59 +CLogServCacheStrings* CLogServCacheStrings::NewL(MLogServDatabaseTransactionInterface& aDatabase)
1.60 + {
1.61 + CLogServCacheStrings* self = new(ELeave) CLogServCacheStrings(aDatabase);
1.62 + CleanupStack::PushL(self);
1.63 + self->ConstructL();
1.64 + CleanupStack::Pop(self);
1.65 + return self;
1.66 + }
1.67 +
1.68 +/////////////////////////////////////////////////////////////////////////////////////////
1.69 +/////////////////////////////////////////////////////////////////////////////////////////
1.70 +/////////////////////////////////////////////////////////////////////////////////////////
1.71 +
1.72 +/**
1.73 +Find the descriptor corresponding to a given string id. KNullDesC if the id is not found.
1.74 +*/
1.75 +const TPtrC CLogServCacheStrings::FindString(TLogStringId aId) const
1.76 + {
1.77 + if(aId != KLogNullStringId)
1.78 + {
1.79 + for(TInt i=iStrings.Count()-1;i>=0;--i)
1.80 + {
1.81 + if(iStrings[i]->iId == aId)
1.82 + {
1.83 + return iStrings[i]->String();
1.84 + }
1.85 + }
1.86 + }
1.87 + return KNullDesC();
1.88 + }
1.89 +
1.90 +
1.91 +/**
1.92 +Find the id of a given string. KLogNullStringId if no string is found.
1.93 +*/
1.94 +TLogStringId CLogServCacheStrings::FindId(const TDesC& aString)
1.95 + {
1.96 + if(aString.Length() == 0)
1.97 + {
1.98 + return KLogNullStringId;
1.99 + }
1.100 + TInt position = iStrings.FindInOrder(aString, &CLogServCacheStrings::Compare1);
1.101 + return position >= 0 ? iStrings[position]->iId : KLogNullStringId;
1.102 + }
1.103 +
1.104 +/**
1.105 +Find the id of a given string. Add the string to the cache if the string is not there.
1.106 +If the aString length is 0, then do not search the cache, do not add the string, just return KLogNullStringId.
1.107 +If the string has to be added - the string will be added to the cache and
1.108 +a new record will be inserted into the database.
1.109 +If the database is in transaction, the string in the cache will have its "dirty" flag set. During the rollback
1.110 +(if a rollback occurs) all strings with "dirty" flag set will be removed from the cache.
1.111 +The idea is to keep the cache content consistent with the database content.
1.112 +*/
1.113 +TLogStringId CLogServCacheStrings::GetIdL(const TDesC& aString)
1.114 + {
1.115 + if(aString.Length() == 0)
1.116 + {
1.117 + return KLogNullStringId;
1.118 + }
1.119 + TLogStringId id = FindId(aString);
1.120 + if(id == KLogNullStringId)
1.121 + {
1.122 + id = DoAddStringL(aString);
1.123 + }
1.124 + return id;
1.125 + }
1.126 +
1.127 +/**
1.128 +Clears the dirty flag of the cache entries that have been added during the last transaction.
1.129 +*/
1.130 +void CLogServCacheStrings::Commit()
1.131 + {
1.132 + if(iDirty)
1.133 + {
1.134 + for(TInt i=iStrings.Count()-1;i>=0;--i)
1.135 + {
1.136 + iStrings[i]->iDirty = EFalse;
1.137 + }
1.138 + iDirty = EFalse;
1.139 + }
1.140 + }
1.141 +
1.142 +
1.143 +/**
1.144 +Removes any strings added to the cache of strings since the beginning of last transaction (with iDirty flag set).
1.145 +*/
1.146 +void CLogServCacheStrings::Rollback()
1.147 + {
1.148 + if(iDirty)
1.149 + {
1.150 + for(TInt i=iStrings.Count()-1;i>=0;--i)
1.151 + {
1.152 + if(iStrings[i]->iDirty)
1.153 + {
1.154 + TLogServCacheStringEntry::DeleteEntry(iStrings[i]);
1.155 + iStrings.Remove(i);
1.156 + }
1.157 + }
1.158 + iDirty = EFalse;
1.159 + }
1.160 + }
1.161 +
1.162 +/////////////////////////////////////////////////////////////////////////////////////////
1.163 +/////////////////////////////////////////////////////////////////////////////////////////
1.164 +/////////////////////////////////////////////////////////////////////////////////////////
1.165 +
1.166 +void CLogServCacheStrings::ReadStringsFromDatabaseL()
1.167 + {
1.168 + DestroyCache();
1.169 + RDbTable tbl;
1.170 + CleanupClosePushL(tbl);
1.171 + User::LeaveIfError(tbl.Open(iDatabase.DTIDatabase(), KLogNameStringString, RDbRowSet::EReadOnly));
1.172 + if(tbl.FirstL())
1.173 + {
1.174 + InitializeColNumsL(tbl);
1.175 + iStrings.ReserveL(tbl.CountL());
1.176 + do
1.177 + {
1.178 + tbl.GetL();
1.179 + const TLogStringId id = tbl.ColInt16(iIdColNo);
1.180 + const TPtrC pString(tbl.ColDes(iStringColNo));
1.181 + TLinearOrder<TLogServCacheStringEntry*> orderer(&CLogServCacheStrings::Compare2);
1.182 + TLogServCacheStringEntry* entry = TLogServCacheStringEntry::NewEntryL(id, pString);
1.183 + TInt err = iStrings.InsertInOrder(entry, orderer);
1.184 + __ASSERT_ALWAYS(err == KErrNone, Panic(ELogStringsCacheReserved));
1.185 + }
1.186 + while(tbl.NextL());
1.187 + }
1.188 + CleanupStack::PopAndDestroy(&tbl);
1.189 + }
1.190 +
1.191 +//Atomic "add string to cache" operation.
1.192 +TLogStringId CLogServCacheStrings::DoAddStringL(const TDesC& aString)
1.193 + {
1.194 + //Reserve space for the new string in the cache
1.195 + iStrings.ReserveL(iStrings.Count() + 1);
1.196 + //Open the database table and push it on the cleanup stack.
1.197 + //If the InitializeColNumsL() operation leaves then the table will be closed automatically.
1.198 + RDbTable tbl;
1.199 + CleanupClosePushL(tbl);
1.200 + User::LeaveIfError(tbl.Open(iDatabase.DTIDatabase(), KLogNameStringString));
1.201 + InitializeColNumsL(tbl);
1.202 + //Allocate space for the new record in the table. Push the Cancel() function on the cleanup stack.
1.203 + //If some of the next calls leaves, the insert operation will be automatically cancelled.
1.204 + tbl.InsertL();
1.205 + const TLogStringId id = tbl.ColInt16(iIdColNo);
1.206 + tbl.SetColL(iStringColNo, aString);
1.207 + //Create new cache entry and push it on the cleanup stack.
1.208 + TLogServCacheStringEntry* entry = TLogServCacheStringEntry::NewEntryLC(id, aString, iDatabase.DTIInTransaction());
1.209 + //Finish the "insert record" operation. If PutL() leaves, then:
1.210 + // - the new cache entry is deleted
1.211 + // - the insert operation is cancelled
1.212 + // - the table is closed
1.213 + tbl.PutL();
1.214 + //Pop the entry and the Cancel() from the cleanup stack. Close the table.
1.215 + CleanupStack::Pop();//TLogServCacheStringEntry
1.216 + CleanupStack::PopAndDestroy(&tbl);
1.217 + //The next operation is guaranteed to be a non-failing "add entry" operation.
1.218 + TLinearOrder<TLogServCacheStringEntry*> orderer(&CLogServCacheStrings::Compare2);
1.219 + TInt err = iStrings.InsertInOrder(entry, orderer);
1.220 + __ASSERT_ALWAYS(err == KErrNone, Panic(ELogStringsCacheReserved));
1.221 + //Mark the cache as dirty. Later if there was an outstanding transaction and that transaction failed,
1.222 + //The database rollback operation will restore the original state of the table.
1.223 + //The CLogServCacheStrings::RollbackAddStringsL() will remove from the cache all "dirty" strings.
1.224 + iDirty = ETrue;
1.225 + return id;
1.226 + }
1.227 +
1.228 +TInt CLogServCacheStrings::Compare1(const TDesC* aString, TLogServCacheStringEntry* const& aRight)
1.229 + {
1.230 + __ASSERT_DEBUG(aString != NULL, Panic(ELogStringsCacheNullArg1));
1.231 + __ASSERT_DEBUG(aRight != NULL, Panic(ELogStringsCacheNullArg1));
1.232 + return aString->Compare(aRight->String());
1.233 + }
1.234 +
1.235 +TInt CLogServCacheStrings::Compare2(TLogServCacheStringEntry* const& aLeft, TLogServCacheStringEntry* const& aRight)
1.236 + {
1.237 + __ASSERT_DEBUG(aLeft != NULL, Panic(ELogStringsCacheNullArg2));
1.238 + __ASSERT_DEBUG(aRight != NULL, Panic(ELogStringsCacheNullArg2));
1.239 + return aLeft->String().Compare(aRight->String());
1.240 + }
1.241 +
1.242 +void CLogServCacheStrings::InitializeColNumsL(RDbRowSet& aRowSet)
1.243 + {
1.244 + if(iIdColNo == 0)
1.245 + {
1.246 + CDbColSet* colset = aRowSet.ColSetL();
1.247 + iIdColNo = colset->ColNo(KLogFieldStringIdString);
1.248 + iStringColNo = colset->ColNo(KLogFieldStringTextString);
1.249 + delete colset;
1.250 + }
1.251 + __ASSERT_DEBUG(iIdColNo > 0, Panic(ELogInvalidStringColNo));
1.252 + __ASSERT_DEBUG(iStringColNo > 0, Panic(ELogInvalidStringColNo));
1.253 + }
1.254 +
1.255 +void CLogServCacheStrings::TLogServCacheStringEntry::CleanupEntry(TAny* aEntry)
1.256 + {
1.257 + TLogServCacheStringEntry* entry = reinterpret_cast <TLogServCacheStringEntry*> (aEntry);
1.258 + CLogServCacheStrings::TLogServCacheStringEntry::DeleteEntry(entry);
1.259 + }