--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/genericservices/taskscheduler/SCHSVR/SCHSTORE.CPP Tue Feb 02 02:01:42 2010 +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<TInt>(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<CClientProxy>& aClients,
+ TSglQue<CSchedule>& 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<CStreamStore*>(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<CPermanentFileStore&>(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<CSchedule>& 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; i<count; i++)
+ {
+ // Get stream
+ TStreamId stream = dictionary->AtIndex(i);
+
+ // Restore schedule from stream
+ CSchedule* schedule = CSchedule::NewL(static_cast<CFileStore&>(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<TSchScheduleMapplet>(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<CClientProxy>& aClients, CClientProxy* aClient)
+ {
+ CClientProxy* currentClient;
+ TDblQueIter<CClientProxy> 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<CClientProxy>& 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; i<count; i++)
+ {
+ // Get stream
+ TStreamId streamId = dictionary->AtIndex(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<CSchClientMapplet>(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; i<count; i++)
+ {
+ CSchClientMapplet* mapplet = CSchClientMapplet::NewLC(aStream);
+ iMappings->AppendL(mapplet);
+ CleanupStack::Pop(); // mapplet
+ }
+ }
+
+void CSchClientIndex::CSchClientDictionary::ExternalizeL(RWriteStream& aStream) const
+ {
+ const TInt count = iMappings->Count();
+ aStream.WriteInt32L(count);
+ for(TInt i=0; i<count; i++)
+ aStream << *iMappings->At(i);
+ }