[FileRepo] Added some cache code based on the problems in r97512.
authorAaron Schulz <aschulz@wikimedia.org>
Fri, 6 Apr 2012 17:38:38 +0000 (10:38 -0700)
committerAaron Schulz <aschulz@wikimedia.org>
Fri, 6 Apr 2012 19:39:58 +0000 (12:39 -0700)
* Made RepoGroup avoid caching files with large metadata and also reduced max cache size to 500 to avoid OOMs.
* Factored out a pingCache() function in RepoGroup.

Change-Id: I52f6413b9eb8b11fbffbde0f0e7acf97c7a2ff89

includes/filerepo/RepoGroup.php
includes/filerepo/file/File.php
includes/filerepo/file/LocalFile.php

index 8096336..b109803 100644 (file)
@@ -12,7 +12,6 @@
  * @ingroup FileRepo
  */
 class RepoGroup {
-
        /**
         * @var LocalRepo
         */
@@ -26,7 +25,7 @@ class RepoGroup {
         * @var RepoGroup
         */
        protected static $instance;
-       const MAX_CACHE_SIZE = 1000;
+       const MAX_CACHE_SIZE = 500;
 
        /**
         * Get a RepoGroup instance. At present only one instance of RepoGroup is
@@ -114,48 +113,41 @@ class RepoGroup {
                        && empty( $options['private'] )
                        && empty( $options['bypassCache'] ) )
                {
-                       $useCache = true;
                        $time = isset( $options['time'] ) ? $options['time'] : '';
                        $dbkey = $title->getDBkey();
                        if ( isset( $this->cache[$dbkey][$time] ) ) {
                                wfDebug( __METHOD__.": got File:$dbkey from process cache\n" );
                                # Move it to the end of the list so that we can delete the LRU entry later
-                               $tmp = $this->cache[$dbkey];
-                               unset( $this->cache[$dbkey] );
-                               $this->cache[$dbkey] = $tmp;
+                               $this->pingCache( $dbkey );
                                # Return the entry
                                return $this->cache[$dbkey][$time];
-                       } else {
-                               # Add a negative cache entry, may be overridden
-                               $this->trimCache();
-                               $this->cache[$dbkey][$time] = false;
-                               $cacheEntry =& $this->cache[$dbkey][$time];
                        }
+                       $useCache = true;
                } else {
                        $useCache = false;
                }
 
                # Check the local repo
                $image = $this->localRepo->findFile( $title, $options );
-               if ( $image ) {
-                       if ( $useCache ) {
-                               $cacheEntry = $image;
-                       }
-                       return $image;
-               }
 
                # Check the foreign repos
-               foreach ( $this->foreignRepos as $repo ) {
-                       $image = $repo->findFile( $title, $options );
-                       if ( $image ) {
-                               if ( $useCache ) {
-                                       $cacheEntry = $image;
+               if ( !$image ) {
+                       foreach ( $this->foreignRepos as $repo ) {
+                               $image = $repo->findFile( $title, $options );
+                               if ( $image ) {
+                                       break;
                                }
-                               return $image;
                        }
                }
-               # Not found, do not override negative cache
-               return false;
+
+               $image = $image ? $image : false; // type sanity
+               # Cache file existence or non-existence
+               if ( $useCache && ( !$image || $image->isCacheable() ) ) {
+                       $this->trimCache();
+                       $this->cache[$dbkey][$time] = $image;
+               }
+
+               return $image;
        }
 
        function findFiles( $inputItems ) {
@@ -371,6 +363,17 @@ class RepoGroup {
                }
        }
 
+       /**
+        * Move a cache entry to the top (such as when accessed)
+        */
+       protected function pingCache( $key ) {
+               if ( isset( $this->cache[$key] ) ) {
+                       $tmp = $this->cache[$key];
+                       unset( $this->cache[$key] );
+                       $this->cache[$key] = $tmp;
+               }
+       }
+
        /**
         * Limit cache memory
         */
index 56272da..ce69a03 100644 (file)
@@ -755,7 +755,7 @@ abstract class File {
 
        /**
         * Return either a MediaTransformError or placeholder thumbnail (if $wgIgnoreImageErrors)
-        * 
+        *
         * @param $thumbPath string Thumbnail storage path
         * @param $thumbUrl string Thumbnail URL
         * @param $params Array
@@ -1705,6 +1705,14 @@ abstract class File {
                return false;
        }
 
+       /**
+        * Check if this file object is small and can be cached
+        * @return boolean
+        */
+       public function isCacheable() {
+               return true;
+       }
+
        /**
         * Assert that $this->repo is set to a valid FileRepo instance
         * @throws MWException
index b709709..40ee0fa 100644 (file)
@@ -29,6 +29,8 @@ define( 'MW_FILE_VERSION', 8 );
  * @ingroup FileAbstraction
  */
 class LocalFile extends File {
+       const CACHE_FIELD_MAX_LEN = 1000;
+
        /**#@+
         * @private
         */
@@ -1021,9 +1023,9 @@ class LocalFile extends File {
                );
 
                if ( $dbw->affectedRows() == 0 ) {
-                       # (bug 34993) Note: $oldver can be empty here, if the previous 
-                       # version of the file was broken. Allow registration of the new 
-                       # version to continue anyway, because that's better than having 
+                       # (bug 34993) Note: $oldver can be empty here, if the previous
+                       # version of the file was broken. Allow registration of the new
+                       # version to continue anyway, because that's better than having
                        # an image that's not fixable by user operations.
 
                        $reupload = true;
@@ -1431,6 +1433,11 @@ class LocalFile extends File {
                return $this->sha1;
        }
 
+       function isCacheable() {
+               $this->load();
+               return strlen( $this->metadata ) <= self::CACHE_FIELD_MAX_LEN; // avoid OOMs
+       }
+
        /**
         * Start a transaction and lock the image for update
         * Increments a reference counter if the lock is already held