genericservices/taskscheduler/SCHSVR/SCHSTORE.CPP
changeset 31 ce057bb09d0b
parent 0 e4d67989cc36
equal deleted inserted replaced
30:e20de85af2ee 31:ce057bb09d0b
       
     1 // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 // User includes
       
    17 #include "SCHSTORE.H"
       
    18 #include "SchLogger.h"
       
    19 #include "SCHEDULE.H"
       
    20 #include "SCHCLI.H"
       
    21 #include "SCHEXEC.H"
       
    22 
       
    23 #define UNUSED_VAR(a) a = a
       
    24 
       
    25 // Constants
       
    26 const TInt KMaxChangesBeforeCompact = 5;
       
    27 //
       
    28 
       
    29 
       
    30 //
       
    31 // -----> SchBackupManagerUtils (header)
       
    32 //
       
    33 
       
    34 void SchBackupManagerUtils::Panic(TSchStorePanic aPanic)
       
    35 	{
       
    36 	_LIT(KSchStorePanic, "SchStore");
       
    37 	User::Panic(KSchStorePanic, aPanic);
       
    38 	}
       
    39 
       
    40 //
       
    41 // -----> CSchBackupManager (header)
       
    42 //
       
    43 
       
    44 CSchBackupManager::CSchBackupManager(RFs& aFsSession)
       
    45 :	CActive(EPriorityIdle), iFsSession(aFsSession)
       
    46 	{
       
    47 	// construct backup filename
       
    48 	iBackupFileName.Copy(KSchsvrBackupFileName);
       
    49 	iBackupFileName[0] = 'A' + static_cast<TInt>(RFs::GetSystemDrive()); 
       
    50 
       
    51 	CActiveScheduler::Add(this);
       
    52 	}
       
    53 
       
    54 CSchBackupManager::~CSchBackupManager()
       
    55 	{
       
    56 	// This will delete the store and close the compactor
       
    57 	Cancel();
       
    58 	//
       
    59 	delete iScheduleIndex;
       
    60 	delete iClientIndex;
       
    61 	}
       
    62 
       
    63 void CSchBackupManager::ConstructL()
       
    64 	{
       
    65 	iScheduleIndex = CSchScheduleIndex::NewL();
       
    66 	iClientIndex = CSchClientIndex::NewL(iFsSession);
       
    67 	}
       
    68 
       
    69 /**
       
    70 If this is called during a restore, we want to make sure we want to append
       
    71 to existing structure not always create new object and just append to the queue
       
    72 for example we want to append task to existing client if they have the same name
       
    73 and priority not create another one.
       
    74 */
       
    75 void CSchBackupManager::RestoreL(TPriQue<CClientProxy>& aClients, 
       
    76 								TSglQue<CSchedule>& aTimeSchedules,
       
    77 								CSchLogManager& aSchLogManager,TBool aBUR)
       
    78 	{
       
    79 	LOGSTRING("CSchBackupManager::RestoreL");
       
    80 
       
    81 	// Open store
       
    82 	CPermanentFileStore* store = OpenOrCreateBackupStoreLC();
       
    83 
       
    84 	// Restore root stream (two pointers to other streams)
       
    85 	RStoreReadStream stream;
       
    86 	stream.OpenLC(*store, store->Root());
       
    87 	stream >> iIndexStreamSchedules;
       
    88 	stream >> iIndexStreamClients;
       
    89 	CleanupStack::PopAndDestroy(); // stream
       
    90 
       
    91 	// Restore clients
       
    92 	iClientIndex->RestoreClientsL(aClients, *store, iIndexStreamClients, aSchLogManager,aBUR);
       
    93 
       
    94 	// Restore schedules
       
    95 	iScheduleIndex->RestoreSchedulesL(aTimeSchedules, *store, iIndexStreamSchedules);
       
    96 
       
    97 	// Cleanup store.
       
    98 	CleanupStack::PopAndDestroy(store);
       
    99 	}
       
   100 
       
   101 void CSchBackupManager::PerformStoreOperationL(TSchBackupOperation aAction, const CSchedule& aSchedule)
       
   102 //
       
   103 //	Perform an schedule-related operation.
       
   104 //
       
   105 	{
       
   106 	LOGSTRING3("CSchBackupManager::PerformStoreOperationL - Schedule: %S (%d)", &aSchedule.Name(), aSchedule.Id());
       
   107 	
       
   108 	if(aSchedule.Persists())
       
   109 		{
       
   110 		// Cancel any compaction that may be going on
       
   111 		Cancel();
       
   112 
       
   113 		// Perform the operation
       
   114 		CStreamStore* store = OpenOrCreateBackupStoreLC();
       
   115 		CleanupRevertPushLC(*store);
       
   116 
       
   117 		switch(aAction)
       
   118 			{
       
   119 		case ESchBackupOperationAdd:
       
   120 			LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpAdd");
       
   121 			iScheduleIndex->AddL(iIndexStreamSchedules, *store, aSchedule);
       
   122 			break;
       
   123 		case ESchBackupOperationEdit:
       
   124 			LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpEdit");
       
   125 			iScheduleIndex->EditL(iIndexStreamSchedules, *store, aSchedule);
       
   126 			break;
       
   127 		case ESchBackupOperationDelete:
       
   128 			LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpDelete");
       
   129 			iScheduleIndex->DeleteL(iIndexStreamSchedules, *store, aSchedule);
       
   130 			break;
       
   131 		default:
       
   132 			__ASSERT_DEBUG(EFalse, User::Invariant());
       
   133 			User::Leave(KErrNotSupported);
       
   134 			}	
       
   135 		// Save changes to store
       
   136 		store->CommitL();
       
   137 
       
   138 		CleanupStack::Pop(); // Store reversion cleanup item
       
   139 		CleanupStack::PopAndDestroy(store);
       
   140 
       
   141 		// Indicate the store has changed and attempt to compact 
       
   142 		// the store, but only if the required number of store 
       
   143 		// changes has been met
       
   144 		StoreChangedL();
       
   145 		}
       
   146 	}
       
   147 
       
   148 void CSchBackupManager::PerformStoreOperationL(TSchBackupOperation aAction, const CClientProxy& aClient)
       
   149 //
       
   150 //	Perform an schedule-related operation.
       
   151 //
       
   152 	{
       
   153 	LOGSTRING2("CSchBackupManager::PerformStoreOperationL - Client: %S", &aClient.ExecutorFileName());
       
   154 
       
   155 	// Cancel any compaction that may be going on
       
   156 	Cancel();
       
   157 
       
   158 	// Perform the operation
       
   159 	CStreamStore* store = OpenOrCreateBackupStoreLC();
       
   160 	CleanupRevertPushLC(*store);
       
   161 
       
   162 	switch(aAction)
       
   163 		{
       
   164 	case ESchBackupOperationAdd:
       
   165 		LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpAdd");
       
   166 		iClientIndex->AddL(iIndexStreamClients, *store, aClient);
       
   167 		break;
       
   168 	case ESchBackupOperationEdit:
       
   169 		LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpEdit");
       
   170 		iClientIndex->EditL(iIndexStreamClients, *store, aClient);
       
   171 		break;
       
   172 	case ESchBackupOperationDelete:
       
   173 		LOGSTRING("CSchBackupManager::PerformStoreOperationL - OpDelete");
       
   174 		iClientIndex->DeleteL(iIndexStreamClients, *store, aClient);
       
   175 		break;
       
   176 	default:
       
   177 		__ASSERT_DEBUG(EFalse, User::Invariant());
       
   178 		User::Leave(KErrNotSupported);
       
   179 		}
       
   180 
       
   181 	// Save changes to store
       
   182 	store->CommitL();
       
   183 
       
   184 	CleanupStack::Pop(); // Store reversion cleanup item
       
   185 	CleanupStack::PopAndDestroy(store);
       
   186 
       
   187 	// Indicate the store has changed and attempt to compact 
       
   188 	// the store, but only if the required number of store 
       
   189 	// changes has been met
       
   190 	StoreChangedL();
       
   191 	}
       
   192 
       
   193 void CSchBackupManager::RunL()
       
   194 //
       
   195 //	Perform a store compaction step
       
   196 //
       
   197 	{
       
   198 	LOGSTRING("CSchBackupManager::RunL - Performing compaction step");
       
   199 
       
   200 	// Is there any more processing required?
       
   201 	if	(iStoreReclaimerCount() > 0)
       
   202 		{
       
   203 		// Yes, so start next step
       
   204 		iStoreReclaimer.Next(iStoreReclaimerCount, iStatus);
       
   205 		SetActive();
       
   206 		LOGSTRING("CSchBackupManager::RunL - Requesting another compaction step");
       
   207 		}
       
   208 	else
       
   209 		{
       
   210 		// No, we've finised. Clean up previously allocated
       
   211 		// resources
       
   212 		iStoreReclaimer.Close();
       
   213 		//
       
   214 		TRAPD(errNotRef, iStoreOpenForCompaction->CommitL());
       
   215         UNUSED_VAR(errNotRef);
       
   216 		delete iStoreOpenForCompaction;
       
   217 		iStoreOpenForCompaction = NULL;
       
   218 
       
   219 		// Set this to zero again...
       
   220 		ResetStoreChanges();
       
   221 		LOGSTRING("CSchBackupManager::RunL - Compaction complete");
       
   222 		}
       
   223 	}
       
   224 
       
   225 void CSchBackupManager::DoCancel()
       
   226 //
       
   227 //	Cancel's any asynchronous store compaction
       
   228 //
       
   229 	{
       
   230 	LOGSTRING("CSchBackupManager::RunL - Cancelling compaction");
       
   231 
       
   232 	iStoreReclaimer.Release();
       
   233 	iStoreReclaimer.Close();
       
   234 	//
       
   235 	TRAPD(errNotRef, iStoreOpenForCompaction->CommitL());
       
   236     UNUSED_VAR(errNotRef);
       
   237 	delete iStoreOpenForCompaction;
       
   238 	iStoreOpenForCompaction = NULL;
       
   239 	}
       
   240 
       
   241 void CSchBackupManager::StoreChangedL()
       
   242 	{
       
   243 	__ASSERT_DEBUG(!IsActive() && !iStoreOpenForCompaction, User::Invariant());
       
   244 
       
   245 	if	(RecordStoreChange() >= KMaxChangesBeforeCompact)
       
   246 		{
       
   247 		// Open the store
       
   248 		CStreamStore* store = OpenBackupStoreLC();
       
   249 
       
   250 		// Prepare for compaction
       
   251 		TInt count;
       
   252 		iStoreReclaimer.CompactL(*store, count);
       
   253 		iStoreReclaimerCount = count;
       
   254 
       
   255 		// Safe to do this now
       
   256 		iStoreOpenForCompaction = store;
       
   257 		CleanupStack::Pop();
       
   258 
       
   259 		// Start asynchronous compaction...
       
   260 		iStoreReclaimer.Next(iStoreReclaimerCount, iStatus);
       
   261 		SetActive();
       
   262 		}
       
   263 	}
       
   264 
       
   265 CPermanentFileStore* CSchBackupManager::OpenBackupStoreLC()
       
   266 	{
       
   267 	return CPermanentFileStore::OpenLC(iFsSession, iBackupFileName, EFileWrite);
       
   268 	}
       
   269 
       
   270 CPermanentFileStore* CSchBackupManager::OpenOrCreateBackupStoreLC()
       
   271 	{
       
   272 	CPermanentFileStore* store = NULL;
       
   273 	TInt error = KErrNone;
       
   274 	TRAP(error, 
       
   275 		store = CPermanentFileStore::OpenL(iFsSession, iBackupFileName, EFileWrite);
       
   276 		);
       
   277 	if	(error < KErrNone)
       
   278 		{
       
   279 		if	(error == KErrNotFound)
       
   280 			{
       
   281 			CreateEmptyBackupL();
       
   282 			store = CPermanentFileStore::OpenL(iFsSession, iBackupFileName, EFileWrite);
       
   283 			}
       
   284 		else
       
   285 			{
       
   286 			User::Leave(error);
       
   287 			}
       
   288 		}
       
   289 	LOGSTRING("CSchBackupManager::OpenOrCreateBackupStoreLC - store opened");
       
   290 	CleanupStack::PushL(store);
       
   291 	return store;
       
   292 	}
       
   293 
       
   294 void CSchBackupManager::CleanupRevertPushLC(CStreamStore& aStore)
       
   295 	{
       
   296 	CleanupStack::PushL(TCleanupItem(RevertStore, &aStore));
       
   297 	}
       
   298 
       
   299 void CSchBackupManager::RevertStore(TAny* aStore)
       
   300 //
       
   301 //	The Cleanup Item callback function which is used to rever the store
       
   302 //	should a leave occur.
       
   303 //
       
   304 	{
       
   305 	CStreamStore* store = reinterpret_cast<CStreamStore*>(aStore);
       
   306 	store->Revert();
       
   307 	LOGSTRING("CSchBackupManager::RevertStore - store reverted");
       
   308 	}
       
   309 
       
   310 /**
       
   311 Creates an initialised empty store.
       
   312 The creation process is performed as an atomic operation.
       
   313 If the operation fails somewhere at the middle, CreateEmptyBackupL()
       
   314 will cleanup after itself - the store file will be deleted,
       
   315 iIndexStreamSchedules and iIndexStreamClients stream IDs will be reinitialised
       
   316 with invalid values.
       
   317 */
       
   318 void CSchBackupManager::CreateEmptyBackupL()
       
   319 	{
       
   320 	TRAPD(err, DoCreateEmptyBackupL());
       
   321 	if(err != KErrNone)
       
   322 		{
       
   323 		//Cleanup & leave
       
   324 		// If unable to delete file record the fact
       
   325 		TInt err2 = iFsSession.Delete(iBackupFileName);
       
   326 		if (err2 != KErrNone)
       
   327 			{
       
   328 			LOGSTRING2("CSchBackupManager::CreateEmptyBackupL - File delete error = %d", err2);
       
   329 			}
       
   330 		iIndexStreamSchedules = iIndexStreamClients = KNullStreamId;
       
   331 		User::Leave(err);
       
   332 		}
       
   333 	}
       
   334 
       
   335 /**
       
   336 Creates an initialised empty store.
       
   337 */
       
   338 void CSchBackupManager::DoCreateEmptyBackupL()
       
   339 	{
       
   340 	LOGSTRING("CSchBackupManager::CreateEmptyBackupL - trying to create new store");
       
   341 	CPermanentFileStore* store = CPermanentFileStore::ReplaceLC(iFsSession, iBackupFileName, EFileWrite);
       
   342 	store->SetTypeL(KPermanentFileStoreLayoutUid);	
       
   343 
       
   344 	// Create emtpy schedule index stream
       
   345 	CSchScheduleIndex* indexSchedule = CSchScheduleIndex::NewL();
       
   346 	CleanupStack::PushL(indexSchedule);
       
   347 	iIndexStreamSchedules = indexSchedule->CreateEmptyIndexL(*store);
       
   348 	CleanupStack::PopAndDestroy(indexSchedule);
       
   349 
       
   350 	// Create emtpy client index stream
       
   351 	CSchClientIndex* indexClient = CSchClientIndex::NewL(iFsSession);
       
   352 	CleanupStack::PushL(indexClient);
       
   353 	iIndexStreamClients = indexClient->CreateEmptyIndexL(*store);
       
   354 	CleanupStack::PopAndDestroy(indexClient);
       
   355 
       
   356 	// Write root stream
       
   357 	WriteRootStreamL(*store);
       
   358 
       
   359 	// Finalise
       
   360 	store->CommitL();							
       
   361 	CleanupStack::PopAndDestroy(store);
       
   362 	LOGSTRING("CSchBackupManager::CreateEmptyBackupL - new store created");
       
   363 	}
       
   364 	
       
   365 void CSchBackupManager::WriteRootStreamL(CStreamStore& aStore)
       
   366 //
       
   367 //	Write the root stream which contains the two stream id's
       
   368 //
       
   369 	{
       
   370 	LOGSTRING("CSchBackupManager::WriteRootStreamL - trying to write root stream");
       
   371 	RStoreWriteStream stream;
       
   372 	TStreamId id = stream.CreateLC(aStore);	
       
   373 	
       
   374 	// This writes a stream id - it doesn't write the actual
       
   375 	// dictionary since this is written after every operation.
       
   376 	stream << iIndexStreamSchedules;
       
   377 	stream << iIndexStreamClients;
       
   378 
       
   379 	// 
       
   380 	stream.CommitL();						
       
   381     CleanupStack::PopAndDestroy();// outstream
       
   382 	static_cast<CPermanentFileStore&>(aStore).SetRootL(id);
       
   383 	LOGSTRING("CSchBackupManager::WriteRootStreamL - root stream written");
       
   384 	}
       
   385 
       
   386 //
       
   387 // -----> CSchScheduleIndex (header)
       
   388 //
       
   389 
       
   390 CSchScheduleIndex::CSchScheduleIndex()
       
   391 	{
       
   392 	}
       
   393 
       
   394 CSchScheduleIndex* CSchScheduleIndex::NewL()
       
   395 	{
       
   396 	CSchScheduleIndex* self = new(ELeave) CSchScheduleIndex;
       
   397 	return self;
       
   398 	}
       
   399 
       
   400 void CSchScheduleIndex::RestoreSchedulesL(TSglQue<CSchedule>& aTimeSchedules, 
       
   401 										CStreamStore& aStore, 
       
   402 										TStreamId aDictionaryStreamId)
       
   403 	{
       
   404 	CSchScheduleDictionary* dictionary = DictionaryLC(aStore, aDictionaryStreamId);
       
   405 
       
   406 	// Restore every schedule in the dictionary
       
   407 	const TInt count = dictionary->Count();
       
   408 	LOGSTRING2("CSchScheduleIndex::RestoreSchedulesL - read %d dictionary entries", count);
       
   409 
       
   410 	for(TInt i=0; i<count; i++)
       
   411 		{
       
   412 		// Get stream
       
   413 		TStreamId stream = dictionary->AtIndex(i);
       
   414 
       
   415 		// Restore schedule from stream
       
   416 		CSchedule* schedule = CSchedule::NewL(static_cast<CFileStore&>(aStore), stream);
       
   417 
       
   418 		// Save schedule
       
   419 		aTimeSchedules.AddLast(*schedule); // takes ownership
       
   420 
       
   421 		LOGSTRING3("CSchScheduleIndex::RestoreSchedulesL - restored schedule: %S, %d", &schedule->Name(), schedule->Id());
       
   422 		}
       
   423 	CleanupStack::PopAndDestroy(dictionary);
       
   424 	}
       
   425 
       
   426 TStreamId CSchScheduleIndex::CreateEmptyIndexL(CStreamStore& aStore) const
       
   427 	{
       
   428 	CSchScheduleDictionary* dictionary = CSchScheduleDictionary::NewLC();
       
   429 	RStoreWriteStream stream;
       
   430 	TStreamId id = stream.CreateLC(aStore);
       
   431 	stream << *dictionary;
       
   432 	stream.CommitL();
       
   433 	CleanupStack::PopAndDestroy(2); // stream, dictionary
       
   434 	return id;
       
   435 	}
       
   436 
       
   437 void CSchScheduleIndex::AddL(TStreamId aIndexStream, CStreamStore& aStore, const CSchedule& aSchedule)
       
   438 //
       
   439 //	Saves the specified schedule to the store and adds a new entry to the
       
   440 //	dictionary.
       
   441 //
       
   442 	{
       
   443 	LOGSTRING2("CSchScheduleIndex::AddL - adding a new schedule (id is %d)", aSchedule.Id());
       
   444 	RStoreWriteStream stream;
       
   445 	TStreamId id = stream.CreateLC(aStore);
       
   446 	stream << aSchedule;
       
   447 	stream.CommitL();
       
   448 	CleanupStack::PopAndDestroy(); // stream
       
   449 
       
   450 	// Read the dictionary and update an entry
       
   451 	CSchScheduleDictionary* dictionary = DictionaryLC(aStore, aIndexStream);
       
   452 	dictionary->AssignL(aSchedule.Id(), id);
       
   453 
       
   454 	// Store the dictionary
       
   455 	StoreDictionaryL(aStore, *dictionary, aIndexStream);
       
   456 	CleanupStack::PopAndDestroy(dictionary);
       
   457 	LOGSTRING("CSchScheduleIndex::AddL - new schedule added okay");
       
   458 	}
       
   459 
       
   460 void CSchScheduleIndex::EditL(TStreamId aIndexStream, CStreamStore& aStore, const CSchedule& aSchedule)
       
   461 //
       
   462 //	Replace an existing stream with the contents of aSchedule. 
       
   463 //
       
   464 	{
       
   465 	// Locate the existing stream (to be replaced)
       
   466 	CSchScheduleDictionary* dictionary = DictionaryLC(aStore, aIndexStream);
       
   467 	LOGSTRING2("CSchScheduleIndex::EditL - editing schedule with id of %d", aSchedule.Id());
       
   468 	TStreamId id = dictionary->At(aSchedule.Id());
       
   469 	CleanupStack::PopAndDestroy(dictionary);
       
   470 	if	(id == KNullStreamId)
       
   471 		{
       
   472 		// Wasn't found, add it instead...
       
   473 		LOGSTRING("CSchScheduleIndex::EditL - schedule wasn't found, adding new entry to the store");
       
   474 		AddL(aIndexStream, aStore, aSchedule);
       
   475 		}
       
   476 	else
       
   477 		{
       
   478 		// Replace - the original stream is orphaned but the new
       
   479 		// stream retains the old id.
       
   480 		LOGSTRING("CSchScheduleIndex::EditL - replacing original stream");
       
   481 		RStoreWriteStream stream;
       
   482 		stream.ReplaceLC(aStore, id);
       
   483 		stream << aSchedule;
       
   484 		stream.CommitL();
       
   485 		CleanupStack::PopAndDestroy(); // stream
       
   486 		}
       
   487 	}
       
   488 
       
   489 void CSchScheduleIndex::DeleteL(TStreamId aIndexStream, CStreamStore& aStore, const CSchedule& aSchedule)
       
   490 //
       
   491 //	Remove an existing schedule from the store.
       
   492 //
       
   493 	{
       
   494 	// Locate the existing stream (to be deleted)
       
   495 	CSchScheduleDictionary* dictionary = DictionaryLC(aStore, aIndexStream);
       
   496 	LOGSTRING2("CSchScheduleIndex::DeleteL - deleting schedule with id of %d", aSchedule.Id());
       
   497 	TStreamId id = dictionary->At(aSchedule.Id());
       
   498 	if	(id == KNullStreamId)
       
   499 		{
       
   500 		LOGSTRING("CSchScheduleIndex::DeleteL - schedule wasn't found! Would panic in debug");
       
   501 		__ASSERT_DEBUG(EFalse, SchBackupManagerUtils::Panic(SchBackupManagerUtils::ESchBackupManagerScheduleStreamToDeleteNotFound));
       
   502 		}
       
   503 	else
       
   504 		{
       
   505 		// Remove the stream
       
   506 		aStore.DeleteL(id);
       
   507 
       
   508 		// Save changes to store - we have to do this here since
       
   509 		// we must assure that the store is fully updated before
       
   510 		// we remove this stream from the dictionary (in order to 
       
   511 		// maintain integrity).
       
   512 		aStore.CommitL();
       
   513 
       
   514 		// Remove entry from the stream dictionary
       
   515 		dictionary->Remove(aSchedule.Id());
       
   516 		StoreDictionaryL(aStore, *dictionary, aIndexStream);
       
   517 		}
       
   518 	CleanupStack::PopAndDestroy(dictionary);
       
   519 	}
       
   520 
       
   521 CSchScheduleIndex::CSchScheduleDictionary* CSchScheduleIndex::DictionaryLC(CStreamStore& aStore, TStreamId aIndexStream)
       
   522 	{
       
   523 	LOGSTRING("CSchScheduleIndex::DictionaryLC - restoring dictionary");
       
   524 	CSchScheduleDictionary* dictionary = CSchScheduleDictionary::NewLC();
       
   525 	RStoreReadStream stream;
       
   526 	stream.OpenLC(aStore, aIndexStream);
       
   527 	stream >> *dictionary;
       
   528 	CleanupStack::PopAndDestroy(); // stream
       
   529 	LOGSTRING("CSchScheduleIndex::DictionaryLC - dictionary restored");
       
   530 	return dictionary;
       
   531 	}
       
   532 
       
   533 void CSchScheduleIndex::StoreDictionaryL(CStreamStore& aStore, const CSchScheduleDictionary& aDictionary, TStreamId aStreamToReplace)
       
   534 	{
       
   535 	LOGSTRING("CSchScheduleIndex::DictionaryLC - storing dictionary");
       
   536 	RStoreWriteStream stream;
       
   537 	stream.ReplaceLC(aStore, aStreamToReplace);
       
   538 	stream << aDictionary;
       
   539 	stream.CommitL();
       
   540 	CleanupStack::PopAndDestroy(); // stream
       
   541 	LOGSTRING("CSchScheduleIndex::DictionaryLC - dictionary stored");
       
   542 	}
       
   543 
       
   544 //
       
   545 // -----> CSchScheduleDictionary (header)
       
   546 //
       
   547 
       
   548 CSchScheduleIndex::CSchScheduleDictionary::CSchScheduleDictionary()
       
   549 	{
       
   550 	}
       
   551 
       
   552 CSchScheduleIndex::CSchScheduleDictionary::~CSchScheduleDictionary()
       
   553 	{
       
   554 	delete iMappings;
       
   555 	}
       
   556 
       
   557 void CSchScheduleIndex::CSchScheduleDictionary::ConstructL()
       
   558 	{
       
   559 	const TInt KGranularity = 3;
       
   560 	iMappings = new(ELeave) CArrayFixSeg<TSchScheduleMapplet>(KGranularity);
       
   561 	}
       
   562 
       
   563 CSchScheduleIndex::CSchScheduleDictionary* CSchScheduleIndex::CSchScheduleDictionary::NewLC()
       
   564 	{
       
   565 	CSchScheduleDictionary* self = new(ELeave) CSchScheduleDictionary();
       
   566 	CleanupStack::PushL(self);
       
   567 	self->ConstructL();
       
   568 	return self;
       
   569 	}
       
   570 
       
   571 void CSchScheduleIndex::CSchScheduleDictionary::AssignL(TInt aKey, TStreamId aId)
       
   572 	{
       
   573 	if	(aId == KNullStreamId)
       
   574 		{
       
   575 		Remove(aKey); // default associated stream is null
       
   576 		return;
       
   577 		}
       
   578 	//
       
   579 	TSchScheduleMapplet entry(aKey, KNullStreamId);
       
   580 	TKeyArrayFix key(TSchScheduleMapplet::KeyOffset(), ECmpTInt32);
       
   581 	TInt i;
       
   582 	if	(iMappings->FindIsq(entry, key, i) == 0)
       
   583 		{
       
   584 		iMappings->At(i).SetStream(aId);
       
   585 		return;
       
   586 		}
       
   587 	//
       
   588 	entry.SetStream(aId);
       
   589 	iMappings->InsertIsqL(entry, key);
       
   590 	}
       
   591 
       
   592 void CSchScheduleIndex::CSchScheduleDictionary::Remove(TInt aKey)
       
   593 	{
       
   594 	TSchScheduleMapplet entry(aKey, KNullStreamId);
       
   595 	TKeyArrayFix key(TSchScheduleMapplet::KeyOffset(), ECmpTInt32);
       
   596 	TInt i;
       
   597 	if	(iMappings->FindIsq(entry, key, i) == 0)
       
   598 		iMappings->Delete(i);
       
   599 	}
       
   600 
       
   601 TInt CSchScheduleIndex::CSchScheduleDictionary::Count() const
       
   602 	{
       
   603 	return iMappings->Count();
       
   604 	}
       
   605 
       
   606 TStreamId CSchScheduleIndex::CSchScheduleDictionary::At(TInt aKey) const
       
   607 	{
       
   608 	TSchScheduleMapplet entry(aKey, KNullStreamId);
       
   609 	TKeyArrayFix key(TSchScheduleMapplet::KeyOffset(), ECmpTInt32);
       
   610 	TInt i;
       
   611 	if	(iMappings->FindIsq(entry, key, i) != 0)
       
   612 		return KNullStreamId;
       
   613 	//
       
   614 	return iMappings->At(i).Stream();
       
   615 	}
       
   616 
       
   617 TStreamId CSchScheduleIndex::CSchScheduleDictionary::AtIndex(TInt aIndex) const
       
   618 	{
       
   619 	return iMappings->At(aIndex).Stream();
       
   620 	}
       
   621 
       
   622 void CSchScheduleIndex::CSchScheduleDictionary::InternalizeL(RReadStream& aStream)
       
   623 	{
       
   624 	aStream >> *iMappings;
       
   625 	}
       
   626 
       
   627 void CSchScheduleIndex::CSchScheduleDictionary::ExternalizeL(RWriteStream& aStream) const
       
   628 	{
       
   629 	aStream << *iMappings;
       
   630 	}
       
   631 
       
   632 //
       
   633 // -----> CSchClientIndex (header)
       
   634 //
       
   635 
       
   636 CSchClientIndex::CSchClientIndex(RFs& aFsSession)
       
   637 :	iFsSession(aFsSession)
       
   638 	{
       
   639 	}
       
   640 
       
   641 CSchClientIndex* CSchClientIndex::NewL(RFs& aFsSession)
       
   642 	{
       
   643 	return new(ELeave) CSchClientIndex(aFsSession);
       
   644 	}
       
   645 
       
   646 void CSchClientIndex::AppendClientToListL(TPriQue<CClientProxy>& aClients, CClientProxy* aClient)
       
   647 	{
       
   648 	CClientProxy* currentClient;
       
   649 	TDblQueIter<CClientProxy> clientIter(aClients);
       
   650 	clientIter.SetToFirst();
       
   651 	while ((currentClient = clientIter++) != NULL)
       
   652 		{	
       
   653 		//if match on same client name and priority	
       
   654 		if (currentClient->IsEqual(aClient->ExecutorFileName(),aClient->Priority()))
       
   655 			{
       
   656 			//transfer all the tasks in aClient to this client
       
   657 			aClient->TransferTasks(*currentClient);
       
   658 			//now that we have transferred all the task ownership, we can safely delete the source client
       
   659 			delete aClient;
       
   660 			return;
       
   661 			}
       
   662 		}
       
   663 	//since that there is no matching one just add the aClient directly
       
   664 	aClients.Add(*aClient);	
       
   665 	}
       
   666 
       
   667 void CSchClientIndex::RestoreClientsL(TPriQue<CClientProxy>& aClients, 
       
   668 									CStreamStore& aStore, 
       
   669 									TStreamId aIndexStream,
       
   670 									CSchLogManager& aSchLogManager,TBool aBUR)
       
   671 	{
       
   672 	CSchClientDictionary* dictionary = DictionaryLC(aStore, aIndexStream);
       
   673 
       
   674 	// Restore every schedule in the dictionary
       
   675 	const TInt count = dictionary->Count();
       
   676 	LOGSTRING2("CSchClientIndex::RestoreClientsL - read %d dictionary entries", count);
       
   677 
       
   678 	for(TInt i=0; i<count; i++)
       
   679 		{
       
   680 		// Get stream
       
   681 		TStreamId streamId = dictionary->AtIndex(i);
       
   682 
       
   683 		RStoreReadStream stream;
       
   684 		stream.OpenLC(aStore, streamId);
       
   685 
       
   686 		// Restore client
       
   687 		CClientProxy* client = CClientProxy::NewL(iFsSession,stream,aSchLogManager);
       
   688 		CleanupStack::PopAndDestroy(); // stream
       
   689 
       
   690 		// Save schedule
       
   691 		// only when this is called through restore we need to append to existing client which
       
   692 		// might already contain other transient tasks
       
   693 		if (aBUR)
       
   694 			{
       
   695 			AppendClientToListL(aClients,client);
       
   696 			}
       
   697 		else
       
   698 			{
       
   699 			aClients.Add(*client); // takes ownership				
       
   700 			}
       
   701 		LOGSTRING2("CSchClientIndex::RestoreClientsL - restored client: %S", &client->ExecutorFileName());
       
   702 		}
       
   703 	CleanupStack::PopAndDestroy(dictionary);
       
   704 	}
       
   705 
       
   706 TStreamId CSchClientIndex::CreateEmptyIndexL(CStreamStore& aStore) const
       
   707 	{
       
   708 	CSchClientDictionary* dictionary = CSchClientDictionary::NewLC();
       
   709 	RStoreWriteStream stream;
       
   710 	TStreamId id = stream.CreateLC(aStore);
       
   711 	stream << *dictionary;
       
   712 	stream.CommitL();
       
   713 	CleanupStack::PopAndDestroy(2); // stream, dictionary
       
   714 	return id;
       
   715 	}
       
   716 
       
   717 void CSchClientIndex::AddL(TStreamId aIndexStream, CStreamStore& aStore, const CClientProxy& aClient)
       
   718 	{
       
   719 	RStoreWriteStream stream;
       
   720 	TStreamId id = stream.CreateLC(aStore);
       
   721 	stream << aClient;
       
   722 	stream.CommitL();
       
   723 	CleanupStack::PopAndDestroy(); // stream
       
   724 
       
   725 	// Read the dictionary and update an entry
       
   726 	CSchClientDictionary* dictionary = DictionaryLC(aStore, aIndexStream);
       
   727 	dictionary->AssignL(aClient.ExecutorFileName(), id);
       
   728 
       
   729 	// Store the dictionary
       
   730 	StoreDictionaryL(aStore, *dictionary, aIndexStream);
       
   731 	CleanupStack::PopAndDestroy(dictionary);
       
   732 	}
       
   733 
       
   734 void CSchClientIndex::EditL(TStreamId aIndexStream, CStreamStore& aStore, const CClientProxy& aClient)
       
   735 	{
       
   736 	// Locate the existing stream (to be replaced)
       
   737 	CSchClientDictionary* dictionary = DictionaryLC(aStore, aIndexStream);
       
   738 	TStreamId id = dictionary->AtL(aClient.ExecutorFileName());
       
   739 	CleanupStack::PopAndDestroy(dictionary);
       
   740 	if	(id == KNullStreamId)
       
   741 		{
       
   742 		// Wasn't found, add it instead...
       
   743 		AddL(aIndexStream, aStore, aClient);
       
   744 		}
       
   745 	else
       
   746 		{
       
   747 		// Replace - the original stream is orphaned but the new
       
   748 		// stream retains the old id.
       
   749 		RStoreWriteStream stream;
       
   750 		stream.ReplaceLC(aStore, id);
       
   751 		stream << aClient;
       
   752 		stream.CommitL();
       
   753 		CleanupStack::PopAndDestroy(); // stream
       
   754 		}
       
   755 	}
       
   756 
       
   757 void CSchClientIndex::DeleteL(TStreamId aIndexStream, CStreamStore& aStore, const CClientProxy& aClient)
       
   758 	{
       
   759 	// Locate the existing stream (to be deleted)
       
   760 	CSchClientDictionary* dictionary = DictionaryLC(aStore, aIndexStream);
       
   761 	TStreamId id = dictionary->AtL(aClient.ExecutorFileName());
       
   762 	__ASSERT_ALWAYS(id != KNullStreamId, SchBackupManagerUtils::Panic(SchBackupManagerUtils::ESchBackupManagerScheduleStreamToDeleteNotFound));
       
   763 
       
   764 	// Remove the stream
       
   765 	aStore.DeleteL(id);
       
   766 
       
   767 	// Save changes to store - we have to do this here since
       
   768 	// we must assure that the store is fully updated before
       
   769 	// we remove this stream from the dictionary (in order to 
       
   770 	// maintain integrity).
       
   771 	aStore.CommitL();
       
   772 
       
   773 	// Remove entry from the stream dictionary
       
   774 	dictionary->RemoveL(aClient.ExecutorFileName());
       
   775 	StoreDictionaryL(aStore, *dictionary, aIndexStream);
       
   776 	CleanupStack::PopAndDestroy(dictionary);
       
   777 	}
       
   778 
       
   779 CSchClientIndex::CSchClientDictionary* CSchClientIndex::DictionaryLC(CStreamStore& aStore, TStreamId aIndexStream)
       
   780 	{
       
   781 	LOGSTRING("CSchClientIndex::DictionaryLC - restoring dictionary");
       
   782 	CSchClientDictionary* dictionary = CSchClientDictionary::NewLC();
       
   783 	RStoreReadStream stream;
       
   784 	stream.OpenLC(aStore, aIndexStream);
       
   785 	stream >> *dictionary;
       
   786 	CleanupStack::PopAndDestroy(); // stream
       
   787 	LOGSTRING("CSchClientIndex::DictionaryLC - dictionary restored");
       
   788 	return dictionary;
       
   789 	}
       
   790 
       
   791 void CSchClientIndex::StoreDictionaryL(CStreamStore& aStore, const CSchClientDictionary& aDictionary, TStreamId aStreamToReplace)
       
   792 	{
       
   793 	LOGSTRING("CSchClientIndex::DictionaryLC - storing dictionary");
       
   794 	RStoreWriteStream stream;
       
   795 	stream.ReplaceLC(aStore, aStreamToReplace);
       
   796 	stream << aDictionary;
       
   797 	stream.CommitL();
       
   798 	CleanupStack::PopAndDestroy(); // stream
       
   799 	LOGSTRING("CSchClientIndex::DictionaryLC - dictionary stored");
       
   800 	}
       
   801 
       
   802 //
       
   803 // -----> TKeyArrayPtr (header)
       
   804 //
       
   805 NONSHARABLE_CLASS(TKeyArrayMapping) : public TKeyArrayFix
       
   806 {
       
   807 public:
       
   808 	inline TKeyArrayMapping(TInt aOffset) : TKeyArrayFix(aOffset, TKeyCmpText()) {iHBufType=ETrue;}
       
   809 	//
       
   810 	virtual TAny* At(TInt aIndex) const;
       
   811 	virtual TInt Compare(TInt aLeft,TInt aRight) const;	
       
   812 
       
   813 private:
       
   814 	TBool iHBufType;
       
   815 	};
       
   816 
       
   817 TAny* TKeyArrayMapping::At(TInt aIndex) const
       
   818 	{
       
   819 	if	(aIndex==KIndexPtr)
       
   820 		{
       
   821 		const CSchClientIndex::CSchClientMapplet** ppItem = (const CSchClientIndex::CSchClientMapplet**) iPtr;
       
   822 		const CSchClientIndex::CSchClientMapplet* pItem = *ppItem;
       
   823 		return (TAny*) pItem;
       
   824 		}
       
   825 	else
       
   826 		{
       
   827 		TInt baseOffset = aIndex * sizeof(const CSchClientIndex::CSchClientMapplet*);
       
   828 		const TUint8* pItemUncast = iBase->Ptr(baseOffset).Ptr();
       
   829 		const CSchClientIndex::CSchClientMapplet** ppItem = (const CSchClientIndex::CSchClientMapplet**) pItemUncast;
       
   830 		const CSchClientIndex::CSchClientMapplet* pItem = *ppItem;
       
   831 		return (TAny*) pItem;
       
   832 		}
       
   833 	}
       
   834 
       
   835 TInt TKeyArrayMapping::Compare(TInt aLeft,TInt aRight) const
       
   836 	{
       
   837 	if	(iHBufType)
       
   838 		{
       
   839 		const CSchClientIndex::CSchClientMapplet* left = (const CSchClientIndex::CSchClientMapplet*) At(aLeft);
       
   840 		const CSchClientIndex::CSchClientMapplet* right = (const CSchClientIndex::CSchClientMapplet*) At(aRight);
       
   841 
       
   842 		return (left->Key().Compare(right->Key()));
       
   843 		}
       
   844 	else
       
   845 		User::Invariant();
       
   846 	return KErrNotFound;
       
   847 	}
       
   848 
       
   849 //
       
   850 // -----> CSchClientIndex::CSchClientMapplet (header)
       
   851 //
       
   852 
       
   853 CSchClientIndex::CSchClientMapplet::~CSchClientMapplet()
       
   854 	{
       
   855 	delete iKey;
       
   856 	}
       
   857 
       
   858 CSchClientIndex::CSchClientMapplet* CSchClientIndex::CSchClientMapplet::NewLC(RReadStream& aStream)
       
   859 	{
       
   860 	CSchClientMapplet* self = new(ELeave) CSchClientMapplet;
       
   861 	CleanupStack::PushL(self);
       
   862 	aStream >> *self;
       
   863 	return self;
       
   864 	}
       
   865 
       
   866 CSchClientIndex::CSchClientMapplet* CSchClientIndex::CSchClientMapplet::NewLC(const TDesC& aKey, TStreamId aStream)
       
   867 	{
       
   868 	CSchClientMapplet* self = new(ELeave) CSchClientMapplet;
       
   869 	CleanupStack::PushL(self);
       
   870 	self->iKey = aKey.AllocL();
       
   871 	self->iStream = aStream;
       
   872 	return self;
       
   873 	}
       
   874 
       
   875 void CSchClientIndex::CSchClientMapplet::InternalizeL(RReadStream& aStream)
       
   876 	{
       
   877 	HBufC* key = HBufC::NewLC(aStream, KMaxTInt);
       
   878 	delete iKey;
       
   879 	iKey = key;
       
   880 	CleanupStack::Pop(); // key
       
   881 	aStream >> iStream;
       
   882 	}
       
   883 
       
   884 void CSchClientIndex::CSchClientMapplet::ExternalizeL(RWriteStream& aStream) const
       
   885 	{
       
   886 	aStream << *iKey;
       
   887 	aStream << iStream;
       
   888 	}
       
   889 
       
   890 
       
   891 //
       
   892 // -----> CSchClientIndex::CSchClientDictionary (header)
       
   893 //
       
   894 
       
   895 CSchClientIndex::CSchClientDictionary::CSchClientDictionary()
       
   896 	{
       
   897 	}
       
   898 
       
   899 CSchClientIndex::CSchClientDictionary::~CSchClientDictionary()
       
   900 	{	
       
   901 	if(iMappings)
       
   902 		{
       
   903 		for(int index = 0; index < iMappings->Count();index++)
       
   904 			{
       
   905 			delete iMappings->At(index);
       
   906 			}
       
   907 		delete iMappings;	
       
   908 		}
       
   909 	}
       
   910 
       
   911 void CSchClientIndex::CSchClientDictionary::ConstructL()
       
   912 	{
       
   913 	const TInt KGranularity = 2;
       
   914 	iMappings = new(ELeave) CArrayPtrSeg<CSchClientMapplet>(KGranularity);
       
   915 	}
       
   916 
       
   917 CSchClientIndex::CSchClientDictionary* CSchClientIndex::CSchClientDictionary::NewLC()
       
   918 	{
       
   919 	CSchClientDictionary* self = new(ELeave) CSchClientDictionary();
       
   920 	CleanupStack::PushL(self);
       
   921 	self->ConstructL();
       
   922 	return self;
       
   923 	}
       
   924 
       
   925 void CSchClientIndex::CSchClientDictionary::AssignL(const TDesC& aKey, TStreamId aId)
       
   926 	{
       
   927 	if	(aId == KNullStreamId)
       
   928 		{
       
   929 		RemoveL(aKey); // default associated stream is null
       
   930 		return;
       
   931 		}
       
   932 
       
   933 	CSchClientMapplet* entry = CSchClientMapplet::NewLC(aKey, KNullStreamId);
       
   934 	TKeyArrayMapping key(CSchClientMapplet::KeyOffset());
       
   935 	TInt i;
       
   936 	if	(iMappings->FindIsq(entry, key, i) == 0)
       
   937 		{
       
   938 		iMappings->At(i)->SetStream(aId);
       
   939 		CleanupStack::PopAndDestroy(); // entry
       
   940 		return;
       
   941 		}
       
   942 
       
   943 	entry->SetStream(aId);
       
   944 	iMappings->InsertIsqL(entry, key);
       
   945 	CleanupStack::Pop(); // entry
       
   946 	}
       
   947 
       
   948 void CSchClientIndex::CSchClientDictionary::RemoveL(const TDesC& aKey)
       
   949 	{
       
   950 	CSchClientMapplet* entry = CSchClientMapplet::NewLC(aKey, KNullStreamId);
       
   951 	TKeyArrayMapping key(CSchClientMapplet::KeyOffset());
       
   952 	TInt i;
       
   953 	if	(iMappings->FindIsq(entry, key, i) == 0)
       
   954 		{
       
   955 		delete iMappings->At(i);
       
   956 		iMappings->Delete(i);
       
   957 		}
       
   958 	CleanupStack::PopAndDestroy(); // entry
       
   959 	}
       
   960 
       
   961 TInt CSchClientIndex::CSchClientDictionary::Count() const
       
   962 	{
       
   963 	return iMappings->Count();
       
   964 	}
       
   965 
       
   966 TStreamId CSchClientIndex::CSchClientDictionary::AtL(const TDesC& aKey) const
       
   967 	{
       
   968 	CSchClientMapplet* entry = CSchClientMapplet::NewLC(aKey, KNullStreamId);
       
   969 	TKeyArrayMapping key(CSchClientMapplet::KeyOffset());
       
   970 	TInt i;
       
   971 	TInt found = iMappings->FindIsq(entry, key, i);
       
   972 	CleanupStack::PopAndDestroy(); // entry
       
   973 	if	(found != 0)
       
   974 		return KNullStreamId;
       
   975 	return iMappings->At(i)->Stream();
       
   976 	}
       
   977 
       
   978 TStreamId CSchClientIndex::CSchClientDictionary::AtIndex(TInt aIndex) const
       
   979 	{
       
   980 	return iMappings->At(aIndex)->Stream();
       
   981 	}
       
   982 
       
   983 void CSchClientIndex::CSchClientDictionary::InternalizeL(RReadStream& aStream)
       
   984 	{
       
   985 	const TInt count = aStream.ReadInt32L();
       
   986 	for(TInt i=0; i<count; i++)
       
   987 		{
       
   988 		CSchClientMapplet* mapplet = CSchClientMapplet::NewLC(aStream);
       
   989 		iMappings->AppendL(mapplet);
       
   990 		CleanupStack::Pop(); // mapplet
       
   991 		}
       
   992 	}
       
   993 
       
   994 void CSchClientIndex::CSchClientDictionary::ExternalizeL(RWriteStream& aStream) const
       
   995 	{
       
   996 	const TInt count = iMappings->Count();
       
   997 	aStream.WriteInt32L(count);
       
   998 	for(TInt i=0; i<count; i++)
       
   999 		aStream << *iMappings->At(i);
       
  1000 	}