MDL-41436 implement new increment_revision_number() function
authorPetr Škoda <commits@skodak.org>
Tue, 3 Sep 2013 14:42:42 +0000 (16:42 +0200)
committerMarina Glancy <marina@moodle.com>
Tue, 10 Sep 2013 04:11:44 +0000 (14:11 +1000)
This is intended as a revision counter for local modinfo caching. It should be a lot more reliable and faster than doing it in PHP. Please note you need to invalidate all course caches after using this.

lib/datalib.php
lib/tests/datalib_test.php

index c7ef03c..175bce4 100644 (file)
@@ -1232,6 +1232,36 @@ function update_timezone_records($timezones) {
     }
 }
 
+/**
+ * Increment standard revision field.
+ *
+ * The revision are based on current time and are incrementing.
+ * There is a protection for runaway revisions, it may not go further than
+ * one hour into future.
+ *
+ * The field has to be XMLDB_TYPE_INTEGER with size 10.
+ *
+ * @param string $table
+ * @param string $field name of the field containing revision
+ * @param string $select use empty string when updating all records
+ * @param array $params optional select parameters
+ */
+function increment_revision_number($table, $field, $select, array $params = null) {
+    global $DB;
+
+    $now = time();
+    $sql = "UPDATE {{$table}}
+                   SET $field = (CASE
+                       WHEN $field IS NULL THEN $now
+                       WHEN $field < $now THEN $now
+                       WHEN $field > $now + 3600 THEN $now
+                       ELSE $field + 1 END)";
+    if ($select) {
+        $sql = $sql . " WHERE $select";
+    }
+    $DB->execute($sql, $params);
+}
+
 
 /// MODULE FUNCTIONS /////////////////////////////////////////////////
 
index 465bd4a..0357707 100644 (file)
@@ -289,4 +289,58 @@ class core_datalib_testcase extends advanced_testcase {
         $this->assertSame('ZOMBIES', $result->shortname);
         $this->assertEquals($before + 1, $DB->perf_get_queries());
     }
+
+    public function test_increment_revision_number() {
+        global $DB;
+        $this->resetAfterTest();
+
+        // Let's abuse course.timemodified column for now.
+        $course1 = $this->getDataGenerator()->create_course();
+        $course2 = $this->getDataGenerator()->create_course();
+        $DB->set_field('course', 'timemodified', 1, array());
+
+        $record1 = $DB->get_record('course', array('id'=>$course1->id));
+        $record2 = $DB->get_record('course', array('id'=>$course2->id));
+        $this->assertEquals(1, $record1->timemodified);
+        $this->assertEquals(1, $record2->timemodified);
+
+        // Incrementing some lower value.
+        $now = time();
+        increment_revision_number('course', 'timemodified', 'id = :id', array('id'=>$course1->id));
+        $record1 = $DB->get_record('course', array('id'=>$course1->id));
+        $record2 = $DB->get_record('course', array('id'=>$course2->id));
+        $this->assertGreaterThanOrEqual($now, $record1->timemodified);
+        $this->assertLessThanOrEqual($now+1, $record1->timemodified);
+        $this->assertEquals(1, $record2->timemodified);
+
+        // Incrementing in the same second.
+        $rev1 = $DB->get_field('course', 'timemodified', array('id'=>$course1->id));
+        $now = time();
+        increment_revision_number('course', 'timemodified', 'id = :id', array('id'=>$course1->id));
+        $this->assertGreaterThan($rev1, $rev1 = $DB->get_field('course', 'timemodified', array('id'=>$course1->id)));
+        increment_revision_number('course', 'timemodified', 'id = :id', array('id'=>$course1->id));
+        $this->assertGreaterThan($rev1, $rev1 = $DB->get_field('course', 'timemodified', array('id'=>$course1->id)));
+        increment_revision_number('course', 'timemodified', 'id = :id', array('id'=>$course1->id));
+        $this->assertGreaterThan($rev1, $rev1 = $DB->get_field('course', 'timemodified', array('id'=>$course1->id)));
+        $this->assertGreaterThan($now+2, $rev1);
+
+        // Recovering from runaway revision.
+        $DB->set_field('course', 'timemodified', time()+60*60*60, array('id'=>$course2->id));
+        $record2 = $DB->get_record('course', array('id'=>$course2->id));
+        $this->assertGreaterThan(time(), $record2->timemodified);
+        increment_revision_number('course', 'timemodified', 'id = :id', array('id'=>$course2->id));
+        $record2b = $DB->get_record('course', array('id'=>$course2->id));
+        $this->assertLessThan($record2->timemodified, $record2b->timemodified);
+        $this->assertGreaterThanOrEqual(time(), $record2b->timemodified);
+
+        // Update all revisions.
+        $now = time();
+        $DB->set_field('course', 'timemodified', 1, array());
+        increment_revision_number('course', 'timemodified', '');
+        $record1 = $DB->get_record('course', array('id'=>$course1->id));
+        $record2 = $DB->get_record('course', array('id'=>$course2->id));
+        $this->assertGreaterThanOrEqual($now, $record1->timemodified);
+        $this->assertLessThanOrEqual($now+1, $record1->timemodified);
+        $this->assertEquals($record1->timemodified, $record2->timemodified);
+    }
 }