From 7cf1af15cbbe12fe2b8f88582febc3499b31e48e Mon Sep 17 00:00:00 2001 From: Thomas Gelf Date: Tue, 28 Jun 2016 12:56:53 +0200 Subject: [PATCH] Import/Sync: cleanly rollback transactions Helps to avoid side-effects --- library/Director/Import/Import.php | 75 ++++++++++--------- library/Director/Import/Sync.php | 114 +++++++++++++++-------------- 2 files changed, 102 insertions(+), 87 deletions(-) diff --git a/library/Director/Import/Import.php b/library/Director/Import/Import.php index 3f6b970e..b4de844c 100644 --- a/library/Director/Import/Import.php +++ b/library/Director/Import/Import.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\Import; +use Exception; use Icinga\Exception\IcingaException; use Icinga\Module\Director\Hook\ImportSourceHook; use Icinga\Module\Director\Objects\ImportSource; @@ -322,43 +323,49 @@ class Import $db->beginTransaction(); - if ($this->isEmpty()) { - $newRows = array(); - $newProperties = array(); - } else { - $newRows = $this->newChecksums('imported_row', $this->rowChecksums); - $newProperties = $this->newChecksums('imported_property', array_keys($this->properties)); - } + try { - $db->insert('imported_rowset', array('checksum' => $this->quoteBinary($rowset))); - - foreach ($newProperties as $checksum) { - $db->insert('imported_property', $this->properties[$checksum]); - } - - foreach ($newRows as $row) { - $db->insert('imported_row', $rows[$row]); - foreach ($this->rowProperties[$row] as $property) { - $db->insert('imported_row_property', array( - 'row_checksum' => $this->quoteBinary($row), - 'property_checksum' => $property - )); + if ($this->isEmpty()) { + $newRows = array(); + $newProperties = array(); + } else { + $newRows = $this->newChecksums('imported_row', $this->rowChecksums); + $newProperties = $this->newChecksums('imported_property', array_keys($this->properties)); } + + $db->insert('imported_rowset', array('checksum' => $this->quoteBinary($rowset))); + + foreach ($newProperties as $checksum) { + $db->insert('imported_property', $this->properties[$checksum]); + } + + foreach ($newRows as $row) { + $db->insert('imported_row', $rows[$row]); + foreach ($this->rowProperties[$row] as $property) { + $db->insert('imported_row_property', array( + 'row_checksum' => $this->quoteBinary($row), + 'property_checksum' => $property + )); + } + } + + foreach (array_keys($rows) as $row) { + $db->insert( + 'imported_rowset_row', + array( + 'rowset_checksum' => $this->quoteBinary($rowset), + 'row_checksum' => $this->quoteBinary($row) + ) + ); + } + + $db->commit(); + + $this->rowsetExists = true; + } catch (Exception $e) { + $db->rollBack(); + throw $e; } - - foreach (array_keys($rows) as $row) { - $db->insert( - 'imported_rowset_row', - array( - 'rowset_checksum' => $this->quoteBinary($rowset), - 'row_checksum' => $this->quoteBinary($row) - ) - ); - } - - $db->commit(); - - $this->rowsetExists = true; } /** diff --git a/library/Director/Import/Sync.php b/library/Director/Import/Sync.php index ae55aa38..87d70983 100644 --- a/library/Director/Import/Sync.php +++ b/library/Director/Import/Sync.php @@ -2,6 +2,7 @@ namespace Icinga\Module\Director\Import; +use Exception; use Icinga\Data\Filter\Filter; use Icinga\Module\Director\Objects\IcingaObject; use Icinga\Module\Director\Objects\ImportSource; @@ -685,63 +686,70 @@ class Sync $db = $this->db; $dba = $db->getDbAdapter(); $dba->beginTransaction(); - $formerActivityChecksum = Util::hex2binary( - $db->getLastActivityChecksum() - ); - $created = 0; - $modified = 0; - $deleted = 0; - foreach ($objects as $object) { - if ($object instanceof IcingaObject && $object->isTemplate()) { - // TODO: allow to sync templates - if ($object->hasBeenModified()) { - throw new IcingaException( - 'Sync is not allowed to modify template "%s"', - $object->$objectKey - ); - } - continue; - } - if ($object instanceof IcingaObject && $object->shouldBeRemoved()) { - $object->delete($db); - $deleted++; - continue; - } - - if ($object->hasBeenModified()) { - if ($object->hasBeenLoadedFromDb()) { - $modified++; - } else { - $created++; - } - $object->store($db); - } - } - - $runProperties = array( - 'objects_created' => $created, - 'objects_deleted' => $deleted, - 'objects_modified' => $modified, - ); - - if ($created + $deleted + $modified > 0) { - // TODO: What if this has been the very first activity? - $runProperties['last_former_activity'] = $db->quoteBinary($formerActivityChecksum); - $runProperties['last_related_activity'] = $db->quoteBinary(Util::hex2binary( + try { + $formerActivityChecksum = Util::hex2binary( $db->getLastActivityChecksum() - )); + ); + $created = 0; + $modified = 0; + $deleted = 0; + foreach ($objects as $object) { + if ($object instanceof IcingaObject && $object->isTemplate()) { + // TODO: allow to sync templates + if ($object->hasBeenModified()) { + throw new IcingaException( + 'Sync is not allowed to modify template "%s"', + $object->$objectKey + ); + } + continue; + } + + if ($object instanceof IcingaObject && $object->shouldBeRemoved()) { + $object->delete($db); + $deleted++; + continue; + } + + if ($object->hasBeenModified()) { + if ($object->hasBeenLoadedFromDb()) { + $modified++; + } else { + $created++; + } + $object->store($db); + } + } + + $runProperties = array( + 'objects_created' => $created, + 'objects_deleted' => $deleted, + 'objects_modified' => $modified, + ); + + if ($created + $deleted + $modified > 0) { + // TODO: What if this has been the very first activity? + $runProperties['last_former_activity'] = $db->quoteBinary($formerActivityChecksum); + $runProperties['last_related_activity'] = $db->quoteBinary(Util::hex2binary( + $db->getLastActivityChecksum() + )); + } + + $this->run->setProperties($runProperties)->store(); + + $dba->commit(); + + // Store duration after commit, as the commit might take some time + $this->run->set('duration_ms', (int) round( + (microtime(true) - $this->runStartTime) * 1000 + ))->store(); + + } catch (Exception $e) { + $dba->rollBack(); + throw $e; } - $this->run->setProperties($runProperties)->store(); - - $dba->commit(); - - // Store duration after commit, as the commit might take some time - $this->run->set('duration_ms', (int) round( - (microtime(true) - $this->runStartTime) * 1000 - ))->store(); - return $this->run->id; } }