objectcache: let BagOStuff::getWithSetCallback() callbacks modify the TTL
authorAaron Schulz <aschulz@wikimedia.org>
Tue, 23 Jul 2019 14:33:40 +0000 (07:33 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Tue, 23 Jul 2019 14:33:40 +0000 (07:33 -0700)
Also simplify the code by removing the is_callable() check and relying on
regular PHP errors instead of an exception for bad callbacks.

Change-Id: I084b0132c5fb05f1941a6d6839cfa74e2cf677f0

includes/libs/objectcache/BagOStuff.php
tests/phpunit/includes/libs/objectcache/BagOStuffTest.php

index 906e955..18b9524 100644 (file)
@@ -115,7 +115,8 @@ abstract class BagOStuff implements IExpiringStore, IStoreKeyEncoder, LoggerAwar
        /**
         * Get an item with the given key, regenerating and setting it if not found
         *
-        * Nothing is stored nor deleted if the callback returns false
+        * The callback can take $ttl as argument by reference and modify it.
+        * Nothing is stored nor deleted if the callback returns false.
         *
         * @param string $key
         * @param int $ttl Time-to-live (seconds)
@@ -128,10 +129,7 @@ abstract class BagOStuff implements IExpiringStore, IStoreKeyEncoder, LoggerAwar
                $value = $this->get( $key, $flags );
 
                if ( $value === false ) {
-                       if ( !is_callable( $callback ) ) {
-                               throw new InvalidArgumentException( "Invalid cache miss callback provided." );
-                       }
-                       $value = call_user_func( $callback );
+                       $value = $callback( $ttl );
                        if ( $value !== false ) {
                                $this->set( $key, $value, $ttl, $flags );
                        }
index 522af43..4a56fc5 100644 (file)
@@ -113,6 +113,9 @@ class BagOStuffTest extends MediaWikiTestCase {
         * @covers MediumSpecificBagOStuff::changeTTL
         */
        public function testChangeTTL() {
+               $now = 1563892142;
+               $this->cache->setMockTime( $now );
+
                $key = $this->cache->makeKey( self::TEST_KEY );
                $value = 'meow';
 
@@ -126,7 +129,7 @@ class BagOStuffTest extends MediaWikiTestCase {
                $this->assertFalse( $this->cache->changeTTL( $key, 15 ) );
 
                $this->cache->add( $key, $value, 5 );
-               $this->assertTrue( $this->cache->changeTTL( $key, time() - 3600 ) );
+               $this->assertTrue( $this->cache->changeTTL( $key, $now - 3600 ) );
                $this->assertFalse( $this->cache->get( $key ) );
        }
 
@@ -134,6 +137,9 @@ class BagOStuffTest extends MediaWikiTestCase {
         * @covers MediumSpecificBagOStuff::changeTTLMulti
         */
        public function testChangeTTLMulti() {
+               $now = 1563892142;
+               $this->cache->setMockTime( $now );
+
                $key1 = $this->cache->makeKey( 'test-key1' );
                $key2 = $this->cache->makeKey( 'test-key2' );
                $key3 = $this->cache->makeKey( 'test-key3' );
@@ -166,7 +172,7 @@ class BagOStuffTest extends MediaWikiTestCase {
                $this->assertEquals( 2, $this->cache->get( $key2 ) );
                $this->assertEquals( 3, $this->cache->get( $key3 ) );
 
-               $ok = $this->cache->changeTTLMulti( [ $key1, $key2, $key3 ], time() + 86400 );
+               $ok = $this->cache->changeTTLMulti( [ $key1, $key2, $key3 ], $now + 86400 );
                $this->assertTrue( $ok, "Expiry set for all keys" );
 
                $ok = $this->cache->changeTTLMulti( [ $key1, $key2, $key3, $key4 ], 300 );
@@ -210,17 +216,28 @@ class BagOStuffTest extends MediaWikiTestCase {
         * @covers MediumSpecificBagOStuff::getWithSetCallback
         */
        public function testGetWithSetCallback() {
+               $now = 1563892142;
+               $this->cache->setMockTime( $now );
                $key = $this->cache->makeKey( self::TEST_KEY );
+
+               $this->assertFalse( $this->cache->get( $key ), "No value" );
+
                $value = $this->cache->getWithSetCallback(
                        $key,
                        30,
-                       function () {
+                       function ( &$ttl ) {
+                               $ttl = 10;
+
                                return 'hello kitty';
                        }
                );
 
                $this->assertEquals( 'hello kitty', $value );
-               $this->assertEquals( $value, $this->cache->get( $key ) );
+               $this->assertEquals( $value, $this->cache->get( $key ), "Value set" );
+
+               $now += 11;
+
+               $this->assertFalse( $this->cache->get( $key ), "Value expired" );
        }
 
        /**