浏览代码

#965 Since 2.0.3, for each synchronized object, around 100 queries are performed (2 are required), and this is multiplied be the number of duplicate replicas (then resulting in a significant slowdown).

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@3380 a333f486-631f-4898-b8df-5754b55c2be0
romainq 10 年之前
父节点
当前提交
879495a4ee
共有 2 个文件被更改,包括 101 次插入67 次删除
  1. 19 14
      application/cmdbabstract.class.inc.php
  2. 82 53
      core/dbobject.class.php

+ 19 - 14
application/cmdbabstract.class.inc.php

@@ -125,27 +125,29 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
 	
 		// Master data sources
 		$sSynchroIcon = '';
-		$oReplicaSet = $this->GetMasterReplica();
 		$bSynchronized = false;
 		$oCreatorTask = null;
 		$bCanBeDeletedByTask = false;
 		$bCanBeDeletedByUser = true;
 		$aMasterSources = array();
-		if ($oReplicaSet->Count() > 0)
+		$aSyncData = $this->GetSynchroData();
+		if (count($aSyncData) > 0)
 		{
 			$bSynchronized = true;
-			while($aData = $oReplicaSet->FetchAssoc())
+			foreach ($aSyncData as $iSourceId => $aSourceData)
 			{
-				// Assumption: $aData['datasource'] will not be null because the data source id is always set...
-				$sApplicationURL = $aData['datasource']->GetApplicationUrl($this, $aData['replica']);
-				$sLink = $aData['datasource']->GetName();
+				$oDataSource = $aSourceData['source'];
+				$oReplica = reset($aSourceData['replica']); // Take the first one!
+
+				$sApplicationURL = $oDataSource->GetApplicationUrl($this, $oReplica);
+				$sLink = $oDataSource->GetName();
 				if (!empty($sApplicationURL))
 				{
-					$sLink = "<a href=\"$sApplicationURL\" target=\"_blank\">".$aData['datasource']->GetName()."</a>";
+					$sLink = "<a href=\"$sApplicationURL\" target=\"_blank\">".$oDataSource->GetName()."</a>";
 				}
-				if ($aData['replica']->Get('status_dest_creator') == 1)
+				if ($oReplica->Get('status_dest_creator') == 1)
 				{
-					$oCreatorTask = $aData['datasource'];
+					$oCreatorTask = $oDataSource;
 					$bCreatedByTask = true;
 				}
 				else
@@ -154,12 +156,12 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
 				}
 				if ($bCreatedByTask)
 				{
-					$sDeletePolicy = $aData['datasource']->Get('delete_policy');
+					$sDeletePolicy = $oDataSource->Get('delete_policy');
 					if (($sDeletePolicy == 'delete') || ($sDeletePolicy == 'update_then_delete'))
 					{
 						$bCanBeDeletedByTask = true;
 					}
-					$sUserDeletePolicy = $aData['datasource']->Get('user_delete_policy');
+					$sUserDeletePolicy = $oDataSource->Get('user_delete_policy');
 					if ($sUserDeletePolicy == 'nobody')
 					{
 						$bCanBeDeletedByUser = false;
@@ -172,9 +174,9 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
 					{
 					}
 				}
-				$aMasterSources[$aData['datasource']->GetKey()]['datasource'] = $aData['datasource'];
-				$aMasterSources[$aData['datasource']->GetKey()]['url'] = $sLink;
-				$aMasterSources[$aData['datasource']->GetKey()]['last_synchro'] = $aData['replica']->Get('status_last_seen');
+				$aMasterSources[$iSourceId]['datasource'] = $oDataSource;
+				$aMasterSources[$iSourceId]['url'] = $sLink;
+				$aMasterSources[$iSourceId]['last_synchro'] = $oReplica->Get('status_last_seen');
 			}
 
 			if (is_object($oCreatorTask))
@@ -1402,6 +1404,8 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
 		$sHtml .= "<p>\n";
 		$aFilterCriteria = $oSet->GetFilter()->GetCriteria();
 		$aMapCriteria = array();
+		// Todo: Investigate... The search criteria is an expression, i.e. a tree!
+		//     I wonder if that code could work... cleanup required/recommended
 		foreach($aFilterCriteria as $aCriteria)
 		{
 			$aMapCriteria[$aCriteria['filtercode']][] = array('value' => $aCriteria['value'], 'opcode' => $aCriteria['opcode']);
@@ -1429,6 +1433,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
 						$sFilterValue = $aMapCriteria[$sFilterCode][0]['value'];
 						$sFilterOpCode = $aMapCriteria[$sFilterCode][0]['opcode'];
 					}
+					// Todo: Investigate...
 					if ($sFilterCode != 'company')
 					{
 						$oUnlimitedFilter->AddCondition($sFilterCode, $sFilterValue, $sFilterOpCode);

+ 82 - 53
core/dbobject.class.php

@@ -94,7 +94,7 @@ abstract class DBObject implements iDisplay
 	private $m_bFullyLoaded = false; // Compound objects can be partially loaded
 	private $m_aLoadedAtt = array(); // Compound objects can be partially loaded, array of sAttCode
 	protected $m_aModifiedAtt = array(); // list of (potentially) modified sAttCodes
-	protected $m_oMasterReplicaSet = null; // Set of SynchroReplica related to this object
+	protected $m_aSynchroData = null; // Set of Synch data related to this object
 	protected $m_sHighlightCode = null;
 
 	// Use the MetaModel::NewObject to build an object (do we have to force it?)
@@ -1178,48 +1178,45 @@ abstract class DBObject implements iDisplay
 
 		if ($this->InSyncScope())
 		{
-			$oReplicaSet = $this->GetMasterReplica();
-			if ($oReplicaSet->Count() > 0)
+
+			foreach ($this->GetSynchroData() as $iSourceId => $aSourceData)
 			{
-				while($aData = $oReplicaSet->FetchAssoc())
+				foreach ($aSourceData['replica'] as $oReplica)
 				{
-					$oDataSource = $aData['datasource'];
-					$oReplica = $aData['replica'];
-
 					$oDeletionPlan->AddToDelete($oReplica, DEL_SILENT);
+				}
+				$oDataSource = $aSourceData['source'];
+				if ($oDataSource->GetKey() == SynchroExecution::GetCurrentTaskId())
+				{
+					// The current task has the right to delete the object
+					continue;
+				}
+				$oReplica = reset($aSourceData['replica']); // Take the first one
+				if ($oReplica->Get('status_dest_creator') != 1)
+				{
+					// The object is not owned by the task
+					continue;
+				}
 
-					if ($oDataSource->GetKey() == SynchroExecution::GetCurrentTaskId())
-					{
-						// The current task has the right to delete the object
-						continue;
-					}
-					
-					if ($oReplica->Get('status_dest_creator') != 1)
-					{
-						// The object is not owned by the task
-						continue;
-					}
+				$sLink = $oDataSource->GetName();
+				$sUserDeletePolicy = $oDataSource->Get('user_delete_policy');
+				switch($sUserDeletePolicy)
+				{
+				case 'nobody':
+					$this->m_aDeleteIssues[] = Dict::Format('Core:Synchro:TheObjectCannotBeDeletedByUser_Source', $sLink);
+					break;
 
-					$sLink = $oDataSource->GetName();
-					$sUserDeletePolicy = $oDataSource->Get('user_delete_policy');
-					switch($sUserDeletePolicy)
+				case 'administrators':
+					if (!UserRights::IsAdministrator())
 					{
-					case 'nobody':
 						$this->m_aDeleteIssues[] = Dict::Format('Core:Synchro:TheObjectCannotBeDeletedByUser_Source', $sLink);
-						break;
-
-					case 'administrators':
-						if (!UserRights::IsAdministrator())
-						{
-							$this->m_aDeleteIssues[] = Dict::Format('Core:Synchro:TheObjectCannotBeDeletedByUser_Source', $sLink);
-						}
-						break;
-
-					case 'everybody':
-					default:
-						// Ok
-						break;
 					}
+					break;
+
+				case 'everybody':
+				default:
+					// Ok
+					break;
 				}
 			}
 		}
@@ -2588,45 +2585,77 @@ abstract class DBObject implements iDisplay
 	}
 
 	/**
+	 * WILL DEPRECATED SOON
+	 * Caching relying on an object set is not efficient since 2.0.3
+	 * Use GetSynchroData instead
+	 * 	 
 	 * Get all the synchro replica related to this object
 	 * @param none
 	 * @return DBObjectSet Set with two columns: R=SynchroReplica S=SynchroDataSource
 	 */
 	public function GetMasterReplica()
 	{
-		if ($this->m_oMasterReplicaSet == null)
+		$sOQL = "SELECT replica,datasource FROM SynchroReplica AS replica JOIN SynchroDataSource AS datasource ON replica.sync_source_id=datasource.id WHERE replica.dest_class = :dest_class AND replica.dest_id = :dest_id";
+		$oReplicaSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array() /* order by*/, array('dest_class' => get_class($this), 'dest_id' => $this->GetKey()));
+		return $oReplicaSet;
+	}
+
+	/**
+	 * Get all the synchro data related to this object
+	 * @param none
+	 * @return array of data_source_id => array
+	 * 	'source' => $oSource,
+	 * 	'attributes' => array of $oSynchroAttribute
+	 * 	'replica' => array of $oReplica (though only one should exist, misuse of the data sync can have this consequence)
+	 */
+	public function GetSynchroData()
+	{
+		if ($this->m_aSynchroData == null)
 		{
-			//$aParentClasses = MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL);
-			//$sClassesList = "'".implode("','", $aParentClasses)."'";
 			$sOQL = "SELECT replica,datasource FROM SynchroReplica AS replica JOIN SynchroDataSource AS datasource ON replica.sync_source_id=datasource.id WHERE replica.dest_class = :dest_class AND replica.dest_id = :dest_id";
 			$oReplicaSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array() /* order by*/, array('dest_class' => get_class($this), 'dest_id' => $this->GetKey()));
-			$this->m_oMasterReplicaSet = $oReplicaSet;
-		}
-		else
-		{
-			$this->m_oMasterReplicaSet->Rewind();		
+			$this->m_aSynchroData = array();
+			while($aData = $oReplicaSet->FetchAssoc())
+			{
+				$iSourceId = $aData['datasource']->GetKey();
+				if (!array_key_exists($iSourceId, $this->m_aSynchroData))
+				{
+					$aAttributes = array();
+					$oAttrSet = $aData['datasource']->Get('attribute_list');
+					while($oSyncAttr = $oAttrSet->Fetch())
+					{
+						$aAttributes[$oSyncAttr->Get('attcode')] = $oSyncAttr;
+					}
+					$this->m_aSynchroData[$iSourceId] = array(
+						'source' => $aData['datasource'],
+						'attributes' => $aAttributes,
+						'replica' => array()
+					);
+				}
+				// Assumption: $aData['datasource'] will not be null because the data source id is always set...
+				$this->m_aSynchroData[$iSourceId]['replica'][] = $aData['replica'];
+			}
 		}
-		return $this->m_oMasterReplicaSet;
+		return $this->m_aSynchroData;
 	}
 	
 	public function GetSynchroReplicaFlags($sAttCode, &$aReason)
 	{
 		$iFlags = OPT_ATT_NORMAL;
-		$oSet = $this->GetMasterReplica();
-		while($aData = $oSet->FetchAssoc())
+		foreach ($this->GetSynchroData() as $iSourceId => $aSourceData)
 		{
-			if ($aData['datasource']->GetKey() == SynchroExecution::GetCurrentTaskId())
+			if ($iSourceId == SynchroExecution::GetCurrentTaskId())
 			{
 				// Ignore the current task (check to write => ok)
 				continue;
 			}
-			// Assumption: $aData['datasource'] will not be null because the data source id is always set...
-			$oReplica = $aData['replica'];
-			$oSource = $aData['datasource'];
-			$oAttrSet = $oSource->Get('attribute_list');
-			while($oSyncAttr = $oAttrSet->Fetch())
+			// Assumption: one replica - take the first one!
+			$oReplica = reset($aSourceData['replica']);
+			$oSource = $aSourceData['source'];
+			if (array_key_exists($sAttCode, $aSourceData['attributes']))
 			{
-				if (($oSyncAttr->Get('attcode') == $sAttCode) && ($oSyncAttr->Get('update') == 1) && ($oSyncAttr->Get('update_policy') == 'master_locked'))
+				$oSyncAttr = $aSourceData['attributes'][$sAttCode];
+				if (($oSyncAttr->Get('update') == 1) && ($oSyncAttr->Get('update_policy') == 'master_locked'))
 				{
 					$iFlags |= OPT_ATT_SLAVE;
 					$sUrl = $oSource->GetApplicationUrl($this, $oReplica);