From ce9806b01ce4850016bc0cde32dc33bd58859928 Mon Sep 17 00:00:00 2001 From: Denis Flaven Date: Tue, 1 Apr 2014 09:50:21 +0000 Subject: [PATCH] Allow re-entrance in the same named mutex within the same PHP page. SVN:trunk[3115] --- core/mutex.class.inc.php | 42 ++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/core/mutex.class.inc.php b/core/mutex.class.inc.php index 1df42f6a8..40e4bd104 100644 --- a/core/mutex.class.inc.php +++ b/core/mutex.class.inc.php @@ -31,12 +31,18 @@ class iTopMutex { protected $sName; protected $hDBLink; + static protected $aAcquiredLocks = array(); public function __construct($sName) { // Compute the name of a lock for mysql // Note: the name is server-wide!!! $this->sName = 'itop.'.$sName; + + if (!array_key_exists($this->sName, self::$aAcquiredLocks)) + { + self::$aAcquiredLocks[$this->sName] = 0; + } // It is a MUST to create a dedicated session each time a lock is required, because // using GET_LOCK anytime on the same session will RELEASE the current and unique session lock (known issue) @@ -55,17 +61,21 @@ class iTopMutex */ public function Lock() { - do + if (self::$aAcquiredLocks[$this->sName] == 0) { - $res = $this->QueryToScalar("SELECT GET_LOCK('".$this->sName."', 3600)"); - if (is_null($res)) + do { - throw new Exception("Failed to acquire the lock '".$this->sName."'"); + $res = $this->QueryToScalar("SELECT GET_LOCK('".$this->sName."', 3600)"); + if (is_null($res)) + { + throw new Exception("Failed to acquire the lock '".$this->sName."'"); + } + // $res === '1' means I hold the lock + // $res === '0' means it timed out } - // $res === '1' means I hold the lock - // $res === '0' means it timed out + while ($res !== '1'); } - while ($res !== '1'); + self::$aAcquiredLocks[$this->sName]++; } /** @@ -74,6 +84,12 @@ class iTopMutex */ public function TryLock() { + if (self::$aAcquiredLocks[$this->sName] > 0) + { + self::$aAcquiredLocks[$this->sName]++; + return true; + } + $res = $this->QueryToScalar("SELECT GET_LOCK('".$this->sName."', 0)"); if (is_null($res)) { @@ -81,6 +97,10 @@ class iTopMutex } // $res === '1' means I hold the lock // $res === '0' means it timed out + if ($res === '1') + { + self::$aAcquiredLocks[$this->sName]++; + } return ($res === '1'); } @@ -89,7 +109,13 @@ class iTopMutex */ public function Unlock() { - $res = $this->QueryToScalar("SELECT RELEASE_LOCK('".$this->sName."')"); + if (self::$aAcquiredLocks[$this->sName] == 0) return; // Safety net + + if (self::$aAcquiredLocks[$this->sName] == 1) + { + $res = $this->QueryToScalar("SELECT RELEASE_LOCK('".$this->sName."')"); + } + self::$aAcquiredLocks[$this->sName]--; }