BranchMerger: use Activity instances

This commit is contained in:
Thomas Gelf 2021-10-05 22:27:32 +02:00
parent 7ad9cf6c6c
commit dc52a54888

View File

@ -3,9 +3,9 @@
namespace Icinga\Module\Director\Db\Branch; namespace Icinga\Module\Director\Db\Branch;
use Icinga\Module\Director\Data\Db\DbObject; use Icinga\Module\Director\Data\Db\DbObject;
use Icinga\Module\Director\Data\InvalidDataException; use Icinga\Module\Director\Data\Db\DbObjectTypeRegistry;
use Icinga\Module\Director\Db; use Icinga\Module\Director\Db;
use Ramsey\Uuid\Uuid; use Icinga\Module\Director\Objects\IcingaObject;
use Ramsey\Uuid\UuidInterface; use Ramsey\Uuid\UuidInterface;
class BranchMerger class BranchMerger
@ -20,7 +20,7 @@ class BranchMerger
protected $db; protected $db;
/** @var array */ /** @var array */
protected $ignoreUuids = []; protected $ignoreActivities = [];
/** @var bool */ /** @var bool */
protected $ignoreDeleteWhenMissing = false; protected $ignoreDeleteWhenMissing = false;
@ -64,88 +64,76 @@ class BranchMerger
} }
/** /**
* @param array $uuids * @param int $key
*/ */
public function ignoreUuids(array $uuids) public function ignoreActivity($key)
{ {
foreach ($uuids as $uuid) { $this->ignoreActivities[$key] = true;
$this->ignoreUuid($uuid);
}
} }
/** /**
* @param UuidInterface|string $uuid * @param BranchActivity $activity
* @return bool
*/ */
public function ignoreUuid($uuid) public function ignoresActivity(BranchActivity $activity)
{ {
if (is_string($uuid)) { return isset($this->ignoreActivities[$activity->getTimestampNs()]);
$uuid = Uuid::fromString($uuid);
} elseif (! ($uuid instanceof UuidInterface)) {
throw new InvalidDataException('UUID', $uuid);
}
$binary = $uuid->getBytes();
$this->ignoreUuids[$binary] = $binary;
} }
/** /**
* @throws MergeError * @throws MergeError
* @throws \Exception
*/ */
public function merge() public function merge()
{ {
$this->connection->runFailSafeTransaction(function () { $this->connection->runFailSafeTransaction(function () {
$activities = new BranchActivityStore($this->connection); $query = $this->db->select()
$rows = $activities->loadAll($this->branchUuid); ->from(BranchActivity::DB_TABLE)
->where('branch_uuid = ?', $this->connection->quoteBinary($this->branchUuid->getBytes()))
->order('timestamp_ns ASC');
$rows = $this->db->fetchAll($query);
foreach ($rows as $row) { foreach ($rows as $row) {
$modification = BranchActivityStore::objectModificationForDbRow($row); $activity = BranchActivity::fromDbRow($row);
$this->applyModification($modification, Uuid::fromBytes($row->uuid)); $this->applyModification($activity);
} }
$this->db->delete('director_branch', $this->db->quoteInto('uuid = ?', $this->branchUuid->getBytes())); (new BranchStore($this->connection))->deleteByUuid($this->branchUuid);
}); });
} }
/** /**
* @param ObjectModification $modification * @param BranchActivity $activity
* @param UuidInterface $uuid
* @throws MergeError * @throws MergeError
* @throws \Icinga\Exception\NotFoundError * @throws \Icinga\Exception\NotFoundError
* @throws \Icinga\Module\Director\Exception\DuplicateKeyException * @throws \Icinga\Module\Director\Exception\DuplicateKeyException
*/ */
protected function applyModification(ObjectModification $modification, UuidInterface $uuid) protected function applyModification(BranchActivity $activity)
{ {
$binaryUuid = $uuid->getBytes();
/** @var string|DbObject $class */ /** @var string|DbObject $class */
$class = $modification->getClassName(); $class = DbObjectTypeRegistry::classByType($activity->getObjectTable());
$keyParams = (array) $modification->getKeyParams(); $uuid = $activity->getObjectUuid();
if (array_keys($keyParams) === ['object_name']) {
$keyParams = $keyParams['object_name'];
}
$exists = $class::exists($keyParams, $this->connection); $exists = $class::uniqueIdExists($uuid, $this->connection);
if ($modification->isCreation()) { if ($activity->isActionCreate()) {
if ($exists) { if ($exists) {
if (! isset($this->ignoreUuids[$uuid->getBytes()])) { if (! $this->ignoresActivity($activity)) {
throw new MergeErrorRecreateOnMerge($modification, $uuid); throw new MergeErrorRecreateOnMerge($activity);
} }
} else { } else {
$object = IcingaObjectModification::applyModification($modification, null, $this->connection); $activity->createDbObject()->store($this->connection);
$object->store($this->connection);
} }
} elseif ($modification->isDeletion()) { } elseif ($activity->isActionDelete()) {
if ($exists) { if ($exists) {
$object = IcingaObjectModification::applyModification($modification, $class::load($keyParams, $this->connection), $this->connection); $activity->deleteDbObject($this->connection);
$object->setConnection($this->connection); } elseif (! $this->ignoreDeleteWhenMissing && ! $this->ignoresActivity($activity)) {
$object->delete(); throw new MergeErrorDeleteMissingObject($activity);
} elseif (! $this->ignoreDeleteWhenMissing && ! isset($this->ignoreUuids[$binaryUuid])) {
throw new MergeErrorDeleteMissingObject($modification, $uuid);
} }
} else { } else {
if ($exists) { if ($exists) {
$object = IcingaObjectModification::applyModification($modification, $class::load($keyParams, $this->connection), $this->connection); $current = $class::requireWithUniqueId($uuid, $this->connection);
// TODO: du änderst ein Objekt, und die geänderte Eigenschaften haben sich seit der Änderung geändert $activity->applyToDbObject($class::requireWithUniqueId($uuid, $this->connection))->store();
$object->store($this->connection); // TODO: you modified an object, and related properties have been changed in the meantime.
} elseif (! $this->ignoreModificationWhenMissing && ! isset($this->ignoreUuids[$binaryUuid])) { // We're able to detect this with the given data, and might want to offer a rebase.
throw new MergeErrorModificationForMissingObject($modification, $uuid); } elseif (! $this->ignoreModificationWhenMissing && ! $this->ignoresActivity($activity)) {
throw new MergeErrorModificationForMissingObject($activity);
} }
} }
} }