diff -r 000000000000 -r bde4ae8d615e os/ossrv/genericservices/taskscheduler/SCHSVR/SCHSTORE.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/ossrv/genericservices/taskscheduler/SCHSVR/SCHSTORE.CPP Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,1000 @@ +// Copyright (c) 2004-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: +// + +// User includes +#include "SCHSTORE.H" +#include "SchLogger.h" +#include "SCHEDULE.H" +#include "SCHCLI.H" +#include "SCHEXEC.H" + +#define UNUSED_VAR(a) a = a + +// Constants +const TInt KMaxChangesBeforeCompact = 5; +// + + +// +// -----> SchBackupManagerUtils (header) +// + +void SchBackupManagerUtils::Panic(TSchStorePanic aPanic) + { + _LIT(KSchStorePanic, "SchStore"); + User::Panic(KSchStorePanic, aPanic); + } + +// +// -----> CSchBackupManager (header) +// + +CSchBackupManager::CSchBackupManager(RFs& aFsSession) +: CActive(EPriorityIdle), iFsSession(aFsSession) + { + // construct backup filename + iBackupFileName.Copy(KSchsvrBackupFileName); + iBackupFileName[0] = 'A' + static_cast(RFs::GetSystemDrive()); + + CActiveScheduler::Add(this); + } + +CSchBackupManager::~CSchBackupManager() + { + // This will delete the store and close the compactor + Cancel(); + // + delete iScheduleIndex; + delete iClientIndex; + } + +void CSchBackupManager::ConstructL() + { + iScheduleIndex = CSchScheduleIndex::NewL(); + iClientIndex = CSchClientIndex::NewL(iFsSession); + } + +/** +If this is called during a restore, we want to make sure we want to append +to existing structure not always create new object and just append to the queue +for example we want to append task to existing client if they have the same name +and priority not create another one. +*/ +void CSchBackupManager::RestoreL(TPriQue& aClients, + TSglQue& aTimeSchedules, + CSchLogManager& aSchLogManager,TBool aBUR) + { + LOGSTRING("CSchBackupManager::RestoreL"); + + // Open store + CPermanentFileStore* store = OpenOrCreateBackupStoreLC(); + + // Restore root stream (two pointers to other streams) + RStoreReadStream stream; + stream.OpenLC(*store, store->Root()); + stream >> iIndexStreamSchedules; + stream >> iIndexStreamClients; + CleanupStack::PopAndDestroy(); // stream + + // Restore clients + iClientIndex->RestoreClientsL(aClients, *store, iIndexStreamClients, aSchLogManager,aBUR); + + // Restore schedules + iScheduleIndex->RestoreSchedulesL(aTimeSchedules, *store, iIndexStreamSchedules); + + // Cleanup store. + CleanupStack::PopAndDestroy(store); + } + +void CSchBackupManager::PerformStoreOperationL(TSchBackupOperation aAction, const CSchedule& aSchedule) +// +// Perform an schedule-related operation. +// + { + LOGSTRING3("CSchBackupManager::PerformStoreOperationL - Schedule: %S (%d)", &aSchedule.Name(), aSchedule.Id()); + + if(aSchedule.Persists()) + { + // Cancel any compaction that may be going on + Cancel(); + + // Perform the operation + CStreamStore* store = OpenOrCreateBackupStoreLC(); + CleanupRevertPushLC(*store); + + switch(aAction) + { + case ESchBackupOperationAdd: + LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpAdd"); + iScheduleIndex->AddL(iIndexStreamSchedules, *store, aSchedule); + break; + case ESchBackupOperationEdit: + LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpEdit"); + iScheduleIndex->EditL(iIndexStreamSchedules, *store, aSchedule); + break; + case ESchBackupOperationDelete: + LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpDelete"); + iScheduleIndex->DeleteL(iIndexStreamSchedules, *store, aSchedule); + break; + default: + __ASSERT_DEBUG(EFalse, User::Invariant()); + User::Leave(KErrNotSupported); + } + // Save changes to store + store->CommitL(); + + CleanupStack::Pop(); // Store reversion cleanup item + CleanupStack::PopAndDestroy(store); + + // Indicate the store has changed and attempt to compact + // the store, but only if the required number of store + // changes has been met + StoreChangedL(); + } + } + +void CSchBackupManager::PerformStoreOperationL(TSchBackupOperation aAction, const CClientProxy& aClient) +// +// Perform an schedule-related operation. +// + { + LOGSTRING2("CSchBackupManager::PerformStoreOperationL - Client: %S", &aClient.ExecutorFileName()); + + // Cancel any compaction that may be going on + Cancel(); + + // Perform the operation + CStreamStore* store = OpenOrCreateBackupStoreLC(); + CleanupRevertPushLC(*store); + + switch(aAction) + { + case ESchBackupOperationAdd: + LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpAdd"); + iClientIndex->AddL(iIndexStreamClients, *store, aClient); + break; + case ESchBackupOperationEdit: + LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpEdit"); + iClientIndex->EditL(iIndexStreamClients, *store, aClient); + break; + case ESchBackupOperationDelete: + LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpDelete"); + iClientIndex->DeleteL(iIndexStreamClients, *store, aClient); + break; + default: + __ASSERT_DEBUG(EFalse, User::Invariant()); + User::Leave(KErrNotSupported); + } + + // Save changes to store + store->CommitL(); + + CleanupStack::Pop(); // Store reversion cleanup item + CleanupStack::PopAndDestroy(store); + + // Indicate the store has changed and attempt to compact + // the store, but only if the required number of store + // changes has been met + StoreChangedL(); + } + +void CSchBackupManager::RunL() +// +// Perform a store compaction step +// + { + LOGSTRING("CSchBackupManager::RunL - Performing compaction step"); + + // Is there any more processing required? + if (iStoreReclaimerCount() > 0) + { + // Yes, so start next step + iStoreReclaimer.Next(iStoreReclaimerCount, iStatus); + SetActive(); + LOGSTRING("CSchBackupManager::RunL - Requesting another compaction step"); + } + else + { + // No, we've finised. Clean up previously allocated + // resources + iStoreReclaimer.Close(); + // + TRAPD(errNotRef, iStoreOpenForCompaction->CommitL()); + UNUSED_VAR(errNotRef); + delete iStoreOpenForCompaction; + iStoreOpenForCompaction = NULL; + + // Set this to zero again... + ResetStoreChanges(); + LOGSTRING("CSchBackupManager::RunL - Compaction complete"); + } + } + +void CSchBackupManager::DoCancel() +// +// Cancel's any asynchronous store compaction +// + { + LOGSTRING("CSchBackupManager::RunL - Cancelling compaction"); + + iStoreReclaimer.Release(); + iStoreReclaimer.Close(); + // + TRAPD(errNotRef, iStoreOpenForCompaction->CommitL()); + UNUSED_VAR(errNotRef); + delete iStoreOpenForCompaction; + iStoreOpenForCompaction = NULL; + } + +void CSchBackupManager::StoreChangedL() + { + __ASSERT_DEBUG(!IsActive() && !iStoreOpenForCompaction, User::Invariant()); + + if (RecordStoreChange() >= KMaxChangesBeforeCompact) + { + // Open the store + CStreamStore* store = OpenBackupStoreLC(); + + // Prepare for compaction + TInt count; + iStoreReclaimer.CompactL(*store, count); + iStoreReclaimerCount = count; + + // Safe to do this now + iStoreOpenForCompaction = store; + CleanupStack::Pop(); + + // Start asynchronous compaction... + iStoreReclaimer.Next(iStoreReclaimerCount, iStatus); + SetActive(); + } + } + +CPermanentFileStore* CSchBackupManager::OpenBackupStoreLC() + { + return CPermanentFileStore::OpenLC(iFsSession, iBackupFileName, EFileWrite); + } + +CPermanentFileStore* CSchBackupManager::OpenOrCreateBackupStoreLC() + { + CPermanentFileStore* store = NULL; + TInt error = KErrNone; + TRAP(error, + store = CPermanentFileStore::OpenL(iFsSession, iBackupFileName, EFileWrite); + ); + if (error < KErrNone) + { + if (error == KErrNotFound) + { + CreateEmptyBackupL(); + store = CPermanentFileStore::OpenL(iFsSession, iBackupFileName, EFileWrite); + } + else + { + User::Leave(error); + } + } + LOGSTRING("CSchBackupManager::OpenOrCreateBackupStoreLC - store opened"); + CleanupStack::PushL(store); + return store; + } + +void CSchBackupManager::CleanupRevertPushLC(CStreamStore& aStore) + { + CleanupStack::PushL(TCleanupItem(RevertStore, &aStore)); + } + +void CSchBackupManager::RevertStore(TAny* aStore) +// +// The Cleanup Item callback function which is used to rever the store +// should a leave occur. +// + { + CStreamStore* store = reinterpret_cast(aStore); + store->Revert(); + LOGSTRING("CSchBackupManager::RevertStore - store reverted"); + } + +/** +Creates an initialised empty store. +The creation process is performed as an atomic operation. +If the operation fails somewhere at the middle, CreateEmptyBackupL() +will cleanup after itself - the store file will be deleted, +iIndexStreamSchedules and iIndexStreamClients stream IDs will be reinitialised +with invalid values. +*/ +void CSchBackupManager::CreateEmptyBackupL() + { + TRAPD(err, DoCreateEmptyBackupL()); + if(err != KErrNone) + { + //Cleanup & leave + // If unable to delete file record the fact + TInt err2 = iFsSession.Delete(iBackupFileName); + if (err2 != KErrNone) + { + LOGSTRING2("CSchBackupManager::CreateEmptyBackupL - File delete error = %d", err2); + } + iIndexStreamSchedules = iIndexStreamClients = KNullStreamId; + User::Leave(err); + } + } + +/** +Creates an initialised empty store. +*/ +void CSchBackupManager::DoCreateEmptyBackupL() + { + LOGSTRING("CSchBackupManager::CreateEmptyBackupL - trying to create new store"); + CPermanentFileStore* store = CPermanentFileStore::ReplaceLC(iFsSession, iBackupFileName, EFileWrite); + store->SetTypeL(KPermanentFileStoreLayoutUid); + + // Create emtpy schedule index stream + CSchScheduleIndex* indexSchedule = CSchScheduleIndex::NewL(); + CleanupStack::PushL(indexSchedule); + iIndexStreamSchedules = indexSchedule->CreateEmptyIndexL(*store); + CleanupStack::PopAndDestroy(indexSchedule); + + // Create emtpy client index stream + CSchClientIndex* indexClient = CSchClientIndex::NewL(iFsSession); + CleanupStack::PushL(indexClient); + iIndexStreamClients = indexClient->CreateEmptyIndexL(*store); + CleanupStack::PopAndDestroy(indexClient); + + // Write root stream + WriteRootStreamL(*store); + + // Finalise + store->CommitL(); + CleanupStack::PopAndDestroy(store); + LOGSTRING("CSchBackupManager::CreateEmptyBackupL - new store created"); + } + +void CSchBackupManager::WriteRootStreamL(CStreamStore& aStore) +// +// Write the root stream which contains the two stream id's +// + { + LOGSTRING("CSchBackupManager::WriteRootStreamL - trying to write root stream"); + RStoreWriteStream stream; + TStreamId id = stream.CreateLC(aStore); + + // This writes a stream id - it doesn't write the actual + // dictionary since this is written after every operation. + stream << iIndexStreamSchedules; + stream << iIndexStreamClients; + + // + stream.CommitL(); + CleanupStack::PopAndDestroy();// outstream + static_cast(aStore).SetRootL(id); + LOGSTRING("CSchBackupManager::WriteRootStreamL - root stream written"); + } + +// +// -----> CSchScheduleIndex (header) +// + +CSchScheduleIndex::CSchScheduleIndex() + { + } + +CSchScheduleIndex* CSchScheduleIndex::NewL() + { + CSchScheduleIndex* self = new(ELeave) CSchScheduleIndex; + return self; + } + +void CSchScheduleIndex::RestoreSchedulesL(TSglQue& aTimeSchedules, + CStreamStore& aStore, + TStreamId aDictionaryStreamId) + { + CSchScheduleDictionary* dictionary = DictionaryLC(aStore, aDictionaryStreamId); + + // Restore every schedule in the dictionary + const TInt count = dictionary->Count(); + LOGSTRING2("CSchScheduleIndex::RestoreSchedulesL - read %d dictionary entries", count); + + for(TInt i=0; iAtIndex(i); + + // Restore schedule from stream + CSchedule* schedule = CSchedule::NewL(static_cast(aStore), stream); + + // Save schedule + aTimeSchedules.AddLast(*schedule); // takes ownership + + LOGSTRING3("CSchScheduleIndex::RestoreSchedulesL - restored schedule: %S, %d", &schedule->Name(), schedule->Id()); + } + CleanupStack::PopAndDestroy(dictionary); + } + +TStreamId CSchScheduleIndex::CreateEmptyIndexL(CStreamStore& aStore) const + { + CSchScheduleDictionary* dictionary = CSchScheduleDictionary::NewLC(); + RStoreWriteStream stream; + TStreamId id = stream.CreateLC(aStore); + stream << *dictionary; + stream.CommitL(); + CleanupStack::PopAndDestroy(2); // stream, dictionary + return id; + } + +void CSchScheduleIndex::AddL(TStreamId aIndexStream, CStreamStore& aStore, const CSchedule& aSchedule) +// +// Saves the specified schedule to the store and adds a new entry to the +// dictionary. +// + { + LOGSTRING2("CSchScheduleIndex::AddL - adding a new schedule (id is %d)", aSchedule.Id()); + RStoreWriteStream stream; + TStreamId id = stream.CreateLC(aStore); + stream << aSchedule; + stream.CommitL(); + CleanupStack::PopAndDestroy(); // stream + + // Read the dictionary and update an entry + CSchScheduleDictionary* dictionary = DictionaryLC(aStore, aIndexStream); + dictionary->AssignL(aSchedule.Id(), id); + + // Store the dictionary + StoreDictionaryL(aStore, *dictionary, aIndexStream); + CleanupStack::PopAndDestroy(dictionary); + LOGSTRING("CSchScheduleIndex::AddL - new schedule added okay"); + } + +void CSchScheduleIndex::EditL(TStreamId aIndexStream, CStreamStore& aStore, const CSchedule& aSchedule) +// +// Replace an existing stream with the contents of aSchedule. +// + { + // Locate the existing stream (to be replaced) + CSchScheduleDictionary* dictionary = DictionaryLC(aStore, aIndexStream); + LOGSTRING2("CSchScheduleIndex::EditL - editing schedule with id of %d", aSchedule.Id()); + TStreamId id = dictionary->At(aSchedule.Id()); + CleanupStack::PopAndDestroy(dictionary); + if (id == KNullStreamId) + { + // Wasn't found, add it instead... + LOGSTRING("CSchScheduleIndex::EditL - schedule wasn't found, adding new entry to the store"); + AddL(aIndexStream, aStore, aSchedule); + } + else + { + // Replace - the original stream is orphaned but the new + // stream retains the old id. + LOGSTRING("CSchScheduleIndex::EditL - replacing original stream"); + RStoreWriteStream stream; + stream.ReplaceLC(aStore, id); + stream << aSchedule; + stream.CommitL(); + CleanupStack::PopAndDestroy(); // stream + } + } + +void CSchScheduleIndex::DeleteL(TStreamId aIndexStream, CStreamStore& aStore, const CSchedule& aSchedule) +// +// Remove an existing schedule from the store. +// + { + // Locate the existing stream (to be deleted) + CSchScheduleDictionary* dictionary = DictionaryLC(aStore, aIndexStream); + LOGSTRING2("CSchScheduleIndex::DeleteL - deleting schedule with id of %d", aSchedule.Id()); + TStreamId id = dictionary->At(aSchedule.Id()); + if (id == KNullStreamId) + { + LOGSTRING("CSchScheduleIndex::DeleteL - schedule wasn't found! Would panic in debug"); + __ASSERT_DEBUG(EFalse, SchBackupManagerUtils::Panic(SchBackupManagerUtils::ESchBackupManagerScheduleStreamToDeleteNotFound)); + } + else + { + // Remove the stream + aStore.DeleteL(id); + + // Save changes to store - we have to do this here since + // we must assure that the store is fully updated before + // we remove this stream from the dictionary (in order to + // maintain integrity). + aStore.CommitL(); + + // Remove entry from the stream dictionary + dictionary->Remove(aSchedule.Id()); + StoreDictionaryL(aStore, *dictionary, aIndexStream); + } + CleanupStack::PopAndDestroy(dictionary); + } + +CSchScheduleIndex::CSchScheduleDictionary* CSchScheduleIndex::DictionaryLC(CStreamStore& aStore, TStreamId aIndexStream) + { + LOGSTRING("CSchScheduleIndex::DictionaryLC - restoring dictionary"); + CSchScheduleDictionary* dictionary = CSchScheduleDictionary::NewLC(); + RStoreReadStream stream; + stream.OpenLC(aStore, aIndexStream); + stream >> *dictionary; + CleanupStack::PopAndDestroy(); // stream + LOGSTRING("CSchScheduleIndex::DictionaryLC - dictionary restored"); + return dictionary; + } + +void CSchScheduleIndex::StoreDictionaryL(CStreamStore& aStore, const CSchScheduleDictionary& aDictionary, TStreamId aStreamToReplace) + { + LOGSTRING("CSchScheduleIndex::DictionaryLC - storing dictionary"); + RStoreWriteStream stream; + stream.ReplaceLC(aStore, aStreamToReplace); + stream << aDictionary; + stream.CommitL(); + CleanupStack::PopAndDestroy(); // stream + LOGSTRING("CSchScheduleIndex::DictionaryLC - dictionary stored"); + } + +// +// -----> CSchScheduleDictionary (header) +// + +CSchScheduleIndex::CSchScheduleDictionary::CSchScheduleDictionary() + { + } + +CSchScheduleIndex::CSchScheduleDictionary::~CSchScheduleDictionary() + { + delete iMappings; + } + +void CSchScheduleIndex::CSchScheduleDictionary::ConstructL() + { + const TInt KGranularity = 3; + iMappings = new(ELeave) CArrayFixSeg(KGranularity); + } + +CSchScheduleIndex::CSchScheduleDictionary* CSchScheduleIndex::CSchScheduleDictionary::NewLC() + { + CSchScheduleDictionary* self = new(ELeave) CSchScheduleDictionary(); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +void CSchScheduleIndex::CSchScheduleDictionary::AssignL(TInt aKey, TStreamId aId) + { + if (aId == KNullStreamId) + { + Remove(aKey); // default associated stream is null + return; + } + // + TSchScheduleMapplet entry(aKey, KNullStreamId); + TKeyArrayFix key(TSchScheduleMapplet::KeyOffset(), ECmpTInt32); + TInt i; + if (iMappings->FindIsq(entry, key, i) == 0) + { + iMappings->At(i).SetStream(aId); + return; + } + // + entry.SetStream(aId); + iMappings->InsertIsqL(entry, key); + } + +void CSchScheduleIndex::CSchScheduleDictionary::Remove(TInt aKey) + { + TSchScheduleMapplet entry(aKey, KNullStreamId); + TKeyArrayFix key(TSchScheduleMapplet::KeyOffset(), ECmpTInt32); + TInt i; + if (iMappings->FindIsq(entry, key, i) == 0) + iMappings->Delete(i); + } + +TInt CSchScheduleIndex::CSchScheduleDictionary::Count() const + { + return iMappings->Count(); + } + +TStreamId CSchScheduleIndex::CSchScheduleDictionary::At(TInt aKey) const + { + TSchScheduleMapplet entry(aKey, KNullStreamId); + TKeyArrayFix key(TSchScheduleMapplet::KeyOffset(), ECmpTInt32); + TInt i; + if (iMappings->FindIsq(entry, key, i) != 0) + return KNullStreamId; + // + return iMappings->At(i).Stream(); + } + +TStreamId CSchScheduleIndex::CSchScheduleDictionary::AtIndex(TInt aIndex) const + { + return iMappings->At(aIndex).Stream(); + } + +void CSchScheduleIndex::CSchScheduleDictionary::InternalizeL(RReadStream& aStream) + { + aStream >> *iMappings; + } + +void CSchScheduleIndex::CSchScheduleDictionary::ExternalizeL(RWriteStream& aStream) const + { + aStream << *iMappings; + } + +// +// -----> CSchClientIndex (header) +// + +CSchClientIndex::CSchClientIndex(RFs& aFsSession) +: iFsSession(aFsSession) + { + } + +CSchClientIndex* CSchClientIndex::NewL(RFs& aFsSession) + { + return new(ELeave) CSchClientIndex(aFsSession); + } + +void CSchClientIndex::AppendClientToListL(TPriQue& aClients, CClientProxy* aClient) + { + CClientProxy* currentClient; + TDblQueIter clientIter(aClients); + clientIter.SetToFirst(); + while ((currentClient = clientIter++) != NULL) + { + //if match on same client name and priority + if (currentClient->IsEqual(aClient->ExecutorFileName(),aClient->Priority())) + { + //transfer all the tasks in aClient to this client + aClient->TransferTasks(*currentClient); + //now that we have transferred all the task ownership, we can safely delete the source client + delete aClient; + return; + } + } + //since that there is no matching one just add the aClient directly + aClients.Add(*aClient); + } + +void CSchClientIndex::RestoreClientsL(TPriQue& aClients, + CStreamStore& aStore, + TStreamId aIndexStream, + CSchLogManager& aSchLogManager,TBool aBUR) + { + CSchClientDictionary* dictionary = DictionaryLC(aStore, aIndexStream); + + // Restore every schedule in the dictionary + const TInt count = dictionary->Count(); + LOGSTRING2("CSchClientIndex::RestoreClientsL - read %d dictionary entries", count); + + for(TInt i=0; iAtIndex(i); + + RStoreReadStream stream; + stream.OpenLC(aStore, streamId); + + // Restore client + CClientProxy* client = CClientProxy::NewL(iFsSession,stream,aSchLogManager); + CleanupStack::PopAndDestroy(); // stream + + // Save schedule + // only when this is called through restore we need to append to existing client which + // might already contain other transient tasks + if (aBUR) + { + AppendClientToListL(aClients,client); + } + else + { + aClients.Add(*client); // takes ownership + } + LOGSTRING2("CSchClientIndex::RestoreClientsL - restored client: %S", &client->ExecutorFileName()); + } + CleanupStack::PopAndDestroy(dictionary); + } + +TStreamId CSchClientIndex::CreateEmptyIndexL(CStreamStore& aStore) const + { + CSchClientDictionary* dictionary = CSchClientDictionary::NewLC(); + RStoreWriteStream stream; + TStreamId id = stream.CreateLC(aStore); + stream << *dictionary; + stream.CommitL(); + CleanupStack::PopAndDestroy(2); // stream, dictionary + return id; + } + +void CSchClientIndex::AddL(TStreamId aIndexStream, CStreamStore& aStore, const CClientProxy& aClient) + { + RStoreWriteStream stream; + TStreamId id = stream.CreateLC(aStore); + stream << aClient; + stream.CommitL(); + CleanupStack::PopAndDestroy(); // stream + + // Read the dictionary and update an entry + CSchClientDictionary* dictionary = DictionaryLC(aStore, aIndexStream); + dictionary->AssignL(aClient.ExecutorFileName(), id); + + // Store the dictionary + StoreDictionaryL(aStore, *dictionary, aIndexStream); + CleanupStack::PopAndDestroy(dictionary); + } + +void CSchClientIndex::EditL(TStreamId aIndexStream, CStreamStore& aStore, const CClientProxy& aClient) + { + // Locate the existing stream (to be replaced) + CSchClientDictionary* dictionary = DictionaryLC(aStore, aIndexStream); + TStreamId id = dictionary->AtL(aClient.ExecutorFileName()); + CleanupStack::PopAndDestroy(dictionary); + if (id == KNullStreamId) + { + // Wasn't found, add it instead... + AddL(aIndexStream, aStore, aClient); + } + else + { + // Replace - the original stream is orphaned but the new + // stream retains the old id. + RStoreWriteStream stream; + stream.ReplaceLC(aStore, id); + stream << aClient; + stream.CommitL(); + CleanupStack::PopAndDestroy(); // stream + } + } + +void CSchClientIndex::DeleteL(TStreamId aIndexStream, CStreamStore& aStore, const CClientProxy& aClient) + { + // Locate the existing stream (to be deleted) + CSchClientDictionary* dictionary = DictionaryLC(aStore, aIndexStream); + TStreamId id = dictionary->AtL(aClient.ExecutorFileName()); + __ASSERT_ALWAYS(id != KNullStreamId, SchBackupManagerUtils::Panic(SchBackupManagerUtils::ESchBackupManagerScheduleStreamToDeleteNotFound)); + + // Remove the stream + aStore.DeleteL(id); + + // Save changes to store - we have to do this here since + // we must assure that the store is fully updated before + // we remove this stream from the dictionary (in order to + // maintain integrity). + aStore.CommitL(); + + // Remove entry from the stream dictionary + dictionary->RemoveL(aClient.ExecutorFileName()); + StoreDictionaryL(aStore, *dictionary, aIndexStream); + CleanupStack::PopAndDestroy(dictionary); + } + +CSchClientIndex::CSchClientDictionary* CSchClientIndex::DictionaryLC(CStreamStore& aStore, TStreamId aIndexStream) + { + LOGSTRING("CSchClientIndex::DictionaryLC - restoring dictionary"); + CSchClientDictionary* dictionary = CSchClientDictionary::NewLC(); + RStoreReadStream stream; + stream.OpenLC(aStore, aIndexStream); + stream >> *dictionary; + CleanupStack::PopAndDestroy(); // stream + LOGSTRING("CSchClientIndex::DictionaryLC - dictionary restored"); + return dictionary; + } + +void CSchClientIndex::StoreDictionaryL(CStreamStore& aStore, const CSchClientDictionary& aDictionary, TStreamId aStreamToReplace) + { + LOGSTRING("CSchClientIndex::DictionaryLC - storing dictionary"); + RStoreWriteStream stream; + stream.ReplaceLC(aStore, aStreamToReplace); + stream << aDictionary; + stream.CommitL(); + CleanupStack::PopAndDestroy(); // stream + LOGSTRING("CSchClientIndex::DictionaryLC - dictionary stored"); + } + +// +// -----> TKeyArrayPtr (header) +// +NONSHARABLE_CLASS(TKeyArrayMapping) : public TKeyArrayFix +{ +public: + inline TKeyArrayMapping(TInt aOffset) : TKeyArrayFix(aOffset, TKeyCmpText()) {iHBufType=ETrue;} + // + virtual TAny* At(TInt aIndex) const; + virtual TInt Compare(TInt aLeft,TInt aRight) const; + +private: + TBool iHBufType; + }; + +TAny* TKeyArrayMapping::At(TInt aIndex) const + { + if (aIndex==KIndexPtr) + { + const CSchClientIndex::CSchClientMapplet** ppItem = (const CSchClientIndex::CSchClientMapplet**) iPtr; + const CSchClientIndex::CSchClientMapplet* pItem = *ppItem; + return (TAny*) pItem; + } + else + { + TInt baseOffset = aIndex * sizeof(const CSchClientIndex::CSchClientMapplet*); + const TUint8* pItemUncast = iBase->Ptr(baseOffset).Ptr(); + const CSchClientIndex::CSchClientMapplet** ppItem = (const CSchClientIndex::CSchClientMapplet**) pItemUncast; + const CSchClientIndex::CSchClientMapplet* pItem = *ppItem; + return (TAny*) pItem; + } + } + +TInt TKeyArrayMapping::Compare(TInt aLeft,TInt aRight) const + { + if (iHBufType) + { + const CSchClientIndex::CSchClientMapplet* left = (const CSchClientIndex::CSchClientMapplet*) At(aLeft); + const CSchClientIndex::CSchClientMapplet* right = (const CSchClientIndex::CSchClientMapplet*) At(aRight); + + return (left->Key().Compare(right->Key())); + } + else + User::Invariant(); + return KErrNotFound; + } + +// +// -----> CSchClientIndex::CSchClientMapplet (header) +// + +CSchClientIndex::CSchClientMapplet::~CSchClientMapplet() + { + delete iKey; + } + +CSchClientIndex::CSchClientMapplet* CSchClientIndex::CSchClientMapplet::NewLC(RReadStream& aStream) + { + CSchClientMapplet* self = new(ELeave) CSchClientMapplet; + CleanupStack::PushL(self); + aStream >> *self; + return self; + } + +CSchClientIndex::CSchClientMapplet* CSchClientIndex::CSchClientMapplet::NewLC(const TDesC& aKey, TStreamId aStream) + { + CSchClientMapplet* self = new(ELeave) CSchClientMapplet; + CleanupStack::PushL(self); + self->iKey = aKey.AllocL(); + self->iStream = aStream; + return self; + } + +void CSchClientIndex::CSchClientMapplet::InternalizeL(RReadStream& aStream) + { + HBufC* key = HBufC::NewLC(aStream, KMaxTInt); + delete iKey; + iKey = key; + CleanupStack::Pop(); // key + aStream >> iStream; + } + +void CSchClientIndex::CSchClientMapplet::ExternalizeL(RWriteStream& aStream) const + { + aStream << *iKey; + aStream << iStream; + } + + +// +// -----> CSchClientIndex::CSchClientDictionary (header) +// + +CSchClientIndex::CSchClientDictionary::CSchClientDictionary() + { + } + +CSchClientIndex::CSchClientDictionary::~CSchClientDictionary() + { + if(iMappings) + { + for(int index = 0; index < iMappings->Count();index++) + { + delete iMappings->At(index); + } + delete iMappings; + } + } + +void CSchClientIndex::CSchClientDictionary::ConstructL() + { + const TInt KGranularity = 2; + iMappings = new(ELeave) CArrayPtrSeg(KGranularity); + } + +CSchClientIndex::CSchClientDictionary* CSchClientIndex::CSchClientDictionary::NewLC() + { + CSchClientDictionary* self = new(ELeave) CSchClientDictionary(); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +void CSchClientIndex::CSchClientDictionary::AssignL(const TDesC& aKey, TStreamId aId) + { + if (aId == KNullStreamId) + { + RemoveL(aKey); // default associated stream is null + return; + } + + CSchClientMapplet* entry = CSchClientMapplet::NewLC(aKey, KNullStreamId); + TKeyArrayMapping key(CSchClientMapplet::KeyOffset()); + TInt i; + if (iMappings->FindIsq(entry, key, i) == 0) + { + iMappings->At(i)->SetStream(aId); + CleanupStack::PopAndDestroy(); // entry + return; + } + + entry->SetStream(aId); + iMappings->InsertIsqL(entry, key); + CleanupStack::Pop(); // entry + } + +void CSchClientIndex::CSchClientDictionary::RemoveL(const TDesC& aKey) + { + CSchClientMapplet* entry = CSchClientMapplet::NewLC(aKey, KNullStreamId); + TKeyArrayMapping key(CSchClientMapplet::KeyOffset()); + TInt i; + if (iMappings->FindIsq(entry, key, i) == 0) + { + delete iMappings->At(i); + iMappings->Delete(i); + } + CleanupStack::PopAndDestroy(); // entry + } + +TInt CSchClientIndex::CSchClientDictionary::Count() const + { + return iMappings->Count(); + } + +TStreamId CSchClientIndex::CSchClientDictionary::AtL(const TDesC& aKey) const + { + CSchClientMapplet* entry = CSchClientMapplet::NewLC(aKey, KNullStreamId); + TKeyArrayMapping key(CSchClientMapplet::KeyOffset()); + TInt i; + TInt found = iMappings->FindIsq(entry, key, i); + CleanupStack::PopAndDestroy(); // entry + if (found != 0) + return KNullStreamId; + return iMappings->At(i)->Stream(); + } + +TStreamId CSchClientIndex::CSchClientDictionary::AtIndex(TInt aIndex) const + { + return iMappings->At(aIndex)->Stream(); + } + +void CSchClientIndex::CSchClientDictionary::InternalizeL(RReadStream& aStream) + { + const TInt count = aStream.ReadInt32L(); + for(TInt i=0; iAppendL(mapplet); + CleanupStack::Pop(); // mapplet + } + } + +void CSchClientIndex::CSchClientDictionary::ExternalizeL(RWriteStream& aStream) const + { + const TInt count = iMappings->Count(); + aStream.WriteInt32L(count); + for(TInt i=0; iAt(i); + }