]> scripts.mit.edu Git - autoinstalls/mediawiki.git/blob - includes/filerepo/FileCache.php
MediaWiki 1.15.0
[autoinstalls/mediawiki.git] / includes / filerepo / FileCache.php
1 <?php
2 /**
3  * Cache of file objects, wrapping some RepoGroup functions to avoid redundant
4  * queries.  Loosely inspired by the LinkCache / LinkBatch classes for titles.
5  *
6  * ISSUE: Merge with RepoGroup?
7  *
8  * @ingroup FileRepo
9  */
10 class FileCache {
11         var $repoGroup;
12         var $cache = array(), $notFound = array();
13
14         protected static $instance;
15
16         /**
17          * Get a FileCache instance.  Typically, only one instance of FileCache
18          * is needed in a MediaWiki invocation.
19          */
20         static function singleton() {
21                 if ( self::$instance ) {
22                         return self::$instance;
23                 }
24                 self::$instance = new FileCache( RepoGroup::singleton() );
25                 return self::$instance;
26         }
27
28         /**
29          * Destroy the singleton instance, so that a new one will be created next
30          * time singleton() is called.
31          */
32         static function destroySingleton() {
33                 self::$instance = null;
34         }
35
36         /**
37          * Set the singleton instance to a given object
38          */
39         static function setSingleton( $instance ) {
40                 self::$instance = $instance;
41         }
42
43         /**
44          * Construct a group of file repositories.
45          * @param RepoGroup $repoGroup
46          */
47         function __construct( $repoGroup ) {
48                 $this->repoGroup = $repoGroup;
49         }
50
51
52         /**
53          * Add some files to the cache.  This is a fairly low-level function,
54          * which most users should not need to call.  Note that any existing
55          * entries for the same keys will not be replaced.  Call clearFiles()
56          * first if you need that.
57          * @param array $files array of File objects, indexed by DB key
58          */
59         function addFiles( $files ) {
60                 wfDebug( "FileCache adding ".count( $files )." files\n" );
61                 $this->cache += $files;
62         }
63
64         /**
65          * Remove some files from the cache, so that their existence will be
66          * rechecked.  This is a fairly low-level function, which most users
67          * should not need to call.
68          * @param array $remove array indexed by DB keys to remove (the values are ignored)
69          */
70         function clearFiles( $remove ) {
71                 wfDebug( "FileCache clearing data for ".count( $remove )." files\n" );
72                 $this->cache = array_diff_keys( $this->cache, $remove );
73                 $this->notFound = array_diff_keys( $this->notFound, $remove );
74         }
75
76         /**
77          * Mark some DB keys as nonexistent.  This is a fairly low-level
78          * function, which most users should not need to call.
79          * @param array $dbkeys array of DB keys
80          */
81         function markNotFound( $dbkeys ) {
82                 wfDebug( "FileCache marking ".count( $dbkeys )." files as not found\n" );
83                 $this->notFound += array_fill_keys( $dbkeys, true );
84         }
85
86
87         /**
88          * Search the cache for a file.
89          * @param mixed $title Title object or string
90          * @return File object or false if it is not found
91          * @todo Implement searching for old file versions(?)
92          */
93         function findFile( $title ) {
94                 if( !( $title instanceof Title ) ) {
95                         $title = Title::makeTitleSafe( NS_FILE, $title );
96                 }
97                 if( !$title ) {
98                         return false;  // invalid title?
99                 }
100
101                 $dbkey = $title->getDBkey();
102                 if( array_key_exists( $dbkey, $this->cache ) ) {
103                         wfDebug( "FileCache HIT for $dbkey\n" );
104                         return $this->cache[$dbkey];
105                 }
106                 if( array_key_exists( $dbkey, $this->notFound ) ) {
107                         wfDebug( "FileCache negative HIT for $dbkey\n" );
108                         return false;
109                 }
110
111                 // Not in cache, fall back to a direct query
112                 $file = $this->repoGroup->findFile( $title );
113                 if( $file ) {
114                         wfDebug( "FileCache MISS for $dbkey\n" );
115                         $this->cache[$dbkey] = $file;
116                 } else {
117                         wfDebug( "FileCache negative MISS for $dbkey\n" );
118                         $this->notFound[$dbkey] = true;
119                 }
120                 return $file;
121         }
122
123         /**
124          * Search the cache for multiple files.
125          * @param array $titles Title objects or strings to search for
126          * @return array of File objects, indexed by DB key
127          */
128         function findFiles( $titles ) {
129                 $titleObjs = array();
130                 foreach ( $titles as $title ) {
131                         if ( !( $title instanceof Title ) ) {
132                                 $title = Title::makeTitleSafe( NS_FILE, $title );
133                         }
134                         if ( $title ) {
135                                 $titleObjs[$title->getDBkey()] = $title;
136                         }
137                 }
138
139                 $result = array_intersect_key( $this->cache, $titleObjs );
140
141                 $unsure = array_diff_key( $titleObjs, $result, $this->notFound );
142                 if( $unsure ) {
143                         wfDebug( "FileCache MISS for ".count( $unsure )." files out of ".count( $titleObjs )."...\n" );
144                         // XXX: We assume the array returned by findFiles() is
145                         // indexed by DBkey; this appears to be true, but should
146                         // be explicitly documented.
147                         $found = $this->repoGroup->findFiles( $unsure );
148                         $result += $found;
149                         $this->addFiles( $found );
150                         $this->markNotFound( array_keys( array_diff_key( $unsure, $found ) ) );
151                 }
152
153                 wfDebug( "FileCache found ".count( $result )." files out of ".count( $titleObjs )."\n" );
154                 return $result;
155         }
156 }