From 4533dacd4bbd40a53b0a808b8940adc6f2b055fc Mon Sep 17 00:00:00 2001 From: Kijin Sung Date: Wed, 30 May 2018 21:04:30 +0900 Subject: [PATCH] Add Storage::getLock() for exclusive access to a named lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 여러 프로세스를 동시에 실행할 경우 1개만 작동하도록 lock을 관리하는 기능을 코어 프레임워크에서 제공하도록 한다. 두 개 이상의 프로세스에서 동일한 이름의 lock을 요청할 경우 먼저 요청한 프로세스는 true, 나머지 프로세스들은 false를 받게 된다. lock을 갖고 있던 프로세스가 종료되면 다시 요청할 수 있다. 예를 들어 크론탭에서 1분마다 실행하는 CLI 스크립트가 있는데 간혹 1분 이상 소요된다면 2개가 동시에 실행될 수도 있다. 이 때 lock을 받지 못한 쪽을 종료하면 동시 실행을 방지할 수 있다. --- common/framework/storage.php | 59 ++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/common/framework/storage.php b/common/framework/storage.php index 8861af790..4ac59397d 100644 --- a/common/framework/storage.php +++ b/common/framework/storage.php @@ -22,6 +22,11 @@ class Storage */ protected static $_opcache; + /** + * Cache locks here. + */ + protected static $_locks = array(); + /** * Check if a path really exists. * @@ -858,4 +863,58 @@ class Storage } } } + + /** + * Obtain an exclusive lock. + * + * @return bool + */ + public static function getLock($name) + { + $name = str_replace('.', '%2E', rawurlencode($name)); + if (isset(self::$_locks[$name])) + { + return false; + } + + $lockdir = \RX_BASEDIR . 'files/locks'; + if (!self::isDirectory($lockdir) && !self::createDirectory($lockdir)) + { + return false; + } + + self::$_locks[$name] = @fopen($lockdir . '/' . $name . '.lock', 'w'); + if (!self::$_locks[$name]) + { + unset(self::$_locks[$name]); + return false; + } + + $result = @flock(self::$_locks[$name], \LOCK_EX | \LOCK_NB); + if (!$result) + { + @fclose(self::$_locks[$name]); + unset(self::$_locks[$name]); + return false; + } + + register_shutdown_function('\\Rhymix\\Framework\\Storage::clearLocks'); + return true; + } + + /** + * Clear all locks. + * + * @return void + */ + public static function clearLocks() + { + foreach (self::$_locks as $name => $lock) + { + @flock($lock, \LOCK_UN); + @fclose($lock); + @unlink(\RX_BASEDIR . 'files/locks/' . $name . '.lock'); + unset(self::$_locks[$name]); + } + } }