|
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 } |