Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 28 additions & 21 deletions synchro/synchrodatasource.class.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -3002,8 +3002,6 @@ class SynchroExecution
* </ul>
*/
protected $m_oLastFullLoadStartDate = null;
/** @var bool true if the caller script gave the datetime before import phase was launched */
protected $m_bIsImportPhaseDateKnown;

/** @var \CMDBChange */
protected $m_oChange = null;
Expand All @@ -3028,10 +3026,7 @@ class SynchroExecution
public function __construct($oDataSource, $oImportPhaseStartDate = null)
{
$this->m_oDataSource = $oDataSource;

$this->m_bIsImportPhaseDateKnown = ($oImportPhaseStartDate != null);
$this->m_oImportPhaseStartDate = $oImportPhaseStartDate;

$this->m_oCtx = new ContextTag(ContextTag::TAG_SYNCHRO);
$this->m_oCtx1 = new ContextTag('Synchro:'.$oDataSource->GetRawName()); // More precise context information
}
Expand Down Expand Up @@ -3108,7 +3103,7 @@ protected function PrepareLogs()
$this->m_oStatLog->Set('stats_nb_replica_total', $this->m_iCountAllReplicas);

$this->m_oStatLog->DBInsert();
$sLastFullLoad = ($this->m_bIsImportPhaseDateKnown) ? $this->m_oImportPhaseStartDate->format('Y-m-d H:i:s') : 'not specified';
$sLastFullLoad = (is_null($this->m_oImportPhaseStartDate)) ? 'not specified' : $this->m_oImportPhaseStartDate->format('Y-m-d H:i:s');
$this->m_oStatLog->AddTrace("###### STARTING SYNCHRONIZATION ##### Total: {$this->m_iCountAllReplicas} replica(s). Last full load: '$sLastFullLoad' ");
$sSql = 'SELECT NOW();';
$sDBNow = CMDBSource::QueryToScalar($sSql);
Expand Down Expand Up @@ -3212,21 +3207,18 @@ public function PrepareProcessing($bFirstPass = true)
// Compute and keep track of the limit date taken into account for obsoleting replicas
//
$iFullLoadInterval = $this->m_oDataSource->Get('full_load_periodicity'); // Duration in seconds
if ($this->m_bIsImportPhaseDateKnown) {
$oLimitDate = clone $this->m_oImportPhaseStartDate;
$sInterval = "-$iFullLoadInterval seconds";
$oLimitDate->Modify($sInterval);
} else {
if (is_null($this->m_oImportPhaseStartDate)) {
if ($iFullLoadInterval <= 0) {
// we are doing exec phase alone, and the full load interval is set to 0 => we should not update/delete replicas !!
// This will prevent actions in DoJob1() method
$oLimitDate = new DateTime('1970-01-01');
} else {
$oLimitDate = self::GetDataBaseCurrentDateTime();
$sInterval = "-$iFullLoadInterval seconds";
$oLimitDate->Modify($sInterval);
}
} else {
$oLimitDate = clone $this->m_oImportPhaseStartDate;
}
$this->ExactlySubtractSeconds($oLimitDate, $iFullLoadInterval);
$this->m_oLastFullLoadStartDate = $oLimitDate;
if ($bFirstPass) {
$this->m_oStatLog->AddTrace('Limit Date: '.$this->m_oLastFullLoadStartDate->Format('Y-m-d H:i:s'));
Expand Down Expand Up @@ -3346,10 +3338,10 @@ protected function DoSynchronize()
$aArguments['log'] = $this->m_oStatLog->GetKey();
$aArguments['change'] = $this->m_oChange->GetKey();
$aArguments['chunk'] = $iMaxChunkSize;
if ($this->m_bIsImportPhaseDateKnown) {
$aArguments['last_full_load'] = $this->m_oImportPhaseStartDate->Format('Y-m-d H:i:s');
} else {
if (is_null($this->m_oImportPhaseStartDate)) {
$aArguments['last_full_load'] = '';
} else {
$aArguments['last_full_load'] = $this->m_oImportPhaseStartDate->Format('Y-m-d H:i:s');
}

$this->m_oStatLog->DBUpdate();
Comment thread
odain-cbd marked this conversation as resolved.
Expand Down Expand Up @@ -3701,13 +3693,11 @@ protected function DoJob3DeleteItopObjectsAndReplicas($iMaxReplica = null, $iCur

// Get all the replicas that are to be deleted
//
$oDeletionDate = $this->m_oLastFullLoadStartDate;
$oDeletionDate = clone $this->m_oLastFullLoadStartDate;
$iDeleteRetention = $this->m_oDataSource->Get('delete_policy_retention'); // Duration in seconds
if ($iDeleteRetention > 0) {
$sInterval = "-$iDeleteRetention seconds";
$oDeletionDate->Modify($sInterval);
}
$this->ExactlySubtractSeconds($oDeletionDate, $iDeleteRetention);
$sDeletionDate = $oDeletionDate->Format('Y-m-d H:i:s');

if ($bFirstPass) {
$this->m_oStatLog->AddTrace("Deletion date: $sDeletionDate");
}
Expand Down Expand Up @@ -3757,4 +3747,21 @@ protected function DoJob3DeleteItopObjectsAndReplicas($iMaxReplica = null, $iCur

return false;
}

/** Take into account timechange to apply date difference operation
* @param \DateTime $oDate
* @param $iDurationInSeconds
* @return void
* @throws \Exception
*/
public function ExactlySubtractSeconds(DateTime $oDate, $iDurationInSeconds): void
{
if ($iDurationInSeconds > 0) {
$oDate->setTimezone(new DateTimeZone('UTC'));
$sInterval = "-$iDurationInSeconds seconds";
$oDate->Modify($sInterval);
$sTimezone = MetaModel::GetConfig()->Get('timezone');
$oDate->setTimezone(new DateTimeZone($sTimezone));
Comment on lines +3760 to +3764
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

use Combodo\iTop\Test\UnitTest\ItopDataTestCase;

class SynchroExecutionTest extends ItopDataTestCase
{
private function InitAndGetTZ($sTZ = null): string
{
$sTZ = $sTZ ?? 'Europe/Paris';
MetaModel::GetConfig()->Set('timezone', $sTZ);
return $sTZ;
}

public function testGetDateMinusRetentionWithTimeChange()
{
$sTZ = $this->InitAndGetTZ();
$oObj = new SynchroExecution($this->createMock(SynchroDataSource::class));
$oDate = DateTime::createFromFormat('Y-m-d H:i:s', "2026-03-29 03:30:01", new DateTimeZone($sTZ));

$oObj->ExactlySubtractSeconds($oDate, 3600);
//03h30 minus 1hours => 03h minus 30mn => 03h
// => 03h with timechange => 2h
// => 02 minus 30mn => 01h30
$this->assertEquals("2026-03-29 01:30:01", $oDate->Format('Y-m-d H:i:s'));
}

public function testGetDateMinusRetentioLinuxTimeZero()
{
$oObj = new SynchroExecution($this->createMock(SynchroDataSource::class));
$oDate = new DateTime('1970-01-01');

$oObj->ExactlySubtractSeconds($oDate, 3600);
$this->assertEquals("1969-12-31 23:00:00", $oDate->Format('Y-m-d H:i:s'));
}

public function testGetDateMinusRetentionWithTimeChangeAndUTC()
{
$sTZ = $this->InitAndGetTZ('UTC');
$oObj = new SynchroExecution($this->createMock(SynchroDataSource::class));
$oDate = DateTime::createFromFormat('Y-m-d H:i:s', "2026-03-29 03:30:01", new DateTimeZone($sTZ));

$oObj->ExactlySubtractSeconds($oDate, 3600);
$this->assertEquals("2026-03-29 02:30:01", $oDate->Format('Y-m-d H:i:s'));
}

public function testGetDateMinusRetention()
{
$sTZ = $this->InitAndGetTZ();
$oObj = new SynchroExecution($this->createMock(SynchroDataSource::class));
$oDate = DateTime::createFromFormat('Y-m-d H:i:s', "2026-04-01 03:30:01", new DateTimeZone($sTZ));

$oObj->ExactlySubtractSeconds($oDate, 3600);
$this->assertEquals("2026-04-01 02:30:01", $oDate->Format('Y-m-d H:i:s'));
}
}