MDL-46151 cachestore_memcache: now checks extension version for support
authorSam Hemelryk <sam@moodle.com>
Sun, 20 Jul 2014 20:48:14 +0000 (08:48 +1200)
committerSam Hemelryk <sam@moodle.com>
Mon, 13 Oct 2014 19:27:45 +0000 (08:27 +1300)
cache/stores/memcache/lib.php
cache/stores/memcache/tests/memcache_test.php
cache/tests/fixtures/stores.php

index 4cedf01..9179ee5 100644 (file)
@@ -105,6 +105,12 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
      */
     protected $setconnections = array();
 
+    /**
+     * If true data going in and out will be encoded.
+     * @var bool
+     */
+    protected $encode = true;
+
     /**
      * Default prefix for key names.
      * @var string
@@ -202,6 +208,24 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
         }
         $this->definition = $definition;
         $this->isinitialised = true;
+        $this->encode = self::require_encoding();
+    }
+
+    /**
+     * Tests if encoding is going to be required.
+     *
+     * Prior to memcache 3.0.3 scalar data types were not preserved.
+     * For earlier versions of the memcache extension we need to encode and decode scalar types
+     * to ensure that it is preserved.
+     *
+     * @param string $version The version to check, if null it is fetched from PHP.
+     * @return bool
+     */
+    public static function require_encoding($version = null) {
+        if (!$version) {
+            $version = phpversion('memcache');
+        }
+        return (version_compare($version, '3.0.3', '<'));
     }
 
     /**
@@ -292,7 +316,11 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
      * @return mixed The data that was associated with the key, or false if the key did not exist.
      */
     public function get($key) {
-        return $this->connection->get($this->parse_key($key));
+        $result = $this->connection->get($this->parse_key($key));
+        if ($this->encode && $result !== false) {
+            return @unserialize($result);
+        }
+        return $result;
     }
 
     /**
@@ -319,6 +347,9 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
                 $return[$key] = false;
             } else {
                 $return[$key] = $result[$mkey];
+                if ($this->encode && $return[$key] !== false) {
+                    $return[$key] = @unserialize($return[$key]);
+                }
             }
         }
         return $return;
@@ -332,6 +363,11 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
      * @return bool True if the operation was a success false otherwise.
      */
     public function set($key, $data) {
+        if ($this->encode) {
+            // We must serialise this data.
+            $data = serialize($data);
+        }
+
         if ($this->clustered) {
             $status = true;
             foreach ($this->setconnections as $connection) {
index 63d366c..0cba975 100644 (file)
@@ -264,4 +264,30 @@ class cachestore_memcache_test extends cachestore_tests {
             }
         }
     }
+
+    /**
+     * Test our checks for encoding.
+     */
+    public function test_require_encoding() {
+        $this->assertTrue(cachestore_memcache::require_encoding('dev'));
+        $this->assertTrue(cachestore_memcache::require_encoding('1.0'));
+        $this->assertTrue(cachestore_memcache::require_encoding('1.0.0'));
+        $this->assertTrue(cachestore_memcache::require_encoding('2.0'));
+        $this->assertTrue(cachestore_memcache::require_encoding('2.0.8'));
+        $this->assertTrue(cachestore_memcache::require_encoding('2.2.8'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0-dev'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0.0'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0.1'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0.2-dev'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0.2'));
+        $this->assertTrue(cachestore_memcache::require_encoding('3.0.3-dev'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.0.3'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.0.4'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.0.4-dev'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.0.8'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.1.0'));
+        $this->assertFalse(cachestore_memcache::require_encoding('3.1.2'));
+
+    }
 }
index ee5f373..8d4f11c 100644 (file)
@@ -86,19 +86,39 @@ abstract class cachestore_tests extends advanced_testcase {
      */
     public function run_tests(cache_store $instance) {
 
-        // Test set.
+        // Test set with a string.
         $this->assertTrue($instance->set('test1', 'test1'));
         $this->assertTrue($instance->set('test2', 'test2'));
+        $this->assertTrue($instance->set('test3', '3'));
 
-        // Test get.
-        $this->assertEquals('test1', $instance->get('test1'));
-        $this->assertEquals('test2', $instance->get('test2'));
+        // Test get with a string.
+        $this->assertSame('test1', $instance->get('test1'));
+        $this->assertSame('test2', $instance->get('test2'));
+        $this->assertSame('3', $instance->get('test3'));
+
+        // Test set with an int.
+        $this->assertTrue($instance->set('test1', 1));
+        $this->assertTrue($instance->set('test2', 2));
+
+        // Test get with an int.
+        $this->assertSame(1, $instance->get('test1'));
+        $this->assertInternalType('int', $instance->get('test1'));
+        $this->assertSame(2, $instance->get('test2'));
+        $this->assertInternalType('int', $instance->get('test2'));
+
+        // Test set with a bool.
+        $this->assertTrue($instance->set('test1', true));
+
+        // Test get with an bool.
+        $this->assertSame(true, $instance->get('test1'));
+        $this->assertInternalType('boolean', $instance->get('test1'));
 
         // Test delete.
         $this->assertTrue($instance->delete('test1'));
+        $this->assertTrue($instance->delete('test3'));
         $this->assertFalse($instance->delete('test3'));
         $this->assertFalse($instance->get('test1'));
-        $this->assertEquals('test2', $instance->get('test2'));
+        $this->assertSame(2, $instance->get('test2'));
         $this->assertTrue($instance->set('test1', 'test1'));
 
         // Test purge.
@@ -114,16 +134,16 @@ abstract class cachestore_tests extends advanced_testcase {
             array('key' => 'many4', 'value' => 'many4'),
             array('key' => 'many5', 'value' => 'many5')
         ));
-        $this->assertEquals(5, $outcome);
-        $this->assertEquals('many1', $instance->get('many1'));
-        $this->assertEquals('many5', $instance->get('many5'));
+        $this->assertSame(5, $outcome);
+        $this->assertSame('many1', $instance->get('many1'));
+        $this->assertSame('many5', $instance->get('many5'));
         $this->assertFalse($instance->get('many6'));
 
         // Test get_many.
         $result = $instance->get_many(array('many1', 'many3', 'many5', 'many6'));
         $this->assertInternalType('array', $result);
         $this->assertCount(4, $result);
-        $this->assertEquals(array(
+        $this->assertSame(array(
             'many1' => 'many1',
             'many3' => 'many3',
             'many5' => 'many5',
@@ -131,7 +151,7 @@ abstract class cachestore_tests extends advanced_testcase {
         ), $result);
 
         // Test delete_many.
-        $this->assertEquals(3, $instance->delete_many(array('many2', 'many3', 'many4')));
-        $this->assertEquals(2, $instance->delete_many(array('many1', 'many5', 'many6')));
+        $this->assertSame(3, $instance->delete_many(array('many2', 'many3', 'many4')));
+        $this->assertSame(2, $instance->delete_many(array('many1', 'many5', 'many6')));
     }
 }
\ No newline at end of file