X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FUtil%2FLock.php;h=9c449844597c56620bb90106ce67bd19fe4772c8;hb=7099a54b3d209bd5eb04613010ac3484563f0c45;hp=af15e106d56545a4c976976e609382bc85de93d8;hpb=f4652d6e5026abe7d7b352d2307622bd567aa433;p=friendica.git diff --git a/src/Util/Lock.php b/src/Util/Lock.php index af15e106d5..9c44984459 100644 --- a/src/Util/Lock.php +++ b/src/Util/Lock.php @@ -1,66 +1,101 @@ connect($memcache_host, $memcache_port)) { - return false; - } + $memcache = new Memcache; - return $memcache; - } + if (!$memcache->connect($memcache_host, $memcache_port)) { + return false; + } + + return $memcache; + } /** - * @brief Sets a lock for a given name + * @brief Creates a semaphore key * * @param string $fn_name Name of the lock + * + * @return ressource the semaphore key + */ + private static function semaphoreKey($fn_name) + { + $temp = get_temppath(); + + $file = $temp.'/'.$fn_name.'.sem'; + + if (!file_exists($file)) { + file_put_contents($file, $function); + } + + return ftok($file, 'f'); + } + + /** + * @brief Sets a lock for a given name + * + * @param string $fn_name Name of the lock * @param integer $timeout Seconds until we give up * * @return boolean Was the lock successful? */ - public static function set($fn_name, $timeout = 120) { + public static function set($fn_name, $timeout = 120) + { $got_lock = false; $start = time(); - $memcache = self::memcache(); + // The second parameter for "sem_acquire" doesn't exist before 5.6.1 + if (function_exists('sem_get') && version_compare(PHP_VERSION, '5.6.1', '>=')) { + self::$semaphore[$fn_name] = sem_get(self::semaphoreKey($fn_name)); + if (self::$semaphore[$fn_name]) { + return sem_acquire(self::$semaphore[$fn_name], ($timeout == 0)); + } + } + + $memcache = self::connectMemcache(); if (is_object($memcache)) { - $wait_sec = 0.2; $cachekey = get_app()->get_hostname().";lock:".$fn_name; do { + // We only lock to be sure that nothing happens at exactly the same time + dba::lock('locks'); $lock = $memcache->get($cachekey); if (!is_bool($lock)) { @@ -68,7 +103,7 @@ class Lock { // When the process id isn't used anymore, we can safely claim the lock for us. // Or we do want to lock something that was already locked by us. - if (!posix_kill($pid, 0) OR ($pid == getmypid())) { + if (!posix_kill($pid, 0) || ($pid == getmypid())) { $lock = false; } } @@ -76,21 +111,22 @@ class Lock { $memcache->set($cachekey, getmypid(), MEMCACHE_COMPRESSED, 300); $got_lock = true; } - if (!$got_lock AND ($timeout > 0)) { - usleep($wait_sec * 1000000); + + dba::unlock(); + + if (!$got_lock && ($timeout > 0)) { + usleep(rand(10000, 200000)); } - } while (!$got_lock AND ((time() - $start) < $timeout)); + } while (!$got_lock && ((time() - $start) < $timeout)); return $got_lock; } - $wait_sec = 2; - do { dba::lock('locks'); $lock = dba::select('locks', array('locked', 'pid'), array('name' => $fn_name), array('limit' => 1)); - if (dbm::is_result($lock)) { + if (DBM::is_result($lock)) { if ($lock['locked']) { // When the process id isn't used anymore, we can safely claim the lock for us. if (!posix_kill($lock['pid'], 0)) { @@ -105,17 +141,17 @@ class Lock { dba::update('locks', array('locked' => true, 'pid' => getmypid()), array('name' => $fn_name)); $got_lock = true; } - } elseif (!dbm::is_result($lock)) { + } elseif (!DBM::is_result($lock)) { dba::insert('locks', array('name' => $fn_name, 'locked' => true, 'pid' => getmypid())); $got_lock = true; } dba::unlock(); - if (!$got_lock AND ($timeout > 0)) { - sleep($wait_sec); + if (!$got_lock && ($timeout > 0)) { + usleep(rand(100000, 2000000)); } - } while (!$got_lock AND ((time() - $start) < $timeout)); + } while (!$got_lock && ((time() - $start) < $timeout)); return $got_lock; } @@ -124,9 +160,21 @@ class Lock { * @brief Removes a lock if it was set by us * * @param string $fn_name Name of the lock + * @return mixed */ - public static function remove($fn_name) { - $memcache = self::memcache(); + public static function remove($fn_name) + { + if (function_exists('sem_get') && version_compare(PHP_VERSION, '5.6.1', '>=')) { + if (empty(self::$semaphore[$fn_name])) { + return false; + } else { + $success = @sem_release(self::$semaphore[$fn_name]); + unset(self::$semaphore[$fn_name]); + return $success; + } + } + + $memcache = self::connectMemcache(); if (is_object($memcache)) { $cachekey = get_app()->get_hostname().";lock:".$fn_name; $lock = $memcache->get($cachekey); @@ -145,9 +193,11 @@ class Lock { /** * @brief Removes all lock that were set by us + * @return void */ - public static function removeAll() { - $memcache = self::memcache(); + public static function removeAll() + { + $memcache = self::connectMemcache(); if (is_object($memcache)) { // We cannot delete all cache entries, but this doesn't matter with memcache return;