harvester/harvesterserver/src/cindexingmanager.cpp
changeset 0 671dee74050a
child 1 6f2c1c46032b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/harvester/harvesterserver/src/cindexingmanager.cpp	Mon Apr 19 14:40:16 2010 +0300
@@ -0,0 +1,549 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+#include <f32file.h>
+#include <s32file.h>
+#include "CIndexingManager.h"
+#include "HarvesterServerLogger.h"
+#include "CBlacklistMgr.h"
+
+_LIT(KManagerFileName, "CPixConfig.bin");
+const TInt KManagerFileVersion = 1;
+
+// How often harvester states are checked (in minutes)
+const TUint KDefaultWaitTimeInMinutes = 1;
+
+// How often harvester states are checked (in microseconds)
+const TUint KDefaultWaitTime = KDefaultWaitTimeInMinutes*60*1000000; // 1 minute
+
+// If time difference between RunL calls is less than this value (i.e system time
+// changed to past) update harvesters start and complete times.
+const TInt KMinTimeDifference = 0;
+
+// If time difference between RunL calls is more than this value (i.e system time
+// changed to future) update harvesters start and complete times. This value is
+// default difference in RunL calls with additional buffer.
+const TInt KMaxTimeDifference = 1 + KDefaultWaitTimeInMinutes;
+
+
+// -----------------------------------------------------------------------------
+// CHarvesterServer::NewL()
+// -----------------------------------------------------------------------------
+//
+CIndexingManager* CIndexingManager::NewL()
+	{
+	CIndexingManager* instance = new (ELeave)CIndexingManager();
+	CleanupStack::PushL(instance);
+	instance->ConstructL();
+	CleanupStack::Pop(instance);
+	return instance;
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::CIndexingManager()
+// -----------------------------------------------------------------------------
+//
+CIndexingManager::CIndexingManager()
+	: CActive(CActive::EPriorityStandard),
+	iState(EStateNone), iPreviousRun(0)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::~CIndexingManager()
+// -----------------------------------------------------------------------------
+//
+CIndexingManager::~CIndexingManager()
+	{
+	// Active Object cancel
+	Cancel();
+
+	iHarvesterArray.Close();
+
+	// Delete all plugins
+	iPluginArray.ResetAndDestroy();
+
+	// Close the array handle
+	iPluginArray.Close();
+	
+	// Close the timer
+	iTimer.Close();
+	
+	// Close search server connection
+	iSearchSession.Close();
+	
+	// Close file system connection
+	iFs.Close();
+	
+	delete iBlacklistMgr;
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::ConstructL()
+// -----------------------------------------------------------------------------
+//
+void CIndexingManager::ConstructL()
+	{
+	// connect to file system
+	User::LeaveIfError(iFs.Connect());
+	
+	// Load the configuration
+	TFileName pathWithoutDrive;
+	iFs.CreatePrivatePath(EDriveC);
+	iManagerFilePath = _L("C:");
+		
+	iFs.PrivatePath( pathWithoutDrive );
+	iManagerFilePath.Append(pathWithoutDrive);
+	iManagerFilePath.Append(KManagerFileName);
+	
+	// Loads the saved list of file transfers
+	Internalize();
+	
+	// Create the timer
+	User::LeaveIfError(iTimer.CreateLocal());
+
+	// This server must be connected before passing to harvester plugins
+	User::LeaveIfError(iSearchSession.Connect());
+	
+	//instantiate blacklist database
+	iBlacklistMgr = CBlacklistMgr::NewL();
+
+	// Load plugins
+	LoadPluginsL();
+	
+	//release the Blacklist manager as the blacklist functionality is done
+	delete iBlacklistMgr;
+
+	StartPlugins();
+	
+	// Wait before running RunL
+	iState = EStateRunning;
+	iTimer.After(iStatus, 10000000); // 10s
+	SetActive();
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::DoCancel()
+// -----------------------------------------------------------------------------
+//
+void CIndexingManager::DoCancel()
+	{
+	// Cancel the timer
+	if (iState == EStateRunning)
+		{
+		iTimer.Cancel();
+		iState = EStateCancelling;
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::RunL()
+// -----------------------------------------------------------------------------
+//
+void CIndexingManager::RunL()
+	{
+
+	// Take next harvester from the list to be run
+    CPIXLOGSTRING("CIndexingManager::RunL() ");
+
+    // If system time is changed update harvester last complete and start time accordingly.
+    // This ensures that no extra reharvesting is done if system time is changed.
+    TTime timenow;
+    timenow.UniversalTime();
+    
+    TTimeIntervalMinutes timeDifference(0);
+    TInt err = timenow.MinutesFrom(iPreviousRun, timeDifference);
+
+    if ( err == KErrNone && iPreviousRun.Int64() != 0 &&
+         ( timeDifference.Int() < KMinTimeDifference || timeDifference.Int() > KMaxTimeDifference ) )
+        {
+        CPIXLOGSTRING("CIndexingManager::RunL() time changed. Update harvester completion and start times");
+        for (TInt i=0; i<iHarvesterArray.Count(); i++)
+            {
+            iHarvesterArray[i].iLastComplete += timeDifference;
+            iHarvesterArray[i].iLastStart += timeDifference;
+            }
+        }
+
+    iPreviousRun = timenow;
+
+    
+    // Do nothing if already harvesting
+    if (iState != EStateRunning)
+    	{
+        CPIXLOGSTRING("CIndexingManager::RunL() the indexing manager is not running anymore ");
+    	return;
+    	}
+
+	// Check if harvesters running
+	TBool harvesterRunning = EFalse;
+	for (TInt i=0; i<iHarvesterArray.Count(); i++)
+		{
+		switch (iHarvesterArray[i].iStatus)
+			{
+			case EHarvesterStatusWaiting:
+		        CPIXLOGSTRING2("CIndexingManager::RunL(): <%S>, waiting for scheduling...", &iHarvesterArray[i].iQualifiedBaseAppClass);
+				break;
+			case EHarvesterStatusHibernate:
+		        CPIXLOGSTRING2("CIndexingManager::RunL(): <%S>, hibernating.", &iHarvesterArray[i].iQualifiedBaseAppClass);
+				break;
+			case EHarvesterStatusRunning:
+		        CPIXLOGSTRING2("CIndexingManager::RunL(): <%S>, running...", &iHarvesterArray[i].iQualifiedBaseAppClass);
+		        break;
+			}
+		TTimeIntervalMinutes mins_last_complete;
+		TTimeIntervalMinutes mins_last_start;
+		timenow.MinutesFrom(iHarvesterArray[i].iLastComplete, mins_last_complete);
+		timenow.MinutesFrom(iHarvesterArray[i].iLastStart, mins_last_start);
+        CPIXLOGSTRING3("CIndexingManager::RunL():  ^^^ previous start %d mins ago, previous complete %d mins ago.", mins_last_start.Int(), mins_last_complete.Int());
+
+        if (iHarvesterArray[i].iStatus == EHarvesterStatusRunning)
+			harvesterRunning = ETrue;
+		}
+
+    
+    // If not already running, just pick the next harvester and run it
+	if (!harvesterRunning)
+		{
+		for (TInt i=0; i<iHarvesterArray.Count(); i++)
+			{
+			if ((iHarvesterArray[i].iPlugin != NULL) && // Must be valid plugin
+				(iHarvesterArray[i].iStatus == EHarvesterStatusWaiting) && // Must be waiting
+				((iHarvesterArray[i].iLastComplete > timenow) || // Last completion after timenow (invalid time!) 
+				 (iHarvesterArray[i].iLastComplete < timenow - TTimeIntervalDays(7)))) 
+				// Last completion over 1 week ago (change to TTimeIntervalMinutes for debugging) 
+				{
+				// Set new status
+				iHarvesterArrayChanged = ETrue;
+				iHarvesterArray[i].iStatus = EHarvesterStatusRunning;
+				iHarvesterArray[i].iLastStart.UniversalTime();
+
+				// TODO Why are we trapping StartHarvestingL()? 
+				// Consider handling the leave in ::RunError instead. 
+
+				// Run the harvester
+			    CPIXLOGSTRING2("CIndexingManager::RunL(): Starting harvesting <%S>.", &iHarvesterArray[i].iQualifiedBaseAppClass);
+				TRAPD(err, iHarvesterArray[i].iPlugin->StartHarvestingL(iHarvesterArray[i].iQualifiedBaseAppClass));
+
+				// No need to continue, if something was already started 
+				if (err == KErrNone)
+					{
+				    CPIXLOGSTRING("CIndexingManager::RunL(): Successfully started harvesting. ");
+					break;
+					}
+				
+				// Set the error status
+				iHarvesterArray[i].iLastComplete.UniversalTime();
+				iHarvesterArray[i].iError = err;
+				// Do not run it again, unless CIndexingMgr informed to do so
+				iHarvesterArray[i].iStatus = EHarvesterStatusHibernate;
+			    CPIXLOGSTRING2("CIndexingManager::RunL(): Error %d in starting harvesting. ", err);
+				}
+			}
+		}
+	
+	// Save status here if changed.
+	if (iHarvesterArrayChanged)
+		{
+		iHarvesterArrayChanged = EFalse;
+		Externalize();
+		}
+
+	// Always issue new wait
+	iTimer.After(iStatus, KDefaultWaitTime);
+	SetActive();
+	
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::LoadPluginsL()
+// -----------------------------------------------------------------------------
+//
+void CIndexingManager::LoadPluginsL()
+	{
+    RImplInfoPtrArray infoArray;    
+    TCleanupItem cleanupItem( CPixSearchECom::CleanupEComArray, &infoArray );
+    CleanupStack::PushL( cleanupItem );
+    
+    CIndexingPlugin::ListImplementationsL( infoArray );
+    TInt count( 0 );
+    count = infoArray.Count();
+    
+    //FFLOGSTRING2( "CFastFindHarvesterPluginControl:: PLUGINS COUNT %d", count );
+    CIndexingPlugin* plugin = NULL;
+    
+    for ( TInt i = 0; i < count; i++ )
+        {
+        TUid uid = infoArray[i]->ImplementationUid();    // Create the plug-ins
+        TInt version = infoArray[i]->Version();
+        //FFLOGSTRING2( "CFastFindHarvesterPluginControl:: PLUGINS UID %x", uid );
+        plugin = NULL;
+        TBool pluginblacklisted = EFalse;
+        
+        pluginblacklisted = iBlacklistMgr->FindL( uid , version );        
+        
+        if ( !pluginblacklisted )
+            {
+            // Plugin is not black listed. Add it to database and try to load the plugin
+            iBlacklistMgr->AddL( uid , version );
+            CPIXLOGSTRING2("CIndexingManager::LoadPluginsL(): Plugin with uid = %x is added to database", uid.iUid);
+            TRAPD( err, plugin = CIndexingPlugin::NewL( uid ) );
+            //FFLOGSTRING2( "CFastFindHarvesterPluginControl:: ERROR %d", err );
+            if ( err == KErrNone )
+                {
+                // Plugin loaded succesfully. Remove it from the database
+                iBlacklistMgr->Remove(uid);
+                CPIXLOGSTRING2("CIndexingManager::LoadPluginsL(): Plugin with uid = %x is removed from database", uid.iUid);
+                CleanupStack::PushL( plugin );
+                plugin->SetObserver( *this );
+                plugin->SetSearchSession( iSearchSession );
+                iPluginArray.AppendL( plugin ); // and add them to array
+                CleanupStack::Pop( plugin );
+                CPIXLOGSTRING2("CIndexingManager::LoadPluginsL(): Plugin with uid = %x is loaded succesfully", uid.iUid);
+                }
+            }
+        }    
+    CleanupStack::PopAndDestroy( &infoArray ); // infoArray, results in a call to CleanupEComArray
+    //FFLOGSTRING( "CFastFindHarvesterPluginControl::LoadPluginsL() plugin!" );    
+    
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::StartPlugins()
+// -----------------------------------------------------------------------------
+//
+void CIndexingManager::StartPlugins()
+	{
+	for (TInt i = 0; i < iPluginArray.Count(); i++)
+		{
+		TRAPD(err, iPluginArray[i]->StartPluginL());
+		if (err != KErrNone)
+			{
+			// Failed to start the plugin
+			}
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::AddHarvestingQueue()
+// -----------------------------------------------------------------------------
+//
+void CIndexingManager::AddHarvestingQueue(CIndexingPlugin* aPlugin,
+										  const TDesC& aQualifiedBaseAppClass,
+										  TBool aForceReharvest)
+	{
+    CPIXLOGSTRING2("CIndexingManager::AddHarvestingQueue(): Queuing requested for <%S>.", &aQualifiedBaseAppClass);	
+	
+	// Find if this harvesting task already exists
+	for (TInt i=0; i<iHarvesterArray.Count(); i++)
+		{
+		// Not check the iPlugin here, only qualified, as iPlugin is inserted later
+		if (iHarvesterArray[i].iQualifiedBaseAppClass.Compare(aQualifiedBaseAppClass)==0)
+			{
+			// Already exists, change the status if hibernating 
+			if (iHarvesterArray[i].iStatus == EHarvesterStatusHibernate)
+				{
+				// No need to set iHarvesterArrayChanged when changing the status only (which is not saved)
+				iHarvesterArray[i].iPlugin = aPlugin;
+				iHarvesterArray[i].iStatus = EHarvesterStatusWaiting;
+				if (aForceReharvest)
+					{
+					CPIXLOGSTRING("CIndexingManager::AddHarvestingQueue(): Needs Reharvesting.");
+					// iLastCompete Time is reset so that will be reharvested as soon
+					// as possible
+					iHarvesterArray[i].iLastComplete = TTime(0);
+					// No need to reset iLastStart or iError
+					iHarvesterArrayChanged = ETrue;
+					}
+				}
+		    CPIXLOGSTRING("CIndexingManager::AddHarvestingQueue(): Harvester already in the queue.");	
+			return;
+			}
+		}	
+	
+	// Create new harvesting task
+	iHarvesterArray.Append(THarvesterRecord(aPlugin, aQualifiedBaseAppClass));
+	iHarvesterArrayChanged = ETrue;
+
+	// Cancel current wait to launch RunL immediately
+	if (iState == EStateRunning)
+		iTimer.Cancel();
+
+    CPIXLOGSTRING("CIndexingManager::AddHarvestingQueue(): Harvester added successfully to the queue.");	
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::RemoveHarvestingQueue()
+// -----------------------------------------------------------------------------
+//
+void CIndexingManager::RemoveHarvestingQueue(CIndexingPlugin* aPlugin, const TDesC& aQualifiedBaseAppClass)
+	{
+    CPIXLOGSTRING2("CIndexingManager::RemoveHarvestingQueue(): De-queuing requested for <%S>.", &aQualifiedBaseAppClass);	
+
+    // Find if this harvesting task exists
+	for (TInt i=0; i<iHarvesterArray.Count(); i++)
+		{
+		if (iHarvesterArray[i].iPlugin == aPlugin && 
+			iHarvesterArray[i].iQualifiedBaseAppClass.Compare(aQualifiedBaseAppClass)==0)
+			{
+			// Found, hibernate it
+			if (iHarvesterArray[i].iStatus == EHarvesterStatusWaiting)
+				{
+				// No need to set iHarvesterArrayChanged when changing the status only (which is not saved)
+				iHarvesterArray[i].iStatus = EHarvesterStatusHibernate;
+				}
+			CPIXLOGSTRING("CIndexingManager::RemoveHarvestingQueue(): Harvester de-queued successfully.");	
+			return;
+			}
+		}
+
+	CPIXLOGSTRING("CIndexingManager::RemoveHarvestingQueue(): Harvester in the queue.");	
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::HarvestingCompleted()
+// -----------------------------------------------------------------------------
+//
+void CIndexingManager::HarvestingCompleted(CIndexingPlugin* aPlugin, const TDesC& aQualifiedBaseAppClass, TInt aError)
+	{
+    CPIXLOGSTRING2("CIndexingManager::HarvestingCompleted(): Harvesting completed reported for <%S>.", &aQualifiedBaseAppClass);	
+
+    // Find this task 
+	for (TInt i=0; i<iHarvesterArray.Count(); i++)
+		{
+		if (iHarvesterArray[i].iPlugin == aPlugin && 
+			iHarvesterArray[i].iQualifiedBaseAppClass.Compare(aQualifiedBaseAppClass)==0)
+			{
+			// Found the task, now its waiting
+			iHarvesterArray[i].iError = aError;
+			iHarvesterArray[i].iStatus = EHarvesterStatusWaiting;
+			iHarvesterArray[i].iLastComplete.UniversalTime();
+			iHarvesterArrayChanged = ETrue;
+			
+			// Cancel current wait to launch RunL immediately
+			if (iState == EStateRunning)
+				iTimer.Cancel();
+
+			CPIXLOGSTRING("CIndexingManager::HarvestingCompleted(): Harvesting status changed successfully.");
+			return;			
+			}
+		}
+	CPIXLOGSTRING("CIndexingManager::HarvestingCompleted(): Harvester not in the queue.");
+	}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::Internalize()
+// -----------------------------------------------------------------------------
+//
+TInt CIndexingManager::Internalize()
+{
+	TRAPD(err, LoadL());
+	return err;
+}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::Externalize()
+// -----------------------------------------------------------------------------
+//
+TInt CIndexingManager::Externalize()
+{
+	TRAPD(err, SaveL());
+	return err;
+}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::LoadL()
+// -----------------------------------------------------------------------------
+//
+void CIndexingManager::LoadL()
+{
+	// Open the stream
+	RFile file;
+	User::LeaveIfError(file.Open(iFs, iManagerFilePath, EFileRead));
+	CleanupClosePushL(file);
+	RFileReadStream rd(file);
+	rd.PushL();
+	
+	// Read the version
+	TInt version = rd.ReadInt32L();
+	if (version != KManagerFileVersion)
+		{
+		User::Leave(KErrGeneral);
+		}
+
+	// Read harvester count
+	TInt count = rd.ReadInt32L();
+
+	// Read the harvesters
+	for (TInt i=0; i<count; i++)
+		{
+		THarvesterRecord record;
+		TInt length = rd.ReadInt32L();
+		rd.ReadL(record.iQualifiedBaseAppClass, length);
+		TInt64 laststart;
+		TInt64 lastcomplete;		
+		rd.ReadL((TUint8*)&laststart, sizeof(TInt64));
+		rd.ReadL((TUint8*)&lastcomplete, sizeof(TInt64));
+		record.iLastStart = laststart;
+		record.iLastComplete = lastcomplete;
+		record.iError = rd.ReadInt32L();
+		record.iStatus = EHarvesterStatusHibernate;
+		iHarvesterArray.AppendL(record);
+		}
+	
+	// Cleanup
+	CleanupStack::PopAndDestroy(2, &file);
+}
+
+// -----------------------------------------------------------------------------
+// CIndexingManager::SaveL()
+// -----------------------------------------------------------------------------
+//
+void CIndexingManager::SaveL()
+{
+	// Open the stream
+	RFile file;
+	User::LeaveIfError(file.Replace(iFs, iManagerFilePath, EFileWrite));
+	CleanupClosePushL(file);
+	
+	RFileWriteStream wr(file);
+	wr.PushL();
+		
+	// Write the version
+	wr.WriteInt32L(KManagerFileVersion);
+	
+	// Write harvester count
+	wr.WriteInt32L(iHarvesterArray.Count());
+	
+	// Write harvesters
+	for (TInt i=0; i<iHarvesterArray.Count(); i++)
+		{
+		wr.WriteInt32L(iHarvesterArray[i].iQualifiedBaseAppClass.Length());
+		wr.WriteL(iHarvesterArray[i].iQualifiedBaseAppClass);
+		TInt64 laststart = iHarvesterArray[i].iLastStart.Int64();
+		TInt64 lastcomplete = iHarvesterArray[i].iLastComplete.Int64();
+		wr.WriteL((TUint8*)&laststart, sizeof(TInt64));
+		wr.WriteL((TUint8*)&lastcomplete, sizeof(TInt64));
+		wr.WriteInt32L(iHarvesterArray[i].iError);
+		}
+	
+	// Commit and cleanup
+	wr.CommitL();
+	CleanupStack::PopAndDestroy(2, &file);
+}
+