浏览代码

Proper handling of the re-entrence of the Lock/Unlock within the same PHP page. Previously the code was sometimes performing 2 Unlock() for each Lock().

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@3217 a333f486-631f-4898-b8df-5754b55c2be0
dflaven 11 年之前
父节点
当前提交
3185bbf95c
共有 1 个文件被更改,包括 30 次插入4 次删除
  1. 30 4
      core/mutex.class.inc.php

+ 30 - 4
core/mutex.class.inc.php

@@ -31,14 +31,16 @@ class iTopMutex
 {
 {
 	protected $sName;
 	protected $sName;
 	protected $hDBLink;
 	protected $hDBLink;
-	static protected $aAcquiredLocks = array();
+	protected $bLocked; // Whether or not this instance of the Mutex is locked
+	static protected $aAcquiredLocks = array(); // Number of instances of the Mutex, having the lock, in this page
 
 
 	public function __construct($sName)
 	public function __construct($sName)
 	{
 	{
 		// Compute the name of a lock for mysql
 		// Compute the name of a lock for mysql
 		// Note: the name is server-wide!!!
 		// Note: the name is server-wide!!!
 		$this->sName = 'itop.'.$sName;
 		$this->sName = 'itop.'.$sName;
-		
+		$this->bLocked = false; // Not yet locked
+
 		if (!array_key_exists($this->sName, self::$aAcquiredLocks))
 		if (!array_key_exists($this->sName, self::$aAcquiredLocks))
 		{
 		{
 			self::$aAcquiredLocks[$this->sName] = 0;
 			self::$aAcquiredLocks[$this->sName] = 0;
@@ -52,7 +54,10 @@ class iTopMutex
 
 
 	public function __destruct()
 	public function __destruct()
 	{
 	{
-		$this->Unlock();
+		if ($this->bLocked)
+		{
+			$this->Unlock();
+		}
 		mysqli_close($this->hDBLink);
 		mysqli_close($this->hDBLink);
 	}
 	}
 
 
@@ -61,6 +66,11 @@ class iTopMutex
 	 */	
 	 */	
 	public function Lock()
 	public function Lock()
 	{
 	{
+		if ($this->bLocked)
+		{
+			// Lock already acquired
+			return;
+		}
 		if (self::$aAcquiredLocks[$this->sName] == 0)
 		if (self::$aAcquiredLocks[$this->sName] == 0)
 		{
 		{
 			do
 			do
@@ -75,6 +85,7 @@ class iTopMutex
 			}
 			}
 			while ($res !== '1');
 			while ($res !== '1');
 		}
 		}
+		$this->bLocked = true;
 		self::$aAcquiredLocks[$this->sName]++;
 		self::$aAcquiredLocks[$this->sName]++;
 	}
 	}
 
 
@@ -84,9 +95,14 @@ class iTopMutex
 	 */	
 	 */	
 	public function TryLock()
 	public function TryLock()
 	{
 	{
+		if ($this->bLocked)
+		{
+			return true; // Already acquired
+		}
 		if (self::$aAcquiredLocks[$this->sName] > 0)
 		if (self::$aAcquiredLocks[$this->sName] > 0)
 		{
 		{
 			self::$aAcquiredLocks[$this->sName]++;
 			self::$aAcquiredLocks[$this->sName]++;
+			$this->bLocked = true;
 			return true;
 			return true;
 		}
 		}
 		
 		
@@ -99,6 +115,7 @@ class iTopMutex
 		// $res === '0' means it timed out
 		// $res === '0' means it timed out
 		if ($res === '1')
 		if ($res === '1')
 		{
 		{
+			$this->bLocked = true;
 			self::$aAcquiredLocks[$this->sName]++;
 			self::$aAcquiredLocks[$this->sName]++;
 		}
 		}
 		return ($res === '1');
 		return ($res === '1');
@@ -109,12 +126,21 @@ class iTopMutex
 	 */	
 	 */	
 	public function Unlock()
 	public function Unlock()
 	{
 	{
-		if (self::$aAcquiredLocks[$this->sName] == 0) return; // Safety net
+		if (!$this->bLocked)
+		{
+			// ??? the lock is not acquired, exit
+	        return;	
+		}
+		if (self::$aAcquiredLocks[$this->sName] == 0)
+		{
+			return; // Safety net
+		}
 		
 		
 		if (self::$aAcquiredLocks[$this->sName] == 1)
 		if (self::$aAcquiredLocks[$this->sName] == 1)
 		{
 		{
 			$res = $this->QueryToScalar("SELECT RELEASE_LOCK('".$this->sName."')");
 			$res = $this->QueryToScalar("SELECT RELEASE_LOCK('".$this->sName."')");
 		}
 		}
+		$this->bLocked = false;
 		self::$aAcquiredLocks[$this->sName]--;
 		self::$aAcquiredLocks[$this->sName]--;
 	}
 	}