From 3a144049e58168bf47932b7d357648786633fee8 Mon Sep 17 00:00:00 2001 From: Thierry Bugier Date: Thu, 12 Jul 2018 09:29:23 +0200 Subject: [PATCH] fix(invitation): add locks to protect concurrent rules edition The purpose is to avoid simultaneous modification of rules in some specific cases Signed-off-by: Thierry Bugier --- .../entityruleeditionexception.class.php | 6 +++ inc/fusioninventory.class.php | 41 ++++++++++++++++++- 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 inc/exception/entityruleeditionexception.class.php diff --git a/inc/exception/entityruleeditionexception.class.php b/inc/exception/entityruleeditionexception.class.php new file mode 100644 index 00000000..bf1cc87c --- /dev/null +++ b/inc/exception/entityruleeditionexception.class.php @@ -0,0 +1,6 @@ +getLock(self::LOCK_NAME); + usleep(50000); // 50 milliseconds + $attempts++; + } while ($locked !== 1 && $attempts < 10); + if ($locked !== 1) { + return; // No lock, then give up disabling + } + $rows = $ruleCriteria->find("`$ruleFk` = '$ruleId' AND `criteria` = 'tag' AND `condition` = '0'"); if (count($rows) === 0) { $rule = new PluginFusioninventoryInventoryRuleEntity(); @@ -125,6 +146,7 @@ public function deleteInvitationRuleCriteria(PluginFlyvemdmInvitation $invitatio 'is_active' => '0', ]); } + $DB->releaseLock(self::LOCK_NAME); } /** @@ -144,10 +166,23 @@ private function getRuleCriteriaValue(PluginFlyvemdmInvitation $invitation) { * * @return PluginFusioninventoryInventoryRuleEntity|null * @throws FusionInventoryRuleInconsistency + * @throws EntityRuleEditionException */ private function getRule($entityId, $create = true) { global $DB; + // get a lock + $attempts = 0; + $locked = 0; + do { + $locked = $DB->getLock(self::LOCK_NAME); + usleep(50000); // 50 milliseconds + $attempts++; + } while ($locked !== 1 && $attempts < 10); + if ($locked !== 1) { + throw new EntityRuleEditionException(__('Cannot get lock for entity rules edition')); + } + $ruleEntityTable = PluginFusioninventoryInventoryRuleEntity::getTable(); $ruleActionTable = RuleAction::getTable(); $request = [ @@ -175,13 +210,16 @@ private function getRule($entityId, $create = true) { $rule = new PluginFusioninventoryInventoryRuleEntity(); $row = $result->next(); $rule->getFromDB($row['id']); + $DB->releaseLock(self::LOCK_NAME); return $rule; } if ($result->count() > 1) { + $DB->releaseLock(self::LOCK_NAME); throw new FusionInventoryRuleInconsistency(__('Import rule is not unique')); } if (!$create) { + $DB->releaseLock(self::LOCK_NAME); return null; } @@ -203,6 +241,7 @@ private function getRule($entityId, $create = true) { 'field' => Entity::getForeignKeyField(), 'value' => $entityId, ]); + $DB->releaseLock(self::LOCK_NAME); return $rule; } } \ No newline at end of file