]> git.mxchange.org Git - friendica.git/blobdiff - src/Core/Lock/DatabaseLockDriver.php
Merge pull request #6732 from MrPetovan/bug/1777-fix-blocked-contact-group
[friendica.git] / src / Core / Lock / DatabaseLockDriver.php
index 8761a1479ee219ca24c86cace4481bc240fbe7d0..a137ef12edcac6e6766af4f704128e3ce97085d3 100644 (file)
@@ -2,52 +2,60 @@
 
 namespace Friendica\Core\Lock;
 
-use dba;
-use Friendica\Database\DBM;
+use Friendica\Core\Cache;
+use Friendica\Database\DBA;
+use Friendica\Util\DateTimeFormat;
 
 /**
  * Locking driver that stores the locks in the database
  */
-class DatabaseLockDriver implements ILockDriver
+class DatabaseLockDriver extends AbstractLockDriver
 {
        /**
-        * @brief Sets a lock for a given name
+        * The current ID of the process
         *
-        * @param string  $key      The Name of the lock
-        * @param integer $timeout  Seconds until we give up
-        *
-        * @return boolean Was the lock successful?
+        * @var int
+        */
+       private $pid;
+
+       /**
+        * @param null|int $pid The Id of the current process (null means determine automatically)
         */
-       public function acquireLock($key, $timeout = 120)
+       public function __construct($pid = null)
+       {
+               $this->pid = isset($pid) ? $pid : getmypid();
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function acquireLock($key, $timeout = 120, $ttl = Cache::FIVE_MINUTES)
        {
                $got_lock = false;
                $start = time();
 
                do {
-                       dba::lock('locks');
-                       $lock = dba::selectFirst('locks', ['locked', 'pid'], ['name' => $key]);
+                       DBA::lock('locks');
+                       $lock = DBA::selectFirst('locks', ['locked', 'pid'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
 
-                       if (DBM::is_result($lock)) {
+                       if (DBA::isResult($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)) {
-                                               $lock['locked'] = false;
-                                       }
                                        // We want to lock something that was already locked by us? So we got the lock.
-                                       if ($lock['pid'] == getmypid()) {
+                                       if ($lock['pid'] == $this->pid) {
                                                $got_lock = true;
                                        }
                                }
                                if (!$lock['locked']) {
-                                       dba::update('locks', ['locked' => true, 'pid' => getmypid()], ['name' => $key]);
+                                       DBA::update('locks', ['locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')], ['name' => $key]);
                                        $got_lock = true;
                                }
-                       } elseif (!DBM::is_result($lock)) {
-                               dba::insert('locks', ['name' => $key, 'locked' => true, 'pid' => getmypid()]);
+                       } else {
+                               DBA::insert('locks', ['name' => $key, 'locked' => true, 'pid' => $this->pid, 'expires' => DateTimeFormat::utc('now + ' . $ttl . 'seconds')]);
                                $got_lock = true;
+                               $this->markAcquire($key);
                        }
 
-                       dba::unlock();
+                       DBA::unlock();
 
                        if (!$got_lock && ($timeout > 0)) {
                                usleep(rand(100000, 2000000));
@@ -58,26 +66,44 @@ class DatabaseLockDriver implements ILockDriver
        }
 
        /**
-        * @brief Removes a lock if it was set by us
-        *
-        * @param string $key Name of the lock
-        *
-        * @return mixed
+        * (@inheritdoc)
         */
-       public function releaseLock($key)
+       public function releaseLock($key, $override = false)
        {
-               dba::update('locks', ['locked' => false, 'pid' => 0], ['name' => $key, 'pid' => getmypid()]);
+               if ($override) {
+                       $where = ['name' => $key];
+               } else {
+                       $where = ['name' => $key, 'pid' => $this->pid];
+               }
+
+               DBA::delete('locks', $where);
+
+               $this->markRelease($key);
 
                return;
        }
 
        /**
-        * @brief Removes all lock that were set by us
-        *
-        * @return void
+        * (@inheritdoc)
         */
        public function releaseAll()
        {
-               dba::update('locks', ['locked' => false, 'pid' => 0], ['pid' => getmypid()]);
+               DBA::delete('locks', ['pid' => $this->pid]);
+
+               $this->acquiredLocks = [];
+       }
+
+       /**
+        * (@inheritdoc)
+        */
+       public function isLocked($key)
+       {
+               $lock = DBA::selectFirst('locks', ['locked'], ['`name` = ? AND `expires` >= ?', $key, DateTimeFormat::utcNow()]);
+
+               if (DBA::isResult($lock)) {
+                       return $lock['locked'] !== false;
+               } else {
+                       return false;
+               }
        }
 }