ncdengine/provider/server/src/ncdnodecachecleaner.cpp
changeset 4 32704c33136d
equal deleted inserted replaced
-1:000000000000 4:32704c33136d
       
     1 /*
       
     2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   Implements CNcdNodeCacheCleaner class
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 #include "ncdnodecachecleaner.h"
       
    20 
       
    21 #include "ncdnodeidentifierutils.h"
       
    22 #include "ncdnodemanager.h"
       
    23 #include "ncdnodedbmanager.h"
       
    24 #include "ncdnodefactory.h"
       
    25 #include "ncdnodeidentifiereditor.h"
       
    26 #include "ncdnodeimpl.h"
       
    27 #include "ncdnodefolder.h"
       
    28 #include "ncdrootnode.h"
       
    29 #include "ncdnodemetadataimpl.h"
       
    30 #include "ncdnodelink.h"
       
    31 #include "ncdnodeiconimpl.h"
       
    32 #include "ncdnodescreenshotimpl.h"
       
    33 #include "ncdnodeidentifier.h"
       
    34 #include "ncdchildentity.h"
       
    35 #include "catalogsconstants.h"
       
    36 #include "ncdproviderdefines.h"
       
    37 #include "catalogsutils.h"
       
    38 #include "ncdgeneralmanager.h"
       
    39 
       
    40 #include "catalogsdebug.h"
       
    41 
       
    42 
       
    43 
       
    44 // Uncomment this if the node cache cleaner should be turned off.
       
    45 // For example, when debugging other functionalities.
       
    46 //#define NCD_NODE_CACHE_CLEANER_TURN_OFF
       
    47 
       
    48 
       
    49 #ifdef CATALOGS_BUILD_CONFIG_DEBUG
       
    50 // Uncomment this if the array prints should be printed when the
       
    51 // debug mode is on. This is set optional because the array print
       
    52 // may take a long time when data is written into the log file.
       
    53 //#define NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
    54 #endif
       
    55 
       
    56 
       
    57 // These priority values are used for this active object.
       
    58 // The default value is used when normal cleaning is done
       
    59 const CActive::TPriority KDefaultCleaningPriority( CActive::EPriorityIdle );
       
    60 // This priority value is used if the database size has been exceeded
       
    61 // and the cleaning should be done with the higher priority
       
    62 const CActive::TPriority KIncreasedCleaningPriority( CActive::EPriorityLow );
       
    63 // This priority value is used if the database size has been exceeded
       
    64 // too much and the cleaning should be done with really high priority.
       
    65 // This will slow down the other actions even more because cleaning
       
    66 // takes more time.
       
    67 const CActive::TPriority KMaxCleaningPriority( CActive::EPriorityStandard );
       
    68 
       
    69 // The max db size value is divided by this number to get the
       
    70 // value for the limit until which the db is freed after max size
       
    71 // has been reached and cleaning started.
       
    72 const TInt KMaxSizeDivider( 2 );
       
    73 
       
    74 // If the db size is over double the accepted db size, then the max cleaning
       
    75 // priority should be used. Because most likely the lower priority does not work
       
    76 // efficiently enough
       
    77 const TInt KMaxDbSizeRatio( 2 );
       
    78 
       
    79 // The checking of the database should be done at least in some time intervals
       
    80 // even if the db size has not been exceeded.
       
    81 const TTimeIntervalMinutes KCheckPeriod( 60 );
       
    82 
       
    83 
       
    84 
       
    85 CNcdNodeCacheCleaner* CNcdNodeCacheCleaner::NewL( CNcdGeneralManager& aGeneralManager,
       
    86                                                   CNcdNodeDbManager& aNodeDbManager,
       
    87                                                   TInt aDbDefaultMaxSize,                                                  
       
    88                                                   CNcdNodeFactory& aNodeFactory )
       
    89     {
       
    90     CNcdNodeCacheCleaner* self =   
       
    91         CNcdNodeCacheCleaner::NewLC( aGeneralManager, 
       
    92                                      aNodeDbManager, 
       
    93                                      aDbDefaultMaxSize,
       
    94                                      aNodeFactory );
       
    95     CleanupStack::Pop( self );
       
    96     return self;        
       
    97     }
       
    98 
       
    99 CNcdNodeCacheCleaner* CNcdNodeCacheCleaner::NewLC( CNcdGeneralManager& aGeneralManager,
       
   100                                                    CNcdNodeDbManager& aNodeDbManager,
       
   101                                                    TInt aDbDefaultMaxSize,
       
   102                                                    CNcdNodeFactory& aNodeFactory )
       
   103     {
       
   104     CNcdNodeCacheCleaner* self = 
       
   105         new( ELeave ) CNcdNodeCacheCleaner( aGeneralManager, 
       
   106                                             aNodeDbManager,
       
   107                                             aDbDefaultMaxSize, 
       
   108                                             aNodeFactory );
       
   109     CleanupStack::PushL( self );
       
   110     self->ConstructL();
       
   111     return self;        
       
   112     }
       
   113 
       
   114 
       
   115 
       
   116 CNcdNodeCacheCleaner::CNcdNodeCacheCleaner( CNcdGeneralManager& aGeneralManager,
       
   117                                             CNcdNodeDbManager& aNodeDbManager,
       
   118                                             TInt aDbDefaultMaxSize,
       
   119                                             CNcdNodeFactory& aNodeFactory )
       
   120 : CActive( KDefaultCleaningPriority ),
       
   121   iGeneralManager( aGeneralManager ),
       
   122   iNodeManager( aGeneralManager.NodeManager() ),
       
   123   iNodeDbManager( aNodeDbManager ),
       
   124   iDbMaxSize( aDbDefaultMaxSize ),
       
   125   iNodeFactory( aNodeFactory ),
       
   126   // EFalse by default so that we don't clean anything even in error situations
       
   127   // for clients that don't allow it
       
   128   iAllowCleaning( EFalse ), 
       
   129   iIncreasePriority( KDefaultCleaningPriority ),
       
   130   iLastCleanupTime( 0 )
       
   131     {
       
   132     }
       
   133 
       
   134 
       
   135 void CNcdNodeCacheCleaner::ConstructL()
       
   136     {
       
   137     // These values have to be set. 
       
   138 
       
   139     // These types will be removed from the db.
       
   140 
       
   141     // iNodeCleanupTypes are used to search the node items from db.
       
   142     // This array is only for node type. So, it contains only one value.
       
   143     iNodeCleanupTypes.AppendL( NcdNodeClassIds::ENcdNode );
       
   144     
       
   145     // Meta cleanup types are also removed from the db.
       
   146     // These types use the metadata identifier to remove the items
       
   147     // from db
       
   148     iMetaCleanupTypes.AppendL( NcdNodeClassIds::ENcdMetaData );
       
   149 
       
   150     // These types should be permanent info 
       
   151     // or not to be removed by this cleaner for some other reason.
       
   152     // Uncomment these if specifications change.
       
   153     //iMetaCleanupTypes.Append( NcdNodeClassIds::ENcdNodeUserData );
       
   154     //iMetaCleanupTypes.Append( NcdNodeClassIds::ENcdSubscriptionsData );
       
   155 
       
   156         
       
   157     // Special cleanup types are removed from the db.
       
   158     // But node or metadata ids cannot be directly used for these.
       
   159     // They require special handling to get the right ids.
       
   160     iIconCleanupTypes.AppendL( NcdNodeClassIds::ENcdIconData );
       
   161 
       
   162     iScreenshotCleanupTypes.AppendL( NcdNodeClassIds::ENcdScreenshotData );
       
   163     
       
   164 
       
   165     // These namespaces should not be cleaned by this cleaner
       
   166     iDoNotCleanNameSpaces = new(ELeave) CPtrCArray( KListGranularity );
       
   167     iDoNotCleanNameSpaces->AppendL( 
       
   168         NcdProviderDefines::KDownloadNamespace() );
       
   169     iDoNotCleanNameSpaces->AppendL( 
       
   170         NcdProviderDefines::KSubscriptionNamespace() );
       
   171     iDoNotCleanNameSpaces->AppendL( 
       
   172         NcdProviderDefines::KPreviewStorageNamespace() );
       
   173 
       
   174     // Because this is an active object, we need to inform
       
   175     // scheduler about it.    
       
   176     CActiveScheduler::Add( this );    
       
   177     }
       
   178 
       
   179 
       
   180 CNcdNodeCacheCleaner::~CNcdNodeCacheCleaner()
       
   181     {
       
   182     DLTRACEIN((""));
       
   183     
       
   184     // It is always safe to call Cancel for active object
       
   185     // when destructor is called.
       
   186     Cancel();
       
   187 
       
   188     // This object is automatically removed from the active scheduler when
       
   189     // this object is deleted.
       
   190 
       
   191     // Delete member variables that are owned by this class object here.
       
   192 
       
   193     iNodeCleanupTypes.Reset();
       
   194     iMetaCleanupTypes.Reset();
       
   195     iIconCleanupTypes.Reset();
       
   196 
       
   197     iScreenshotCleanupTypes.Reset();
       
   198     iCleanupIdentifiers.ResetAndDestroy();
       
   199     iAllDbStorageNodeItems.ResetAndDestroy();
       
   200     iAllDbIconItems.ResetAndDestroy();
       
   201 
       
   202     iAllDbScreenshotItems.ResetAndDestroy();
       
   203     iDbMetaIdentifiers.ResetAndDestroy();
       
   204     iWaitingIdentifiers.ResetAndDestroy();
       
   205     iWaitingParentIdentifiers.ResetAndDestroy();
       
   206     iDoNotRemoves.ResetAndDestroy();
       
   207     iRootChildren.ResetAndDestroy();
       
   208     iBundleChildren.ResetAndDestroy();
       
   209 
       
   210     // Notice that this delete also deletes the objects owned by the array.
       
   211     delete iDoNotCleanNameSpaces;
       
   212         
       
   213     DLTRACEOUT((""));
       
   214     }        
       
   215 
       
   216 
       
   217 TInt CNcdNodeCacheCleaner::NodeIdentifierArraySortById( const CNcdNodeIdentifier& aNodeId1,
       
   218                                                         const CNcdNodeIdentifier& aNodeId2 )
       
   219     {
       
   220     //DLTRACEIN((""));
       
   221     
       
   222     TInt depth1( 0 );
       
   223     TInt depth2( 0 );
       
   224     TInt trapError1( KErrNone );
       
   225     TInt trapError2( KErrNone );
       
   226 
       
   227     TRAP( trapError1, depth1 = NcdNodeIdentifierEditor::NodeDepthL( aNodeId1 ) );
       
   228     TRAP( trapError2, depth2 = NcdNodeIdentifierEditor::NodeDepthL( aNodeId2 ) );
       
   229 
       
   230     // Decide the order according to the depth. If the identifier is not
       
   231     // an actual nodeidentifier. Then insert it to the beginning of the array
       
   232     // and sort those identifiers by their lengths.
       
   233 
       
   234     if ( trapError1 == KErrNone && trapError2 == KErrNone )
       
   235         {
       
   236         // Both of the given identifiers were for the node.
       
   237             
       
   238         // This function returns zero if depths are equal and lengths are equal.
       
   239         TInt order( depth1 - depth2 );
       
   240         if ( depth1 == depth2 )
       
   241             {
       
   242             // Depths are equal. So, check if the id lengths differ.
       
   243             // If nodeid1 is shorter, then it should be first in the array.
       
   244             // If they are equal length then the order does not matter.
       
   245             // If the node1 is longer, then node2 should be first.
       
   246             order = aNodeId1.NodeId().Length() - aNodeId2.NodeId().Length();
       
   247             }
       
   248             
       
   249         // Negative number if depth1 is smaller.
       
   250         // Positive number if id1 is greater.
       
   251         return order;        
       
   252         }
       
   253     else if ( trapError1 != KErrNone && trapError2 != KErrNone )
       
   254         {
       
   255         // Because neither was not a node, use the id length to get the
       
   256         // order. This way the shortest will be the first one etc.
       
   257         DLERROR(("Neither was node"));
       
   258         DASSERT( trapError1 == KErrArgument );
       
   259         DASSERT( trapError2 == KErrArgument );
       
   260 
       
   261         return aNodeId1.NodeId().Length() - aNodeId2.NodeId().Length();
       
   262         }
       
   263     else if ( trapError1 != KErrNone )
       
   264         {
       
   265         // Here we should get only the KErrArgument that informs that the
       
   266         // aNodeId1 was not an actual node id. It is most likely some metadata id.
       
   267         // Insert these in the beginning of the array. So, return negative number
       
   268         DLERROR(("aNodeId1 not node"));
       
   269         DASSERT( trapError1 == KErrArgument );
       
   270         return -1;
       
   271         }        
       
   272     else
       
   273         {
       
   274         DLERROR(("aNodeId2 not node"));
       
   275         // Here we should get only the KErrArgument that informs that the
       
   276         // aNodeId2 was not an actual node id. It is most likely some metadata id.
       
   277         // Insert these in the beginning of the array. So, return positive number
       
   278         DASSERT( trapError2 == KErrArgument );
       
   279         return 1;
       
   280         }
       
   281     }
       
   282 
       
   283 
       
   284 const TUid& CNcdNodeCacheCleaner::ClientUid() const
       
   285     {
       
   286     return iGeneralManager.FamilyId();
       
   287     }
       
   288 
       
   289 
       
   290 CNcdNodeCacheCleaner::TCleanupState CNcdNodeCacheCleaner::CleanupState() const
       
   291     {
       
   292     return iCleanupState;
       
   293     }
       
   294 
       
   295 
       
   296 void CNcdNodeCacheCleaner::SetAllowCleaning( TBool aAllow )
       
   297     {
       
   298     DLTRACEIN((""));
       
   299     if ( aAllow != AllowCleaning()
       
   300          && !aAllow )
       
   301         {
       
   302         DLINFO(("Cancel on going operation because cleaning is not allowed anymore."))
       
   303         Cancel();        
       
   304         }
       
   305     iAllowCleaning = aAllow;
       
   306     }
       
   307 
       
   308 
       
   309 TBool CNcdNodeCacheCleaner::AllowCleaning() const
       
   310     {
       
   311     return iAllowCleaning;
       
   312     }
       
   313 
       
   314 
       
   315 void CNcdNodeCacheCleaner::StartCleanupL()
       
   316     {
       
   317     DLTRACEIN((""));
       
   318 
       
   319     // Set the last cleanup time here. So, next automatic start will
       
   320     // occure after the specified period.
       
   321     iLastCleanupTime.HomeTime();
       
   322 
       
   323     #ifdef NCD_NODE_CACHE_CLEANER_TURN_OFF
       
   324     // Nothing to do here. Because cleaning should not be done.
       
   325     DLWARNING(("*** CNcdNodeCacheCleaner turned off ***"));
       
   326     #warning *** CNcdNodeCacheCleaner turned off ***
       
   327     return;
       
   328     #endif
       
   329 
       
   330     if ( !AllowCleaning() )
       
   331         {
       
   332         DLINFO(("Cleaning is not allowed."));
       
   333         return;
       
   334         }
       
   335 
       
   336     if ( CleanupState() != ENotStarted
       
   337          || IsActive() )
       
   338         {
       
   339         DLINFO(("Cleaning already started"));
       
   340         return;
       
   341         }
       
   342 
       
   343     if ( iResetPriority )
       
   344         {
       
   345         // The priority may have been increased before. 
       
   346         // But it has been marked to be resetted when possible.
       
   347         // So, reset it here. We come here only if Cancel was
       
   348         // called when the object was active.
       
   349         SetPriority( KDefaultCleaningPriority );
       
   350         iResetPriority = EFalse;
       
   351         }
       
   352 
       
   353     // Update the node items list. 
       
   354     // This is an initial list that will be used when the nodes are examined.
       
   355     // The node items list should not be updated anywhere else but here or
       
   356     // in the start clean excess function. If the array is updated somewhere else, it
       
   357     // may result an infinite loop if some deepest nodes cannot be removed when
       
   358     // excess cleaning is done and those nodes are in the end of the list all the time.
       
   359     // Notice, that it does not matter if all the nodes are not check this time. They
       
   360     // will be checked next time cleaning is started. Also, if some nodes are missing
       
   361     // in the list, wrong nodes will not be deleted because parent and child checks 
       
   362     // are done by using the other array such as do not remove and wait arrays.
       
   363     SetAllDbStorageNodeItemsL();
       
   364     
       
   365     // Cleaning special cases is the first thing to do when cleanup is started.        
       
   366     iCleanupState = ECleaningSpecialCases;
       
   367     
       
   368     // Mark this active object to be ready for action.
       
   369     // Instead of using some other class object to do the job,
       
   370     // this active object handles everything itself. New job
       
   371     // is started everytime when the RunL is called until there is
       
   372     // nothing to be done. Or, until user cancels or stops the action.
       
   373     iStatus = KRequestPending;
       
   374 
       
   375     // Let the active object know that RunL can be called when the
       
   376     // action is completed.
       
   377     SetActive();
       
   378     
       
   379     // Because there is not anything special to be done here.
       
   380     // Set the action complete. So, the RunL will be called.
       
   381     TRequestStatus* ptrStatus = &iStatus;
       
   382     User::RequestComplete( ptrStatus, KErrNone );
       
   383 
       
   384     DLTRACEOUT((""));
       
   385     }
       
   386 
       
   387 
       
   388 void CNcdNodeCacheCleaner::StopCleanup()
       
   389     {
       
   390     DLTRACEIN((""));
       
   391     
       
   392     if ( CleanupState() != ENotStarted
       
   393          || IsActive() )
       
   394         {
       
   395         DLINFO(("Stop cleanup"));
       
   396         Cancel();
       
   397         }
       
   398 
       
   399     DLTRACEOUT((""));
       
   400     }
       
   401 
       
   402 
       
   403 void CNcdNodeCacheCleaner::CheckDbSizeL()
       
   404     {
       
   405     DLTRACEIN((""));
       
   406 
       
   407     // If the db size has been exceeded, then
       
   408     // start the cleaning operation.
       
   409     // This function may be called for example 
       
   410     // when new nodes have been added to the db.
       
   411     TInt dbSize( 
       
   412         NodeDbManager().StorageSizeL( ClientUid(),
       
   413                                       *iDoNotCleanNameSpaces ) );
       
   414 
       
   415     TTime currentTime;
       
   416     currentTime.HomeTime();    
       
   417     TBool timePassed( EFalse );
       
   418     if ( iLastCleanupTime + KCheckPeriod < currentTime  )
       
   419         {
       
   420         timePassed = ETrue;
       
   421         }
       
   422     
       
   423     // Start cleaning if the database size is too large
       
   424     // or if it is too long time from the last cleanup.
       
   425     if ( DbMaxSize() < dbSize )
       
   426         {
       
   427         DLINFO(("Too much data in db: %d", dbSize));
       
   428 
       
   429         // Because the db size has been exceeded we want to clean
       
   430         // the db with higher priority than usually.
       
   431         // When the cleanup finishes, the priority should be set back
       
   432         // to lower level.
       
   433         if ( IsActive() )
       
   434             {
       
   435             if ( DbMaxSize() * KMaxDbSizeRatio < dbSize )
       
   436                 {
       
   437                 DLINFO(("Highest priority should be used db size is way too big"));
       
   438                 // Set the priority to max, the next time RunL is called
       
   439                 // because the cleaner is not doing its work efficiently enough
       
   440                 iIncreasePriority = KMaxCleaningPriority;
       
   441                 }
       
   442             else
       
   443                 {
       
   444                 DLINFO(("Increased priority should be used"));
       
   445                 // Set the priority higher, the next time
       
   446                 // RunL is called. The db size is too large but does not
       
   447                 // exceed the "panic" level.
       
   448                 iIncreasePriority = KIncreasedCleaningPriority;                
       
   449                 }
       
   450             }
       
   451         else if ( DbMaxSize() * KMaxDbSizeRatio < dbSize )
       
   452             {
       
   453             DLINFO(("Not active. Max priority set"));
       
   454             SetPriority( KMaxCleaningPriority );
       
   455             }
       
   456         else
       
   457             {
       
   458             DLINFO(("Not active. Increased priority set"));
       
   459             SetPriority( KIncreasedCleaningPriority );            
       
   460             }
       
   461 
       
   462         // To be sure that the cleanup does not reset the priority.
       
   463         // No need to reset it because new values have been given above.
       
   464         iResetPriority = EFalse;
       
   465         
       
   466         // Start the actual cleaning.
       
   467         StartCleanupL();
       
   468         }
       
   469     else if ( timePassed )
       
   470         {
       
   471         DLINFO(("Time passed"));
       
   472         // Start the actual cleaning but no need to increase the priority.
       
   473         StartCleanupL();        
       
   474         }
       
   475 
       
   476     DLTRACEOUT((""));
       
   477     }
       
   478 
       
   479 
       
   480 void CNcdNodeCacheCleaner::AddCleanupIdentifiersL( const RPointerArray<CNcdNodeIdentifier>& aIdentifiers )
       
   481     {
       
   482     DLTRACEIN((""));
       
   483     
       
   484     for ( TInt i = 0; i < aIdentifiers.Count(); ++i )
       
   485         {
       
   486         AddCleanupIdentifierL( *aIdentifiers[ i ] );
       
   487         }
       
   488     
       
   489     DLTRACEOUT((""));
       
   490     }
       
   491 
       
   492 void CNcdNodeCacheCleaner::AddCleanupIdentifierL( const CNcdNodeIdentifier& aIdentifier )
       
   493     {
       
   494     DLTRACEIN((""));
       
   495     DLNODEID(( aIdentifier ));
       
   496     if ( ContainsIdentifier( aIdentifier, iDoNotRemoves ) )
       
   497         {
       
   498         // Do not remove list already contains the given identifier.
       
   499         // So, insert the given identifier to the wait list.
       
   500         // Notice that identifier should be left also into the do not remove list.
       
   501         AddIdentifierL( aIdentifier, iWaitingIdentifiers );
       
   502         }
       
   503     else if ( !NcdNodeIdentifierUtils::ContainsIdentifier(
       
   504               aIdentifier, iWaitingIdentifiers ) &&
       
   505               !NcdNodeIdentifierUtils::ContainsIdentifier(
       
   506               aIdentifier, iWaitingParentIdentifiers ) )
       
   507         {
       
   508         // Just insert the given identifier into the cleanup list unless
       
   509         // it already existed in some waiting array or in do not remove list.
       
   510         AddIdentifierL( aIdentifier, iCleanupIdentifiers );
       
   511         }
       
   512     
       
   513     // No need to check the waiting parents, because it will be checked when items
       
   514     // are going to be removed.
       
   515     
       
   516     DLTRACEOUT((""));
       
   517     }
       
   518 
       
   519 
       
   520 void CNcdNodeCacheCleaner::RemoveCleanupIdentifiers( const RPointerArray<CNcdNodeIdentifier>& aIdentifiers )
       
   521     {
       
   522     DLTRACEIN((""));
       
   523 
       
   524     for ( TInt i = 0; i < aIdentifiers.Count(); ++i )
       
   525         {
       
   526         RemoveCleanupIdentifier( *aIdentifiers[ i ] );
       
   527         }
       
   528     
       
   529     DLTRACEOUT((""));
       
   530     }
       
   531 
       
   532 void CNcdNodeCacheCleaner::RemoveCleanupIdentifier( const CNcdNodeIdentifier& aIdentifier )
       
   533     {
       
   534     DLTRACEIN((""));
       
   535 
       
   536     // If wait list contains the given identifier.
       
   537     // So, remove the given identifier from the wait list.
       
   538     RemoveIdentifier( aIdentifier, iWaitingIdentifiers );
       
   539 
       
   540     // If wait list contains the given identifier.
       
   541     // So, remove the given identifier from the wait list.
       
   542     RemoveIdentifier( aIdentifier, iWaitingParentIdentifiers );
       
   543     
       
   544     // Remove the given identifier from cleanup list
       
   545     RemoveIdentifier( aIdentifier, iCleanupIdentifiers );
       
   546 
       
   547     DLTRACEOUT((""));
       
   548     }
       
   549 
       
   550 
       
   551 void CNcdNodeCacheCleaner::AddDoNotRemoveIdentifiersL( 
       
   552     const RPointerArray<CNcdNodeIdentifier>& aIdentifiers,
       
   553     TBool aCanRemoveParent )
       
   554     {
       
   555     DLTRACEIN((""));
       
   556 
       
   557     // Check if the identifiers should be inserted into the waiting or do not remove
       
   558     // array.    
       
   559     for ( TInt i = 0; i < aIdentifiers.Count(); ++i )
       
   560         {
       
   561         AddDoNotRemoveIdentifierL( *aIdentifiers[ i ], aCanRemoveParent );
       
   562         }
       
   563     
       
   564     DLTRACEOUT((""));
       
   565     }
       
   566 
       
   567 void CNcdNodeCacheCleaner::AddDoNotRemoveIdentifierL( 
       
   568     const CNcdNodeIdentifier& aIdentifier, 
       
   569     TBool aCanRemoveParent )
       
   570     {
       
   571     DLTRACEIN((""));
       
   572     DLNODEID(( aIdentifier ));
       
   573 
       
   574     if ( RemoveIdentifier( aIdentifier, iCleanupIdentifiers ) )
       
   575         {
       
   576         // Cleanup list already contained the given identifier.
       
   577         // So, insert the given identifier to the wait list.
       
   578         AddIdentifierL( aIdentifier, iWaitingIdentifiers );
       
   579         }
       
   580 
       
   581     // Insert the given identifier into the do not remove list.
       
   582     // It should be ther until RemoveDoNotRemoveIdentifiers is used.
       
   583     // So, even if identifier is in waiting list it will be also,
       
   584     // in the do not remove list.
       
   585     
       
   586     // Compare given identifier to the identifiers in the array.
       
   587     TInt i = 0;
       
   588     for ( ; i < iDoNotRemoves.Count(); ++i )
       
   589         {
       
   590         if ( iDoNotRemoves[ i ]->Key().Equals( aIdentifier ) )
       
   591             {
       
   592             // Flag is only updated if it goes from EFalse -> ETrue
       
   593             if ( aCanRemoveParent ) 
       
   594                 {
       
   595                 DLTRACE(( _L("Updating parent removal flag for: %S"),
       
   596                     &iDoNotRemoves[ i ]->Key().NodeId() ));
       
   597                 // The given identifier was found from the array
       
   598                 // update 
       
   599                 iDoNotRemoves[ i ]->SetValue( ETrue );
       
   600                 }
       
   601             break;
       
   602             }
       
   603         }
       
   604 
       
   605     
       
   606     if ( i == iDoNotRemoves.Count() ) 
       
   607         {
       
   608         DLTRACE(("Adding a non-removable identifier"));
       
   609         CNcdNodeIdentifier* id = CNcdNodeIdentifier::NewLC( aIdentifier );
       
   610         // ownership is transferred
       
   611         CDoNotRemoveIdentifier* pair = new ( ELeave ) 
       
   612             CDoNotRemoveIdentifier( id, aCanRemoveParent );
       
   613         CleanupStack::Pop( id );
       
   614         
       
   615         CleanupStack::PushL( pair );
       
   616         iDoNotRemoves.AppendL( pair );
       
   617         CleanupStack::Pop( pair );
       
   618         }
       
   619             
       
   620     DLTRACEOUT((""));
       
   621     }
       
   622 
       
   623 
       
   624 void CNcdNodeCacheCleaner::RemoveDoNotRemoveIdentifiersL( const RPointerArray<CNcdNodeIdentifier>& aIdentifiers )
       
   625     {
       
   626     DLTRACEIN((""));
       
   627 
       
   628     // Check if the identifiers should be moved from the waiting back to the
       
   629     // cleanup array and remove identifier from the do not remove array.    
       
   630     for ( TInt i = 0; i < aIdentifiers.Count(); ++i )
       
   631         {
       
   632         RemoveDoNotRemoveIdentifierL( *aIdentifiers[ i ] );
       
   633         }    
       
   634 
       
   635     DLTRACEOUT((""));
       
   636     }
       
   637 
       
   638 void CNcdNodeCacheCleaner::RemoveDoNotRemoveIdentifierL( 
       
   639     const CNcdNodeIdentifier& aIdentifier, 
       
   640     TBool aForceRemove )
       
   641     {
       
   642     DLTRACEIN((""));
       
   643     DLNODEID(( aIdentifier ));
       
   644     
       
   645     TBool waitingRemoved( 
       
   646         RemoveIdentifier( aIdentifier, iWaitingIdentifiers ) );
       
   647     TBool waitingParentRemoved( 
       
   648         RemoveIdentifier( aIdentifier, iWaitingParentIdentifiers ) );
       
   649         
       
   650     if ( waitingRemoved || waitingParentRemoved )
       
   651         {
       
   652         // Wait list contained the given identifier.
       
   653         // So, move the given identifier back to the cleanup list.
       
   654         AddIdentifierL( aIdentifier, iCleanupIdentifiers );
       
   655         }
       
   656     
       
   657     RemoveIdentifier( aIdentifier, iDoNotRemoves, aForceRemove );
       
   658 
       
   659     DLTRACEOUT((""));
       
   660     }
       
   661 
       
   662 
       
   663 TInt CNcdNodeCacheCleaner::DbMaxSize() const
       
   664     {
       
   665     DLTRACEIN((""));
       
   666     return iDbMaxSize;
       
   667     }
       
   668  
       
   669  
       
   670 void CNcdNodeCacheCleaner::SetDbMaxSize( const TInt aDbMaxSize )
       
   671     {
       
   672     DLTRACEIN((""));
       
   673     iDbMaxSize = aDbMaxSize;
       
   674     }
       
   675 
       
   676 
       
   677 void CNcdNodeCacheCleaner::ForceCleanupL()
       
   678     {
       
   679     DLTRACEIN((""));
       
   680 
       
   681     // Print array debug infos into the log file
       
   682     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
   683     DLINFO(("iDoNotRemoves array:"));
       
   684     ArrayDebugPrint( iDoNotRemoves );
       
   685 
       
   686     DLINFO(("iWaitingIdentifiers array:"));
       
   687     ArrayDebugPrint( iWaitingIdentifiers );
       
   688 
       
   689     DLINFO(("iWaitingParentIdentifiers array:"));
       
   690     ArrayDebugPrint( iWaitingParentIdentifiers );
       
   691     #endif
       
   692 
       
   693     
       
   694     // iDoNotRemoves array is not reseted here. So, those nodes will not be deleted even here.
       
   695     // This way some nodes can be saved from deletion. But, the nodes that are waiting to 
       
   696     // be deleted are forced to be deleted now.
       
   697 
       
   698     // Move waiting identifiers to the cleanup array.
       
   699     AddIdentifiersL( iWaitingIdentifiers, iCleanupIdentifiers );
       
   700     iWaitingIdentifiers.ResetAndDestroy();
       
   701 
       
   702     AddIdentifiersL( iWaitingParentIdentifiers, iCleanupIdentifiers );
       
   703     iWaitingParentIdentifiers.ResetAndDestroy();
       
   704         
       
   705     // Clean the items that are in the cleanup array from db.
       
   706     HandleCleaningL();
       
   707 
       
   708     DLTRACEOUT((""));
       
   709     }
       
   710 
       
   711 
       
   712 void CNcdNodeCacheCleaner::HandleCleaningL()
       
   713     {
       
   714     DLTRACEIN((""));
       
   715 
       
   716     // Asynchronous operations have to be stopped before 
       
   717     // starting synchronous cleaning. Otherwise the
       
   718     // asynchronous cleaning may work wrong later.
       
   719     Cancel();
       
   720         
       
   721     // Update the arrays and handle cleaning.
       
   722     // Thde node array will be emptied when this is done.
       
   723     HandleCleaningL( ETrue, ETrue );
       
   724 
       
   725     DLTRACEOUT((""));
       
   726     }
       
   727 
       
   728 
       
   729 void CNcdNodeCacheCleaner::HandleCleaningL( TBool aReloadNodeList, TBool aResetNodeList )
       
   730     {
       
   731     DLTRACEIN((""));
       
   732 
       
   733     #ifdef NCD_NODE_CACHE_CLEANER_TURN_OFF
       
   734     // Nothing to do here. Because cleaning should not be done.
       
   735     DLWARNING(("*** CNcdNodeCacheCleaner turned off ***"));
       
   736     #warning *** CNcdNodeCacheCleaner turned off ***
       
   737     return;
       
   738     #endif
       
   739 
       
   740     if ( !AllowCleaning() )
       
   741         {
       
   742         DLINFO(("Cleaning is not allowed."));
       
   743         return;
       
   744         }
       
   745 
       
   746     // Clean all the nodes from the list.
       
   747     // Notice that we only delete the nodes here. 
       
   748     // The metadata and metadata related
       
   749     // data will be removed later, when this cleaner checks 
       
   750     // if they are left hanging and
       
   751     // do not belong to any node anymore.
       
   752 
       
   753     // Print array debug info into the log file
       
   754     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
   755     DLINFO(("iCleanupIdentifiers array before parent and child check:"));
       
   756     ArrayDebugPrint( iCleanupIdentifiers );
       
   757     #endif
       
   758 
       
   759     if ( aReloadNodeList )
       
   760         {
       
   761         DLINFO(("Reload node list"));
       
   762         // The caller may require the list to be updated.
       
   763         // So, make sure that all the necessary ids are in the
       
   764         // list. It may also be so, that the db is empty.
       
   765         // This check is required for example if some other class wants to
       
   766         // clean some nodes.
       
   767         SetAllDbStorageNodeItemsL();        
       
   768         }
       
   769 
       
   770     if ( iAllDbStorageNodeItems.Count() == 0 )
       
   771         {
       
   772         // Because there are not nodeitems in the db,
       
   773         // just return.
       
   774         DLTRACEOUT(("No nodes to remove"));
       
   775         return;
       
   776         }
       
   777 
       
   778     // Because the name of the children starts with the same id
       
   779     // as the name of the parent, check that also the children
       
   780     // of the parents will be deleted, unless they are in do not remove list
       
   781     // or in the waiting list.
       
   782     AddChildrenToCleanupArrayL();
       
   783     ParentCleaningCheckL();
       
   784  
       
   785     // In some cases there are unremovable items in the cleanup array
       
   786     // so let's remove them
       
   787     RemoveDoNotRemovesFromCleanupArray();
       
   788  
       
   789     DLINFO(("Remove nodes from db"));
       
   790     // Print array debug info into the log file
       
   791     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
   792     DLINFO(("iCleanupIdentifiers array:"));
       
   793     ArrayDebugPrint( iCleanupIdentifiers );
       
   794     #endif
       
   795 
       
   796     // Now the parents and their children are in the array.
       
   797     NodeDbManager().
       
   798         RemoveDataFromDatabaseL( iCleanupIdentifiers,
       
   799                                  iNodeCleanupTypes );
       
   800                                          
       
   801     // Because all the items have been marked as removable in db
       
   802     // manager, we can clear the array.
       
   803     iCleanupIdentifiers.ResetAndDestroy(); 
       
   804 
       
   805     if ( aResetNodeList )
       
   806         {
       
   807         DLINFO(("Reset node list"));
       
   808         // The list should be reseted to save some memory.
       
   809         iAllDbStorageNodeItems.ResetAndDestroy();
       
   810         }
       
   811     
       
   812     DLTRACEOUT((""));       
       
   813     }
       
   814 
       
   815 
       
   816 void CNcdNodeCacheCleaner::DoCancel()
       
   817     {
       
   818     DLTRACEIN((""));
       
   819     
       
   820     // Do not continue the action any more
       
   821     // because cancel was called.
       
   822     ResetState();
       
   823 
       
   824     // Also, make sure that the active object will know that the
       
   825     // cancel is ready. If active process is going on, the status is
       
   826     // set to KRequestPending.
       
   827     
       
   828     // There is no need for additional User::RequestComplete 
       
   829     // call here because DoCancel is executed only if this object is active 
       
   830     // and there has always been a call to User::RequestComplete when this 
       
   831     // object has been put to active state in other function calls.
       
   832 
       
   833     DLTRACEOUT((""));
       
   834     }
       
   835 
       
   836 
       
   837 void CNcdNodeCacheCleaner::RunL()
       
   838     {
       
   839     DLTRACEIN((""));
       
   840 
       
   841     if ( iIncreasePriority != KDefaultCleaningPriority )
       
   842         {
       
   843         // Increase priority flag has been set.
       
   844         // So, increase the priority from idle to suggested value.
       
   845         SetPriority( iIncreasePriority );
       
   846         iIncreasePriority = KDefaultCleaningPriority;        
       
   847         }
       
   848             
       
   849     User::LeaveIfError( iStatus.Int() );
       
   850 
       
   851     // Continue working if there is something to be done.
       
   852     switch ( iCleanupState )
       
   853         {
       
   854         case ECleaningSpecialCases:
       
   855             DLINFO(("KErrNone cleaning specials"));
       
   856             CleanSpecialsL();
       
   857             break;
       
   858 
       
   859         case ECleaningTemporaryNodes:
       
   860             DLINFO(("KErrNone cleaning temporary nodes"));
       
   861             CleanTemporaryNodesL();
       
   862             break;
       
   863 
       
   864         case ECleaningHangingCases:
       
   865             DLINFO(("KErrNone cleaning hangings"));
       
   866             CleanHangingsL();
       
   867             break;
       
   868 
       
   869         case EStartCleaningHangingSpecialCases:
       
   870             DLINFO(("KErrNone start cleaning special hangings"));
       
   871             StartCleanSpecialHangingsL();
       
   872             break;
       
   873             
       
   874         case ECleaningHangingSpecialCases:
       
   875             DLINFO(("KErrNone cleaning special hangings"));
       
   876             CleanSpecialHangingsL();
       
   877             break;
       
   878 
       
   879         case EFinishCleaningHangingSpecialCases:
       
   880             DLINFO(("KErrNone finish cleaning special hangings"));
       
   881             FinishCleanSpecialHangingsL();
       
   882             break;
       
   883 
       
   884         case EStartCleaningExcess:
       
   885             DLINFO(("KErrNone start cleaning excess"));
       
   886             StartCleanExcessL();
       
   887             break;
       
   888 
       
   889         case EStartRootChildrenCheck:
       
   890             DLINFO(("KErrNone start root children check"));
       
   891             StartRootChildrenCheckL();
       
   892             break;
       
   893 
       
   894         case ECheckRootChildren:
       
   895             DLINFO(("KErrNone check root children"));
       
   896             CheckRootChildrenL();
       
   897             break;
       
   898 
       
   899         case EHandleBundleChildren:
       
   900             DLINFO(("KErrNone handle bundle children"));
       
   901             HandleBundleChildrenL();
       
   902             break;
       
   903 
       
   904         case ECleaningExpireds:
       
   905             DLINFO(("KErrNone cleaning expireds"));
       
   906             CleanExpiredsL();
       
   907             break;
       
   908                             
       
   909         case ECleaningExcess:
       
   910             DLINFO(("KErrNone cleaning excess"));
       
   911             CleanExcessL();
       
   912             break;
       
   913 
       
   914         case EStopping:
       
   915             DLINFO(("KErrNone EStopping"));
       
   916             StoppingL();
       
   917             break;
       
   918 
       
   919         case ENotStarted:
       
   920             DLINFO(("KErrNone ENotStarted"));
       
   921             // Nothing to do here
       
   922             break;
       
   923             
       
   924         default:
       
   925             DLERROR(("KErrNone default"));
       
   926             DASSERT( EFalse );
       
   927             break;
       
   928         }
       
   929 
       
   930     DLTRACEOUT((""));
       
   931     }
       
   932 
       
   933 
       
   934 TInt CNcdNodeCacheCleaner::RunError( TInt aError )
       
   935     {
       
   936     DLTRACEIN(( "aError: %d", aError ));
       
   937     (void) aError;
       
   938     ResetState();
       
   939     return KErrNone;
       
   940     }
       
   941 
       
   942 CNcdNodeManager& CNcdNodeCacheCleaner::NodeManager() const
       
   943     {
       
   944     return iNodeManager;
       
   945     }
       
   946 
       
   947 
       
   948 CNcdNodeDbManager& CNcdNodeCacheCleaner::NodeDbManager() const
       
   949     {
       
   950     return iNodeDbManager;
       
   951     }
       
   952 
       
   953 
       
   954 CNcdNodeFactory& CNcdNodeCacheCleaner::NodeFactory() const
       
   955     {
       
   956     return iNodeFactory;
       
   957     }
       
   958 
       
   959 
       
   960 TBool CNcdNodeCacheCleaner::ContainsIdentifier( 
       
   961     const CNcdNodeIdentifier& aIdentifier,
       
   962     const RPointerArray<CDoNotRemoveIdentifier>& aTargetIdentifiers ) const
       
   963     {
       
   964     const TInt count = aTargetIdentifiers.Count();    
       
   965     // Compare given identifier to the identifiers in the array.
       
   966     for ( TInt i = 0; i < count; ++i )
       
   967         {
       
   968         if ( aTargetIdentifiers[ i ]->Key().Equals( aIdentifier ) )
       
   969             {
       
   970             // The given identifier was found from the array
       
   971             return ETrue;
       
   972             }
       
   973         }
       
   974     // Identifier was not found.
       
   975     return EFalse;
       
   976     }
       
   977 
       
   978 
       
   979 TBool CNcdNodeCacheCleaner::AddIdentifiersL( const RPointerArray<CNcdNodeIdentifier>& aIdentifiers,
       
   980                                              RPointerArray<CNcdNodeIdentifier>& aTargetArray )
       
   981     {
       
   982     DLTRACEIN((""));
       
   983     
       
   984     TBool targetArrayChanged( EFalse );
       
   985     TBool identifierAdded( EFalse );
       
   986     const TInt count = aIdentifiers.Count(); 
       
   987     
       
   988     for ( TInt i = 0; i < count; ++i )
       
   989         {
       
   990         DASSERT( aIdentifiers[ i ] != NULL );
       
   991         
       
   992         identifierAdded = 
       
   993             AddIdentifierL( *aIdentifiers[ i ],
       
   994                             aTargetArray );
       
   995                             
       
   996         if ( !targetArrayChanged && identifierAdded )
       
   997             {
       
   998             DLINFO(("Identifier was added"));
       
   999             // Because the identifier was added into the array.
       
  1000             // This is set only once because if something was added
       
  1001             // then the array has been changed.
       
  1002             // But, let the loop add all the other identifiers also.
       
  1003             // So, do not break here.
       
  1004             targetArrayChanged = ETrue;
       
  1005             }
       
  1006         }
       
  1007 
       
  1008     DLTRACEOUT((""));
       
  1009 
       
  1010     // Inform the called if something was added into the target array.
       
  1011     return targetArrayChanged;
       
  1012     }
       
  1013 
       
  1014 TBool CNcdNodeCacheCleaner::AddIdentifierL( const CNcdNodeIdentifier& aIdentifier,
       
  1015                                             RPointerArray<CNcdNodeIdentifier>& aTargetArray )
       
  1016     {
       
  1017     DLTRACEIN((""));
       
  1018     
       
  1019     // Compare the given identifier to the identifiers that have already inserted into the
       
  1020     // array.
       
  1021     const TInt count = aTargetArray.Count(); 
       
  1022     for ( TInt i = 0; i < count; ++i )
       
  1023         {
       
  1024         DASSERT( aTargetArray[ i ] != NULL );
       
  1025         
       
  1026         // If the identifier was already in the array then, do not add it again.
       
  1027         if ( aIdentifier.Equals( *aTargetArray[ i ] ) )
       
  1028             {
       
  1029             DLINFO(("Identifier was found. Return false."));
       
  1030             // The identifier was found.
       
  1031             // So, return EFalse to inform that identifier was not added.
       
  1032             return EFalse;
       
  1033             }
       
  1034         }
       
  1035 
       
  1036     // The item was not in the array yet. So, append it into the array.
       
  1037 
       
  1038     CNcdNodeIdentifier* copyIdentifier = 
       
  1039         CNcdNodeIdentifier::NewLC( aIdentifier );
       
  1040     aTargetArray.AppendL( copyIdentifier );
       
  1041     CleanupStack::Pop( copyIdentifier );
       
  1042 
       
  1043     DLTRACEOUT((""));
       
  1044 
       
  1045     // Return ETrue, because addition was done into the target array.
       
  1046     return ETrue;
       
  1047     }
       
  1048 
       
  1049 
       
  1050 TBool CNcdNodeCacheCleaner::RemoveIdentifiers( const RPointerArray<CNcdNodeIdentifier>& aIdentifiers,
       
  1051                                                RPointerArray<CNcdNodeIdentifier>& aTargetArray )
       
  1052     {
       
  1053     DLTRACEIN((""));
       
  1054     
       
  1055     TBool targetArrayChanged( EFalse );
       
  1056     TBool identifierRemoved( EFalse );
       
  1057     const TInt count = aIdentifiers.Count();
       
  1058     for ( TInt i = 0; i < count; ++i )
       
  1059         {
       
  1060         DASSERT( aIdentifiers[ i ] != NULL );
       
  1061         
       
  1062         identifierRemoved = 
       
  1063             RemoveIdentifier( *aIdentifiers[ i ],
       
  1064                               aTargetArray );
       
  1065                             
       
  1066         if ( !targetArrayChanged && identifierRemoved )
       
  1067             {
       
  1068             DLINFO(("Identifier was removed"));
       
  1069             // The identifier was removed from the array.
       
  1070             // This value is set only once because if something was added
       
  1071             // then the array has been changed.
       
  1072             targetArrayChanged = ETrue;
       
  1073             }
       
  1074         }
       
  1075 
       
  1076     DLTRACEOUT((""));
       
  1077 
       
  1078     // Inform the caller if something was added into the target array.
       
  1079     return targetArrayChanged;
       
  1080     }
       
  1081 
       
  1082 TBool CNcdNodeCacheCleaner::RemoveIdentifier( const CNcdNodeIdentifier& aIdentifier,
       
  1083                                               RPointerArray<CNcdNodeIdentifier>& aTargetArray )
       
  1084     {
       
  1085     DLTRACEIN((""));
       
  1086 
       
  1087     TBool removed( EFalse );
       
  1088         
       
  1089     // Remove all occurrences of the identifier from the target array.
       
  1090     // Start from the end of the array and move towards the beginning.
       
  1091     for ( TInt i = aTargetArray.Count() - 1; i >= 0; --i )
       
  1092         {
       
  1093         DASSERT( aTargetArray[ i ] != NULL );
       
  1094 
       
  1095         if ( aIdentifier.Equals( *aTargetArray[ i ] ) )
       
  1096             {
       
  1097             DLINFO(("Remove identifier"));
       
  1098             // The identifier was found from the array. So, remove it.
       
  1099             delete aTargetArray[ i ];
       
  1100             aTargetArray.Remove( i );
       
  1101             removed = ETrue;
       
  1102             // Because the indexing comes from the counter value towards
       
  1103             // the zero, no need to update indexing here even if the removal
       
  1104             // was done above.
       
  1105             }
       
  1106         }
       
  1107 
       
  1108     DLTRACEOUT((""));
       
  1109     
       
  1110     return removed;
       
  1111     }
       
  1112 
       
  1113 
       
  1114 TBool CNcdNodeCacheCleaner::RemoveIdentifier( 
       
  1115     const CNcdNodeIdentifier& aIdentifier,
       
  1116     RPointerArray<CDoNotRemoveIdentifier>& aTargetArray,
       
  1117     TBool aForceRemove )
       
  1118     {
       
  1119     DLTRACEIN((""));
       
  1120     // Remove all occurrences of the identifier from the target array.
       
  1121     // Start from the end of the array and move towards the beginning.
       
  1122     TInt i = aTargetArray.Count();
       
  1123     while ( i-- )    
       
  1124         {
       
  1125         DASSERT( aTargetArray[ i ] != NULL );
       
  1126 
       
  1127         if ( aIdentifier.Equals( aTargetArray[ i ]->Key() ) )
       
  1128             {
       
  1129             // Make sure that favorites are removed only if they are actually
       
  1130             // removed from favorites
       
  1131             if ( aForceRemove ||
       
  1132                  !aTargetArray[ i ]->Value() ) 
       
  1133                 {                
       
  1134                 DLINFO(("Remove identifier"));
       
  1135                 // The identifier was found from the array. So, remove it.
       
  1136                 delete aTargetArray[ i ];
       
  1137                 aTargetArray.Remove( i );
       
  1138                 }
       
  1139             return ETrue;
       
  1140             }
       
  1141         }
       
  1142 
       
  1143     DLTRACEOUT((""));    
       
  1144     return EFalse;
       
  1145     }
       
  1146 
       
  1147 
       
  1148 void CNcdNodeCacheCleaner::SetAllDbStorageNodeItemsL()
       
  1149     {
       
  1150     DLTRACEIN((""));
       
  1151 
       
  1152     // Just in case, first clean the identifier list.
       
  1153     iAllDbStorageNodeItems.ResetAndDestroy();
       
  1154     
       
  1155     // Yes, we intentionally push a member variable to the cleanupstack
       
  1156     CleanupResetAndDestroyPushL( iAllDbStorageNodeItems );
       
  1157     // Get the new values for cleaning.
       
  1158     // Note that some of the items are not accepted
       
  1159     // for this list.
       
  1160 
       
  1161     NodeDbManager().
       
  1162         GetAllClientItemIdentifiersL(
       
  1163             iAllDbStorageNodeItems, 
       
  1164             ClientUid(),
       
  1165             *iDoNotCleanNameSpaces,
       
  1166             iNodeCleanupTypes );
       
  1167     
       
  1168     CleanupStack::Pop( &iAllDbStorageNodeItems );
       
  1169     // Sort the identifiers in the array.
       
  1170     // The first item is closest to the root. The last item is
       
  1171     // deepest in the hierarchy.    
       
  1172     // Give the function pointer of the static function as a parameter.
       
  1173     
       
  1174     DLTRACE(("start sorting"));
       
  1175     TLinearOrder<CNcdNodeIdentifier> sorter( &NodeIdentifierArraySortById );
       
  1176     iAllDbStorageNodeItems.Sort( sorter );
       
  1177     DLTRACE(("sorting ended"));
       
  1178     
       
  1179     // Print array debug info into the log file
       
  1180     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1181     DLINFO(("iAllDbStorageNodeItems array:"));
       
  1182     ArrayDebugPrint( iAllDbStorageNodeItems );
       
  1183     #endif
       
  1184 
       
  1185     DLTRACEOUT((""));
       
  1186     }
       
  1187 
       
  1188 
       
  1189 void CNcdNodeCacheCleaner::SetAllDbStorageIconItemsL()
       
  1190     {
       
  1191     DLTRACEIN((""));
       
  1192     
       
  1193     // Just in case first clean the identifier list.
       
  1194     iAllDbIconItems.ResetAndDestroy();
       
  1195     
       
  1196     // Yes, we intentionally push a member variable to the cleanupstack
       
  1197     CleanupResetAndDestroyPushL( iAllDbIconItems );
       
  1198     
       
  1199     // Get the new values for cleaning.
       
  1200     // Note that some of the items are not accepted
       
  1201     // for this list.
       
  1202     
       
  1203     NodeDbManager().
       
  1204         GetAllClientItemIdentifiersL(
       
  1205             iAllDbIconItems, 
       
  1206             ClientUid(),
       
  1207             *iDoNotCleanNameSpaces,
       
  1208             iIconCleanupTypes );
       
  1209     
       
  1210     CleanupStack::Pop( &iAllDbIconItems );
       
  1211     // Icon ids do not need to be sorted, because they do not contain node ids but
       
  1212     // are something else.
       
  1213         
       
  1214     // Print array debug info into the log file
       
  1215     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1216     DLINFO(("iAllDbIconItems array:"));
       
  1217     ArrayDebugPrint( iAllDbIconItems );
       
  1218     #endif   
       
  1219     
       
  1220     DLTRACEOUT(("")); 
       
  1221     }
       
  1222 
       
  1223 
       
  1224 
       
  1225 void CNcdNodeCacheCleaner::SetAllDbStorageScreenshotItemsL()
       
  1226     {
       
  1227     DLTRACEIN((""));
       
  1228     // Just in case first clean the identifier list.
       
  1229     iAllDbScreenshotItems.ResetAndDestroy();
       
  1230     
       
  1231     // Yes, we intentionally push a member variable to the cleanupstack
       
  1232     CleanupResetAndDestroyPushL( iAllDbScreenshotItems );
       
  1233     
       
  1234     // Get the new values for cleaning.
       
  1235     // Note that some of the items are not accepted
       
  1236     // for this list.
       
  1237     NodeDbManager().
       
  1238         GetAllClientItemIdentifiersL(
       
  1239             iAllDbScreenshotItems, 
       
  1240             ClientUid(),
       
  1241             *iDoNotCleanNameSpaces,
       
  1242             iScreenshotCleanupTypes );    
       
  1243 
       
  1244     CleanupStack::Pop( &iAllDbScreenshotItems );
       
  1245     
       
  1246     // Print array debug info into the log file
       
  1247     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1248     DLINFO(("iAllDbScreenshotItems array:"));
       
  1249     ArrayDebugPrint( iAllDbScreenshotItems );
       
  1250     #endif           
       
  1251     }
       
  1252 
       
  1253     
       
  1254 void CNcdNodeCacheCleaner::AddChildrenToCleanupArrayL()
       
  1255     {
       
  1256     DLTRACEIN((""));
       
  1257     
       
  1258     // Get the counter value. So, we know how many items are
       
  1259     // in the list before children are added
       
  1260     TInt counter = iCleanupIdentifiers.Count();
       
  1261     
       
  1262     // Check if any children are found from the db items.
       
  1263     // If they are found, then move them to the cleanup array.
       
  1264     CNcdNodeIdentifier* cleanupIdentifier( NULL );
       
  1265     CNcdNodeIdentifier* storageItemIdentifier( NULL );
       
  1266     for ( TInt i = 0; i < counter; ++i )
       
  1267         {
       
  1268         cleanupIdentifier = iCleanupIdentifiers[ i ];
       
  1269         // Start from the end of the list. So, the indexing is
       
  1270         // always correct even if an item is moved
       
  1271         for ( TInt j = iAllDbStorageNodeItems.Count(); j > 0; --j )
       
  1272             {
       
  1273             storageItemIdentifier = iAllDbStorageNodeItems[ j - 1 ];
       
  1274             if ( NcdNodeIdentifierEditor::NodeDepthL( *cleanupIdentifier ) 
       
  1275                     > NcdNodeIdentifierEditor::NodeDepthL( *storageItemIdentifier ) )
       
  1276                 {
       
  1277                 // Because the db items array is sorted so that the deepest items are
       
  1278                 // in the end of the array, the children can not be found anymore.
       
  1279                 // (Notice that db items are gone through from the end of the array.)
       
  1280                 DLINFO(("Child parent barrier passed: %d", j - 1 ));
       
  1281                 break;
       
  1282                 }
       
  1283             else if ( NcdNodeIdentifierEditor::ParentOf( *cleanupIdentifier,
       
  1284                                                          *storageItemIdentifier )
       
  1285                       && !ContainsIdentifier( *storageItemIdentifier, 
       
  1286                                               iDoNotRemoves )
       
  1287                       && !NcdNodeIdentifierUtils::ContainsIdentifier(
       
  1288                         *storageItemIdentifier, iWaitingIdentifiers )
       
  1289                       && !NcdNodeIdentifierUtils::ContainsIdentifier(
       
  1290                         *storageItemIdentifier, iWaitingParentIdentifiers ) )
       
  1291                 {
       
  1292                 DLINFO(("Children items found and can be moved"));
       
  1293                 // The child is not in do not remove list or in the waiting list.
       
  1294                 // So, it can be inserted into the cleanup list. 
       
  1295                 // Notice that before cleaning it should
       
  1296                 // be checked that the child is not a parent of some other child that
       
  1297                 // can not be removed. 
       
  1298                 // Use this function to check that the item is not appended twice
       
  1299                 AddCleanupIdentifierL( *storageItemIdentifier );
       
  1300                 // Remove the data from its original place. Notice that identifier
       
  1301                 // is copied in the function above.
       
  1302                 delete storageItemIdentifier;
       
  1303                 iAllDbStorageNodeItems.Remove( j - 1 );
       
  1304                 }
       
  1305             }
       
  1306         }
       
  1307 
       
  1308     // Print array debug info into the log file
       
  1309     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1310     DLINFO(("iCleanupIdentifiers array:"))
       
  1311     ArrayDebugPrint( iCleanupIdentifiers );
       
  1312     #endif
       
  1313     
       
  1314     DLTRACEOUT((""));
       
  1315     }
       
  1316 
       
  1317 
       
  1318 void CNcdNodeCacheCleaner::ParentCleaningCheckL()
       
  1319     {
       
  1320     DLTRACEIN((""));
       
  1321 
       
  1322     // Print array debug info into the log file
       
  1323     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1324     DLINFO(("iDoNotRemoves array:"));
       
  1325     ArrayDebugPrint( iDoNotRemoves );
       
  1326     #endif
       
  1327 
       
  1328     // Print array debug info into the log file
       
  1329     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1330     DLINFO(("iWaitingParentIdentifiers array:"));
       
  1331     ArrayDebugPrint( iWaitingParentIdentifiers );
       
  1332     #endif
       
  1333 
       
  1334     // Print array debug info into the log file
       
  1335     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1336     DLINFO(("iWaitingIdentifiers array:"));
       
  1337     ArrayDebugPrint( iWaitingIdentifiers );
       
  1338     #endif
       
  1339     
       
  1340     // Check if there are some parents that are going to be cleaned but
       
  1341     // they should not be because their children are in the do not remove list
       
  1342     // or in the in the waiting list
       
  1343     for ( TInt i = iCleanupIdentifiers.Count(); i > 0 ; --i )
       
  1344         {
       
  1345         for ( TInt j  = 0; j < iDoNotRemoves.Count(); ++j )
       
  1346             {
       
  1347             // first check if parent can not be removed (for favorites it can be removed)
       
  1348             if ( !iDoNotRemoves[ j ]->Value() && 
       
  1349                  NcdNodeIdentifierEditor::ParentOf( *iCleanupIdentifiers[ i - 1 ], 
       
  1350                                                     iDoNotRemoves[ j ]->Key() ) )
       
  1351                 {
       
  1352                 DLINFO(("Do not remove parent because child is do not remove: %d", i))
       
  1353                 // Because the cleanup identifier was a parent of something that
       
  1354                 // should not be removed, then do not remove the parent either,
       
  1355                 // but insert it to wait.
       
  1356                 AddIdentifierL( *iCleanupIdentifiers[ i - 1 ], iWaitingParentIdentifiers );
       
  1357                 delete iCleanupIdentifiers[ i - 1 ];
       
  1358                 iCleanupIdentifiers.Remove( i - 1 );
       
  1359 
       
  1360                 // Because the identifier was now removed from the array
       
  1361                 // and moved to the waiting array, we skip to the next identifier check.
       
  1362                 // This way the i-indexing will be correct.
       
  1363                 break;
       
  1364                 }
       
  1365             }
       
  1366         }
       
  1367 
       
  1368     // Check the waiting identifiers in their own loop, so the i indexing
       
  1369     // will be correct here if removing has been done above.            
       
  1370     for ( TInt i = iCleanupIdentifiers.Count(); i > 0 ; --i )
       
  1371         {
       
  1372         for ( TInt k = 0; k < iWaitingIdentifiers.Count(); ++k )
       
  1373             {
       
  1374             if ( NcdNodeIdentifierEditor::ParentOf( *iCleanupIdentifiers[ i - 1 ], 
       
  1375                                                     *iWaitingIdentifiers[ k ] ) )
       
  1376                 {
       
  1377                 DLINFO(("Do not remove parent because child is waiting: %d", i))
       
  1378                 // Because the cleanup identifier was a parent of something that
       
  1379                 // should not be removed, then do not remove the parent either,
       
  1380                 // but insert it to wait.
       
  1381                 AddIdentifierL( *iCleanupIdentifiers[ i - 1 ], 
       
  1382                                 iWaitingParentIdentifiers );
       
  1383                 delete iCleanupIdentifiers[ i - 1 ];
       
  1384                 iCleanupIdentifiers.Remove( i - 1 );                
       
  1385 
       
  1386                 // Because the identifier was now removed from the array
       
  1387                 // and moved to the waiting array, we skip to the next identifier check.
       
  1388                 // This way the i-indexing will be correct.
       
  1389                 break;
       
  1390                 }
       
  1391             }
       
  1392         }
       
  1393 
       
  1394     // Now check if there are some parents waiting that should not any more
       
  1395     TBool wasNotFound( ETrue );
       
  1396     for ( TInt i = iWaitingParentIdentifiers.Count(); i > 0 ; --i )
       
  1397         {
       
  1398         wasNotFound = ETrue;
       
  1399         for ( TInt j  = 0; j < iDoNotRemoves.Count(); ++j )
       
  1400             {
       
  1401             if ( !iDoNotRemoves[ j ]->Value() &&
       
  1402                 NcdNodeIdentifierEditor::ParentOf( *iWaitingParentIdentifiers[ i - 1 ], 
       
  1403                                                     iDoNotRemoves[ j ]->Key() ) )
       
  1404                 {
       
  1405                 // The waiting parent should still be waiting
       
  1406                 wasNotFound = EFalse;
       
  1407                 break; 
       
  1408                 }
       
  1409             }
       
  1410         for ( TInt k  = 0; k < iWaitingIdentifiers.Count() && wasNotFound; ++k )
       
  1411             {
       
  1412             if ( NcdNodeIdentifierEditor::ParentOf( *iWaitingParentIdentifiers[ i - 1 ], 
       
  1413                                                     *iWaitingIdentifiers[ k ] ) )
       
  1414                 {
       
  1415                 // The waiting parent should still be waiting
       
  1416                 wasNotFound = EFalse;
       
  1417                 break; 
       
  1418                 }
       
  1419             }
       
  1420 
       
  1421         if ( wasNotFound )
       
  1422             {
       
  1423             DLINFO(("Waiting parent can be moved to the cleanup list: %d", i));
       
  1424             // Because the waiting identifier was not a parent of something that
       
  1425             // should not be removed anymore. Move it to the cleanup list.
       
  1426             AddIdentifierL( *iWaitingParentIdentifiers[ i - 1 ], iCleanupIdentifiers );
       
  1427             delete iWaitingParentIdentifiers[ i - 1 ];
       
  1428             iWaitingParentIdentifiers.Remove( i - 1 );            
       
  1429             }
       
  1430         }
       
  1431 
       
  1432     // Print array debug info into the log file
       
  1433     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1434     DLINFO(("iCleanupIdentifiers array:"));
       
  1435     ArrayDebugPrint( iCleanupIdentifiers );
       
  1436     #endif
       
  1437 
       
  1438     DLTRACEOUT((""));        
       
  1439     }
       
  1440 
       
  1441 
       
  1442 void CNcdNodeCacheCleaner::RemoveDoNotRemovesFromCleanupArray()
       
  1443     {
       
  1444     DLTRACEIN((""));
       
  1445     TInt doNotRemoveCount = iDoNotRemoves.Count();
       
  1446     while ( doNotRemoveCount-- ) 
       
  1447         {
       
  1448         TInt cleanupCount = iCleanupIdentifiers.Count();
       
  1449         while( cleanupCount-- ) 
       
  1450             {
       
  1451             if ( iDoNotRemoves[ doNotRemoveCount ]->Key().Equals( 
       
  1452                 *iCleanupIdentifiers[ cleanupCount ] ) ) 
       
  1453                 {
       
  1454                 DLTRACE(("Removing"));
       
  1455                 DLNODEID(( *iCleanupIdentifiers[ cleanupCount ] ));
       
  1456                 delete iCleanupIdentifiers[ cleanupCount ];
       
  1457                 iCleanupIdentifiers.Remove( cleanupCount );
       
  1458                 break;
       
  1459                 }
       
  1460             }
       
  1461         }
       
  1462     }
       
  1463     
       
  1464     
       
  1465 void CNcdNodeCacheCleaner::CheckTemporaryNodesL()
       
  1466     {
       
  1467     DLTRACEIN((""));
       
  1468     
       
  1469     TInt itemCount( iAllDbStorageNodeItems.Count() );            
       
  1470 
       
  1471     CNcdNodeIdentifier* identifier( NULL );
       
  1472     
       
  1473     for ( TInt i = itemCount; i > 0; --i )
       
  1474         {
       
  1475         identifier = iAllDbStorageNodeItems[ i - 1 ];
       
  1476 
       
  1477         // All the nodes that do not start with the root id are thought to be
       
  1478         // temporary nodes.
       
  1479         if ( NcdNodeIdentifierEditor::IdentifiesTemporaryNodeL( *identifier ) )
       
  1480             {
       
  1481             DLINFO((_L("Remove temporary node: %S, %S, %S, %d"),
       
  1482                     &identifier->NodeNameSpace(), &identifier->NodeId(),
       
  1483                     &identifier->ServerUri(), identifier->ClientUid().iUid));
       
  1484             // This is a temporary node.
       
  1485             // Insert it into the cleanup array if removal is allowed.
       
  1486             AddCleanupIdentifierL( *identifier );
       
  1487 
       
  1488             // Remove the data from its original place. Notice that identifier
       
  1489             // is copied in the function above.
       
  1490             delete iAllDbStorageNodeItems[ i - 1 ];
       
  1491             iAllDbStorageNodeItems.Remove( i - 1 );
       
  1492             }
       
  1493         }
       
  1494     
       
  1495     DLTRACEOUT((""));
       
  1496     }
       
  1497 
       
  1498 
       
  1499 void CNcdNodeCacheCleaner::ResetState()
       
  1500     {
       
  1501     DLTRACEIN((""));
       
  1502 
       
  1503     iExpiredCleaningIndex = 0;
       
  1504     iExcessCleanupStarted = EFalse;
       
  1505         
       
  1506     // Do not waste space with old info.
       
  1507     iAllDbStorageNodeItems.ResetAndDestroy();
       
  1508     iAllDbIconItems.ResetAndDestroy();
       
  1509     iDbMetaIdentifiers.ResetAndDestroy();
       
  1510     iRootChildren.ResetAndDestroy();
       
  1511     iBundleChildren.ResetAndDestroy();
       
  1512 
       
  1513     iAllDbScreenshotItems.ResetAndDestroy();
       
  1514     
       
  1515     // Set the priority to the correct value
       
  1516     // for the next cleaning round. The priority
       
  1517     // may have been changed if db was too full.
       
  1518     iIncreasePriority = KDefaultCleaningPriority;
       
  1519     if ( IsActive() )
       
  1520         {
       
  1521         DLINFO(("Active. Priority should be reseted later."));
       
  1522         // Set the priority flags for the member variables.
       
  1523         // This value will be used in later in StartCleanupL 
       
  1524         // where the priority is set for this active object next time 
       
  1525         // they are called. This check is required because DoCancel uses 
       
  1526         // this function and then the active object may still be active until 
       
  1527         // DoCancel finishes its job.
       
  1528         iResetPriority = ETrue;        
       
  1529         }
       
  1530     else
       
  1531         {
       
  1532         DLINFO(("Not active"));
       
  1533         // Set the correct priority value.
       
  1534         // The priority can also be set for the active object because
       
  1535         // it is not active at the moment.
       
  1536         SetPriority( KDefaultCleaningPriority );        
       
  1537         }
       
  1538     
       
  1539     // Set state and other flags. To inital values.    
       
  1540     iCleanupState = ENotStarted;
       
  1541 
       
  1542     DLTRACEOUT((""));
       
  1543     }
       
  1544 
       
  1545 
       
  1546 #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1547 void CNcdNodeCacheCleaner::ArrayDebugPrint( const RPointerArray<CNcdNodeIdentifier>& aIdentifiers ) const
       
  1548     {
       
  1549     DLTRACEIN((""));
       
  1550     
       
  1551     CNcdNodeIdentifier* identifier( NULL );
       
  1552     (void) *identifier; // prevents compiler warning of unused variable
       
  1553 
       
  1554     for ( TInt i = 0; i < aIdentifiers.Count(); ++i )
       
  1555         {
       
  1556         identifier = aIdentifiers[ i ];
       
  1557         DLINFO((_L("Array identifier: %S, %S, %S, %d"),
       
  1558                 &identifier->NodeNameSpace(), &identifier->NodeId(),
       
  1559                 &identifier->ServerUri(), identifier->ClientUid().iUid));
       
  1560         }    
       
  1561 
       
  1562     DLTRACEOUT((""));
       
  1563     }
       
  1564 
       
  1565 void CNcdNodeCacheCleaner::ArrayDebugPrint( const RPointerArray<CDoNotRemoveIdentifier>& aIdentifiers ) const
       
  1566     {
       
  1567     DLTRACEIN((""));
       
  1568     
       
  1569     const CNcdNodeIdentifier* identifier( NULL );
       
  1570     (void) *identifier; // prevents compiler warning of unused variable
       
  1571 
       
  1572     for ( TInt i = 0; i < aIdentifiers.Count(); ++i )
       
  1573         {
       
  1574         identifier = &aIdentifiers[ i ]->Key();
       
  1575         DLINFO((_L("Array identifier: %S, %S, %S, %d"),
       
  1576                 &identifier->NodeNameSpace(), &identifier->NodeId(),
       
  1577                 &identifier->ServerUri(), identifier->ClientUid().iUid));
       
  1578         }    
       
  1579 
       
  1580     DLTRACEOUT((""));
       
  1581     }
       
  1582 
       
  1583 #endif // NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1584 
       
  1585 
       
  1586 void CNcdNodeCacheCleaner::CleanSpecialsL()
       
  1587     {
       
  1588     DLTRACEIN((""));
       
  1589 
       
  1590     // Try to clean some nodes if they are in the cleanuplist.
       
  1591     // Do not reset the node list or delete it here.
       
  1592     // This list is used throughout the cleaning process. 
       
  1593     // The array might be updated only in the start excess cleaning function.
       
  1594     // Other functions should not update the list, because otherwise the
       
  1595     // excess cleaner may go into the infinite loop if deepest nodes cannot
       
  1596     // be removed. 
       
  1597     HandleCleaningL( EFalse, EFalse );
       
  1598 
       
  1599     // Next step will be cleaning temporary nodes that
       
  1600     // are not used any more. If too much space is used,
       
  1601     // some extra cleaning will also be done by looping these steps.        
       
  1602     iCleanupState = ECleaningTemporaryNodes;
       
  1603 
       
  1604     iStatus = KRequestPending;
       
  1605     SetActive();
       
  1606     TRequestStatus* ptrStatus = &iStatus;
       
  1607     User::RequestComplete( ptrStatus, KErrNone );
       
  1608         
       
  1609     DLTRACEOUT((""));        
       
  1610     }
       
  1611 
       
  1612 
       
  1613 void CNcdNodeCacheCleaner::CleanTemporaryNodesL()
       
  1614     {
       
  1615     DLTRACEIN((""));
       
  1616 
       
  1617     // Notice that the iAllDbStorageNodeItems may not be up to date here if
       
  1618     // some new nodes have been inserted into the database after the cleaning
       
  1619     // has been started. So, if those new items are temporary objects they will
       
  1620     // not be checked here. The update of the array is omitted here to save some
       
  1621     // time, because db-actions may take long time. Also, the array should not
       
  1622     // be updated here, because otherwise excess removing may go into the infinite loop.
       
  1623     // The omitting of some temporary nodes does not matter because they will be 
       
  1624     // cleaned next time the cleaner starts it actions.   
       
  1625     CheckTemporaryNodesL();
       
  1626 
       
  1627     // HandleCleaningL and the functions it uses can handle the removing of the
       
  1628     // item from the db array.
       
  1629     // Just use the old node list.
       
  1630     // Do not delte the list because if excess cleaning is done, then the list should
       
  1631     // not be reloaded. Reloading might cause a infinite loop.
       
  1632     HandleCleaningL( EFalse, EFalse );
       
  1633 
       
  1634     iCleanupState = ECleaningHangingCases;
       
  1635     iStatus = KRequestPending;
       
  1636     SetActive();
       
  1637     TRequestStatus* ptrStatus = &iStatus;
       
  1638     User::RequestComplete( ptrStatus, KErrNone );        
       
  1639             
       
  1640     DLTRACEOUT((""));
       
  1641     }
       
  1642 
       
  1643 
       
  1644 void CNcdNodeCacheCleaner::CleanHangingsL()
       
  1645     {
       
  1646     DLTRACEIN((""));
       
  1647     
       
  1648     // The node items list has to be updated here. So, we can be sure that
       
  1649     // both the node array and metadata array are up to date when hangings
       
  1650     // are searched. If node list were not up to date, then some of the
       
  1651     // the metadata may be mistakenly thought to be hanging.
       
  1652 
       
  1653     // Get the node identifiers for the list. We do not use the member variable
       
  1654     // iAllDbStorageNodeItems here, because it should only be updated when the
       
  1655     // cleaning is started or in the excess clean function.
       
  1656     // Notice that here it does not matter that the nodes are not in specific
       
  1657     // order. Because all the nodes are compared to metadatas.
       
  1658     RPointerArray<CNcdNodeIdentifier> dbNodeIdentifiers;
       
  1659     CleanupResetAndDestroyPushL( dbNodeIdentifiers );
       
  1660     NodeDbManager().
       
  1661         GetAllClientItemIdentifiersL(
       
  1662             dbNodeIdentifiers, 
       
  1663             ClientUid(),
       
  1664             *iDoNotCleanNameSpaces,
       
  1665             iNodeCleanupTypes );    
       
  1666 
       
  1667     // Get all the metadata identifiers from the db.
       
  1668     // (left the do not clean namespaces out because they
       
  1669     // are ignored in all cases here)
       
  1670     RPointerArray<CNcdNodeIdentifier> dbMetaIdentifiers;
       
  1671     CleanupResetAndDestroyPushL( dbMetaIdentifiers );
       
  1672     NodeDbManager().
       
  1673         GetAllClientItemIdentifiersL(
       
  1674             dbMetaIdentifiers, 
       
  1675             ClientUid(),
       
  1676             *iDoNotCleanNameSpaces,
       
  1677             iMetaCleanupTypes );    
       
  1678 
       
  1679     DLINFO(("Db node count: %d", dbNodeIdentifiers.Count()));
       
  1680     // Print array debug info into the log file
       
  1681     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1682     DLINFO(("dbNodeIdentifiers array:"));
       
  1683     ArrayDebugPrint( dbNodeIdentifiers );
       
  1684     #endif
       
  1685 
       
  1686     DLINFO(("Db meta count: %d", dbMetaIdentifiers.Count()));
       
  1687     // Print array debug info into the log file
       
  1688     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1689     DLINFO(("dbNodeIdentifiers array:"));
       
  1690     ArrayDebugPrint( dbMetaIdentifiers );
       
  1691     #endif
       
  1692         
       
  1693     // Check if the node corresponding metadata identifier can be
       
  1694     // found from the db node list.
       
  1695     // If it can not be found, then the item has been left to hang in
       
  1696     // the db and can be removed.
       
  1697     CNcdNodeIdentifier* identifier( NULL );
       
  1698     TBool nodeFound( EFalse );
       
  1699     TInt j = dbMetaIdentifiers.Count();
       
  1700     const TInt count = dbNodeIdentifiers.Count();
       
  1701     
       
  1702     while ( j-- )
       
  1703         {
       
  1704         nodeFound = EFalse;
       
  1705                  
       
  1706         for ( TInt i = 0; i < count; ++i )
       
  1707             {
       
  1708             // Get the metadata part of the node name
       
  1709             identifier = 
       
  1710                 NcdNodeIdentifierEditor::
       
  1711                     CreateMetaDataIdentifierL( *dbNodeIdentifiers[ i ] );
       
  1712                         
       
  1713             // Check if the metadata part of the node id
       
  1714             // equals the metadata part of the list.
       
  1715             if ( identifier->Equals( *dbMetaIdentifiers[ j ] ) )
       
  1716                 {
       
  1717                 // The identifiers equal so corresponding node was found
       
  1718                 nodeFound = ETrue;
       
  1719                 
       
  1720                 delete identifier;
       
  1721                 identifier = NULL;    
       
  1722 
       
  1723                 // Because node was found the meta can be removed from the
       
  1724                 // list
       
  1725                 delete dbMetaIdentifiers[ j ];
       
  1726                 dbMetaIdentifiers.Remove( j );
       
  1727                 
       
  1728                 break;
       
  1729                 }
       
  1730             else
       
  1731                 {
       
  1732                 delete identifier;
       
  1733                 identifier = NULL;                
       
  1734                 }
       
  1735             }                
       
  1736 
       
  1737         if ( !nodeFound )
       
  1738             {
       
  1739             // If node was not found from DB, it is possibly in DoNotRemove list.
       
  1740             // Don't delete the metadata of such a node.
       
  1741             const TInt doNotRemovesCount = iDoNotRemoves.Count();
       
  1742             for ( TInt i = 0; i < doNotRemovesCount; i++ ) 
       
  1743                 {
       
  1744                 identifier =
       
  1745                     NcdNodeIdentifierEditor::CreateMetaDataIdentifierL( 
       
  1746                         iDoNotRemoves[i]->Key() );
       
  1747                 
       
  1748                 // Check if the metadata part of the node id equals the metadata part
       
  1749                 // of the list.
       
  1750                 if ( identifier->Equals( *dbMetaIdentifiers[ j ] ) ) 
       
  1751                     {
       
  1752               
       
  1753                     delete identifier;
       
  1754                     identifier = NULL;
       
  1755                     
       
  1756                     delete dbMetaIdentifiers[ j ];
       
  1757                     dbMetaIdentifiers.Remove( j );
       
  1758                     
       
  1759                     break;
       
  1760                     }
       
  1761                 else 
       
  1762                     {
       
  1763                     delete identifier;
       
  1764                     identifier = NULL;
       
  1765                     }
       
  1766                 }
       
  1767             }            
       
  1768         }
       
  1769 
       
  1770     DLINFO(("Remove hangings from db: %d", dbMetaIdentifiers.Count()));
       
  1771     // Print array debug info into the log file
       
  1772     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1773     DLINFO(("dbMetaIdentifiers array:"));
       
  1774     ArrayDebugPrint( dbMetaIdentifiers );
       
  1775     #endif
       
  1776 
       
  1777     // No need to check do not remove items here, because all the items
       
  1778     // that are hanging are independent from the nodes. That is also why,
       
  1779     // we do not need to do any parent child relation checking either.
       
  1780     NodeDbManager().
       
  1781         RemoveDataFromDatabaseL( dbMetaIdentifiers,
       
  1782                                  iMetaCleanupTypes );
       
  1783 
       
  1784     CleanupStack::PopAndDestroy( &dbMetaIdentifiers );
       
  1785     CleanupStack::PopAndDestroy( &dbNodeIdentifiers );
       
  1786  
       
  1787     // Next handle excess cleaning
       
  1788     iCleanupState = EStartCleaningHangingSpecialCases;
       
  1789     iStatus = KRequestPending;
       
  1790     SetActive();
       
  1791     TRequestStatus* ptrStatus = &iStatus;
       
  1792     User::RequestComplete( ptrStatus, KErrNone );        
       
  1793    
       
  1794     DLTRACEOUT((""));
       
  1795     }
       
  1796 
       
  1797 
       
  1798 void CNcdNodeCacheCleaner::StartCleanSpecialHangingsL()
       
  1799     {
       
  1800     DLTRACEIN((""));
       
  1801 
       
  1802     // Notice that the special hanging only need metadata objects.
       
  1803 
       
  1804     // Get all the metadata identifiers from the db.
       
  1805     // (left the do not clean namespaces out because they
       
  1806     // are ignored in all cases here)
       
  1807     // Notice that the icon array is also updated below. So,
       
  1808     // the metadata and the icon infromation will be in sync.
       
  1809     iDbMetaIdentifiers.ResetAndDestroy();
       
  1810     NodeDbManager().
       
  1811         GetAllClientItemIdentifiersL(
       
  1812             iDbMetaIdentifiers, 
       
  1813             ClientUid(),
       
  1814             *iDoNotCleanNameSpaces,
       
  1815             iMetaCleanupTypes );    
       
  1816 
       
  1817     DLINFO(("Db meta count: %d", iDbMetaIdentifiers.Count()));
       
  1818     // Print array debug info into the log file
       
  1819     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1820     DLINFO(("iDbMetaIdentifiers array:"));
       
  1821     ArrayDebugPrint( iDbMetaIdentifiers );
       
  1822     #endif
       
  1823 
       
  1824     // Start to clean all the special cases.
       
  1825     SetAllDbStorageIconItemsL();
       
  1826 
       
  1827     SetAllDbStorageScreenshotItemsL();    
       
  1828 
       
  1829     // Next clean the excess special cases
       
  1830     iCleanupState = ECleaningHangingSpecialCases;    
       
  1831     iStatus = KRequestPending;
       
  1832     SetActive();
       
  1833     TRequestStatus* ptrStatus = &iStatus;
       
  1834     User::RequestComplete( ptrStatus, KErrNone );        
       
  1835         
       
  1836     DLTRACEOUT((""));
       
  1837     }
       
  1838 
       
  1839 
       
  1840 void CNcdNodeCacheCleaner::CleanSpecialHangingsL()
       
  1841     {
       
  1842     DLTRACEIN((""));
       
  1843 
       
  1844     if ( iDbMetaIdentifiers.Count() > 0 )
       
  1845         {
       
  1846         DLINFO(("More metas left"));
       
  1847 
       
  1848         // There are still some metadatas.
       
  1849         // So, check their special contents.
       
  1850         CNcdNodeMetaData* metaData( NULL );
       
  1851         HBufC8* data( NULL );
       
  1852         CNcdNodeIdentifier* metaDataIdentifier( iDbMetaIdentifiers[ 0 ] );
       
  1853             
       
  1854         // The read operation may leave for example with KErrNotFound if the
       
  1855         // item was not found. Ignore the error and just continue normally.
       
  1856         TRAP_IGNORE( 
       
  1857             data =
       
  1858                 NodeDbManager().
       
  1859                     ReadDataFromDatabaseL( *metaDataIdentifier,
       
  1860                                            NcdNodeClassIds::ENcdMetaData ) );
       
  1861 
       
  1862         if ( data != NULL )
       
  1863             {
       
  1864             CleanupStack::PushL( data );
       
  1865             if ( *data != KNullDesC8 )
       
  1866                 {
       
  1867                 TRAP_IGNORE( 
       
  1868                     metaData = 
       
  1869                         NodeFactory().CreateMetaDataL( *metaDataIdentifier, 
       
  1870                                                        *data ) );
       
  1871                 if ( metaData != NULL )
       
  1872                     {
       
  1873                     DLINFO(("Metadata was found"));
       
  1874                     
       
  1875                     // Notice that the metadata should be closed not deleted!
       
  1876                     CleanupClosePushL( *metaData );
       
  1877 
       
  1878                     // Now that we have the metadata.
       
  1879                     // Check the icons
       
  1880                     CNcdNodeIcon* icon( NULL );
       
  1881                     TRAP_IGNORE( icon = &metaData->IconL() );
       
  1882                     if ( icon != NULL )
       
  1883                         {
       
  1884                         DLINFO(("icon check"));
       
  1885                         // Check if the icon can be found from the icon list
       
  1886                         // If its found then remove it from the list.
       
  1887                         CNcdNodeIdentifier* iconIdentifier( NULL );                        
       
  1888                         for ( TInt i = iAllDbIconItems.Count(); i > 0; --i )
       
  1889                             {
       
  1890                             iconIdentifier = iAllDbIconItems[ i - 1 ];
       
  1891                             if ( icon->IconId() == iconIdentifier->NodeId() )
       
  1892                                 {
       
  1893                                 // Icon was found.
       
  1894                                 DLINFO((_L("Icon found and no need to remove: %S"), 
       
  1895                                         &iconIdentifier->NodeId()));
       
  1896                                 delete iAllDbIconItems[ i - 1 ];
       
  1897                                 iAllDbIconItems.Remove( i - 1 );
       
  1898                                 }
       
  1899                             }
       
  1900                         }
       
  1901 
       
  1902 
       
  1903                     const CNcdNodeScreenshot* screenshot( NULL );
       
  1904                     TRAP_IGNORE( screenshot = &metaData->ScreenshotL() );
       
  1905                     if ( screenshot != NULL )
       
  1906                         {
       
  1907                         DLINFO(("screenshot check"));
       
  1908                         // Check if the screenshot can be found from the icon list
       
  1909                         // If its found then remove it from the list.
       
  1910                         CNcdNodeIdentifier* screenshotIdentifier( NULL );                        
       
  1911                         for ( TInt i = iAllDbScreenshotItems.Count(); i > 0; --i )
       
  1912                             {
       
  1913                             screenshotIdentifier = iAllDbScreenshotItems[ i - 1 ];
       
  1914                             TInt shotCount = screenshot->ScreenshotDownloadCount();
       
  1915                             DLTRACE(("Going through %d screenshots", shotCount ));
       
  1916                             while ( shotCount-- ) 
       
  1917                                 {                                
       
  1918                                 if ( screenshot->ScreenshotDownloadUri( shotCount ) 
       
  1919                                      == screenshotIdentifier->NodeId() )
       
  1920                                     {
       
  1921                                     // Screenshot was found.
       
  1922                                     DLINFO(("screenshot found"));
       
  1923                                     delete iAllDbScreenshotItems[ i - 1 ];
       
  1924                                     iAllDbScreenshotItems.Remove( i - 1 );
       
  1925                                     }
       
  1926                                 }
       
  1927                             }
       
  1928                         }
       
  1929 
       
  1930                     // When metadata is deleted, also icons, 
       
  1931                     // etc. are deleted.
       
  1932                     CleanupStack::PopAndDestroy( metaData );                
       
  1933                     }
       
  1934                 }
       
  1935             CleanupStack::PopAndDestroy( data );
       
  1936             }
       
  1937 
       
  1938         // Remove the used identifier.
       
  1939         // So, next round will have a new identifier in the beginning of the array
       
  1940         delete iDbMetaIdentifiers[ 0 ];
       
  1941         iDbMetaIdentifiers.Remove( 0 );
       
  1942 
       
  1943         // Continue cleaning special cases
       
  1944         iCleanupState = ECleaningHangingSpecialCases;            
       
  1945         }
       
  1946     else
       
  1947         {
       
  1948         // All the metadatas have been gone through.
       
  1949         // So, the special arrays will contain
       
  1950         // identifiers of the items that should be removed
       
  1951         // from the db.
       
  1952         // So, go to the next level.
       
  1953         iCleanupState = EFinishCleaningHangingSpecialCases;        
       
  1954         }
       
  1955 
       
  1956     iStatus = KRequestPending;
       
  1957     SetActive();
       
  1958     TRequestStatus* ptrStatus = &iStatus;
       
  1959     User::RequestComplete( ptrStatus, KErrNone );        
       
  1960         
       
  1961     DLTRACEOUT((""));
       
  1962     }
       
  1963 
       
  1964 
       
  1965 void CNcdNodeCacheCleaner::FinishCleanSpecialHangingsL()
       
  1966     {
       
  1967     DLTRACEIN((""));
       
  1968     
       
  1969     // Special arrays contain only the identifiers that
       
  1970     // belong to no metadata.
       
  1971     // So, delete those icons.
       
  1972 
       
  1973     DLINFO(("Remove icons from db: %d", iAllDbIconItems.Count()));
       
  1974     // Print array debug info into the log file
       
  1975     #ifdef NCD_NODE_CACHE_CLEANER_DEBUG_ARRAY_PRINT
       
  1976     DLINFO(("iAllDbIconItems array:"));
       
  1977     ArrayDebugPrint( iAllDbIconItems );
       
  1978     #endif
       
  1979 
       
  1980     NodeDbManager().
       
  1981         RemoveDataFromDatabaseL( iAllDbIconItems,
       
  1982                                  iIconCleanupTypes );   
       
  1983     iAllDbIconItems.ResetAndDestroy();
       
  1984 
       
  1985 
       
  1986     DLINFO(("Remove screenshot from db: %d", iAllDbScreenshotItems.Count() ));
       
  1987     NodeDbManager().
       
  1988         RemoveDataFromDatabaseL( iAllDbScreenshotItems,
       
  1989                                  iScreenshotCleanupTypes );
       
  1990     iAllDbScreenshotItems.ResetAndDestroy();
       
  1991 
       
  1992     // Everything is done here.
       
  1993     // So, go to the next level.
       
  1994     if ( iExcessCleanupStarted )
       
  1995         {
       
  1996         // Because excess cleanup has already been started we have looped here back.
       
  1997         // So, skip the start and go directly to the correct cleaning procedure.
       
  1998         // Notice, that this also skips the expireds check, which is what we want
       
  1999         // because expired should be checked only once to save some time. If for some
       
  2000         // reason some nodes will expire during this cleanup it does not matter.
       
  2001         // Also, transparency and bundle checks are skipped, because they will be
       
  2002         // handled already during the first loop.
       
  2003         // They will be cleaned another time.
       
  2004         iCleanupState = ECleaningExcess;
       
  2005         }
       
  2006     else
       
  2007         {
       
  2008         // Start cleaning.
       
  2009         iCleanupState = EStartCleaningExcess;        
       
  2010         }
       
  2011     iStatus = KRequestPending;
       
  2012     SetActive();
       
  2013     TRequestStatus* ptrStatus = &iStatus;
       
  2014     User::RequestComplete( ptrStatus, KErrNone );            
       
  2015 
       
  2016     DLTRACEOUT((""));
       
  2017     }
       
  2018 
       
  2019 
       
  2020 void CNcdNodeCacheCleaner::StartCleanExcessL()
       
  2021     {
       
  2022     DLTRACEIN((""));
       
  2023 
       
  2024     TInt currentDbSize(
       
  2025             NodeDbManager().StorageSizeL( ClientUid(),
       
  2026                                           *iDoNotCleanNameSpaces ) );
       
  2027     TInt compareSize( DbMaxSize() );        
       
  2028 
       
  2029     DLINFO(("current db size: %d, compare size: %d", 
       
  2030             currentDbSize, compareSize));
       
  2031 
       
  2032     TBool stopCleaning( ETrue );
       
  2033     if ( compareSize < currentDbSize )
       
  2034         {
       
  2035         // Get the current node items from the db. These will be gone through
       
  2036         // to decide what should be removed if the current database size is too
       
  2037         // big.
       
  2038         // This is the last change to update the list before the excess cleaning
       
  2039         // starts to loop. Then the node list should not be updated because
       
  2040         // that might result to a infinite loop, if deepest nodes can not be removed.
       
  2041         // We will not come back here if excess cleaning is looping.
       
  2042         // Notice that actually it does not matter if not all the items can not be
       
  2043         // checked here. They will be checked next time the cleaning is started.
       
  2044         SetAllDbStorageNodeItemsL();
       
  2045         if ( iAllDbStorageNodeItems.Count() > 0 )
       
  2046             {
       
  2047             // We still have to cleanup some more.
       
  2048             // So, make new request for the next step.
       
  2049             stopCleaning = EFalse;                    
       
  2050             iExcessCleanupStarted = ETrue;
       
  2051             
       
  2052             // Next check the root children, transparent and bundle nodes
       
  2053             // and after that expired nodes before actually removing the
       
  2054             // deepest nodes.
       
  2055             iCleanupState = EStartRootChildrenCheck;
       
  2056             }
       
  2057         }
       
  2058 
       
  2059     // Nothing to clean or the database size is small enough.        
       
  2060     if ( stopCleaning )
       
  2061         {
       
  2062         DLINFO(("Excess cleaned"));
       
  2063         // Just in case somebody has added something for removal.
       
  2064         // This call will update the node list once more from db
       
  2065         // and reset it when cleaning is done. The array update is ok
       
  2066         // here, because no additional loop will be done.
       
  2067         HandleCleaningL( ETrue, ETrue );
       
  2068         // Nothing to do next
       
  2069         iCleanupState = EStopping;
       
  2070         }
       
  2071 
       
  2072     iStatus = KRequestPending;
       
  2073     SetActive();
       
  2074     TRequestStatus* ptrStatus = &iStatus;
       
  2075     User::RequestComplete( ptrStatus, KErrNone );        
       
  2076         
       
  2077     DLTRACEOUT((""));
       
  2078     }
       
  2079 
       
  2080 
       
  2081 void CNcdNodeCacheCleaner::StartRootChildrenCheckL()
       
  2082     {
       
  2083     DLTRACEIN((""));
       
  2084     
       
  2085     // Bundles are always direct children of the root.
       
  2086     // Transparent folders are always direct children of the root
       
  2087     // or the bundles.
       
  2088     // So, start the checking from the root node and its children.
       
  2089     
       
  2090     CNcdNodeIdentifier* rootIdentifier =
       
  2091         NcdNodeIdentifierEditor::CreateRootIdentifierForClientLC( ClientUid() );
       
  2092 
       
  2093     // As a default, make the next step to be cleaning expireds.
       
  2094     // This will skip the transparent and bundle checks.
       
  2095     // If the root is found below, then the state will be changed to the
       
  2096     // required value.
       
  2097     iCleanupState = ECleaningExpireds;
       
  2098     
       
  2099     // Here, we remove the root from the db node list if it is included there.
       
  2100     // The root should not be removed from the db later anyway. 
       
  2101     // So, we may as well remove it from the db node list now.
       
  2102     iRootChildren.ResetAndDestroy();
       
  2103     if ( RemoveIdentifier( *rootIdentifier, iAllDbStorageNodeItems ) )
       
  2104         {
       
  2105         // Root was in the list. So, it can be found from db. 
       
  2106         // Thus, we can try to create the root node here.
       
  2107         // Also, check the root children.
       
  2108         CNcdRootNode* root( NULL );
       
  2109         CNcdNode* node( NULL );
       
  2110         HBufC8* nodeData( NULL );
       
  2111         
       
  2112         // The read operation may leave for example with KErrNotFound if the
       
  2113         // item was not found. Ignore the error and just continue normally.
       
  2114         TRAP_IGNORE( 
       
  2115             nodeData =
       
  2116                 NodeDbManager().
       
  2117                     ReadDataFromDatabaseL( *rootIdentifier,
       
  2118                                            NcdNodeClassIds::ENcdNode ) );
       
  2119         if ( nodeData != NULL )
       
  2120             {
       
  2121             CleanupStack::PushL( nodeData );
       
  2122             if ( *nodeData != KNullDesC8 )
       
  2123                 {
       
  2124                 TRAP_IGNORE( 
       
  2125                     node = 
       
  2126                         NodeFactory().CreateNodeL( *rootIdentifier, 
       
  2127                                                    *nodeData ) );
       
  2128                                                    
       
  2129                 if ( node != NULL )
       
  2130                     {
       
  2131                     // Push the node into the cleanup stack because checking
       
  2132                     // may leave.
       
  2133                     CleanupClosePushL( *node );
       
  2134                     if ( CNcdNodeFactory::NodeTypeL( *node ) 
       
  2135                          == CNcdNodeFactory::ENcdNodeRoot )
       
  2136                         {
       
  2137                         // Only handle the root.
       
  2138                         root = static_cast<CNcdRootNode*>( node );                       
       
  2139                         // Release the node from the cleanupstack.
       
  2140                         // It will be put back as a root next.
       
  2141                         CleanupStack::Pop( node );
       
  2142                         }
       
  2143                     else
       
  2144                         {
       
  2145                         DLERROR(("The node with root identifier was not root."))
       
  2146                         DASSERT( EFalse );
       
  2147                         // Delete the node because it was not of the right type.
       
  2148                         // The root will be left to NULL.
       
  2149                         CleanupStack::PopAndDestroy( node );
       
  2150                         node = NULL;
       
  2151                         }
       
  2152                     }
       
  2153                         
       
  2154                 if ( root != NULL )
       
  2155                     {
       
  2156                     // Notice that the node should be closed not deleted!
       
  2157                     CleanupClosePushL( *root );
       
  2158                     const RPointerArray<CNcdChildEntity>& children = root->ChildArray();
       
  2159                     for ( TInt i = 0; i < children.Count(); i++ )
       
  2160                         {
       
  2161                         // Because the root child will be added into the root list
       
  2162                         // and those children are handled separately, remove
       
  2163                         // the children also from the original node list.
       
  2164                         // When iAllDbStorageNodeItems was initialized it contained all the
       
  2165                         // identifiers of all the nodes in db.
       
  2166                         // Notice, that if the children are not in the db node list, then
       
  2167                         // they will not be removed from the db here.
       
  2168               
       
  2169                         // So, check if the identifier is found from the db list and remove it
       
  2170                         // if found.
       
  2171                         if ( RemoveIdentifier( children[i]->Identifier(), iAllDbStorageNodeItems ) )
       
  2172                             {
       
  2173                             // The root child was in the db list and it was removed.
       
  2174                             // Now, insert the identifier into the temporary root list.
       
  2175                             // So, these children will be checked later for transparency and
       
  2176                             // bundle features.
       
  2177                             AddIdentifierL( children[i]->Identifier(), iRootChildren );
       
  2178                             }
       
  2179                         }
       
  2180                     CleanupStack::PopAndDestroy( root );
       
  2181                     
       
  2182                     // Because we got the root, then next step is to handle its
       
  2183                     // children.
       
  2184                     iCleanupState = ECheckRootChildren; 
       
  2185                     }
       
  2186                 }
       
  2187 
       
  2188             // Delete node data.
       
  2189             CleanupStack::PopAndDestroy( nodeData );
       
  2190             }        
       
  2191         }
       
  2192         
       
  2193     CleanupStack::PopAndDestroy( rootIdentifier );   
       
  2194 
       
  2195     iStatus = KRequestPending;
       
  2196     SetActive();
       
  2197     TRequestStatus* ptrStatus = &iStatus;
       
  2198     User::RequestComplete( ptrStatus, KErrNone );        
       
  2199     
       
  2200     DLTRACEOUT(("")); 
       
  2201     }
       
  2202 
       
  2203 
       
  2204 void CNcdNodeCacheCleaner::CheckRootChildrenL()
       
  2205     {
       
  2206     DLTRACEIN((""));
       
  2207 
       
  2208     if ( iRootChildren.Count() > 0 )
       
  2209         {
       
  2210         DLINFO(("Root children in the array."));
       
  2211 
       
  2212         // As a default loop here after this stuff is done.
       
  2213         // This way next loop will check if there are still more children
       
  2214         // to be checked.
       
  2215         iCleanupState = ECheckRootChildren;                        
       
  2216 
       
  2217         // All the children of the root should always be folders.
       
  2218         CNcdNode* node( NULL );    
       
  2219         CNcdNodeFolder* folder( NULL );
       
  2220         HBufC8* nodeData( NULL );
       
  2221         CNcdNodeIdentifier* rootChildIdentifier( iRootChildren[ 0 ] );
       
  2222 
       
  2223         // The read operation may leave for example with KErrNotFound if the
       
  2224         // item was not found. Ignore the error and just continue normally.
       
  2225         TRAP_IGNORE( 
       
  2226             nodeData =
       
  2227                 NodeDbManager().
       
  2228                     ReadDataFromDatabaseL( *rootChildIdentifier,
       
  2229                                            NcdNodeClassIds::ENcdNode ) );
       
  2230         if ( nodeData != NULL )
       
  2231             {
       
  2232             CleanupStack::PushL( nodeData );
       
  2233             if ( *nodeData != KNullDesC8 )
       
  2234                 {
       
  2235                 TRAP_IGNORE( 
       
  2236                     node =
       
  2237                         NodeFactory().CreateNodeL( *rootChildIdentifier, 
       
  2238                                                    *nodeData ) );
       
  2239                 if ( node != NULL )
       
  2240                     {
       
  2241                     // Push the node into the cleanup stack because checking
       
  2242                     // may leave.
       
  2243                     CleanupClosePushL( *node );
       
  2244                     if ( CNcdNodeFactory::NodeTypeL( *node ) 
       
  2245                          == CNcdNodeFactory::ENcdNodeFolder )
       
  2246                         {
       
  2247                         // Only handle the folders here.
       
  2248                         // Else, the child can not be bundle or transparent.
       
  2249                         folder = static_cast<CNcdNodeFolder*>( node );
       
  2250                         // Remove the node from the cleanup stack but do not delete
       
  2251                         // it here. It will be used as a folder next.            
       
  2252                         CleanupStack::Pop( node );
       
  2253                         }
       
  2254                     else
       
  2255                         {
       
  2256                         // Delete the node because it was not of the right type.
       
  2257                         DLERROR(("The root child was not a folder. Has the specification been changed?"));
       
  2258                         DASSERT( EFalse );
       
  2259                         CleanupStack::PopAndDestroy( node );
       
  2260                         }
       
  2261                     }
       
  2262                         
       
  2263                 if ( folder != NULL )
       
  2264                     {
       
  2265                     // Notice that the node should be closed not deleted!
       
  2266                     CleanupClosePushL( *folder );
       
  2267                     CNcdNodeFactory::TNcdNodePurpose nodePurpose(
       
  2268                         CNcdNodeFactory::NodePurposeL( *folder ) );
       
  2269                         
       
  2270                     if ( nodePurpose == CNcdNodeFactory::ENcdTransparentNode )
       
  2271                         {
       
  2272                         DLINFO(("Transparent folder."));
       
  2273                         const RPointerArray<CNcdChildEntity>& children = folder->ChildArray();
       
  2274                         for ( TInt i = 0; i < children.Count(); i++ )
       
  2275                             {                            
       
  2276                             // Because the folder is transparent folder,
       
  2277                             // remove the child identifiers from the node list. 
       
  2278                             // So, those transparent children will not be
       
  2279                             // removed from the database later.
       
  2280 
       
  2281                             // Notice, that if the children of the transparent folder
       
  2282                             // are not in the db list, then they will not be removed
       
  2283                             // from the db.
       
  2284                             RemoveIdentifier( children[i]->Identifier(), 
       
  2285                                               iAllDbStorageNodeItems );
       
  2286                             }
       
  2287                         }
       
  2288                     else if ( nodePurpose == CNcdNodeFactory::ENcdBundleNode )
       
  2289                         {
       
  2290                         DLINFO(("Bundle folder"))
       
  2291                         // Next, we have to handle the bundle children and check
       
  2292                         // if they are transparent
       
  2293                         iBundleChildren.ResetAndDestroy();
       
  2294                         const RPointerArray<CNcdChildEntity>& children = folder->ChildArray();
       
  2295                         for ( TInt i = 0; i < children.Count(); i++ )
       
  2296                             {
       
  2297                             if ( RemoveIdentifier( children[i]->Identifier(),
       
  2298                                                    iAllDbStorageNodeItems ) )
       
  2299                                 {
       
  2300                                 // The identifier was found from the db list and removed.
       
  2301                                 // So, because the node can be found from the db, it can be
       
  2302                                 // created. So, add it into the bundle children temporary list.
       
  2303                                 AddIdentifierL( children[i]->Identifier(), iBundleChildren );
       
  2304                                 }
       
  2305                             }
       
  2306                             
       
  2307                         // Now that we got the children of the bundle folder,
       
  2308                         // we should handle them separately during next active rounds.
       
  2309                         iCleanupState = EHandleBundleChildren;                        
       
  2310                         }
       
  2311                     CleanupStack::PopAndDestroy( folder );                
       
  2312                     }
       
  2313                 }
       
  2314 
       
  2315             // Delete node data.
       
  2316             CleanupStack::PopAndDestroy( nodeData );
       
  2317             }
       
  2318             
       
  2319         // Now, the root child has been checked. So, remove its identifier 
       
  2320         // from the root array.
       
  2321         delete iRootChildren[ 0 ];
       
  2322         iRootChildren.Remove( 0 );
       
  2323         }
       
  2324     else
       
  2325         {
       
  2326         // No more children to be checked.
       
  2327         // So, skip to expireds.
       
  2328         iCleanupState = ECleaningExpireds;
       
  2329         }
       
  2330 
       
  2331     iStatus = KRequestPending;
       
  2332     SetActive();
       
  2333     TRequestStatus* ptrStatus = &iStatus;
       
  2334     User::RequestComplete( ptrStatus, KErrNone );        
       
  2335     
       
  2336     DLTRACEOUT(("")); 
       
  2337     }
       
  2338 
       
  2339 
       
  2340 void CNcdNodeCacheCleaner::HandleBundleChildrenL()
       
  2341     {
       
  2342     DLTRACEIN((""));
       
  2343     
       
  2344     // Check all the bundle children for transparent folders.
       
  2345     
       
  2346     if ( iBundleChildren.Count() > 0 )
       
  2347         {
       
  2348         DLINFO(("Bundle children in the array."));
       
  2349 
       
  2350         // As a default loop here after this stuff is done.
       
  2351         // This way next loop will check if there are still more children
       
  2352         // to be checked.
       
  2353         iCleanupState = EHandleBundleChildren;                        
       
  2354 
       
  2355         // All the children of the root should always be folders.
       
  2356         CNcdNode* node( NULL );    
       
  2357         CNcdNodeFolder* folder( NULL );
       
  2358         HBufC8* nodeData( NULL );
       
  2359         CNcdNodeIdentifier* bundleChildIdentifier( iBundleChildren[ 0 ] );
       
  2360 
       
  2361         // The read operation may leave for example with KErrNotFound if the
       
  2362         // item was not found. Ignore the error and just continue normally.
       
  2363         TRAP_IGNORE( 
       
  2364             nodeData =
       
  2365                 NodeDbManager().
       
  2366                     ReadDataFromDatabaseL( *bundleChildIdentifier,
       
  2367                                            NcdNodeClassIds::ENcdNode ) );
       
  2368         if ( nodeData != NULL )
       
  2369             {
       
  2370             CleanupStack::PushL( nodeData );
       
  2371             if ( *nodeData != KNullDesC8 )
       
  2372                 {
       
  2373                 TRAP_IGNORE( 
       
  2374                     node =
       
  2375                         NodeFactory().CreateNodeL( *bundleChildIdentifier, 
       
  2376                                                    *nodeData ) );
       
  2377                 if ( node != NULL )
       
  2378                     {
       
  2379                     // Push the node into the cleanup stack because checking
       
  2380                     // may leave.
       
  2381                     CleanupClosePushL( *node );
       
  2382                     if ( CNcdNodeFactory::NodeTypeL( *node ) 
       
  2383                          == CNcdNodeFactory::ENcdNodeFolder )
       
  2384                         {
       
  2385                         // Only handle the folders here.
       
  2386                         // Else, the child can not be transparent.
       
  2387                         folder = static_cast<CNcdNodeFolder*>( node );
       
  2388                         }
       
  2389                     // Remove the node from the cleanup stack but do not delete
       
  2390                     // it here. It will be used as a folder next.            
       
  2391                     CleanupStack::Pop( node );
       
  2392                     }
       
  2393                         
       
  2394                 if ( folder != NULL )
       
  2395                     {
       
  2396                     // Notice that the node should be closed not deleted!
       
  2397                     CleanupClosePushL( *folder );
       
  2398                     CNcdNodeFactory::TNcdNodePurpose nodePurpose(
       
  2399                         CNcdNodeFactory::NodePurposeL( *folder ) );
       
  2400                         
       
  2401                     if ( nodePurpose == CNcdNodeFactory::ENcdTransparentNode )
       
  2402                         {
       
  2403                         DLINFO(("Transparent folder."));
       
  2404                         const RPointerArray<CNcdChildEntity>& children = folder->ChildArray();
       
  2405                         for ( TInt i = 0; i < children.Count(); ++i )
       
  2406                             {
       
  2407                             // Because the folder is transparent folder,
       
  2408                             // remove the child identifiers from the node list. 
       
  2409                             // So, those transparent children will not be
       
  2410                             // removed from the database.
       
  2411 
       
  2412                             // Because the root child will be added into the root list
       
  2413                             // and those children are handled separately, remove
       
  2414                             // the children also from the original node list.
       
  2415                             // Notice, that if the children are not in the db list, then
       
  2416                             // there will not be any need to remove them from the db either.
       
  2417                             // So, check it here.
       
  2418                             RemoveIdentifier( children[i]->Identifier(), 
       
  2419                                               iAllDbStorageNodeItems );
       
  2420                             }
       
  2421                         }
       
  2422                     CleanupStack::PopAndDestroy( folder );                
       
  2423                     }
       
  2424                 }
       
  2425 
       
  2426             // Delete node data.
       
  2427             CleanupStack::PopAndDestroy( nodeData );
       
  2428             }
       
  2429             
       
  2430         // Now the root child has been checked. So, remove its identifier 
       
  2431         // from the root array.
       
  2432         delete iBundleChildren[ 0 ];
       
  2433         iBundleChildren.Remove( 0 );
       
  2434         }
       
  2435     else
       
  2436         {
       
  2437         // No more bundle children to be checked.
       
  2438         // So, skip back to root child checking.
       
  2439         iCleanupState = ECheckRootChildren;
       
  2440         }
       
  2441 
       
  2442     iStatus = KRequestPending;
       
  2443     SetActive();
       
  2444     TRequestStatus* ptrStatus = &iStatus;
       
  2445     User::RequestComplete( ptrStatus, KErrNone );        
       
  2446         
       
  2447     DLTRACEOUT((""));
       
  2448     }
       
  2449 
       
  2450 
       
  2451 void CNcdNodeCacheCleaner::CleanExpiredsL()
       
  2452     {
       
  2453     DLTRACEIN((""));
       
  2454     
       
  2455     // Notice that this function is looped if there are multiple nodes in the
       
  2456     // iAllDbStorageNodeItems. The array may not be uptodate if some nodes are
       
  2457     // inserted into the database during this active object looping. This does
       
  2458     // not matter because then only those new items will not be checked here.
       
  2459     // They will be checked when the cleaner is started next time. The array
       
  2460     // could be updated here every time but because db-actions may take time
       
  2461     // this is omitted here.
       
  2462     
       
  2463     // Notice that because the db items are sorted when the array is created,
       
  2464     // the removing of the children from the end list does not affect this index.
       
  2465     // So, if the current item is removed then also its children are removed, but
       
  2466     // the children exist after the parent in the array.
       
  2467     if ( iExpiredCleaningIndex < iAllDbStorageNodeItems.Count() )
       
  2468         {
       
  2469         CNcdNodeIdentifier* itemIdentifier( 
       
  2470             iAllDbStorageNodeItems[ iExpiredCleaningIndex ] );
       
  2471 
       
  2472         DLINFO((_L("Cleaning index: %d, id: %S"), 
       
  2473                 iExpiredCleaningIndex, &itemIdentifier->NodeId()));
       
  2474 
       
  2475         // Set the expire to be true by default. So, if node can not be initialized
       
  2476         // correctly it will be removed also in that case.
       
  2477         TBool expired( ETrue );
       
  2478         TInt depth( NcdNodeIdentifierEditor::NodeDepthL( *itemIdentifier ) );
       
  2479 
       
  2480         if ( depth < 2 )
       
  2481             {
       
  2482             DLINFO(("No need to check expiration. Depth: %d", depth));
       
  2483             // Root nodes are not removed here. They will be updated by the
       
  2484             // other methods when they expire.
       
  2485             // Only items that are not root or direct children of root should
       
  2486             // be removed here. Notice that temporary items have depth zero, but
       
  2487             // their are cleaned during temporary cleaning. So, omitting them here
       
  2488             // is ok.
       
  2489             // Notice also, that items directly under the root should not be
       
  2490             // removed by the cleaner. For example, bundle folders should be 
       
  2491             // updated only same time as root, because their info is only gotten 
       
  2492             // during the root refresh.
       
  2493             expired = EFalse;
       
  2494             }
       
  2495         else
       
  2496             {
       
  2497             // Node will not be some root so, check the expiration here.
       
  2498             HBufC8* nodeData( NULL );
       
  2499             
       
  2500             // The read operation may leave for example with KErrNotFound if the
       
  2501             // item was not found. Ignore the error and just continue normally.
       
  2502             TRAP_IGNORE( 
       
  2503                 nodeData =
       
  2504                     NodeDbManager().
       
  2505                         ReadDataFromDatabaseL( *itemIdentifier,
       
  2506                                                NcdNodeClassIds::ENcdNode ) );
       
  2507             if ( nodeData != NULL )
       
  2508                 {                
       
  2509                 if ( *nodeData != KNullDesC8 )
       
  2510                     {
       
  2511                     CNcdNode* node( NULL );
       
  2512                     TRAP_IGNORE( 
       
  2513                         node = 
       
  2514                             NodeFactory().CreateNodeL( *itemIdentifier, 
       
  2515                                                        *nodeData ) );
       
  2516                     if ( node != NULL )
       
  2517                         {
       
  2518                         // Notice that the node should be closed not deleted!
       
  2519                         CNcdNodeLink* link = node->NodeLink();
       
  2520                         if ( link )
       
  2521                             {
       
  2522                             // Check if the node should be marked not expired.
       
  2523                             expired = link->IsExpired();
       
  2524                             }
       
  2525                         node->Close();              
       
  2526                         }
       
  2527                     }
       
  2528 
       
  2529                 // Delete node data.
       
  2530                 delete nodeData;
       
  2531                 }        
       
  2532             }
       
  2533             
       
  2534         if ( expired )
       
  2535             {
       
  2536             DLINFO((_L("Expired: %S"), &itemIdentifier->NodeId()));
       
  2537             // Because the node was expired, or it could not be created for some reason
       
  2538             // correctly. Add the identifier to the cleanup list if it is allowed action.
       
  2539             // This function knows how to move the item into the waiting list.
       
  2540             AddCleanupIdentifierL( *itemIdentifier );
       
  2541 
       
  2542             // Remove the data from its original place. Notice that identifier
       
  2543             // is copied in the function above.
       
  2544             delete itemIdentifier;
       
  2545             iAllDbStorageNodeItems.Remove( iExpiredCleaningIndex );
       
  2546             
       
  2547             // HandleCleaningL and the functions it uses can handle the removing of the
       
  2548             // item from the db array.
       
  2549             HandleCleaningL( EFalse, EFalse );
       
  2550             }
       
  2551         else
       
  2552             {
       
  2553             // Increase the cleaning index by one for the next round
       
  2554             // because the current item was not removed.
       
  2555             ++iExpiredCleaningIndex;            
       
  2556             }
       
  2557 
       
  2558         // There may still be something to be done.
       
  2559         // So, make new request for the next step.
       
  2560         iCleanupState = ECleaningExpireds;
       
  2561         }
       
  2562     else
       
  2563         {
       
  2564         DLINFO(("Expireds cleaned"));
       
  2565         // Reset the cleaning index.
       
  2566         iExpiredCleaningIndex = 0;
       
  2567 
       
  2568         // Because expireds are cleaned now. Check if the excess nodes should
       
  2569         // still be removed from the database to free enough space.
       
  2570         iCleanupState = ECleaningExcess;            
       
  2571         }
       
  2572 
       
  2573     iStatus = KRequestPending;
       
  2574     SetActive();
       
  2575     TRequestStatus* ptrStatus = &iStatus;
       
  2576     User::RequestComplete( ptrStatus, KErrNone );        
       
  2577         
       
  2578     DLTRACEOUT((""));
       
  2579     }
       
  2580 
       
  2581                  
       
  2582 void CNcdNodeCacheCleaner::CleanExcessL()
       
  2583     {
       
  2584     DLTRACEIN((""));
       
  2585 
       
  2586     TInt currentDbSize(
       
  2587             NodeDbManager().StorageSizeL( ClientUid(),
       
  2588                                           *iDoNotCleanNameSpaces ) );
       
  2589                                           
       
  2590     // Because cleaning has been started the compare size should be somewhat
       
  2591     // less than the max accepted size after the cleaning operation.
       
  2592     TInt compareSize( DbMaxSize() / KMaxSizeDivider );        
       
  2593 
       
  2594     DLINFO(("current db size: %d, compare size: %d", 
       
  2595             currentDbSize, compareSize));
       
  2596 
       
  2597     // Here the node list may not be uptodate if database has changed during the
       
  2598     // active loops. But do not update it, because otherwise we might try to remove
       
  2599     // same node over and over again. If the deepest nodes are not allowed to be
       
  2600     // removed.
       
  2601     TInt itemCount( iAllDbStorageNodeItems.Count() );
       
  2602     TInt deepestDepth( 0 );
       
  2603 
       
  2604     if ( itemCount > 0  )
       
  2605         {
       
  2606         // Get the depth of the final node in db list. This is the deepest node because
       
  2607         // the array has been sorted.
       
  2608         deepestDepth =
       
  2609             NcdNodeIdentifierEditor::NodeDepthL( *iAllDbStorageNodeItems[ itemCount - 1 ] );
       
  2610         if ( deepestDepth < 2 )
       
  2611             {
       
  2612             DLINFO(("Do not clean excess any more. Depth: %d", deepestDepth));
       
  2613             // Because we should not delete root or its direct children here.
       
  2614             // Reset the node items array and reset the item count. 
       
  2615             // Because the item count will be zero now,
       
  2616             // the cleaning will continue to the stopping state next.
       
  2617             iAllDbStorageNodeItems.ResetAndDestroy();
       
  2618             itemCount = iAllDbStorageNodeItems.Count();
       
  2619             }
       
  2620         }
       
  2621 
       
  2622     // Start actual cleaning if it is still required.
       
  2623     if ( itemCount > 0 
       
  2624          && compareSize < currentDbSize )
       
  2625         {
       
  2626         DLINFO(("Excess cleaning is required"));
       
  2627         
       
  2628         DLINFO(("Deepest depth: %d", deepestDepth));            
       
  2629 
       
  2630         CNcdNodeIdentifier* identifier( NULL );
       
  2631         for ( TInt i = itemCount; i > 0; --i )
       
  2632             {
       
  2633             identifier = iAllDbStorageNodeItems[ i - 1 ];
       
  2634             if ( deepestDepth != NcdNodeIdentifierEditor::NodeDepthL( *identifier ) )
       
  2635                 {
       
  2636                 // Only remove items that have the same depth at once.
       
  2637                 DLINFO(("All the same depth nodes added."));
       
  2638                 break;
       
  2639                 }
       
  2640                 
       
  2641             // This identifier has also the same depth.
       
  2642             // Insert it into the cleanup array if removal is allowed.
       
  2643             AddCleanupIdentifierL( *iAllDbStorageNodeItems[ i - 1 ] );
       
  2644 
       
  2645             // Remove the data from its original place. Notice that identifier
       
  2646             // is copied in the function above.
       
  2647             delete iAllDbStorageNodeItems[ i - 1 ];
       
  2648             iAllDbStorageNodeItems.Remove( i - 1 );
       
  2649             
       
  2650             DLINFO(("Same depth id added to array"));
       
  2651             }
       
  2652 
       
  2653         // Clean the nodes from the database.
       
  2654         HandleCleaningL( EFalse, EFalse );        
       
  2655 
       
  2656         // We may still have to cleanup some more.
       
  2657         // So, make new request for the next step.
       
  2658         // This will clean the metadata related data such as icons.
       
  2659         // The cleaning will loop until enough space is released.
       
  2660         iCleanupState = ECleaningTemporaryNodes;        
       
  2661         }
       
  2662     else
       
  2663         {
       
  2664         DLINFO(("Excess cleaned"));
       
  2665         // Just in case somebody has added something for removal
       
  2666         // while waiting this new round.
       
  2667         // Because we are about to end the cleaning we can update the
       
  2668         // node list one more time before final removing.
       
  2669         HandleCleaningL( ETrue, ETrue );
       
  2670         
       
  2671         // Nothing to do next
       
  2672         iCleanupState = EStopping;
       
  2673         }
       
  2674 
       
  2675     iStatus = KRequestPending;
       
  2676     SetActive();
       
  2677     TRequestStatus* ptrStatus = &iStatus;
       
  2678     User::RequestComplete( ptrStatus, KErrNone );        
       
  2679         
       
  2680     DLTRACEOUT((""));
       
  2681     }
       
  2682 
       
  2683 
       
  2684 void CNcdNodeCacheCleaner::StoppingL()
       
  2685     {
       
  2686     DLTRACEIN((""));
       
  2687     
       
  2688     // This function resets the member variables to default values.
       
  2689     // Also, the priority of this active object is set to the default.
       
  2690     ResetState();
       
  2691     
       
  2692     DLTRACEOUT((""));
       
  2693     }
       
  2694