--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/landmarks/locationlandmarks/server/src/EPos_CPosLmNameIndex.cpp Tue Feb 02 01:06:48 2010 +0200
@@ -0,0 +1,906 @@
+/*
+* Copyright (c) 2007 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: Implementation of CPosLmNameIndex class
+*
+*
+*/
+
+
+#include <e32base.h>
+#include <d32dbms.h>
+#include <EPos_Landmarks.h>
+#include <EPos_CPosLandmark.h>
+#include <epos_cposlmlocaldbaccess.h>
+#include <epos_landmarkdatabasestructure.h>
+#include <epos_poslmlandmarkhandler.h>
+#include <epos_cposlmdiskutilities.h>
+#include <epos_poslmserverutility.h>
+#include <epos_poslmlongtextcolhandler.h>
+
+#include "EPos_PosLmDatabaseManager.h"
+#include "epos_lmdebug.h"
+#include "EPos_CPosLmNameIndex.h"
+
+// ============================ LOCAL FUNCTIONS ===============================
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+//--------------------------------------------------------------------
+// CLmNameIndex::CIndexItem
+//--------------------------------------------------------------------
+//
+CPosLmNameIndex::CIndexItem::CIndexItem()
+: iId ( KPosLmNullItemId )
+ {
+ }
+
+CPosLmNameIndex::CIndexItem::CIndexItem( TPosLmItemId aId )
+: iId ( aId )
+ {
+ }
+
+CPosLmNameIndex::CIndexItem::CIndexItem( TPosLmItemId aId, HBufC* aName )
+: iId ( aId ), iName( aName )
+ {
+ }
+
+CPosLmNameIndex::CIndexItem::~CIndexItem()
+ {
+ delete iName;
+ }
+
+CPosLmNameIndex::CIndexItem* CPosLmNameIndex::CIndexItem::NewLC( TPosLmItemId aId, const TDesC& aName )
+ {
+ CIndexItem* self = new (ELeave) CIndexItem( aId );
+ CleanupStack::PushL( self );
+ self->iName = aName.AllocL();
+ return self;
+ }
+
+CPosLmNameIndex::CIndexItem* CPosLmNameIndex::CIndexItem::NewLC( RReadStream& aIn )
+ {
+ TPosLmItemId id = aIn.ReadUint32L();
+ TInt len = aIn.ReadUint32L();
+ if ( id < 1 || len < 0 ) User::Leave( KErrCorrupt );
+
+ HBufC* name = HBufC::NewLC( len );
+ TPtr ptr = name->Des();
+ aIn.ReadL( ptr, len );
+
+ CIndexItem* self = new (ELeave) CIndexItem( id, name );
+ CleanupStack::Pop( name );
+
+ CleanupStack::PushL( self );
+ return self;
+ }
+
+TPtrC CPosLmNameIndex::CIndexItem::Name() const
+ {
+ if ( iName )
+ return *iName;
+ else
+ return KNullDesC();
+ }
+
+void CPosLmNameIndex::CIndexItem::ExternalizeL( RWriteStream& aOut ) const
+ {
+ aOut.WriteUint32L( iId );
+ aOut.WriteUint32L( Name().Length() );
+ aOut.WriteL( Name() );
+ // state is not stored, it is used only for index verification
+ }
+
+TInt CPosLmNameIndex::CIndexItem::Size() const
+ {
+ return
+ sizeof( TUint32 ) // id size
+ + sizeof( TUint32 ) // string length size
+ + Name().Size(); // string size
+ }
+
+TInt CPosLmNameIndex::CIndexItem::CompareById( const CIndexItem& aLeft, const CIndexItem& aRight )
+ {
+ return aLeft.Id() - aRight.Id();
+ }
+
+//--------------------------------------------------------------------
+// CPosLmNameIndex::TLmIndexNameKey
+//--------------------------------------------------------------------
+//
+CPosLmNameIndex::TLmIndexNameKey::TLmIndexNameKey() :
+ TKeyArrayFix( 0, ECmpCollated )
+ {
+ // the second parameter - comparison type - is used
+ // by TKeyArrayFix::Compare()
+ // the first parameter - offset of the key - is not used:
+ // overridden At() returns pointer to key not using offsets
+ }
+
+TAny* CPosLmNameIndex::TLmIndexNameKey::At( TInt anIndex ) const
+ {
+ TAny* any = TKeyArrayFix::At( anIndex );
+ CIndexItem** ptr = static_cast<CIndexItem**>( any );
+ return (*ptr)->NamePtr();
+ }
+
+//--------------------------------------------------------------------
+// CPosLmNameIndex::TLmIndexIdKey
+//--------------------------------------------------------------------
+//
+CPosLmNameIndex::TLmIndexIdKey::TLmIndexIdKey() :
+ TKeyArrayFix( 0, ECmpTUint32 )
+ {
+ }
+
+TAny* CPosLmNameIndex::TLmIndexIdKey::At( TInt anIndex ) const
+ {
+ TAny* any = TKeyArrayFix::At( anIndex );
+ CIndexItem** ptr = static_cast<CIndexItem**>( any );
+ return (*ptr)->IdPtr();
+ }
+
+//--------------------------------------------------------------------
+// CPosLmNameIndex
+//--------------------------------------------------------------------
+//
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+CPosLmNameIndex::CPosLmNameIndex( CPosLmLocalDbAccess& aDbAccess )
+: iDbAccess( aDbAccess ), iStatus( KErrNotReady )
+ {
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+CPosLmNameIndex::~CPosLmNameIndex()
+ {
+ Reset();
+ delete iArray;
+ delete iKeyItem;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::Reset()
+ {
+ StopEvaluation();
+ iArray->ResetAndDestroy();
+ iDataSize = 0;
+ iStatus = KErrNotReady;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+CPosLmNameIndex* CPosLmNameIndex::NewL( CPosLmLocalDbAccess& aDbAccess )
+ {
+ CPosLmNameIndex* self = NewLC( aDbAccess );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+CPosLmNameIndex* CPosLmNameIndex::NewLC( CPosLmLocalDbAccess& aDbAccess )
+ {
+ CPosLmNameIndex* self = new (ELeave) CPosLmNameIndex( aDbAccess );
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ return self;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::ConstructL()
+ {
+ const TInt KGranularity = 100;
+ iArray = new (ELeave) CArrayPtrSeg<CIndexItem>( KGranularity );
+ iKeyItem = new (ELeave) CIndexItem;
+
+ iDbAccess.GetDatabase( iDatabase );
+
+ iTimeStamp.UniversalTime();
+ TRAPD( err, LoadL() );
+ if ( err )
+ {
+ // need to re-generate index
+ iStatus = KErrNotReady;
+ }
+ else
+ {
+ //if no need to re-generate then set all the landmarks to valid state
+ for(int i =0; i < iArray->Count(); i++)
+ {
+ CIndexItem *item = iArray->At(i);
+ item->SetValid();
+ }
+ iStatus = KErrNone;
+ }
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+TReal32 CPosLmNameIndex::Evaluate()
+ {
+ TReal32 progress = 1.0;
+ if ( iStatus )
+ {
+ TRAPD( err, DoEvaluateL( progress ) );
+ if ( err )
+ {
+ StopEvaluation();
+ iStatus = err;
+ }
+ else if ( progress == 1.0 ) // evaluation completed
+ {
+ StopEvaluation();
+ iStatus = KErrNone;
+ }
+ }
+ return progress;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::StopEvaluation()
+ {
+ if ( iIsTableOpen )
+ {
+ iTable.Close();
+ iIsTableOpen = EFalse;
+ }
+ iIdSortedArray.Reset();
+ RemoveInvalidItems();
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::DoEvaluateL( TReal32& aProgress )
+ {
+ const TInt KRowsPerStep( 100 );
+
+ if ( !iIsTableOpen )
+ {
+ TInt err = iTable.Open( iDatabase, KPosLmLandmarkTable, RDbRowSet::EReadOnly );
+ User::LeaveIfError( err );
+ iIsTableOpen = ETrue;
+
+ if ( iTable.FirstL() )
+ {
+ // Reset();
+ // Don't reset what's loaded - try to check the index with
+ // contents of the database and update accordingly.
+ // Reason: if changes are small (most probable case) this job
+ // is faster than rebuilding new index from scratch
+ CreateByIdSortingL();
+ iTablePosition = 0;
+ iStatus = KErrNotReady;
+ }
+ else
+ {
+ // no records in the table
+ iTable.Close();
+ iIsTableOpen = EFalse;
+ aProgress = 1.0;
+ return;
+ }
+ }
+
+ TInt numRows = KRowsPerStep;
+ while( !iTable.AtEnd() && numRows-- > 0 )
+ {
+ iTable.GetL();
+
+ TPosLmItemId id = iTable.ColUint32( EPosLmLcLandmarkIdCol );
+
+ HBufC* name = PosLmServerUtility::ReadFromLongTextColumnLC(
+ iTable, EPosLmLcNameCol );
+
+ // If the item already exists in the index, mark it as verified
+ // otherwise - add to index
+ CIndexItem* item = ItemById( id );
+ // when comparing contents of the index with database
+ // it is ok to use binary comparison
+ if ( !item || item->Name().Compare( *name ) != 0 )
+ {
+ // the ID has been removed or changed in database
+ if ( item )
+ {
+ // the original item has been changed
+ item->SetInvalid();
+ }
+ // add new item for this ID
+ // here comparison must be done using collation
+ CIndexItem* newItem = DoInsertL( id, name ); // takes onwership of name
+ newItem->SetValid();
+
+ TLinearOrder<CIndexItem> order( CIndexItem::CompareById );
+ iIdSortedArray.InsertInOrder( newItem, order );
+ CleanupStack::Pop( name );
+ }
+ else
+ {
+ // this item already exists in the index
+ item->SetValid();
+ CleanupStack::PopAndDestroy( name );
+ }
+
+ iTable.NextL();
+ iTablePosition++;
+ }
+
+ // return progress;
+ TInt count = iTable.CountL();
+ if ( count > 0 )
+ {
+ aProgress = TReal32( iTablePosition ) / TReal32( count );
+ }
+ else
+ {
+ aProgress = 1.0;
+ }
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+CArrayFixSeg<TPosLmItemId>* CPosLmNameIndex::GetSortedIdsLC() const
+ {
+ return GetSortedIdsLC( 0, Count() );
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+CArrayFixSeg<TPosLmItemId>* CPosLmNameIndex::GetSortedIdsLC( TInt aFirst, TInt aCount ) const
+ {
+ if ( iStatus == KErrNone )
+ {
+ const TInt KGranularity( 512 );
+ CArrayFixSeg<TPosLmItemId>* array = new (ELeave) CArrayFixSeg<TPosLmItemId>( KGranularity );
+ CleanupStack::PushL( array );
+ TInt first = Max( 0, aFirst );
+ TInt last = Min( first + aCount, iArray->Count() );
+ for ( TInt i = first; i < last; i++ )
+ {
+ CIndexItem* item = iArray->At(i);
+ array->AppendL( item->Id() );
+ }
+ return array;
+ }
+ else
+ {
+ User::Leave( iStatus );
+ return NULL;
+ }
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+TInt CPosLmNameIndex::GetSortedIds(
+ TInt aFirst, TInt aCount,
+ TPosLmItemId* aTarget, TInt& aReminder ) const
+ {
+ if ( aFirst < 0 || aCount < 0 || aTarget == NULL )
+ return KErrArgument;
+
+ if ( iStatus == KErrNone )
+ {
+ TInt first = Min( Max( aFirst, 0 ), iArray->Count() );
+ TInt last = Max( 0, Min( aFirst + aCount, iArray->Count() ) );
+ for ( TInt i = first; i < last; i++ )
+ {
+ CIndexItem* item = iArray->At( i );
+ *(aTarget + i-first ) = item->Id();
+ }
+ aReminder = Count() - last;
+ return last - first;
+ }
+ else
+ {
+ return iStatus;
+ }
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::InsertL( const CPosLandmark& aLandmark )
+ {
+ TPtrC name;
+ aLandmark.GetLandmarkName( name );
+ InsertL( aLandmark.LandmarkId(), name );
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::InsertL( TPosLmItemId aLmid, const TDesC& aName )
+ {
+ HBufC* name = aName.AllocLC();
+ InsertL( aLmid, name );
+ CleanupStack::Pop( name );
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::InsertL( TPosLmItemId aLmid, HBufC* aName )
+ {
+ DoInsertL( aLmid, aName );
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+CPosLmNameIndex::CIndexItem* CPosLmNameIndex::DoInsertL( TPosLmItemId aLmid, HBufC* aName )
+ {
+ if ( Find( aLmid ) >= 0 ) // finds valid item
+ {
+ User::Leave( KErrAlreadyExists ); // duplicate ID found
+ }
+
+ CIndexItem* landmark = new (ELeave) CIndexItem( aLmid, aName ); // takes ownership of aName
+ CleanupStack::PushL( landmark );
+
+ TLmIndexNameKey key;
+ iArray->InsertIsqAllowDuplicatesL( landmark, key );
+
+ CleanupStack::Pop( landmark );
+ iDataSize += landmark->Size();
+
+ if ( !iInTransaction )
+ {
+ landmark->SetValid();
+ }
+ // otherwise item remains in Temp state
+
+ return landmark;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::AppendL( TPosLmItemId aLmid, HBufC* aName )
+ {
+ CIndexItem* landmark = new (ELeave) CIndexItem( aLmid, aName );
+ CleanupStack::PushL( landmark );
+ AppendL( landmark );
+ CleanupStack::Pop( landmark );
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::AppendL( CIndexItem* aLandmark )
+ {
+ ASSERT( aLandmark );
+ iArray->AppendL( aLandmark );
+ iDataSize += aLandmark->Size();
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::Remove( TPosLmItemId aLmid )
+ {
+ TInt index = Find( aLmid );
+ if ( index >= 0 )
+ {
+ DoRemove( index );
+ }
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::DoRemove( TInt aIndex )
+ {
+ ASSERT( aIndex >= 0 && aIndex < iArray->Count() );
+
+ CIndexItem* entry = iArray->At( aIndex );
+ if ( !iInTransaction )
+ {
+ iDataSize -= entry->Size();
+ ASSERT( iDataSize >= 0 );
+ delete entry;
+ iArray->Delete( aIndex );
+ }
+ else
+ {
+ entry->SetInvalid();
+ }
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::UpdateL( TPosLmItemId aId, const TDesC& aName )
+ {
+ HBufC* name = aName.AllocLC();
+ UpdateL( aId, name );
+ CleanupStack::Pop( name );
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::UpdateL( TPosLmItemId aLmid, HBufC* aName )
+ {
+ TInt index = Find( aLmid );
+ if ( index >= 0 )
+ {
+ CIndexItem* entry = iArray->At( index );
+ // if name is exactly same, no need to change anything
+ if ( entry->Name().Compare( *aName ) != 0 )
+ {
+ DoRemove( index );
+ InsertL( aLmid, aName );
+ }
+ else
+ {
+ delete aName;
+ }
+ }
+ else
+ {
+ delete aName;
+ }
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+TInt CPosLmNameIndex::Find( TPosLmItemId aLmid ) const
+ {
+ for ( TInt i = 0; i < iArray->Count(); i++ )
+ {
+ CIndexItem* entry = iArray->At(i);
+ if ( entry->Id() == aLmid && entry->IsValid() )
+ {
+ return i;
+ }
+ }
+ return KErrNotFound;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+TInt CPosLmNameIndex::Count() const
+ {
+ return iArray->Count();
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+TInt CPosLmNameIndex::DataSize() const
+ {
+ return
+ sizeof( TUint32 ) // total amount of items
+ + iDataSize;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+const CPosLmNameIndex::CItem& CPosLmNameIndex::Item( TInt aIndex ) const
+ {
+ return *( iArray->At( aIndex ) );
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::ExternalizeL( RWriteStream& aOut ) const
+ {
+ aOut.WriteInt32L( iArray->Count() );
+ for ( TInt i = 0; i < iArray->Count(); i++ )
+ {
+ CIndexItem* item = iArray->At( i );
+ item->ExternalizeL( aOut );
+ }
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::InternalizeL( RReadStream& aIn )
+ {
+ Reset();
+ TInt32 count = aIn.ReadInt32L();
+ if ( count < 0 ) User::Leave( KErrCorrupt );
+ for ( TInt i = 0; i < count; i++ )
+ {
+ CIndexItem* item = CIndexItem::NewLC( aIn );
+ AppendL( item ); // array takes ownership
+ CleanupStack::Pop( item );
+ }
+ iStatus = KErrNone;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::LoadL()
+ {
+ // Skip index loading for empty databases
+ TInt numLandmarks = PosLmServerUtility::TotalLandmarkCountL( iDbAccess );
+ if ( numLandmarks == 0 )
+ {
+ iTimeStamp.UniversalTime();
+ iStatus = KErrNone;
+ return;
+ }
+
+ RDbTable table;
+ TInt err = table.Open( iDatabase, KPosLmIndexTable, RDbRowSet::EReadOnly );
+ if ( err )
+ {
+ LOG("NameIndex::LoadL: index table not found");
+ User::Leave( err );
+ }
+ CleanupClosePushL( table );
+
+ table.FirstL();
+ if ( table.AtEnd() )
+ {
+ LOG("NameIndex::LoadL: index not found");
+ User::Leave( KErrNotFound );
+ }
+
+ table.GetL();
+
+ // verify that index is valid for current language
+ if ( !table.IsColNull( EPosLmIncLanguageCol ) )
+ {
+ TLanguage lang = (TLanguage) table.ColInt32( EPosLmIncLanguageCol );
+ if ( User::Language() != lang )
+ {
+ LOG2("NameIndex::LoadL: index not valid, lang %d, current lang %d",
+ lang, User::Language() );
+ User::Leave( KErrCorrupt );
+ }
+ }
+ else
+ {
+ LOG("NameIndex::LoadL: index lang not found");
+ User::Leave( KErrCorrupt );
+ }
+
+ // read the index
+ if ( !table.IsColNull( EPosLmIncIndexDataCol ) )
+ {
+ RDbColReadStream readStream;
+ readStream.OpenL( table, EPosLmIncIndexDataCol );
+ CleanupClosePushL( readStream );
+ InternalizeL( readStream );
+ CleanupStack::PopAndDestroy( &readStream );
+
+ // basic check for the index
+ if ( Count() != numLandmarks )
+ {
+ LOG2("NameIndex::LoadL: index not valid, count %d, landmarks in db %d",
+ Count(), numLandmarks );
+ User::Leave( KErrCorrupt );
+ }
+ }
+ else
+ {
+ LOG("NameIndex::LoadL: index data not found");
+ User::Leave( KErrCorrupt );
+ }
+
+ // read the time stamp
+ iTimeStamp.UniversalTime();
+ if ( !table.IsColNull( EPosLmIncTimestampCol ) )
+ {
+ iTimeStamp = table.ColTime( EPosLmIncTimestampCol );
+ }
+ else
+ {
+ LOG("NameIndex::LoadL: index timestamp not found");
+ User::Leave( KErrCorrupt );
+ }
+
+ CleanupStack::PopAndDestroy ( &table );
+
+ // index is valid
+ iStatus = KErrNone;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::SaveL( TChar aDrive )
+ {
+ RDbTable table;
+ TInt err = table.Open( iDatabase, KPosLmIndexTable, RDbRowSet::EUpdatable );
+ if ( err == KErrNotFound )
+ {
+ PosLmDatabaseManager::CreateIndexTableL( iDatabase );
+ err = table.Open( iDatabase, KPosLmIndexTable, RDbRowSet::EUpdatable );
+ }
+ User::LeaveIfError( err );
+ CleanupClosePushL( table );
+
+ TInt currentSize = 0;
+ table.FirstL();
+ if ( table.AtEnd() )
+ {
+ table.InsertL();
+ }
+ else
+ {
+ table.GetL();
+ currentSize = table.ColSize( EPosLmIncIndexDataCol );
+ table.UpdateL();
+ }
+
+ if ( currentSize < DataSize() )
+ {
+ // check disk size
+ CPosLmDiskUtilities* diskUtilities = CPosLmDiskUtilities::NewL();
+ CleanupStack::PushL( diskUtilities );
+
+ TInt bytesToWrite = DataSize() - currentSize;
+ diskUtilities->DiskSpaceBelowCriticalLevelL( bytesToWrite, aDrive );
+
+ CleanupStack::PopAndDestroy( diskUtilities );
+ }
+
+ // current language
+ table.SetColL( EPosLmIncLanguageCol, User::Language() );
+
+ // index data
+ RDbColWriteStream writeStream;
+ writeStream.OpenL( table, EPosLmIncIndexDataCol );
+ CleanupClosePushL( writeStream );
+ ExternalizeL( writeStream );
+ CleanupStack::PopAndDestroy( &writeStream );
+
+ // index timestamp
+ TTime now;
+ now.UniversalTime();
+ table.SetColL( EPosLmIncTimestampCol, now );
+
+#ifdef _DEBUG
+ TBuf<64> mtime;
+ now.FormatL( mtime, KPosLmTimeFormat );
+ LOG1( "NameIndex: Saving index timestamp %S", &mtime);
+#endif
+
+ table.PutL();
+ CleanupStack::PopAndDestroy ( &table );
+
+ iTimeStamp = now;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+CPosLmNameIndex::CIndexItem* CPosLmNameIndex::ItemById( TPosLmItemId aId ) const
+ {
+ iKeyItem->SetId( aId );
+
+ TLinearOrder<CIndexItem> order( CIndexItem::CompareById );
+ TInt index = iIdSortedArray.FindInOrder( iKeyItem, order );
+ if ( index >=0 )
+ return iIdSortedArray[index];
+ else
+ return NULL;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::CreateByIdSortingL()
+ {
+ iIdSortedArray.Reset();
+ iIdSortedArray.ReserveL( iArray->Count() );
+
+ for ( TInt i = 0; i < iArray->Count(); i++ )
+ {
+ CIndexItem* item = iArray->At( i );
+ TLinearOrder<CIndexItem> order( CIndexItem::CompareById );
+ iIdSortedArray.InsertInOrder( item, order );
+ }
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::RemoveInvalidItems()
+ {
+ for ( TInt i = iArray->Count() - 1; i >= 0 ; i-- )
+ {
+ CIndexItem* item = iArray->At( i );
+ if ( !item->IsValid() )
+ {
+ delete item;
+ iArray->Delete( i );
+ }
+ }
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::StartTransaction()
+ {
+ ASSERT( !iInTransaction );
+ ASSERT( iStatus == KErrNone );
+ iInTransaction = ETrue;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::CommitTransaction()
+ {
+ ASSERT( iInTransaction );
+ ASSERT( iStatus == KErrNone );
+ // delete items marked as deleted
+ // and validate items marked as temporary
+ for ( TInt i = iArray->Count() - 1; i >= 0 ; i-- )
+ {
+ CIndexItem* item = iArray->At( i );
+ if ( item->IsTemp() )
+ {
+ item->SetValid();
+ }
+ else if ( !item->IsValid() )
+ {
+ delete item;
+ iArray->Delete( i );
+ }
+ }
+ iInTransaction = EFalse;
+ }
+
+//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+//
+void CPosLmNameIndex::RollbackTransaction()
+ {
+ ASSERT( iInTransaction );
+ ASSERT( iStatus == KErrNone );
+ // delete temp items
+ // and validate items marked as invalid
+ for ( TInt i = iArray->Count() - 1; i >= 0 ; i-- )
+ {
+ CIndexItem* item = iArray->At( i );
+ if ( item->IsTemp() )
+ {
+ delete item;
+ iArray->Delete( i );
+ }
+ else if ( !item->IsValid() )
+ {
+ item->SetValid();
+ }
+ }
+ iInTransaction = EFalse;
+ }