Index: trunk/phase3/includes/BacklinkCache.php |
— | — | @@ -1,21 +1,77 @@ |
2 | 2 | <?php |
3 | 3 | /** |
4 | | - * Class for fetching backlink lists, approximate backlink counts and partitions. |
5 | | - * Instances of this class should typically be fetched with $title->getBacklinkCache(). |
| 4 | + * File for BacklinkCache class |
| 5 | + * @file |
| 6 | + */ |
| 7 | + |
| 8 | +/** |
| 9 | + * Class for fetching backlink lists, approximate backlink counts and |
| 10 | + * partitions. This is a shared cache. |
6 | 11 | * |
7 | | - * Ideally you should only get your backlinks from here when you think there is some |
8 | | - * advantage in caching them. Otherwise it's just a waste of memory. |
| 12 | + * Instances of this class should typically be fetched with the method |
| 13 | + * $title->getBacklinkCache(). |
| 14 | + * |
| 15 | + * Ideally you should only get your backlinks from here when you think |
| 16 | + * there is some advantage in caching them. Otherwise it's just a waste |
| 17 | + * of memory. |
| 18 | + * |
| 19 | + * Introduced by r47317 |
| 20 | + * |
| 21 | + * @internal documentation reviewed on 18 Mar 2011 by hashar |
| 22 | + * |
| 23 | + * @author Tim Starling |
| 24 | + * @copyright © 2009, Tim Starling, Domas Mituzas |
| 25 | + * @copyright © 2010, Max Sem |
| 26 | + * @copyright © 2011, Ashar Voultoiz |
9 | 27 | */ |
10 | 28 | class BacklinkCache { |
| 29 | + |
| 30 | + /** |
| 31 | + * Multi dimensions array representing batches. Keys are: |
| 32 | + * > (string) links table name |
| 33 | + * > 'numRows' : Number of rows for this link table |
| 34 | + * > 'batches' : array( $start, $end ) |
| 35 | + * |
| 36 | + * @see BacklinkCache::partitionResult() |
| 37 | + * @todo Should be private |
| 38 | + * |
| 39 | + * Cleared with BacklinkCache::clear() |
| 40 | + */ |
11 | 41 | var $partitionCache = array(); |
| 42 | + |
| 43 | + /** |
| 44 | + * Contains the whole links from a database result. |
| 45 | + * This is raw data that will be partitioned in $partitionCache |
| 46 | + * |
| 47 | + * @todo Should be private |
| 48 | + * |
| 49 | + * Initialized with BacklinkCache::getLinks() |
| 50 | + * Cleared with BacklinkCache::clear() |
| 51 | + */ |
12 | 52 | var $fullResultCache = array(); |
13 | | - var $title; |
| 53 | + |
| 54 | + /** |
| 55 | + * Local copy of a database object. |
| 56 | + * |
| 57 | + * Accessor: BacklinkCache::getDB() |
| 58 | + * Mutator : BacklinkCache::setDB() |
| 59 | + * Cleared with BacklinkCache::clear() |
| 60 | + * |
| 61 | + * @todo Should be private |
| 62 | + */ |
14 | 63 | var $db; |
15 | 64 | |
| 65 | + /** |
| 66 | + * Local copy of a Title object |
| 67 | + * @todo Should be private |
| 68 | + */ |
| 69 | + var $title; |
| 70 | + |
16 | 71 | const CACHE_EXPIRY = 3600; |
17 | 72 | |
18 | 73 | /** |
19 | 74 | * Create a new BacklinkCache |
| 75 | + * @param Title $title : Title object to create a backlink cache for. |
20 | 76 | */ |
21 | 77 | function __construct( $title ) { |
22 | 78 | $this->title = $title; |
— | — | @@ -23,14 +79,15 @@ |
24 | 80 | |
25 | 81 | /** |
26 | 82 | * Serialization handler, diasallows to serialize the database to prevent |
27 | | - * failures after this class is deserialized from cache with dead DB connection. |
| 83 | + * failures after this class is deserialized from cache with dead DB |
| 84 | + * connection. |
28 | 85 | */ |
29 | 86 | function __sleep() { |
30 | 87 | return array( 'partitionCache', 'fullResultCache', 'title' ); |
31 | 88 | } |
32 | 89 | |
33 | 90 | /** |
34 | | - * Clear locally stored data |
| 91 | + * Clear locally stored data and database object. |
35 | 92 | */ |
36 | 93 | function clear() { |
37 | 94 | $this->partitionCache = array(); |
— | — | @@ -45,6 +102,11 @@ |
46 | 103 | $this->db = $db; |
47 | 104 | } |
48 | 105 | |
| 106 | + /** |
| 107 | + * Get the slave connection to the database |
| 108 | + * When non existing, will initialize the connection. |
| 109 | + * @return Database object |
| 110 | + */ |
49 | 111 | protected function getDB() { |
50 | 112 | if ( !isset( $this->db ) ) { |
51 | 113 | $this->db = wfGetDB( DB_SLAVE ); |
— | — | @@ -95,6 +157,7 @@ |
96 | 158 | return $ta; |
97 | 159 | } |
98 | 160 | |
| 161 | + // FIXME : make this a function? |
99 | 162 | if ( !isset( $this->fullResultCache[$table] ) ) { |
100 | 163 | wfDebug( __METHOD__ . ": from DB\n" ); |
101 | 164 | $res = $this->getDB()->select( |
— | — | @@ -117,14 +180,15 @@ |
118 | 181 | |
119 | 182 | /** |
120 | 183 | * Get the field name prefix for a given table |
| 184 | + * @param $table String |
121 | 185 | */ |
122 | 186 | protected function getPrefix( $table ) { |
123 | 187 | static $prefixes = array( |
124 | | - 'pagelinks' => 'pl', |
125 | | - 'imagelinks' => 'il', |
| 188 | + 'pagelinks' => 'pl', |
| 189 | + 'imagelinks' => 'il', |
126 | 190 | 'categorylinks' => 'cl', |
127 | 191 | 'templatelinks' => 'tl', |
128 | | - 'redirect' => 'rd', |
| 192 | + 'redirect' => 'rd', |
129 | 193 | ); |
130 | 194 | |
131 | 195 | if ( isset( $prefixes[$table] ) ) { |
— | — | @@ -135,18 +199,22 @@ |
136 | 200 | } |
137 | 201 | |
138 | 202 | /** |
139 | | - * Get the SQL condition array for selecting backlinks, with a join on the page table |
| 203 | + * Get the SQL condition array for selecting backlinks, with a join |
| 204 | + * on the page table. |
| 205 | + * @param $table String |
140 | 206 | */ |
141 | 207 | protected function getConditions( $table ) { |
142 | 208 | $prefix = $this->getPrefix( $table ); |
143 | 209 | |
| 210 | + // FIXME imagelinks and categorylinks do not rely on getNamespace, |
| 211 | + // they could be moved up for nicer case statements |
144 | 212 | switch ( $table ) { |
145 | 213 | case 'pagelinks': |
146 | 214 | case 'templatelinks': |
147 | 215 | case 'redirect': |
148 | 216 | $conds = array( |
149 | 217 | "{$prefix}_namespace" => $this->title->getNamespace(), |
150 | | - "{$prefix}_title" => $this->title->getDBkey(), |
| 218 | + "{$prefix}_title" => $this->title->getDBkey(), |
151 | 219 | "page_id={$prefix}_from" |
152 | 220 | ); |
153 | 221 | break; |
— | — | @@ -171,6 +239,8 @@ |
172 | 240 | |
173 | 241 | /** |
174 | 242 | * Get the approximate number of backlinks |
| 243 | + * @param $table String |
| 244 | + * @return integer |
175 | 245 | */ |
176 | 246 | public function getNumLinks( $table ) { |
177 | 247 | if ( isset( $this->fullResultCache[$table] ) ) { |
— | — | @@ -189,15 +259,17 @@ |
190 | 260 | |
191 | 261 | /** |
192 | 262 | * Partition the backlinks into batches. |
193 | | - * Returns an array giving the start and end of each range. The first batch has |
194 | | - * a start of false, and the last batch has an end of false. |
| 263 | + * Returns an array giving the start and end of each range. The firsti |
| 264 | + * batch has a start of false, and the last batch has an end of false. |
195 | 265 | * |
196 | 266 | * @param $table String: the links table name |
197 | 267 | * @param $batchSize Integer |
198 | 268 | * @return Array |
199 | 269 | */ |
200 | 270 | public function partition( $table, $batchSize ) { |
201 | | - // Try cache |
| 271 | + |
| 272 | + // 1) try this per process cache first |
| 273 | + |
202 | 274 | if ( isset( $this->partitionCache[$table][$batchSize] ) ) { |
203 | 275 | wfDebug( __METHOD__ . ": got from partition cache\n" ); |
204 | 276 | return $this->partitionCache[$table][$batchSize]['batches']; |
— | — | @@ -206,7 +278,9 @@ |
207 | 279 | $this->partitionCache[$table][$batchSize] = false; |
208 | 280 | $cacheEntry =& $this->partitionCache[$table][$batchSize]; |
209 | 281 | |
210 | | - // Try full result cache |
| 282 | + |
| 283 | + // 2) try full result cache |
| 284 | + |
211 | 285 | if ( isset( $this->fullResultCache[$table] ) ) { |
212 | 286 | $cacheEntry = $this->partitionResult( $this->fullResultCache[$table], $batchSize ); |
213 | 287 | wfDebug( __METHOD__ . ": got from full result cache\n" ); |
— | — | @@ -214,7 +288,9 @@ |
215 | 289 | return $cacheEntry['batches']; |
216 | 290 | } |
217 | 291 | |
218 | | - // Try memcached |
| 292 | + |
| 293 | + // 3) ... fallback to memcached ... |
| 294 | + |
219 | 295 | global $wgMemc; |
220 | 296 | |
221 | 297 | $memcKey = wfMemcKey( |
— | — | @@ -233,7 +309,9 @@ |
234 | 310 | return $cacheEntry['batches']; |
235 | 311 | } |
236 | 312 | |
237 | | - // Fetch from database |
| 313 | + |
| 314 | + // 4) ... finally fetch from the slow database :( |
| 315 | + |
238 | 316 | $this->getLinks( $table ); |
239 | 317 | $cacheEntry = $this->partitionResult( $this->fullResultCache[$table], $batchSize ); |
240 | 318 | // Save to memcached |
— | — | @@ -245,6 +323,9 @@ |
246 | 324 | |
247 | 325 | /** |
248 | 326 | * Partition a DB result with backlinks in it into batches |
| 327 | + * @param $res database result |
| 328 | + * @param $batchSize integer |
| 329 | + * @return array @see |
249 | 330 | */ |
250 | 331 | protected function partitionResult( $res, $batchSize ) { |
251 | 332 | $batches = array(); |