Merge branch 'MDL-65072-fast-locks' of https://github.com/brendanheywood/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Thu, 11 Apr 2019 22:35:15 +0000 (00:35 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Thu, 11 Apr 2019 22:35:15 +0000 (00:35 +0200)
lib/classes/lock/db_record_lock_factory.php
lib/classes/lock/file_lock_factory.php
lib/classes/lock/postgres_lock_factory.php
lib/tests/lock_test.php

index 3a6325c..dd2aa75 100644 (file)
@@ -146,7 +146,7 @@ class db_record_lock_factory implements lock_factory {
             $countparams = array('owner' => $token, 'resourcekey' => $resource);
             $result = $this->db->count_records('lock_db', $countparams);
             $locked = $result === 1;
-            if (!$locked) {
+            if (!$locked && $timeout > 0) {
                 usleep(rand(10000, 250000)); // Sleep between 10 and 250 milliseconds.
             }
             // Try until the giveup time.
index 5062de8..dd20e9b 100644 (file)
@@ -152,7 +152,7 @@ class file_lock_factory implements lock_factory {
             // Will block on windows. So sad.
             $wouldblock = false;
             $locked = flock($filehandle, LOCK_EX | LOCK_NB, $wouldblock);
-            if (!$locked && $wouldblock) {
+            if (!$locked && $wouldblock && $timeout > 0) {
                 usleep(rand(10000, 250000)); // Sleep between 10 and 250 milliseconds.
             }
             // Try until the giveup time.
index 5da94bc..87ae64b 100644 (file)
@@ -188,7 +188,7 @@ class postgres_lock_factory implements lock_factory {
         do {
             $result = $this->db->get_record_sql('SELECT pg_try_advisory_lock(:locktype, :token) AS locked', $params);
             $locked = $result->locked === 't';
-            if (!$locked) {
+            if (!$locked && $timeout > 0) {
                 usleep(rand(10000, 250000)); // Sleep between 10 and 250 milliseconds.
             }
             // Try until the giveup time.
index 17c8e57..695d3a1 100644 (file)
@@ -59,10 +59,31 @@ class lock_testcase extends advanced_testcase {
                     $lock2 = $lockfactory->get_lock('abc', 2);
                     $this->assertNotEmpty($lock2, 'Get a stacked lock');
                     $this->assertTrue($lock2->release(), 'Release a stacked lock');
+
+                    // This stacked lock should be gained almost instantly.
+                    $duration = -microtime(true);
+                    $lock3 = $lockfactory->get_lock('abc', 0);
+                    $duration += microtime(true);
+                    $lock3->release();
+                    $this->assertTrue($duration < 0.100, 'Lock should be gained almost instantly');
+
+                    // We should also assert that locks fail instantly if locked
+                    // from another process but this is hard to unit test.
+
                 } else {
-                    // This should timeout.
+                    // This should timeout after 2 seconds.
+                    $duration = -microtime(true);
                     $lock2 = $lockfactory->get_lock('abc', 2);
+                    $duration += microtime(true);
+                    $this->assertFalse($lock2, 'Cannot get a stacked lock');
+                    $this->assertTrue($duration > 1, 'Lock should timeout after more than 1 second');
+
+                    // This should timeout almost instantly.
+                    $duration = -microtime(true);
+                    $lock2 = $lockfactory->get_lock('abc', 0);
+                    $duration += microtime(true);
                     $this->assertFalse($lock2, 'Cannot get a stacked lock');
+                    $this->assertTrue($duration < 0.100, 'Lock should timeout almost instantly < 100ms');
                 }
             }
             // Release the lock.