r84727 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r84726‎ | r84727 | r84728 >
Date:03:28, 25 March 2011
Author:tstarling
Status:ok
Tags:
Comment:
Merged in the ObjectCache refactor and the Ehcache client. MFT r83135, r83136, r83140, r83143, r83147, r83208, r83416, r83492.
Modified paths:
  • /branches/wmf/1.17wmf1/includes/AutoLoader.php (modified) (history)
  • /branches/wmf/1.17wmf1/includes/BagOStuff.php (deleted) (history)
  • /branches/wmf/1.17wmf1/includes/DefaultSettings.php (modified) (history)
  • /branches/wmf/1.17wmf1/includes/ForkController.php (modified) (history)
  • /branches/wmf/1.17wmf1/includes/GlobalFunctions.php (modified) (history)
  • /branches/wmf/1.17wmf1/includes/MemcachedSessions.php (modified) (history)
  • /branches/wmf/1.17wmf1/includes/ObjectCache.php (deleted) (history)
  • /branches/wmf/1.17wmf1/includes/Setup.php (modified) (history)
  • /branches/wmf/1.17wmf1/includes/memcached-client.php (deleted) (history)
  • /branches/wmf/1.17wmf1/includes/objectcache (added) (history)
  • /branches/wmf/1.17wmf1/includes/objectcache/BagOStuff.php (modified) (history)
  • /branches/wmf/1.17wmf1/includes/objectcache/EhcacheBagOStuff.php (added) (history)
  • /branches/wmf/1.17wmf1/includes/objectcache/EmptyBagOStuff.php (added) (history)
  • /branches/wmf/1.17wmf1/includes/objectcache/MemcachedClient.php (added) (history)
  • /branches/wmf/1.17wmf1/includes/objectcache/MemcachedPhpBagOStuff.php (added) (history)
  • /branches/wmf/1.17wmf1/includes/objectcache/MultiWriteBagOStuff.php (added) (history)
  • /branches/wmf/1.17wmf1/includes/objectcache/ObjectCache.php (modified) (history)
  • /branches/wmf/1.17wmf1/includes/objectcache/SqlBagOStuff.php (modified) (history)
  • /branches/wmf/1.17wmf1/maintenance/mcc.php (modified) (history)

Diff [purge]

Index: branches/wmf/1.17wmf1/maintenance/mcc.php
@@ -10,7 +10,7 @@
1111 /** */
1212 require_once( dirname( __FILE__ ) . '/commandLine.inc' );
1313
14 -$mcc = new MWMemcached( array( 'persistant' => true/*, 'debug' => true*/ ) );
 14+$mcc = new MWMemcached( array( 'persistent' => true/*, 'debug' => true*/ ) );
1515 $mcc->set_servers( $wgMemCachedServers );
1616 # $mcc->set_debug( true );
1717
Index: branches/wmf/1.17wmf1/includes/BagOStuff.php
@@ -1,901 +0,0 @@
2 -<?php
3 -/**
4 - * Classes to cache objects in PHP accelerators, SQL database or DBA files
5 - *
6 - * Copyright © 2003-2004 Brion Vibber <brion@pobox.com>
7 - * http://www.mediawiki.org/
8 - *
9 - * This program is free software; you can redistribute it and/or modify
10 - * it under the terms of the GNU General Public License as published by
11 - * the Free Software Foundation; either version 2 of the License, or
12 - * (at your option) any later version.
13 - *
14 - * This program is distributed in the hope that it will be useful,
15 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 - * GNU General Public License for more details.
18 - *
19 - * You should have received a copy of the GNU General Public License along
20 - * with this program; if not, write to the Free Software Foundation, Inc.,
21 - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 - * http://www.gnu.org/copyleft/gpl.html
23 - *
24 - * @file
25 - * @ingroup Cache
26 - */
27 -
28 -/**
29 - * @defgroup Cache Cache
30 - */
31 -
32 -/**
33 - * interface is intended to be more or less compatible with
34 - * the PHP memcached client.
35 - *
36 - * backends for local hash array and SQL table included:
37 - * <code>
38 - * $bag = new HashBagOStuff();
39 - * $bag = new SqlBagOStuff(); # connect to db first
40 - * </code>
41 - *
42 - * @ingroup Cache
43 - */
44 -abstract class BagOStuff {
45 - var $debugMode = false;
46 -
47 - public function set_debug( $bool ) {
48 - $this->debugMode = $bool;
49 - }
50 -
51 - /* *** THE GUTS OF THE OPERATION *** */
52 - /* Override these with functional things in subclasses */
53 -
54 - /**
55 - * Get an item with the given key. Returns false if it does not exist.
56 - * @param $key string
57 - */
58 - abstract public function get( $key );
59 -
60 - /**
61 - * Set an item.
62 - * @param $key string
63 - * @param $value mixed
64 - * @param $exptime int Either an interval in seconds or a unix timestamp for expiry
65 - */
66 - abstract public function set( $key, $value, $exptime = 0 );
67 -
68 - /*
69 - * Delete an item.
70 - * @param $key string
71 - * @param $time int Amount of time to delay the operation (mostly memcached-specific)
72 - */
73 - abstract public function delete( $key, $time = 0 );
74 -
75 - public function lock( $key, $timeout = 0 ) {
76 - /* stub */
77 - return true;
78 - }
79 -
80 - public function unlock( $key ) {
81 - /* stub */
82 - return true;
83 - }
84 -
85 - public function keys() {
86 - /* stub */
87 - return array();
88 - }
89 -
90 - /* *** Emulated functions *** */
91 - /* Better performance can likely be got with custom written versions */
92 - public function get_multi( $keys ) {
93 - $out = array();
94 -
95 - foreach ( $keys as $key ) {
96 - $out[$key] = $this->get( $key );
97 - }
98 -
99 - return $out;
100 - }
101 -
102 - public function set_multi( $hash, $exptime = 0 ) {
103 - foreach ( $hash as $key => $value ) {
104 - $this->set( $key, $value, $exptime );
105 - }
106 - }
107 -
108 - public function add( $key, $value, $exptime = 0 ) {
109 - if ( !$this->get( $key ) ) {
110 - $this->set( $key, $value, $exptime );
111 -
112 - return true;
113 - }
114 - }
115 -
116 - public function add_multi( $hash, $exptime = 0 ) {
117 - foreach ( $hash as $key => $value ) {
118 - $this->add( $key, $value, $exptime );
119 - }
120 - }
121 -
122 - public function delete_multi( $keys, $time = 0 ) {
123 - foreach ( $keys as $key ) {
124 - $this->delete( $key, $time );
125 - }
126 - }
127 -
128 - public function replace( $key, $value, $exptime = 0 ) {
129 - if ( $this->get( $key ) !== false ) {
130 - $this->set( $key, $value, $exptime );
131 - }
132 - }
133 -
134 - /**
135 - * @param $key String: Key to increase
136 - * @param $value Integer: Value to add to $key (Default 1)
137 - * @return null if lock is not possible else $key value increased by $value
138 - */
139 - public function incr( $key, $value = 1 ) {
140 - if ( !$this->lock( $key ) ) {
141 - return null;
142 - }
143 -
144 - $value = intval( $value );
145 -
146 - if ( ( $n = $this->get( $key ) ) !== false ) {
147 - $n += $value;
148 - $this->set( $key, $n ); // exptime?
149 - }
150 - $this->unlock( $key );
151 -
152 - return $n;
153 - }
154 -
155 - public function decr( $key, $value = 1 ) {
156 - return $this->incr( $key, - $value );
157 - }
158 -
159 - public function debug( $text ) {
160 - if ( $this->debugMode ) {
161 - wfDebug( "BagOStuff debug: $text\n" );
162 - }
163 - }
164 -
165 - /**
166 - * Convert an optionally relative time to an absolute time
167 - */
168 - protected function convertExpiry( $exptime ) {
169 - if ( ( $exptime != 0 ) && ( $exptime < 86400 * 3650 /* 10 years */ ) ) {
170 - return time() + $exptime;
171 - } else {
172 - return $exptime;
173 - }
174 - }
175 -}
176 -
177 -/**
178 - * Functional versions!
179 - * This is a test of the interface, mainly. It stores things in an associative
180 - * array, which is not going to persist between program runs.
181 - *
182 - * @ingroup Cache
183 - */
184 -class HashBagOStuff extends BagOStuff {
185 - var $bag;
186 -
187 - function __construct() {
188 - $this->bag = array();
189 - }
190 -
191 - protected function expire( $key ) {
192 - $et = $this->bag[$key][1];
193 -
194 - if ( ( $et == 0 ) || ( $et > time() ) ) {
195 - return false;
196 - }
197 -
198 - $this->delete( $key );
199 -
200 - return true;
201 - }
202 -
203 - function get( $key ) {
204 - if ( !isset( $this->bag[$key] ) ) {
205 - return false;
206 - }
207 -
208 - if ( $this->expire( $key ) ) {
209 - return false;
210 - }
211 -
212 - return $this->bag[$key][0];
213 - }
214 -
215 - function set( $key, $value, $exptime = 0 ) {
216 - $this->bag[$key] = array( $value, $this->convertExpiry( $exptime ) );
217 - }
218 -
219 - function delete( $key, $time = 0 ) {
220 - if ( !isset( $this->bag[$key] ) ) {
221 - return false;
222 - }
223 -
224 - unset( $this->bag[$key] );
225 -
226 - return true;
227 - }
228 -
229 - function keys() {
230 - return array_keys( $this->bag );
231 - }
232 -}
233 -
234 -/**
235 - * Class to store objects in the database
236 - *
237 - * @ingroup Cache
238 - */
239 -class SqlBagOStuff extends BagOStuff {
240 - var $lb, $db;
241 - var $lastExpireAll = 0;
242 -
243 - protected function getDB() {
244 - global $wgDBtype;
245 -
246 - if ( !isset( $this->db ) ) {
247 - /* We must keep a separate connection to MySQL in order to avoid deadlocks
248 - * However, SQLite has an opposite behaviour.
249 - * @todo Investigate behaviour for other databases
250 - */
251 - if ( $wgDBtype == 'sqlite' ) {
252 - $this->db = wfGetDB( DB_MASTER );
253 - } else {
254 - $this->lb = wfGetLBFactory()->newMainLB();
255 - $this->db = $this->lb->getConnection( DB_MASTER );
256 - $this->db->clearFlag( DBO_TRX );
257 - }
258 - }
259 -
260 - return $this->db;
261 - }
262 -
263 - public function get( $key ) {
264 - # expire old entries if any
265 - $this->garbageCollect();
266 - $db = $this->getDB();
267 - $row = $db->selectRow( 'objectcache', array( 'value', 'exptime' ),
268 - array( 'keyname' => $key ), __METHOD__ );
269 -
270 - if ( !$row ) {
271 - $this->debug( 'get: no matching rows' );
272 - return false;
273 - }
274 -
275 - $this->debug( "get: retrieved data; expiry time is " . $row->exptime );
276 -
277 - if ( $this->isExpired( $row->exptime ) ) {
278 - $this->debug( "get: key has expired, deleting" );
279 - try {
280 - $db->begin();
281 - # Put the expiry time in the WHERE condition to avoid deleting a
282 - # newly-inserted value
283 - $db->delete( 'objectcache',
284 - array(
285 - 'keyname' => $key,
286 - 'exptime' => $row->exptime
287 - ), __METHOD__ );
288 - $db->commit();
289 - } catch ( DBQueryError $e ) {
290 - $this->handleWriteError( $e );
291 - }
292 -
293 - return false;
294 - }
295 -
296 - return $this->unserialize( $db->decodeBlob( $row->value ) );
297 - }
298 -
299 - public function set( $key, $value, $exptime = 0 ) {
300 - $db = $this->getDB();
301 - $exptime = intval( $exptime );
302 -
303 - if ( $exptime < 0 ) {
304 - $exptime = 0;
305 - }
306 -
307 - if ( $exptime == 0 ) {
308 - $encExpiry = $this->getMaxDateTime();
309 - } else {
310 - if ( $exptime < 3.16e8 ) { # ~10 years
311 - $exptime += time();
312 - }
313 -
314 - $encExpiry = $db->timestamp( $exptime );
315 - }
316 - try {
317 - $db->begin();
318 - // (bug 24425) use a replace if the db supports it instead of
319 - // delete/insert to avoid clashes with conflicting keynames
320 - $db->replace( 'objectcache', array( 'keyname' ),
321 - array(
322 - 'keyname' => $key,
323 - 'value' => $db->encodeBlob( $this->serialize( $value ) ),
324 - 'exptime' => $encExpiry
325 - ), __METHOD__ );
326 - $db->commit();
327 - } catch ( DBQueryError $e ) {
328 - $this->handleWriteError( $e );
329 -
330 - return false;
331 - }
332 -
333 - return true;
334 - }
335 -
336 - public function delete( $key, $time = 0 ) {
337 - $db = $this->getDB();
338 -
339 - try {
340 - $db->begin();
341 - $db->delete( 'objectcache', array( 'keyname' => $key ), __METHOD__ );
342 - $db->commit();
343 - } catch ( DBQueryError $e ) {
344 - $this->handleWriteError( $e );
345 -
346 - return false;
347 - }
348 -
349 - return true;
350 - }
351 -
352 - public function incr( $key, $step = 1 ) {
353 - $db = $this->getDB();
354 - $step = intval( $step );
355 -
356 - try {
357 - $db->begin();
358 - $row = $db->selectRow( 'objectcache', array( 'value', 'exptime' ),
359 - array( 'keyname' => $key ), __METHOD__, array( 'FOR UPDATE' ) );
360 - if ( $row === false ) {
361 - // Missing
362 - $db->commit();
363 -
364 - return null;
365 - }
366 - $db->delete( 'objectcache', array( 'keyname' => $key ), __METHOD__ );
367 - if ( $this->isExpired( $row->exptime ) ) {
368 - // Expired, do not reinsert
369 - $db->commit();
370 -
371 - return null;
372 - }
373 -
374 - $oldValue = intval( $this->unserialize( $db->decodeBlob( $row->value ) ) );
375 - $newValue = $oldValue + $step;
376 - $db->insert( 'objectcache',
377 - array(
378 - 'keyname' => $key,
379 - 'value' => $db->encodeBlob( $this->serialize( $newValue ) ),
380 - 'exptime' => $row->exptime
381 - ), __METHOD__ );
382 - $db->commit();
383 - } catch ( DBQueryError $e ) {
384 - $this->handleWriteError( $e );
385 -
386 - return null;
387 - }
388 -
389 - return $newValue;
390 - }
391 -
392 - public function keys() {
393 - $db = $this->getDB();
394 - $res = $db->select( 'objectcache', array( 'keyname' ), false, __METHOD__ );
395 - $result = array();
396 -
397 - foreach ( $res as $row ) {
398 - $result[] = $row->keyname;
399 - }
400 -
401 - return $result;
402 - }
403 -
404 - protected function isExpired( $exptime ) {
405 - return $exptime != $this->getMaxDateTime() && wfTimestamp( TS_UNIX, $exptime ) < time();
406 - }
407 -
408 - protected function getMaxDateTime() {
409 - if ( time() > 0x7fffffff ) {
410 - return $this->getDB()->timestamp( 1 << 62 );
411 - } else {
412 - return $this->getDB()->timestamp( 0x7fffffff );
413 - }
414 - }
415 -
416 - protected function garbageCollect() {
417 - /* Ignore 99% of requests */
418 - if ( !mt_rand( 0, 100 ) ) {
419 - $now = time();
420 - /* Avoid repeating the delete within a few seconds */
421 - if ( $now > ( $this->lastExpireAll + 1 ) ) {
422 - $this->lastExpireAll = $now;
423 - $this->expireAll();
424 - }
425 - }
426 - }
427 -
428 - public function expireAll() {
429 - $db = $this->getDB();
430 - $now = $db->timestamp();
431 -
432 - try {
433 - $db->begin();
434 - $db->delete( 'objectcache', array( 'exptime < ' . $db->addQuotes( $now ) ), __METHOD__ );
435 - $db->commit();
436 - } catch ( DBQueryError $e ) {
437 - $this->handleWriteError( $e );
438 - }
439 - }
440 -
441 - public function deleteAll() {
442 - $db = $this->getDB();
443 -
444 - try {
445 - $db->begin();
446 - $db->delete( 'objectcache', '*', __METHOD__ );
447 - $db->commit();
448 - } catch ( DBQueryError $e ) {
449 - $this->handleWriteError( $e );
450 - }
451 - }
452 -
453 - /**
454 - * Serialize an object and, if possible, compress the representation.
455 - * On typical message and page data, this can provide a 3X decrease
456 - * in storage requirements.
457 - *
458 - * @param $data mixed
459 - * @return string
460 - */
461 - protected function serialize( &$data ) {
462 - $serial = serialize( $data );
463 -
464 - if ( function_exists( 'gzdeflate' ) ) {
465 - return gzdeflate( $serial );
466 - } else {
467 - return $serial;
468 - }
469 - }
470 -
471 - /**
472 - * Unserialize and, if necessary, decompress an object.
473 - * @param $serial string
474 - * @return mixed
475 - */
476 - protected function unserialize( $serial ) {
477 - if ( function_exists( 'gzinflate' ) ) {
478 - $decomp = @gzinflate( $serial );
479 -
480 - if ( false !== $decomp ) {
481 - $serial = $decomp;
482 - }
483 - }
484 -
485 - $ret = unserialize( $serial );
486 -
487 - return $ret;
488 - }
489 -
490 - /**
491 - * Handle a DBQueryError which occurred during a write operation.
492 - * Ignore errors which are due to a read-only database, rethrow others.
493 - */
494 - protected function handleWriteError( $exception ) {
495 - $db = $this->getDB();
496 -
497 - if ( !$db->wasReadOnlyError() ) {
498 - throw $exception;
499 - }
500 -
501 - try {
502 - $db->rollback();
503 - } catch ( DBQueryError $e ) {
504 - }
505 -
506 - wfDebug( __METHOD__ . ": ignoring query error\n" );
507 - $db->ignoreErrors( false );
508 - }
509 -}
510 -
511 -/**
512 - * Backwards compatibility alias
513 - */
514 -class MediaWikiBagOStuff extends SqlBagOStuff { }
515 -
516 -/**
517 - * This is a wrapper for APC's shared memory functions
518 - *
519 - * @ingroup Cache
520 - */
521 -class APCBagOStuff extends BagOStuff {
522 - public function get( $key ) {
523 - $val = apc_fetch( $key );
524 -
525 - if ( is_string( $val ) ) {
526 - $val = unserialize( $val );
527 - }
528 -
529 - return $val;
530 - }
531 -
532 - public function set( $key, $value, $exptime = 0 ) {
533 - apc_store( $key, serialize( $value ), $exptime );
534 -
535 - return true;
536 - }
537 -
538 - public function delete( $key, $time = 0 ) {
539 - apc_delete( $key );
540 -
541 - return true;
542 - }
543 -
544 - public function keys() {
545 - $info = apc_cache_info( 'user' );
546 - $list = $info['cache_list'];
547 - $keys = array();
548 -
549 - foreach ( $list as $entry ) {
550 - $keys[] = $entry['info'];
551 - }
552 -
553 - return $keys;
554 - }
555 -}
556 -
557 -/**
558 - * This is a wrapper for eAccelerator's shared memory functions.
559 - *
560 - * This is basically identical to the deceased Turck MMCache version,
561 - * mostly because eAccelerator is based on Turck MMCache.
562 - *
563 - * @ingroup Cache
564 - */
565 -class eAccelBagOStuff extends BagOStuff {
566 - public function get( $key ) {
567 - $val = eaccelerator_get( $key );
568 -
569 - if ( is_string( $val ) ) {
570 - $val = unserialize( $val );
571 - }
572 -
573 - return $val;
574 - }
575 -
576 - public function set( $key, $value, $exptime = 0 ) {
577 - eaccelerator_put( $key, serialize( $value ), $exptime );
578 -
579 - return true;
580 - }
581 -
582 - public function delete( $key, $time = 0 ) {
583 - eaccelerator_rm( $key );
584 -
585 - return true;
586 - }
587 -
588 - public function lock( $key, $waitTimeout = 0 ) {
589 - eaccelerator_lock( $key );
590 -
591 - return true;
592 - }
593 -
594 - public function unlock( $key ) {
595 - eaccelerator_unlock( $key );
596 -
597 - return true;
598 - }
599 -}
600 -
601 -/**
602 - * Wrapper for XCache object caching functions; identical interface
603 - * to the APC wrapper
604 - *
605 - * @ingroup Cache
606 - */
607 -class XCacheBagOStuff extends BagOStuff {
608 - /**
609 - * Get a value from the XCache object cache
610 - *
611 - * @param $key String: cache key
612 - * @return mixed
613 - */
614 - public function get( $key ) {
615 - $val = xcache_get( $key );
616 -
617 - if ( is_string( $val ) ) {
618 - $val = unserialize( $val );
619 - }
620 -
621 - return $val;
622 - }
623 -
624 - /**
625 - * Store a value in the XCache object cache
626 - *
627 - * @param $key String: cache key
628 - * @param $value Mixed: object to store
629 - * @param $expire Int: expiration time
630 - * @return bool
631 - */
632 - public function set( $key, $value, $expire = 0 ) {
633 - xcache_set( $key, serialize( $value ), $expire );
634 -
635 - return true;
636 - }
637 -
638 - /**
639 - * Remove a value from the XCache object cache
640 - *
641 - * @param $key String: cache key
642 - * @param $time Int: not used in this implementation
643 - * @return bool
644 - */
645 - public function delete( $key, $time = 0 ) {
646 - xcache_unset( $key );
647 -
648 - return true;
649 - }
650 -}
651 -
652 -/**
653 - * Cache that uses DBA as a backend.
654 - * Slow due to the need to constantly open and close the file to avoid holding
655 - * writer locks. Intended for development use only, as a memcached workalike
656 - * for systems that don't have it.
657 - *
658 - * @ingroup Cache
659 - */
660 -class DBABagOStuff extends BagOStuff {
661 - var $mHandler, $mFile, $mReader, $mWriter, $mDisabled;
662 -
663 - public function __construct( $dir = false ) {
664 - global $wgDBAhandler;
665 -
666 - if ( $dir === false ) {
667 - global $wgTmpDirectory;
668 - $dir = $wgTmpDirectory;
669 - }
670 -
671 - $this->mFile = "$dir/mw-cache-" . wfWikiID();
672 - $this->mFile .= '.db';
673 - wfDebug( __CLASS__ . ": using cache file {$this->mFile}\n" );
674 - $this->mHandler = $wgDBAhandler;
675 - }
676 -
677 - /**
678 - * Encode value and expiry for storage
679 - */
680 - function encode( $value, $expiry ) {
681 - # Convert to absolute time
682 - $expiry = $this->convertExpiry( $expiry );
683 -
684 - return sprintf( '%010u', intval( $expiry ) ) . ' ' . serialize( $value );
685 - }
686 -
687 - /**
688 - * @return list containing value first and expiry second
689 - */
690 - function decode( $blob ) {
691 - if ( !is_string( $blob ) ) {
692 - return array( null, 0 );
693 - } else {
694 - return array(
695 - unserialize( substr( $blob, 11 ) ),
696 - intval( substr( $blob, 0, 10 ) )
697 - );
698 - }
699 - }
700 -
701 - function getReader() {
702 - if ( file_exists( $this->mFile ) ) {
703 - $handle = dba_open( $this->mFile, 'rl', $this->mHandler );
704 - } else {
705 - $handle = $this->getWriter();
706 - }
707 -
708 - if ( !$handle ) {
709 - wfDebug( "Unable to open DBA cache file {$this->mFile}\n" );
710 - }
711 -
712 - return $handle;
713 - }
714 -
715 - function getWriter() {
716 - $handle = dba_open( $this->mFile, 'cl', $this->mHandler );
717 -
718 - if ( !$handle ) {
719 - wfDebug( "Unable to open DBA cache file {$this->mFile}\n" );
720 - }
721 -
722 - return $handle;
723 - }
724 -
725 - function get( $key ) {
726 - wfProfileIn( __METHOD__ );
727 - wfDebug( __METHOD__ . "($key)\n" );
728 -
729 - $handle = $this->getReader();
730 - if ( !$handle ) {
731 - wfProfileOut( __METHOD__ );
732 - return null;
733 - }
734 -
735 - $val = dba_fetch( $key, $handle );
736 - list( $val, $expiry ) = $this->decode( $val );
737 -
738 - # Must close ASAP because locks are held
739 - dba_close( $handle );
740 -
741 - if ( !is_null( $val ) && $expiry && $expiry < time() ) {
742 - # Key is expired, delete it
743 - $handle = $this->getWriter();
744 - dba_delete( $key, $handle );
745 - dba_close( $handle );
746 - wfDebug( __METHOD__ . ": $key expired\n" );
747 - $val = null;
748 - }
749 -
750 - wfProfileOut( __METHOD__ );
751 - return $val;
752 - }
753 -
754 - function set( $key, $value, $exptime = 0 ) {
755 - wfProfileIn( __METHOD__ );
756 - wfDebug( __METHOD__ . "($key)\n" );
757 -
758 - $blob = $this->encode( $value, $exptime );
759 -
760 - $handle = $this->getWriter();
761 - if ( !$handle ) {
762 - wfProfileOut( __METHOD__ );
763 - return false;
764 - }
765 -
766 - $ret = dba_replace( $key, $blob, $handle );
767 - dba_close( $handle );
768 -
769 - wfProfileOut( __METHOD__ );
770 - return $ret;
771 - }
772 -
773 - function delete( $key, $time = 0 ) {
774 - wfProfileIn( __METHOD__ );
775 - wfDebug( __METHOD__ . "($key)\n" );
776 -
777 - $handle = $this->getWriter();
778 - if ( !$handle ) {
779 - wfProfileOut( __METHOD__ );
780 - return false;
781 - }
782 -
783 - $ret = dba_delete( $key, $handle );
784 - dba_close( $handle );
785 -
786 - wfProfileOut( __METHOD__ );
787 - return $ret;
788 - }
789 -
790 - function add( $key, $value, $exptime = 0 ) {
791 - wfProfileIn( __METHOD__ );
792 -
793 - $blob = $this->encode( $value, $exptime );
794 -
795 - $handle = $this->getWriter();
796 -
797 - if ( !$handle ) {
798 - wfProfileOut( __METHOD__ );
799 - return false;
800 - }
801 -
802 - $ret = dba_insert( $key, $blob, $handle );
803 -
804 - # Insert failed, check to see if it failed due to an expired key
805 - if ( !$ret ) {
806 - list( $value, $expiry ) = $this->decode( dba_fetch( $key, $handle ) );
807 -
808 - if ( $expiry < time() ) {
809 - # Yes expired, delete and try again
810 - dba_delete( $key, $handle );
811 - $ret = dba_insert( $key, $blob, $handle );
812 - # This time if it failed then it will be handled by the caller like any other race
813 - }
814 - }
815 -
816 - dba_close( $handle );
817 -
818 - wfProfileOut( __METHOD__ );
819 - return $ret;
820 - }
821 -
822 - function keys() {
823 - $reader = $this->getReader();
824 - $k1 = dba_firstkey( $reader );
825 -
826 - if ( !$k1 ) {
827 - return array();
828 - }
829 -
830 - $result[] = $k1;
831 -
832 - while ( $key = dba_nextkey( $reader ) ) {
833 - $result[] = $key;
834 - }
835 -
836 - return $result;
837 - }
838 -}
839 -
840 -/**
841 - * Wrapper for WinCache object caching functions; identical interface
842 - * to the APC wrapper
843 - *
844 - * @ingroup Cache
845 - */
846 -class WinCacheBagOStuff extends BagOStuff {
847 -
848 - /**
849 - * Get a value from the WinCache object cache
850 - *
851 - * @param $key String: cache key
852 - * @return mixed
853 - */
854 - public function get( $key ) {
855 - $val = wincache_ucache_get( $key );
856 -
857 - if ( is_string( $val ) ) {
858 - $val = unserialize( $val );
859 - }
860 -
861 - return $val;
862 - }
863 -
864 - /**
865 - * Store a value in the WinCache object cache
866 - *
867 - * @param $key String: cache key
868 - * @param $value Mixed: object to store
869 - * @param $expire Int: expiration time
870 - * @return bool
871 - */
872 - public function set( $key, $value, $expire = 0 ) {
873 - wincache_ucache_set( $key, serialize( $value ), $expire );
874 -
875 - return true;
876 - }
877 -
878 - /**
879 - * Remove a value from the WinCache object cache
880 - *
881 - * @param $key String: cache key
882 - * @param $time Int: not used in this implementation
883 - * @return bool
884 - */
885 - public function delete( $key, $time = 0 ) {
886 - wincache_ucache_delete( $key );
887 -
888 - return true;
889 - }
890 -
891 - public function keys() {
892 - $info = wincache_ucache_info();
893 - $list = $info['ucache_entries'];
894 - $keys = array();
895 -
896 - foreach ( $list as $entry ) {
897 - $keys[] = $entry['key_name'];
898 - }
899 -
900 - return $keys;
901 - }
902 -}
Index: branches/wmf/1.17wmf1/includes/ObjectCache.php
@@ -1,123 +0,0 @@
2 -<?php
3 -/**
4 - * Functions to get cache objects
5 - *
6 - * @file
7 - * @ingroup Cache
8 - */
9 -
10 -/**
11 - * FakeMemCachedClient imitates the API of memcached-client v. 0.1.2.
12 - * It acts as a memcached server with no RAM, that is, all objects are
13 - * cleared the moment they are set. All set operations succeed and all
14 - * get operations return null.
15 - * @ingroup Cache
16 - */
17 -class FakeMemCachedClient {
18 - function add ($key, $val, $exp = 0) { return true; }
19 - function decr ($key, $amt=1) { return null; }
20 - function delete ($key, $time = 0) { return false; }
21 - function disconnect_all () { }
22 - function enable_compress ($enable) { }
23 - function forget_dead_hosts () { }
24 - function get ($key) { return null; }
25 - function get_multi ($keys) { return array_pad(array(), count($keys), null); }
26 - function incr ($key, $amt=1) { return null; }
27 - function replace ($key, $value, $exp=0) { return false; }
28 - function run_command ($sock, $cmd) { return null; }
29 - function set ($key, $value, $exp=0){ return true; }
30 - function set_compress_threshold ($thresh){ }
31 - function set_debug ($dbg) { }
32 - function set_servers ($list) { }
33 -}
34 -
35 -global $wgCaches;
36 -$wgCaches = array();
37 -
38 -/**
39 - * Get a cache object.
40 - * @param $inputType Integer: cache type, one the the CACHE_* constants.
41 - */
42 -function &wfGetCache( $inputType ) {
43 - global $wgCaches, $wgMemCachedServers, $wgMemCachedDebug, $wgMemCachedPersistent;
44 - $cache = false;
45 -
46 - if ( $inputType == CACHE_ANYTHING ) {
47 - reset( $wgCaches );
48 - $type = key( $wgCaches );
49 - if ( $type === false || $type === CACHE_NONE ) {
50 - $type = CACHE_DB;
51 - }
52 - } else {
53 - $type = $inputType;
54 - }
55 -
56 - if ( $type == CACHE_MEMCACHED ) {
57 - if ( !array_key_exists( CACHE_MEMCACHED, $wgCaches ) ) {
58 - $wgCaches[CACHE_MEMCACHED] = new MemCachedClientforWiki(
59 - array('persistant' => $wgMemCachedPersistent, 'compress_threshold' => 1500 ) );
60 - $wgCaches[CACHE_MEMCACHED]->set_servers( $wgMemCachedServers );
61 - $wgCaches[CACHE_MEMCACHED]->set_debug( $wgMemCachedDebug );
62 - }
63 - $cache =& $wgCaches[CACHE_MEMCACHED];
64 - } elseif ( $type == CACHE_ACCEL ) {
65 - if ( !array_key_exists( CACHE_ACCEL, $wgCaches ) ) {
66 - if ( function_exists( 'eaccelerator_get' ) ) {
67 - $wgCaches[CACHE_ACCEL] = new eAccelBagOStuff;
68 - } elseif ( function_exists( 'apc_fetch') ) {
69 - $wgCaches[CACHE_ACCEL] = new APCBagOStuff;
70 - } elseif( function_exists( 'xcache_get' ) ) {
71 - $wgCaches[CACHE_ACCEL] = new XCacheBagOStuff();
72 - } elseif( function_exists( 'wincache_ucache_get' ) ) {
73 - $wgCaches[CACHE_ACCEL] = new WinCacheBagOStuff();
74 - } else {
75 - $wgCaches[CACHE_ACCEL] = false;
76 - }
77 - }
78 - if ( $wgCaches[CACHE_ACCEL] !== false ) {
79 - $cache =& $wgCaches[CACHE_ACCEL];
80 - }
81 - } elseif ( $type == CACHE_DBA ) {
82 - if ( !array_key_exists( CACHE_DBA, $wgCaches ) ) {
83 - $wgCaches[CACHE_DBA] = new DBABagOStuff;
84 - }
85 - $cache =& $wgCaches[CACHE_DBA];
86 - }
87 -
88 - if ( $type == CACHE_DB || ( $inputType == CACHE_ANYTHING && $cache === false ) ) {
89 - if ( !array_key_exists( CACHE_DB, $wgCaches ) ) {
90 - $wgCaches[CACHE_DB] = new SqlBagOStuff('objectcache');
91 - }
92 - $cache =& $wgCaches[CACHE_DB];
93 - }
94 -
95 - if ( $cache === false ) {
96 - if ( !array_key_exists( CACHE_NONE, $wgCaches ) ) {
97 - $wgCaches[CACHE_NONE] = new FakeMemCachedClient;
98 - }
99 - $cache =& $wgCaches[CACHE_NONE];
100 - }
101 -
102 - return $cache;
103 -}
104 -
105 -/** Get the main cache object */
106 -function &wfGetMainCache() {
107 - global $wgMainCacheType;
108 - $ret =& wfGetCache( $wgMainCacheType );
109 - return $ret;
110 -}
111 -
112 -/** Get the cache object used by the message cache */
113 -function &wfGetMessageCacheStorage() {
114 - global $wgMessageCacheType;
115 - $ret =& wfGetCache( $wgMessageCacheType );
116 - return $ret;
117 -}
118 -
119 -/** Get the cache object used by the parser cache */
120 -function &wfGetParserCacheStorage() {
121 - global $wgParserCacheType;
122 - $ret =& wfGetCache( $wgParserCacheType );
123 - return $ret;
124 -}
Index: branches/wmf/1.17wmf1/includes/memcached-client.php
@@ -1,1096 +0,0 @@
2 -<?php
3 -/**
4 - * +---------------------------------------------------------------------------+
5 - * | memcached client, PHP |
6 - * +---------------------------------------------------------------------------+
7 - * | Copyright (c) 2003 Ryan T. Dean <rtdean@cytherianage.net> |
8 - * | All rights reserved. |
9 - * | |
10 - * | Redistribution and use in source and binary forms, with or without |
11 - * | modification, are permitted provided that the following conditions |
12 - * | are met: |
13 - * | |
14 - * | 1. Redistributions of source code must retain the above copyright |
15 - * | notice, this list of conditions and the following disclaimer. |
16 - * | 2. Redistributions in binary form must reproduce the above copyright |
17 - * | notice, this list of conditions and the following disclaimer in the |
18 - * | documentation and/or other materials provided with the distribution. |
19 - * | |
20 - * | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
21 - * | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
22 - * | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
23 - * | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
24 - * | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
25 - * | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 - * | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 - * | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 - * | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
29 - * | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 - * +---------------------------------------------------------------------------+
31 - * | Author: Ryan T. Dean <rtdean@cytherianage.net> |
32 - * | Heavily influenced by the Perl memcached client by Brad Fitzpatrick. |
33 - * | Permission granted by Brad Fitzpatrick for relicense of ported Perl |
34 - * | client logic under 2-clause BSD license. |
35 - * +---------------------------------------------------------------------------+
36 - *
37 - * @file
38 - * $TCAnet$
39 - */
40 -
41 -/**
42 - * This is the PHP client for memcached - a distributed memory cache daemon.
43 - * More information is available at http://www.danga.com/memcached/
44 - *
45 - * Usage example:
46 - *
47 - * require_once 'memcached.php';
48 - *
49 - * $mc = new MWMemcached(array(
50 - * 'servers' => array('127.0.0.1:10000',
51 - * array('192.0.0.1:10010', 2),
52 - * '127.0.0.1:10020'),
53 - * 'debug' => false,
54 - * 'compress_threshold' => 10240,
55 - * 'persistant' => true));
56 - *
57 - * $mc->add('key', array('some', 'array'));
58 - * $mc->replace('key', 'some random string');
59 - * $val = $mc->get('key');
60 - *
61 - * @author Ryan T. Dean <rtdean@cytherianage.net>
62 - * @version 0.1.2
63 - */
64 -
65 -// {{{ requirements
66 -// }}}
67 -
68 -// {{{ class MWMemcached
69 -/**
70 - * memcached client class implemented using (p)fsockopen()
71 - *
72 - * @author Ryan T. Dean <rtdean@cytherianage.net>
73 - * @ingroup Cache
74 - */
75 -class MWMemcached {
76 - // {{{ properties
77 - // {{{ public
78 -
79 - // {{{ constants
80 - // {{{ flags
81 -
82 - /**
83 - * Flag: indicates data is serialized
84 - */
85 - const SERIALIZED = 1;
86 -
87 - /**
88 - * Flag: indicates data is compressed
89 - */
90 - const COMPRESSED = 2;
91 -
92 - // }}}
93 -
94 - /**
95 - * Minimum savings to store data compressed
96 - */
97 - const COMPRESSION_SAVINGS = 0.20;
98 -
99 - // }}}
100 -
101 -
102 - /**
103 - * Command statistics
104 - *
105 - * @var array
106 - * @access public
107 - */
108 - var $stats;
109 -
110 - // }}}
111 - // {{{ private
112 -
113 - /**
114 - * Cached Sockets that are connected
115 - *
116 - * @var array
117 - * @access private
118 - */
119 - var $_cache_sock;
120 -
121 - /**
122 - * Current debug status; 0 - none to 9 - profiling
123 - *
124 - * @var boolean
125 - * @access private
126 - */
127 - var $_debug;
128 -
129 - /**
130 - * Dead hosts, assoc array, 'host'=>'unixtime when ok to check again'
131 - *
132 - * @var array
133 - * @access private
134 - */
135 - var $_host_dead;
136 -
137 - /**
138 - * Is compression available?
139 - *
140 - * @var boolean
141 - * @access private
142 - */
143 - var $_have_zlib;
144 -
145 - /**
146 - * Do we want to use compression?
147 - *
148 - * @var boolean
149 - * @access private
150 - */
151 - var $_compress_enable;
152 -
153 - /**
154 - * At how many bytes should we compress?
155 - *
156 - * @var integer
157 - * @access private
158 - */
159 - var $_compress_threshold;
160 -
161 - /**
162 - * Are we using persistant links?
163 - *
164 - * @var boolean
165 - * @access private
166 - */
167 - var $_persistant;
168 -
169 - /**
170 - * If only using one server; contains ip:port to connect to
171 - *
172 - * @var string
173 - * @access private
174 - */
175 - var $_single_sock;
176 -
177 - /**
178 - * Array containing ip:port or array(ip:port, weight)
179 - *
180 - * @var array
181 - * @access private
182 - */
183 - var $_servers;
184 -
185 - /**
186 - * Our bit buckets
187 - *
188 - * @var array
189 - * @access private
190 - */
191 - var $_buckets;
192 -
193 - /**
194 - * Total # of bit buckets we have
195 - *
196 - * @var integer
197 - * @access private
198 - */
199 - var $_bucketcount;
200 -
201 - /**
202 - * # of total servers we have
203 - *
204 - * @var integer
205 - * @access private
206 - */
207 - var $_active;
208 -
209 - /**
210 - * Stream timeout in seconds. Applies for example to fread()
211 - *
212 - * @var integer
213 - * @access private
214 - */
215 - var $_timeout_seconds;
216 -
217 - /**
218 - * Stream timeout in microseconds
219 - *
220 - * @var integer
221 - * @access private
222 - */
223 - var $_timeout_microseconds;
224 -
225 - /**
226 - * Connect timeout in seconds
227 - */
228 - var $_connect_timeout;
229 -
230 - /**
231 - * Number of connection attempts for each server
232 - */
233 - var $_connect_attempts;
234 -
235 - // }}}
236 - // }}}
237 - // {{{ methods
238 - // {{{ public functions
239 - // {{{ memcached()
240 -
241 - /**
242 - * Memcache initializer
243 - *
244 - * @param $args Array Associative array of settings
245 - *
246 - * @return mixed
247 - */
248 - public function __construct( $args ) {
249 - global $wgMemCachedTimeout;
250 - $this->set_servers( isset( $args['servers'] ) ? $args['servers'] : array() );
251 - $this->_debug = isset( $args['debug'] ) ? $args['debug'] : false;
252 - $this->stats = array();
253 - $this->_compress_threshold = isset( $args['compress_threshold'] ) ? $args['compress_threshold'] : 0;
254 - $this->_persistant = isset( $args['persistant'] ) ? $args['persistant'] : false;
255 - $this->_compress_enable = true;
256 - $this->_have_zlib = function_exists( 'gzcompress' );
257 -
258 - $this->_cache_sock = array();
259 - $this->_host_dead = array();
260 -
261 - $this->_timeout_seconds = 0;
262 - $this->_timeout_microseconds = $wgMemCachedTimeout;
263 -
264 - $this->_connect_timeout = 0.01;
265 - $this->_connect_attempts = 2;
266 - }
267 -
268 - // }}}
269 - // {{{ add()
270 -
271 - /**
272 - * Adds a key/value to the memcache server if one isn't already set with
273 - * that key
274 - *
275 - * @param $key String: key to set with data
276 - * @param $val Mixed: value to store
277 - * @param $exp Integer: (optional) Expiration time. This can be a number of seconds
278 - * to cache for (up to 30 days inclusive). Any timespans of 30 days + 1 second or
279 - * longer must be the timestamp of the time at which the mapping should expire. It
280 - * is safe to use timestamps in all cases, regardless of exipration
281 - * eg: strtotime("+3 hour")
282 - *
283 - * @return Boolean
284 - */
285 - public function add( $key, $val, $exp = 0 ) {
286 - return $this->_set( 'add', $key, $val, $exp );
287 - }
288 -
289 - // }}}
290 - // {{{ decr()
291 -
292 - /**
293 - * Decrease a value stored on the memcache server
294 - *
295 - * @param $key String: key to decrease
296 - * @param $amt Integer: (optional) amount to decrease
297 - *
298 - * @return Mixed: FALSE on failure, value on success
299 - */
300 - public function decr( $key, $amt = 1 ) {
301 - return $this->_incrdecr( 'decr', $key, $amt );
302 - }
303 -
304 - // }}}
305 - // {{{ delete()
306 -
307 - /**
308 - * Deletes a key from the server, optionally after $time
309 - *
310 - * @param $key String: key to delete
311 - * @param $time Integer: (optional) how long to wait before deleting
312 - *
313 - * @return Boolean: TRUE on success, FALSE on failure
314 - */
315 - public function delete( $key, $time = 0 ) {
316 - if ( !$this->_active ) {
317 - return false;
318 - }
319 -
320 - $sock = $this->get_sock( $key );
321 - if ( !is_resource( $sock ) ) {
322 - return false;
323 - }
324 -
325 - $key = is_array( $key ) ? $key[1] : $key;
326 -
327 - if ( isset( $this->stats['delete'] ) ) {
328 - $this->stats['delete']++;
329 - } else {
330 - $this->stats['delete'] = 1;
331 - }
332 - $cmd = "delete $key $time\r\n";
333 - if( !$this->_safe_fwrite( $sock, $cmd, strlen( $cmd ) ) ) {
334 - $this->_dead_sock( $sock );
335 - return false;
336 - }
337 - $res = trim( fgets( $sock ) );
338 -
339 - if ( $this->_debug ) {
340 - $this->_debugprint( sprintf( "MemCache: delete %s (%s)\n", $key, $res ) );
341 - }
342 -
343 - if ( $res == "DELETED" ) {
344 - return true;
345 - }
346 - return false;
347 - }
348 -
349 - // }}}
350 - // {{{ disconnect_all()
351 -
352 - /**
353 - * Disconnects all connected sockets
354 - */
355 - public function disconnect_all() {
356 - foreach ( $this->_cache_sock as $sock ) {
357 - fclose( $sock );
358 - }
359 -
360 - $this->_cache_sock = array();
361 - }
362 -
363 - // }}}
364 - // {{{ enable_compress()
365 -
366 - /**
367 - * Enable / Disable compression
368 - *
369 - * @param $enable Boolean: TRUE to enable, FALSE to disable
370 - */
371 - public function enable_compress( $enable ) {
372 - $this->_compress_enable = $enable;
373 - }
374 -
375 - // }}}
376 - // {{{ forget_dead_hosts()
377 -
378 - /**
379 - * Forget about all of the dead hosts
380 - */
381 - public function forget_dead_hosts() {
382 - $this->_host_dead = array();
383 - }
384 -
385 - // }}}
386 - // {{{ get()
387 -
388 - /**
389 - * Retrieves the value associated with the key from the memcache server
390 - *
391 - * @param $key Mixed: key to retrieve
392 - *
393 - * @return Mixed
394 - */
395 - public function get( $key ) {
396 - wfProfileIn( __METHOD__ );
397 -
398 - if ( $this->_debug ) {
399 - $this->_debugprint( "get($key)\n" );
400 - }
401 -
402 - if ( !$this->_active ) {
403 - wfProfileOut( __METHOD__ );
404 - return false;
405 - }
406 -
407 - $sock = $this->get_sock( $key );
408 -
409 - if ( !is_resource( $sock ) ) {
410 - wfProfileOut( __METHOD__ );
411 - return false;
412 - }
413 -
414 - if ( isset( $this->stats['get'] ) ) {
415 - $this->stats['get']++;
416 - } else {
417 - $this->stats['get'] = 1;
418 - }
419 -
420 - $cmd = "get $key\r\n";
421 - if ( !$this->_safe_fwrite( $sock, $cmd, strlen( $cmd ) ) ) {
422 - $this->_dead_sock( $sock );
423 - wfProfileOut( __METHOD__ );
424 - return false;
425 - }
426 -
427 - $val = array();
428 - $this->_load_items( $sock, $val );
429 -
430 - if ( $this->_debug ) {
431 - foreach ( $val as $k => $v ) {
432 - $this->_debugprint( sprintf( "MemCache: sock %s got %s\n", serialize( $sock ), $k ) );
433 - }
434 - }
435 -
436 - wfProfileOut( __METHOD__ );
437 - return @$val[$key];
438 - }
439 -
440 - // }}}
441 - // {{{ get_multi()
442 -
443 - /**
444 - * Get multiple keys from the server(s)
445 - *
446 - * @param $keys Array: keys to retrieve
447 - *
448 - * @return Array
449 - */
450 - public function get_multi( $keys ) {
451 - if ( !$this->_active ) {
452 - return false;
453 - }
454 -
455 - if ( isset( $this->stats['get_multi'] ) ) {
456 - $this->stats['get_multi']++;
457 - } else {
458 - $this->stats['get_multi'] = 1;
459 - }
460 - $sock_keys = array();
461 -
462 - foreach ( $keys as $key ) {
463 - $sock = $this->get_sock( $key );
464 - if ( !is_resource( $sock ) ) {
465 - continue;
466 - }
467 - $key = is_array( $key ) ? $key[1] : $key;
468 - if ( !isset( $sock_keys[$sock] ) ) {
469 - $sock_keys[$sock] = array();
470 - $socks[] = $sock;
471 - }
472 - $sock_keys[$sock][] = $key;
473 - }
474 -
475 - // Send out the requests
476 - foreach ( $socks as $sock ) {
477 - $cmd = 'get';
478 - foreach ( $sock_keys[$sock] as $key ) {
479 - $cmd .= ' ' . $key;
480 - }
481 - $cmd .= "\r\n";
482 -
483 - if ( $this->_safe_fwrite( $sock, $cmd, strlen( $cmd ) ) ) {
484 - $gather[] = $sock;
485 - } else {
486 - $this->_dead_sock( $sock );
487 - }
488 - }
489 -
490 - // Parse responses
491 - $val = array();
492 - foreach ( $gather as $sock ) {
493 - $this->_load_items( $sock, $val );
494 - }
495 -
496 - if ( $this->_debug ) {
497 - foreach ( $val as $k => $v ) {
498 - $this->_debugprint( sprintf( "MemCache: got %s\n", $k ) );
499 - }
500 - }
501 -
502 - return $val;
503 - }
504 -
505 - // }}}
506 - // {{{ incr()
507 -
508 - /**
509 - * Increments $key (optionally) by $amt
510 - *
511 - * @param $key String: key to increment
512 - * @param $amt Integer: (optional) amount to increment
513 - *
514 - * @return Integer: null if the key does not exist yet (this does NOT
515 - * create new mappings if the key does not exist). If the key does
516 - * exist, this returns the new value for that key.
517 - */
518 - public function incr( $key, $amt = 1 ) {
519 - return $this->_incrdecr( 'incr', $key, $amt );
520 - }
521 -
522 - // }}}
523 - // {{{ replace()
524 -
525 - /**
526 - * Overwrites an existing value for key; only works if key is already set
527 - *
528 - * @param $key String: key to set value as
529 - * @param $value Mixed: value to store
530 - * @param $exp Integer: (optional) Expiration time. This can be a number of seconds
531 - * to cache for (up to 30 days inclusive). Any timespans of 30 days + 1 second or
532 - * longer must be the timestamp of the time at which the mapping should expire. It
533 - * is safe to use timestamps in all cases, regardless of exipration
534 - * eg: strtotime("+3 hour")
535 - *
536 - * @return Boolean
537 - */
538 - public function replace( $key, $value, $exp = 0 ) {
539 - return $this->_set( 'replace', $key, $value, $exp );
540 - }
541 -
542 - // }}}
543 - // {{{ run_command()
544 -
545 - /**
546 - * Passes through $cmd to the memcache server connected by $sock; returns
547 - * output as an array (null array if no output)
548 - *
549 - * NOTE: due to a possible bug in how PHP reads while using fgets(), each
550 - * line may not be terminated by a \r\n. More specifically, my testing
551 - * has shown that, on FreeBSD at least, each line is terminated only
552 - * with a \n. This is with the PHP flag auto_detect_line_endings set
553 - * to falase (the default).
554 - *
555 - * @param $sock Ressource: socket to send command on
556 - * @param $cmd String: command to run
557 - *
558 - * @return Array: output array
559 - */
560 - public function run_command( $sock, $cmd ) {
561 - if ( !is_resource( $sock ) ) {
562 - return array();
563 - }
564 -
565 - if ( !$this->_safe_fwrite( $sock, $cmd, strlen( $cmd ) ) ) {
566 - return array();
567 - }
568 -
569 - while ( true ) {
570 - $res = fgets( $sock );
571 - $ret[] = $res;
572 - if ( preg_match( '/^END/', $res ) ) {
573 - break;
574 - }
575 - if ( strlen( $res ) == 0 ) {
576 - break;
577 - }
578 - }
579 - return $ret;
580 - }
581 -
582 - // }}}
583 - // {{{ set()
584 -
585 - /**
586 - * Unconditionally sets a key to a given value in the memcache. Returns true
587 - * if set successfully.
588 - *
589 - * @param $key String: key to set value as
590 - * @param $value Mixed: value to set
591 - * @param $exp Integer: (optional) Expiration time. This can be a number of seconds
592 - * to cache for (up to 30 days inclusive). Any timespans of 30 days + 1 second or
593 - * longer must be the timestamp of the time at which the mapping should expire. It
594 - * is safe to use timestamps in all cases, regardless of exipration
595 - * eg: strtotime("+3 hour")
596 - *
597 - * @return Boolean: TRUE on success
598 - */
599 - public function set( $key, $value, $exp = 0 ) {
600 - return $this->_set( 'set', $key, $value, $exp );
601 - }
602 -
603 - // }}}
604 - // {{{ set_compress_threshold()
605 -
606 - /**
607 - * Sets the compression threshold
608 - *
609 - * @param $thresh Integer: threshold to compress if larger than
610 - */
611 - public function set_compress_threshold( $thresh ) {
612 - $this->_compress_threshold = $thresh;
613 - }
614 -
615 - // }}}
616 - // {{{ set_debug()
617 -
618 - /**
619 - * Sets the debug flag
620 - *
621 - * @param $dbg Boolean: TRUE for debugging, FALSE otherwise
622 - *
623 - * @see MWMemcached::__construct
624 - */
625 - public function set_debug( $dbg ) {
626 - $this->_debug = $dbg;
627 - }
628 -
629 - // }}}
630 - // {{{ set_servers()
631 -
632 - /**
633 - * Sets the server list to distribute key gets and puts between
634 - *
635 - * @param $list Array of servers to connect to
636 - *
637 - * @see MWMemcached::__construct()
638 - */
639 - public function set_servers( $list ) {
640 - $this->_servers = $list;
641 - $this->_active = count( $list );
642 - $this->_buckets = null;
643 - $this->_bucketcount = 0;
644 -
645 - $this->_single_sock = null;
646 - if ( $this->_active == 1 ) {
647 - $this->_single_sock = $this->_servers[0];
648 - }
649 - }
650 -
651 - /**
652 - * Sets the timeout for new connections
653 - *
654 - * @param $seconds Integer: number of seconds
655 - * @param $microseconds Integer: number of microseconds
656 - */
657 - public function set_timeout( $seconds, $microseconds ) {
658 - $this->_timeout_seconds = $seconds;
659 - $this->_timeout_microseconds = $microseconds;
660 - }
661 -
662 - // }}}
663 - // }}}
664 - // {{{ private methods
665 - // {{{ _close_sock()
666 -
667 - /**
668 - * Close the specified socket
669 - *
670 - * @param $sock String: socket to close
671 - *
672 - * @access private
673 - */
674 - function _close_sock( $sock ) {
675 - $host = array_search( $sock, $this->_cache_sock );
676 - fclose( $this->_cache_sock[$host] );
677 - unset( $this->_cache_sock[$host] );
678 - }
679 -
680 - // }}}
681 - // {{{ _connect_sock()
682 -
683 - /**
684 - * Connects $sock to $host, timing out after $timeout
685 - *
686 - * @param $sock Integer: socket to connect
687 - * @param $host String: Host:IP to connect to
688 - *
689 - * @return boolean
690 - * @access private
691 - */
692 - function _connect_sock( &$sock, $host ) {
693 - list( $ip, $port ) = explode( ':', $host );
694 - $sock = false;
695 - $timeout = $this->_connect_timeout;
696 - $errno = $errstr = null;
697 - for( $i = 0; !$sock && $i < $this->_connect_attempts; $i++ ) {
698 - wfSuppressWarnings();
699 - if ( $this->_persistant == 1 ) {
700 - $sock = pfsockopen( $ip, $port, $errno, $errstr, $timeout );
701 - } else {
702 - $sock = fsockopen( $ip, $port, $errno, $errstr, $timeout );
703 - }
704 - wfRestoreWarnings();
705 - }
706 - if ( !$sock ) {
707 - if ( $this->_debug ) {
708 - $this->_debugprint( "Error connecting to $host: $errstr\n" );
709 - }
710 - return false;
711 - }
712 -
713 - // Initialise timeout
714 - stream_set_timeout( $sock, $this->_timeout_seconds, $this->_timeout_microseconds );
715 -
716 - return true;
717 - }
718 -
719 - // }}}
720 - // {{{ _dead_sock()
721 -
722 - /**
723 - * Marks a host as dead until 30-40 seconds in the future
724 - *
725 - * @param $sock String: socket to mark as dead
726 - *
727 - * @access private
728 - */
729 - function _dead_sock( $sock ) {
730 - $host = array_search( $sock, $this->_cache_sock );
731 - $this->_dead_host( $host );
732 - }
733 -
734 - function _dead_host( $host ) {
735 - $parts = explode( ':', $host );
736 - $ip = $parts[0];
737 - $this->_host_dead[$ip] = time() + 30 + intval( rand( 0, 10 ) );
738 - $this->_host_dead[$host] = $this->_host_dead[$ip];
739 - unset( $this->_cache_sock[$host] );
740 - }
741 -
742 - // }}}
743 - // {{{ get_sock()
744 -
745 - /**
746 - * get_sock
747 - *
748 - * @param $key String: key to retrieve value for;
749 - *
750 - * @return Mixed: resource on success, false on failure
751 - * @access private
752 - */
753 - function get_sock( $key ) {
754 - if ( !$this->_active ) {
755 - return false;
756 - }
757 -
758 - if ( $this->_single_sock !== null ) {
759 - $this->_flush_read_buffer( $this->_single_sock );
760 - return $this->sock_to_host( $this->_single_sock );
761 - }
762 -
763 - $hv = is_array( $key ) ? intval( $key[0] ) : $this->_hashfunc( $key );
764 -
765 - if ( $this->_buckets === null ) {
766 - foreach ( $this->_servers as $v ) {
767 - if ( is_array( $v ) ) {
768 - for( $i = 0; $i < $v[1]; $i++ ) {
769 - $bu[] = $v[0];
770 - }
771 - } else {
772 - $bu[] = $v;
773 - }
774 - }
775 - $this->_buckets = $bu;
776 - $this->_bucketcount = count( $bu );
777 - }
778 -
779 - $realkey = is_array( $key ) ? $key[1] : $key;
780 - for( $tries = 0; $tries < 20; $tries++ ) {
781 - $host = $this->_buckets[$hv % $this->_bucketcount];
782 - $sock = $this->sock_to_host( $host );
783 - if ( is_resource( $sock ) ) {
784 - $this->_flush_read_buffer( $sock );
785 - return $sock;
786 - }
787 - $hv = $this->_hashfunc( $hv . $realkey );
788 - }
789 -
790 - return false;
791 - }
792 -
793 - // }}}
794 - // {{{ _hashfunc()
795 -
796 - /**
797 - * Creates a hash integer based on the $key
798 - *
799 - * @param $key String: key to hash
800 - *
801 - * @return Integer: hash value
802 - * @access private
803 - */
804 - function _hashfunc( $key ) {
805 - # Hash function must on [0,0x7ffffff]
806 - # We take the first 31 bits of the MD5 hash, which unlike the hash
807 - # function used in a previous version of this client, works
808 - return hexdec( substr( md5( $key ), 0, 8 ) ) & 0x7fffffff;
809 - }
810 -
811 - // }}}
812 - // {{{ _incrdecr()
813 -
814 - /**
815 - * Perform increment/decriment on $key
816 - *
817 - * @param $cmd String: command to perform
818 - * @param $key String: key to perform it on
819 - * @param $amt Integer: amount to adjust
820 - *
821 - * @return Integer: new value of $key
822 - * @access private
823 - */
824 - function _incrdecr( $cmd, $key, $amt = 1 ) {
825 - if ( !$this->_active ) {
826 - return null;
827 - }
828 -
829 - $sock = $this->get_sock( $key );
830 - if ( !is_resource( $sock ) ) {
831 - return null;
832 - }
833 -
834 - $key = is_array( $key ) ? $key[1] : $key;
835 - if ( isset( $this->stats[$cmd] ) ) {
836 - $this->stats[$cmd]++;
837 - } else {
838 - $this->stats[$cmd] = 1;
839 - }
840 - if ( !$this->_safe_fwrite( $sock, "$cmd $key $amt\r\n" ) ) {
841 - return $this->_dead_sock( $sock );
842 - }
843 -
844 - $line = fgets( $sock );
845 - $match = array();
846 - if ( !preg_match( '/^(\d+)/', $line, $match ) ) {
847 - return null;
848 - }
849 - return $match[1];
850 - }
851 -
852 - // }}}
853 - // {{{ _load_items()
854 -
855 - /**
856 - * Load items into $ret from $sock
857 - *
858 - * @param $sock Ressource: socket to read from
859 - * @param $ret Array: returned values
860 - *
861 - * @access private
862 - */
863 - function _load_items( $sock, &$ret ) {
864 - while ( 1 ) {
865 - $decl = fgets( $sock );
866 - if ( $decl == "END\r\n" ) {
867 - return true;
868 - } elseif ( preg_match( '/^VALUE (\S+) (\d+) (\d+)\r\n$/', $decl, $match ) ) {
869 - list( $rkey, $flags, $len ) = array( $match[1], $match[2], $match[3] );
870 - $bneed = $len + 2;
871 - $offset = 0;
872 -
873 - while ( $bneed > 0 ) {
874 - $data = fread( $sock, $bneed );
875 - $n = strlen( $data );
876 - if ( $n == 0 ) {
877 - break;
878 - }
879 - $offset += $n;
880 - $bneed -= $n;
881 - if ( isset( $ret[$rkey] ) ) {
882 - $ret[$rkey] .= $data;
883 - } else {
884 - $ret[$rkey] = $data;
885 - }
886 - }
887 -
888 - if ( $offset != $len + 2 ) {
889 - // Something is borked!
890 - if ( $this->_debug ) {
891 - $this->_debugprint( sprintf( "Something is borked! key %s expecting %d got %d length\n", $rkey, $len + 2, $offset ) );
892 - }
893 -
894 - unset( $ret[$rkey] );
895 - $this->_close_sock( $sock );
896 - return false;
897 - }
898 -
899 - if ( $this->_have_zlib && $flags & self::COMPRESSED ) {
900 - $ret[$rkey] = gzuncompress( $ret[$rkey] );
901 - }
902 -
903 - $ret[$rkey] = rtrim( $ret[$rkey] );
904 -
905 - if ( $flags & self::SERIALIZED ) {
906 - $ret[$rkey] = unserialize( $ret[$rkey] );
907 - }
908 -
909 - } else {
910 - $this->_debugprint( "Error parsing memcached response\n" );
911 - return 0;
912 - }
913 - }
914 - }
915 -
916 - // }}}
917 - // {{{ _set()
918 -
919 - /**
920 - * Performs the requested storage operation to the memcache server
921 - *
922 - * @param $cmd String: command to perform
923 - * @param $key String: key to act on
924 - * @param $val Mixed: what we need to store
925 - * @param $exp Integer: (optional) Expiration time. This can be a number of seconds
926 - * to cache for (up to 30 days inclusive). Any timespans of 30 days + 1 second or
927 - * longer must be the timestamp of the time at which the mapping should expire. It
928 - * is safe to use timestamps in all cases, regardless of exipration
929 - * eg: strtotime("+3 hour")
930 - *
931 - * @return Boolean
932 - * @access private
933 - */
934 - function _set( $cmd, $key, $val, $exp ) {
935 - if ( !$this->_active ) {
936 - return false;
937 - }
938 -
939 - $sock = $this->get_sock( $key );
940 - if ( !is_resource( $sock ) ) {
941 - return false;
942 - }
943 -
944 - if ( isset( $this->stats[$cmd] ) ) {
945 - $this->stats[$cmd]++;
946 - } else {
947 - $this->stats[$cmd] = 1;
948 - }
949 -
950 - $flags = 0;
951 -
952 - if ( !is_scalar( $val ) ) {
953 - $val = serialize( $val );
954 - $flags |= self::SERIALIZED;
955 - if ( $this->_debug ) {
956 - $this->_debugprint( sprintf( "client: serializing data as it is not scalar\n" ) );
957 - }
958 - }
959 -
960 - $len = strlen( $val );
961 -
962 - if ( $this->_have_zlib && $this->_compress_enable &&
963 - $this->_compress_threshold && $len >= $this->_compress_threshold )
964 - {
965 - $c_val = gzcompress( $val, 9 );
966 - $c_len = strlen( $c_val );
967 -
968 - if ( $c_len < $len * ( 1 - self::COMPRESSION_SAVINGS ) ) {
969 - if ( $this->_debug ) {
970 - $this->_debugprint( sprintf( "client: compressing data; was %d bytes is now %d bytes\n", $len, $c_len ) );
971 - }
972 - $val = $c_val;
973 - $len = $c_len;
974 - $flags |= self::COMPRESSED;
975 - }
976 - }
977 - if ( !$this->_safe_fwrite( $sock, "$cmd $key $flags $exp $len\r\n$val\r\n" ) ) {
978 - return $this->_dead_sock( $sock );
979 - }
980 -
981 - $line = trim( fgets( $sock ) );
982 -
983 - if ( $this->_debug ) {
984 - $this->_debugprint( sprintf( "%s %s (%s)\n", $cmd, $key, $line ) );
985 - }
986 - if ( $line == "STORED" ) {
987 - return true;
988 - }
989 - return false;
990 - }
991 -
992 - // }}}
993 - // {{{ sock_to_host()
994 -
995 - /**
996 - * Returns the socket for the host
997 - *
998 - * @param $host String: Host:IP to get socket for
999 - *
1000 - * @return Mixed: IO Stream or false
1001 - * @access private
1002 - */
1003 - function sock_to_host( $host ) {
1004 - if ( isset( $this->_cache_sock[$host] ) ) {
1005 - return $this->_cache_sock[$host];
1006 - }
1007 -
1008 - $sock = null;
1009 - $now = time();
1010 - list( $ip, /* $port */) = explode( ':', $host );
1011 - if ( isset( $this->_host_dead[$host] ) && $this->_host_dead[$host] > $now ||
1012 - isset( $this->_host_dead[$ip] ) && $this->_host_dead[$ip] > $now
1013 - ) {
1014 - return null;
1015 - }
1016 -
1017 - if ( !$this->_connect_sock( $sock, $host ) ) {
1018 - return $this->_dead_host( $host );
1019 - }
1020 -
1021 - // Do not buffer writes
1022 - stream_set_write_buffer( $sock, 0 );
1023 -
1024 - $this->_cache_sock[$host] = $sock;
1025 -
1026 - return $this->_cache_sock[$host];
1027 - }
1028 -
1029 - function _debugprint( $str ) {
1030 - print( $str );
1031 - }
1032 -
1033 - /**
1034 - * Write to a stream, timing out after the correct amount of time
1035 - *
1036 - * @return Boolean: false on failure, true on success
1037 - */
1038 - /*
1039 - function _safe_fwrite( $f, $buf, $len = false ) {
1040 - stream_set_blocking( $f, 0 );
1041 -
1042 - if ( $len === false ) {
1043 - wfDebug( "Writing " . strlen( $buf ) . " bytes\n" );
1044 - $bytesWritten = fwrite( $f, $buf );
1045 - } else {
1046 - wfDebug( "Writing $len bytes\n" );
1047 - $bytesWritten = fwrite( $f, $buf, $len );
1048 - }
1049 - $n = stream_select( $r = null, $w = array( $f ), $e = null, 10, 0 );
1050 - # $this->_timeout_seconds, $this->_timeout_microseconds );
1051 -
1052 - wfDebug( "stream_select returned $n\n" );
1053 - stream_set_blocking( $f, 1 );
1054 - return $n == 1;
1055 - return $bytesWritten;
1056 - }*/
1057 -
1058 - /**
1059 - * Original behaviour
1060 - */
1061 - function _safe_fwrite( $f, $buf, $len = false ) {
1062 - if ( $len === false ) {
1063 - $bytesWritten = fwrite( $f, $buf );
1064 - } else {
1065 - $bytesWritten = fwrite( $f, $buf, $len );
1066 - }
1067 - return $bytesWritten;
1068 - }
1069 -
1070 - /**
1071 - * Flush the read buffer of a stream
1072 - */
1073 - function _flush_read_buffer( $f ) {
1074 - if ( !is_resource( $f ) ) {
1075 - return;
1076 - }
1077 - $n = stream_select( $r = array( $f ), $w = null, $e = null, 0, 0 );
1078 - while ( $n == 1 && !feof( $f ) ) {
1079 - fread( $f, 1024 );
1080 - $n = stream_select( $r = array( $f ), $w = null, $e = null, 0, 0 );
1081 - }
1082 - }
1083 -
1084 - // }}}
1085 - // }}}
1086 - // }}}
1087 -}
1088 -
1089 -// vim: sts=3 sw=3 et
1090 -
1091 -// }}}
1092 -
1093 -class MemCachedClientforWiki extends MWMemcached {
1094 - function _debugprint( $text ) {
1095 - wfDebug( "memcached: $text" );
1096 - }
1097 -}
Index: branches/wmf/1.17wmf1/includes/GlobalFunctions.php
@@ -3615,3 +3615,33 @@
36163616 }
36173617 return $ret;
36183618 }
 3619+
 3620+
 3621+/**
 3622+ * Get a cache object.
 3623+ * @param $inputType Cache type, one the the CACHE_* constants.
 3624+ *
 3625+ * @return BagOStuff
 3626+ */
 3627+function wfGetCache( $inputType ) {
 3628+ return ObjectCache::getInstance( $inputType );
 3629+}
 3630+
 3631+/** Get the main cache object */
 3632+function wfGetMainCache() {
 3633+ global $wgMainCacheType;
 3634+ return ObjectCache::getInstance( $wgMainCacheType );
 3635+}
 3636+
 3637+/** Get the cache object used by the message cache */
 3638+function wfGetMessageCacheStorage() {
 3639+ global $wgMessageCacheType;
 3640+ return ObjectCache::getInstance( $wgMessageCacheType );
 3641+}
 3642+
 3643+/** Get the cache object used by the parser cache */
 3644+function wfGetParserCacheStorage() {
 3645+ global $wgParserCacheType;
 3646+ return ObjectCache::getInstance( $wgParserCacheType );
 3647+}
 3648+
Property changes on: branches/wmf/1.17wmf1/includes/GlobalFunctions.php
___________________________________________________________________
Modified: svn:mergeinfo
36193649 Merged /trunk/phase3/includes/GlobalFunctions.php:r83135-83136,83140,83143,83147,83208,83416,83492
Index: branches/wmf/1.17wmf1/includes/objectcache/ObjectCache.php
@@ -0,0 +1,101 @@
 2+<?php
 3+/**
 4+ * Functions to get cache objects
 5+ *
 6+ * @file
 7+ * @ingroup Cache
 8+ */
 9+class ObjectCache {
 10+ static $instances = array();
 11+
 12+ /**
 13+ * Get a cached instance of the specified type of cache object.
 14+ */
 15+ static function getInstance( $id ) {
 16+ if ( isset( self::$instances[$id] ) ) {
 17+ return self::$instances[$id];
 18+ }
 19+
 20+ $object = self::newFromId( $id );
 21+ self::$instances[$id] = $object;
 22+ return $object;
 23+ }
 24+
 25+ /**
 26+ * Clear all the cached instances.
 27+ */
 28+ static function clear() {
 29+ self::$instances = array();
 30+ }
 31+
 32+ /**
 33+ * Create a new cache object of the specified type.
 34+ */
 35+ static function newFromId( $id ) {
 36+ global $wgObjectCaches;
 37+
 38+ if ( !isset( $wgObjectCaches[$id] ) ) {
 39+ throw new MWException( "Invalid object cache type \"$id\" requested. " .
 40+ "It is not present in \$wgObjectCaches." );
 41+ }
 42+
 43+ return self::newFromParams( $wgObjectCaches[$id] );
 44+ }
 45+
 46+ /**
 47+ * Create a new cache object from parameters
 48+ */
 49+ static function newFromParams( $params ) {
 50+ if ( isset( $params['factory'] ) ) {
 51+ return call_user_func( $params['factory'], $params );
 52+ } elseif ( isset( $params['class'] ) ) {
 53+ $class = $params['class'];
 54+ return new $class( $params );
 55+ } else {
 56+ throw new MWException( "The definition of cache type \"$id\" lacks both " .
 57+ "factory and class parameters." );
 58+ }
 59+ }
 60+
 61+ /**
 62+ * Factory function referenced from DefaultSettings.php for CACHE_ANYTHING
 63+ */
 64+ static function newAnything( $params ) {
 65+ global $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType;
 66+ $candidates = array( $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType );
 67+ foreach ( $candidates as $candidate ) {
 68+ if ( $candidate !== CACHE_NONE && $candidate !== CACHE_ANYTHING ) {
 69+ return self::getInstance( $candidate );
 70+ }
 71+ }
 72+ return self::getInstance( CACHE_DB );
 73+ }
 74+
 75+ /**
 76+ * Factory function referenced from DefaultSettings.php for CACHE_ACCEL.
 77+ */
 78+ static function newAccelerator( $params ) {
 79+ if ( function_exists( 'eaccelerator_get' ) ) {
 80+ $id = 'eaccelerator';
 81+ } elseif ( function_exists( 'apc_fetch') ) {
 82+ $id = 'apc';
 83+ } elseif( function_exists( 'xcache_get' ) ) {
 84+ $id = 'xcache';
 85+ } elseif( function_exists( 'wincache_ucache_get' ) ) {
 86+ $id = 'wincache';
 87+ } else {
 88+ throw new MWException( "CACHE_ACCEL requested but no suitable object " .
 89+ "cache is present. You may want to install APC." );
 90+ }
 91+ return self::newFromId( $id );
 92+ }
 93+
 94+ /**
 95+ * Factory function that creates a memcached client object.
 96+ * The idea of this is that it might eventually detect and automatically
 97+ * support the PECL extension, assuming someone can get it to compile.
 98+ */
 99+ static function newMemcached( $params ) {
 100+ return new MemcachedPhpBagOStuff( $params );
 101+ }
 102+}
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/ObjectCache.php
___________________________________________________________________
Added: svn:keywords
1103 + Author Date Id Revision
Added: svn:eol-style
2104 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/XCacheBagOStuff.php
@@ -0,0 +1,53 @@
 2+<?php
 3+
 4+/**
 5+ * Wrapper for XCache object caching functions; identical interface
 6+ * to the APC wrapper
 7+ *
 8+ * @ingroup Cache
 9+ */
 10+class XCacheBagOStuff extends BagOStuff {
 11+ /**
 12+ * Get a value from the XCache object cache
 13+ *
 14+ * @param $key String: cache key
 15+ * @return mixed
 16+ */
 17+ public function get( $key ) {
 18+ $val = xcache_get( $key );
 19+
 20+ if ( is_string( $val ) ) {
 21+ $val = unserialize( $val );
 22+ }
 23+
 24+ return $val;
 25+ }
 26+
 27+ /**
 28+ * Store a value in the XCache object cache
 29+ *
 30+ * @param $key String: cache key
 31+ * @param $value Mixed: object to store
 32+ * @param $expire Int: expiration time
 33+ * @return bool
 34+ */
 35+ public function set( $key, $value, $expire = 0 ) {
 36+ xcache_set( $key, serialize( $value ), $expire );
 37+
 38+ return true;
 39+ }
 40+
 41+ /**
 42+ * Remove a value from the XCache object cache
 43+ *
 44+ * @param $key String: cache key
 45+ * @param $time Int: not used in this implementation
 46+ * @return bool
 47+ */
 48+ public function delete( $key, $time = 0 ) {
 49+ xcache_unset( $key );
 50+
 51+ return true;
 52+ }
 53+}
 54+
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/XCacheBagOStuff.php
___________________________________________________________________
Added: svn:eol-style
155 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/eAccelBagOStuff.php
@@ -0,0 +1,46 @@
 2+<?php
 3+
 4+/**
 5+ * This is a wrapper for eAccelerator's shared memory functions.
 6+ *
 7+ * This is basically identical to the deceased Turck MMCache version,
 8+ * mostly because eAccelerator is based on Turck MMCache.
 9+ *
 10+ * @ingroup Cache
 11+ */
 12+class eAccelBagOStuff extends BagOStuff {
 13+ public function get( $key ) {
 14+ $val = eaccelerator_get( $key );
 15+
 16+ if ( is_string( $val ) ) {
 17+ $val = unserialize( $val );
 18+ }
 19+
 20+ return $val;
 21+ }
 22+
 23+ public function set( $key, $value, $exptime = 0 ) {
 24+ eaccelerator_put( $key, serialize( $value ), $exptime );
 25+
 26+ return true;
 27+ }
 28+
 29+ public function delete( $key, $time = 0 ) {
 30+ eaccelerator_rm( $key );
 31+
 32+ return true;
 33+ }
 34+
 35+ public function lock( $key, $waitTimeout = 0 ) {
 36+ eaccelerator_lock( $key );
 37+
 38+ return true;
 39+ }
 40+
 41+ public function unlock( $key ) {
 42+ eaccelerator_unlock( $key );
 43+
 44+ return true;
 45+ }
 46+}
 47+
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/eAccelBagOStuff.php
___________________________________________________________________
Added: svn:eol-style
148 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/EmptyBagOStuff.php
@@ -0,0 +1,27 @@
 2+<?php
 3+
 4+/**
 5+ * A BagOStuff object with no objects in it. Used to provide a no-op object to calling code.
 6+ *
 7+ * @ingroup Cache
 8+ */
 9+class EmptyBagOStuff extends BagOStuff {
 10+ function get( $key ) {
 11+ return false;
 12+ }
 13+
 14+ function set( $key, $value, $exp = 0 ) {
 15+ return true;
 16+ }
 17+
 18+ function delete( $key, $time = 0 ) {
 19+ return true;
 20+ }
 21+}
 22+
 23+/**
 24+ * Backwards compatibility alias for EmptyBagOStuff
 25+ * @deprecated
 26+ */
 27+class FakeMemCachedClient extends EmptyBagOStuff {
 28+}
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/EmptyBagOStuff.php
___________________________________________________________________
Added: svn:eol-style
129 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/MemcachedPhpBagOStuff.php
@@ -0,0 +1,116 @@
 2+<?php
 3+
 4+/**
 5+ * A wrapper class for the pure-PHP memcached client, exposing a BagOStuff interface.
 6+ */
 7+class MemcachedPhpBagOStuff extends BagOStuff {
 8+ /**
 9+ * Constructor.
 10+ *
 11+ * Available parameters are:
 12+ * - servers: The list of IP:port combinations holding the memcached servers.
 13+ * - debug: Whether to set the debug flag in the underlying client.
 14+ * - persistent: Whether to use a persistent connection
 15+ * - compress_threshold: The minimum size an object must be before it is compressed
 16+ * - timeout: The read timeout in microseconds
 17+ * - connect_timeout: The connect timeout in seconds
 18+ */
 19+ function __construct( $params ) {
 20+ if ( !isset( $params['servers'] ) ) {
 21+ $params['servers'] = $GLOBALS['wgMemCachedServers'];
 22+ }
 23+ if ( !isset( $params['debug'] ) ) {
 24+ $params['debug'] = $GLOBALS['wgMemCachedDebug'];
 25+ }
 26+ if ( !isset( $params['persistent'] ) ) {
 27+ $params['persistent'] = $GLOBALS['wgMemCachedPersistent'];
 28+ }
 29+ if ( !isset( $params['compress_threshold'] ) ) {
 30+ $params['compress_threshold'] = 1500;
 31+ }
 32+ if ( !isset( $params['timeout'] ) ) {
 33+ $params['timeout'] = $GLOBALS['wgMemCachedTimeout'];
 34+ }
 35+ if ( !isset( $params['connect_timeout'] ) ) {
 36+ $params['connect_timeout'] = 0.1;
 37+ }
 38+
 39+ $this->client = new MemCachedClientforWiki( $params );
 40+ $this->client->set_servers( $params['servers'] );
 41+ $this->client->set_debug( $params['debug'] );
 42+ }
 43+
 44+ public function setDebug( $debug ) {
 45+ $this->client->set_debug( $debug );
 46+ }
 47+
 48+ public function get( $key ) {
 49+ return $this->client->get( $this->encodeKey( $key ) );
 50+ }
 51+
 52+ public function set( $key, $value, $exptime = 0 ) {
 53+ return $this->client->set( $this->encodeKey( $key ), $value, $exptime );
 54+ }
 55+
 56+ public function delete( $key, $time = 0 ) {
 57+ return $this->client->delete( $this->encodeKey( $key ), $time );
 58+ }
 59+
 60+ public function lock( $key, $timeout = 0 ) {
 61+ return $this->client->lock( $this->encodeKey( $key ), $timeout );
 62+ }
 63+
 64+ public function unlock( $key ) {
 65+ return $this->client->unlock( $this->encodeKey( $key ) );
 66+ }
 67+
 68+ public function add( $key, $value, $exptime = 0 ) {
 69+ return $this->client->add( $this->encodeKey( $key ), $value, $exptime );
 70+ }
 71+
 72+ public function replace( $key, $value, $exptime = 0 ) {
 73+ return $this->client->replace( $this->encodeKey( $key ), $value, $exptime );
 74+ }
 75+
 76+ public function incr( $key, $value = 1 ) {
 77+ return $this->client->incr( $this->encodeKey( $key ), $value );
 78+ }
 79+
 80+ public function decr( $key, $value = 1 ) {
 81+ return $this->client->decr( $this->encodeKey( $key ), $value );
 82+ }
 83+
 84+ /**
 85+ * Get the underlying client object. This is provided for debugging
 86+ * purposes.
 87+ */
 88+ public function getClient() {
 89+ return $this->client;
 90+ }
 91+
 92+ /**
 93+ * Encode a key for use on the wire inside the memcached protocol.
 94+ *
 95+ * We encode spaces and line breaks to avoid protocol errors. We encode
 96+ * the other control characters for compatibility with libmemcached
 97+ * verify_key. We leave other punctuation alone, to maximise backwards
 98+ * compatibility.
 99+ */
 100+ public function encodeKey( $key ) {
 101+ return preg_replace_callback( '/[\x00-\x20\x25\x7f]+/',
 102+ array( $this, 'encodeKeyCallback' ), $key );
 103+ }
 104+
 105+ protected function encodeKeyCallback( $m ) {
 106+ return rawurlencode( $m[0] );
 107+ }
 108+
 109+ /**
 110+ * Decode a key encoded with encodeKey(). This is provided as a convenience
 111+ * function for debugging.
 112+ */
 113+ public function decodeKey( $key ) {
 114+ return urldecode( $key );
 115+ }
 116+}
 117+
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/MemcachedPhpBagOStuff.php
___________________________________________________________________
Added: svn:eol-style
1118 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/BagOStuff.php
@@ -0,0 +1,149 @@
 2+<?php
 3+/**
 4+ * Classes to cache objects in PHP accelerators, SQL database or DBA files
 5+ *
 6+ * Copyright © 2003-2004 Brion Vibber <brion@pobox.com>
 7+ * http://www.mediawiki.org/
 8+ *
 9+ * This program is free software; you can redistribute it and/or modify
 10+ * it under the terms of the GNU General Public License as published by
 11+ * the Free Software Foundation; either version 2 of the License, or
 12+ * (at your option) any later version.
 13+ *
 14+ * This program is distributed in the hope that it will be useful,
 15+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 17+ * GNU General Public License for more details.
 18+ *
 19+ * You should have received a copy of the GNU General Public License along
 20+ * with this program; if not, write to the Free Software Foundation, Inc.,
 21+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 22+ * http://www.gnu.org/copyleft/gpl.html
 23+ *
 24+ * @file
 25+ * @ingroup Cache
 26+ */
 27+
 28+/**
 29+ * @defgroup Cache Cache
 30+ */
 31+
 32+/**
 33+ * interface is intended to be more or less compatible with
 34+ * the PHP memcached client.
 35+ *
 36+ * backends for local hash array and SQL table included:
 37+ * <code>
 38+ * $bag = new HashBagOStuff();
 39+ * $bag = new SqlBagOStuff(); # connect to db first
 40+ * </code>
 41+ *
 42+ * @ingroup Cache
 43+ */
 44+abstract class BagOStuff {
 45+ var $debugMode = false;
 46+
 47+ public function setDebug( $bool ) {
 48+ $this->debugMode = $bool;
 49+ }
 50+
 51+ /* *** THE GUTS OF THE OPERATION *** */
 52+ /* Override these with functional things in subclasses */
 53+
 54+ /**
 55+ * Get an item with the given key. Returns false if it does not exist.
 56+ * @param $key string
 57+ */
 58+ abstract public function get( $key );
 59+
 60+ /**
 61+ * Set an item.
 62+ * @param $key string
 63+ * @param $value mixed
 64+ * @param $exptime int Either an interval in seconds or a unix timestamp for expiry
 65+ */
 66+ abstract public function set( $key, $value, $exptime = 0 );
 67+
 68+ /*
 69+ * Delete an item.
 70+ * @param $key string
 71+ * @param $time int Amount of time to delay the operation (mostly memcached-specific)
 72+ */
 73+ abstract public function delete( $key, $time = 0 );
 74+
 75+ public function lock( $key, $timeout = 0 ) {
 76+ /* stub */
 77+ return true;
 78+ }
 79+
 80+ public function unlock( $key ) {
 81+ /* stub */
 82+ return true;
 83+ }
 84+
 85+ public function keys() {
 86+ /* stub */
 87+ return array();
 88+ }
 89+
 90+ /* *** Emulated functions *** */
 91+
 92+ public function add( $key, $value, $exptime = 0 ) {
 93+ if ( !$this->get( $key ) ) {
 94+ $this->set( $key, $value, $exptime );
 95+
 96+ return true;
 97+ }
 98+ }
 99+
 100+ public function replace( $key, $value, $exptime = 0 ) {
 101+ if ( $this->get( $key ) !== false ) {
 102+ $this->set( $key, $value, $exptime );
 103+ }
 104+ }
 105+
 106+ /**
 107+ * @param $key String: Key to increase
 108+ * @param $value Integer: Value to add to $key (Default 1)
 109+ * @return null if lock is not possible else $key value increased by $value
 110+ */
 111+ public function incr( $key, $value = 1 ) {
 112+ if ( !$this->lock( $key ) ) {
 113+ return null;
 114+ }
 115+
 116+ $value = intval( $value );
 117+
 118+ if ( ( $n = $this->get( $key ) ) !== false ) {
 119+ $n += $value;
 120+ $this->set( $key, $n ); // exptime?
 121+ }
 122+ $this->unlock( $key );
 123+
 124+ return $n;
 125+ }
 126+
 127+ public function decr( $key, $value = 1 ) {
 128+ return $this->incr( $key, - $value );
 129+ }
 130+
 131+ public function debug( $text ) {
 132+ if ( $this->debugMode ) {
 133+ $class = get_class( $this );
 134+ wfDebug( "$class debug: $text\n" );
 135+ }
 136+ }
 137+
 138+ /**
 139+ * Convert an optionally relative time to an absolute time
 140+ */
 141+ protected function convertExpiry( $exptime ) {
 142+ if ( ( $exptime != 0 ) && ( $exptime < 86400 * 3650 /* 10 years */ ) ) {
 143+ return time() + $exptime;
 144+ } else {
 145+ return $exptime;
 146+ }
 147+ }
 148+}
 149+
 150+
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/BagOStuff.php
___________________________________________________________________
Added: svn:keywords
1151 + Author Date Id Revision
Added: svn:eol-style
2152 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/SqlBagOStuff.php
@@ -0,0 +1,301 @@
 2+<?php
 3+
 4+/**
 5+ * Class to store objects in the database
 6+ *
 7+ * @ingroup Cache
 8+ */
 9+class SqlBagOStuff extends BagOStuff {
 10+ var $lb, $db, $serverInfo;
 11+ var $lastExpireAll = 0;
 12+
 13+ /**
 14+ * Constructor. Parameters are:
 15+ * - server: A server info structure in the format required by each
 16+ * element in $wgDBServers.
 17+ */
 18+ public function __construct( $params ) {
 19+ if ( isset( $params['server'] ) ) {
 20+ $this->serverInfo = $params['server'];
 21+ $this->serverInfo['load'] = 1;
 22+ }
 23+ }
 24+
 25+ protected function getDB() {
 26+ if ( !isset( $this->db ) ) {
 27+ # If server connection info was given, use that
 28+ if ( $this->serverInfo ) {
 29+ $this->lb = new LoadBalancer( array(
 30+ 'servers' => array( $this->serverInfo ) ) );
 31+ $this->db = $this->lb->getConnection( DB_MASTER );
 32+ $this->db->clearFlag( DBO_TRX );
 33+ } else {
 34+ # We must keep a separate connection to MySQL in order to avoid deadlocks
 35+ # However, SQLite has an opposite behaviour.
 36+ # @todo Investigate behaviour for other databases
 37+ if ( wfGetDB( DB_MASTER )->getType() == 'sqlite' ) {
 38+ $this->db = wfGetDB( DB_MASTER );
 39+ } else {
 40+ $this->lb = wfGetLBFactory()->newMainLB();
 41+ $this->db = $this->lb->getConnection( DB_MASTER );
 42+ $this->db->clearFlag( DBO_TRX );
 43+ }
 44+ }
 45+ }
 46+
 47+ return $this->db;
 48+ }
 49+
 50+ public function get( $key ) {
 51+ # expire old entries if any
 52+ $this->garbageCollect();
 53+ $db = $this->getDB();
 54+ $row = $db->selectRow( 'objectcache', array( 'value', 'exptime' ),
 55+ array( 'keyname' => $key ), __METHOD__ );
 56+
 57+ if ( !$row ) {
 58+ $this->debug( 'get: no matching rows' );
 59+ return false;
 60+ }
 61+
 62+ $this->debug( "get: retrieved data; expiry time is " . $row->exptime );
 63+
 64+ if ( $this->isExpired( $row->exptime ) ) {
 65+ $this->debug( "get: key has expired, deleting" );
 66+ try {
 67+ $db->begin();
 68+ # Put the expiry time in the WHERE condition to avoid deleting a
 69+ # newly-inserted value
 70+ $db->delete( 'objectcache',
 71+ array(
 72+ 'keyname' => $key,
 73+ 'exptime' => $row->exptime
 74+ ), __METHOD__ );
 75+ $db->commit();
 76+ } catch ( DBQueryError $e ) {
 77+ $this->handleWriteError( $e );
 78+ }
 79+
 80+ return false;
 81+ }
 82+
 83+ return $this->unserialize( $db->decodeBlob( $row->value ) );
 84+ }
 85+
 86+ public function set( $key, $value, $exptime = 0 ) {
 87+ $db = $this->getDB();
 88+ $exptime = intval( $exptime );
 89+
 90+ if ( $exptime < 0 ) {
 91+ $exptime = 0;
 92+ }
 93+
 94+ if ( $exptime == 0 ) {
 95+ $encExpiry = $this->getMaxDateTime();
 96+ } else {
 97+ if ( $exptime < 3.16e8 ) { # ~10 years
 98+ $exptime += time();
 99+ }
 100+
 101+ $encExpiry = $db->timestamp( $exptime );
 102+ }
 103+ try {
 104+ $db->begin();
 105+ // (bug 24425) use a replace if the db supports it instead of
 106+ // delete/insert to avoid clashes with conflicting keynames
 107+ $db->replace( 'objectcache', array( 'keyname' ),
 108+ array(
 109+ 'keyname' => $key,
 110+ 'value' => $db->encodeBlob( $this->serialize( $value ) ),
 111+ 'exptime' => $encExpiry
 112+ ), __METHOD__ );
 113+ $db->commit();
 114+ } catch ( DBQueryError $e ) {
 115+ $this->handleWriteError( $e );
 116+
 117+ return false;
 118+ }
 119+
 120+ return true;
 121+ }
 122+
 123+ public function delete( $key, $time = 0 ) {
 124+ $db = $this->getDB();
 125+
 126+ try {
 127+ $db->begin();
 128+ $db->delete( 'objectcache', array( 'keyname' => $key ), __METHOD__ );
 129+ $db->commit();
 130+ } catch ( DBQueryError $e ) {
 131+ $this->handleWriteError( $e );
 132+
 133+ return false;
 134+ }
 135+
 136+ return true;
 137+ }
 138+
 139+ public function incr( $key, $step = 1 ) {
 140+ $db = $this->getDB();
 141+ $step = intval( $step );
 142+
 143+ try {
 144+ $db->begin();
 145+ $row = $db->selectRow( 'objectcache', array( 'value', 'exptime' ),
 146+ array( 'keyname' => $key ), __METHOD__, array( 'FOR UPDATE' ) );
 147+ if ( $row === false ) {
 148+ // Missing
 149+ $db->commit();
 150+
 151+ return null;
 152+ }
 153+ $db->delete( 'objectcache', array( 'keyname' => $key ), __METHOD__ );
 154+ if ( $this->isExpired( $row->exptime ) ) {
 155+ // Expired, do not reinsert
 156+ $db->commit();
 157+
 158+ return null;
 159+ }
 160+
 161+ $oldValue = intval( $this->unserialize( $db->decodeBlob( $row->value ) ) );
 162+ $newValue = $oldValue + $step;
 163+ $db->insert( 'objectcache',
 164+ array(
 165+ 'keyname' => $key,
 166+ 'value' => $db->encodeBlob( $this->serialize( $newValue ) ),
 167+ 'exptime' => $row->exptime
 168+ ), __METHOD__ );
 169+ $db->commit();
 170+ } catch ( DBQueryError $e ) {
 171+ $this->handleWriteError( $e );
 172+
 173+ return null;
 174+ }
 175+
 176+ return $newValue;
 177+ }
 178+
 179+ public function keys() {
 180+ $db = $this->getDB();
 181+ $res = $db->select( 'objectcache', array( 'keyname' ), false, __METHOD__ );
 182+ $result = array();
 183+
 184+ foreach ( $res as $row ) {
 185+ $result[] = $row->keyname;
 186+ }
 187+
 188+ return $result;
 189+ }
 190+
 191+ protected function isExpired( $exptime ) {
 192+ return $exptime != $this->getMaxDateTime() && wfTimestamp( TS_UNIX, $exptime ) < time();
 193+ }
 194+
 195+ protected function getMaxDateTime() {
 196+ if ( time() > 0x7fffffff ) {
 197+ return $this->getDB()->timestamp( 1 << 62 );
 198+ } else {
 199+ return $this->getDB()->timestamp( 0x7fffffff );
 200+ }
 201+ }
 202+
 203+ protected function garbageCollect() {
 204+ /* Ignore 99% of requests */
 205+ if ( !mt_rand( 0, 100 ) ) {
 206+ $now = time();
 207+ /* Avoid repeating the delete within a few seconds */
 208+ if ( $now > ( $this->lastExpireAll + 1 ) ) {
 209+ $this->lastExpireAll = $now;
 210+ $this->expireAll();
 211+ }
 212+ }
 213+ }
 214+
 215+ public function expireAll() {
 216+ $db = $this->getDB();
 217+ $now = $db->timestamp();
 218+
 219+ try {
 220+ $db->begin();
 221+ $db->delete( 'objectcache', array( 'exptime < ' . $db->addQuotes( $now ) ), __METHOD__ );
 222+ $db->commit();
 223+ } catch ( DBQueryError $e ) {
 224+ $this->handleWriteError( $e );
 225+ }
 226+ }
 227+
 228+ public function deleteAll() {
 229+ $db = $this->getDB();
 230+
 231+ try {
 232+ $db->begin();
 233+ $db->delete( 'objectcache', '*', __METHOD__ );
 234+ $db->commit();
 235+ } catch ( DBQueryError $e ) {
 236+ $this->handleWriteError( $e );
 237+ }
 238+ }
 239+
 240+ /**
 241+ * Serialize an object and, if possible, compress the representation.
 242+ * On typical message and page data, this can provide a 3X decrease
 243+ * in storage requirements.
 244+ *
 245+ * @param $data mixed
 246+ * @return string
 247+ */
 248+ protected function serialize( &$data ) {
 249+ $serial = serialize( $data );
 250+
 251+ if ( function_exists( 'gzdeflate' ) ) {
 252+ return gzdeflate( $serial );
 253+ } else {
 254+ return $serial;
 255+ }
 256+ }
 257+
 258+ /**
 259+ * Unserialize and, if necessary, decompress an object.
 260+ * @param $serial string
 261+ * @return mixed
 262+ */
 263+ protected function unserialize( $serial ) {
 264+ if ( function_exists( 'gzinflate' ) ) {
 265+ $decomp = @gzinflate( $serial );
 266+
 267+ if ( false !== $decomp ) {
 268+ $serial = $decomp;
 269+ }
 270+ }
 271+
 272+ $ret = unserialize( $serial );
 273+
 274+ return $ret;
 275+ }
 276+
 277+ /**
 278+ * Handle a DBQueryError which occurred during a write operation.
 279+ * Ignore errors which are due to a read-only database, rethrow others.
 280+ */
 281+ protected function handleWriteError( $exception ) {
 282+ $db = $this->getDB();
 283+
 284+ if ( !$db->wasReadOnlyError() ) {
 285+ throw $exception;
 286+ }
 287+
 288+ try {
 289+ $db->rollback();
 290+ } catch ( DBQueryError $e ) {
 291+ }
 292+
 293+ wfDebug( __METHOD__ . ": ignoring query error\n" );
 294+ $db->ignoreErrors( false );
 295+ }
 296+}
 297+
 298+/**
 299+ * Backwards compatibility alias
 300+ */
 301+class MediaWikiBagOStuff extends SqlBagOStuff { }
 302+
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/SqlBagOStuff.php
___________________________________________________________________
Added: svn:eol-style
1303 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/EhcacheBagOStuff.php
@@ -0,0 +1,230 @@
 2+<?php
 3+
 4+/**
 5+ * Client for the Ehcache RESTful web service - http://ehcache.org/documentation/cache_server.html
 6+ * TODO: Simplify configuration and add to the installer.
 7+ */
 8+class EhcacheBagOStuff extends BagOStuff {
 9+ var $servers, $cacheName, $connectTimeout, $timeout, $curlOptions,
 10+ $requestData, $requestDataPos;
 11+
 12+ var $curls = array();
 13+
 14+ function __construct( $params ) {
 15+ if ( !defined( 'CURLOPT_TIMEOUT_MS' ) ) {
 16+ throw new MWException( __CLASS__.' requires curl version 7.16.2 or later.' );
 17+ }
 18+ if ( !extension_loaded( 'zlib' ) ) {
 19+ throw new MWException( __CLASS__.' requires the zlib extension' );
 20+ }
 21+ if ( !isset( $params['servers'] ) ) {
 22+ throw new MWException( __METHOD__.': servers parameter is required' );
 23+ }
 24+ $this->servers = $params['servers'];
 25+ $this->cacheName = isset( $params['cache'] ) ? $params['cache'] : 'mw';
 26+ $this->connectTimeout = isset( $params['connectTimeout'] )
 27+ ? $params['connectTimeout'] : 1;
 28+ $this->timeout = isset( $params['timeout'] ) ? $params['timeout'] : 1;
 29+ $this->curlOptions = array(
 30+ CURLOPT_CONNECTTIMEOUT_MS => intval( $this->connectTimeout * 1000 ),
 31+ CURLOPT_TIMEOUT_MS => intval( $this->timeout * 1000 ),
 32+ CURLOPT_RETURNTRANSFER => 1,
 33+ CURLOPT_CUSTOMREQUEST => 'GET',
 34+ CURLOPT_POST => 0,
 35+ CURLOPT_POSTFIELDS => '',
 36+ CURLOPT_HTTPHEADER => array(),
 37+ );
 38+ }
 39+
 40+ public function get( $key ) {
 41+ wfProfileIn( __METHOD__ );
 42+ $response = $this->doItemRequest( $key );
 43+ if ( !$response || $response['http_code'] == 404 ) {
 44+ wfProfileOut( __METHOD__ );
 45+ return false;
 46+ }
 47+ if ( $response['http_code'] >= 300 ) {
 48+ wfDebug( __METHOD__.": GET failure, got HTTP {$response['http_code']}\n" );
 49+ wfProfileOut( __METHOD__ );
 50+ return false;
 51+ }
 52+ $body = $response['body'];
 53+ $type = $response['content_type'];
 54+ if ( $type == 'application/vnd.php.serialized+deflate' ) {
 55+ $body = gzinflate( $body );
 56+ if ( !$body ) {
 57+ wfDebug( __METHOD__.": error inflating $key\n" );
 58+ wfProfileOut( __METHOD__ );
 59+ return false;
 60+ }
 61+ $data = unserialize( $body );
 62+ } elseif ( $type == 'application/vnd.php.serialized' ) {
 63+ $data = unserialize( $body );
 64+ } else {
 65+ wfDebug( __METHOD__.": unknown content type \"$type\"\n" );
 66+ wfProfileOut( __METHOD__ );
 67+ return false;
 68+ }
 69+
 70+ wfProfileOut( __METHOD__ );
 71+ return $data;
 72+ }
 73+
 74+ public function set( $key, $value, $expiry = 0 ) {
 75+ wfProfileIn( __METHOD__ );
 76+ $expiry = $this->convertExpiry( $expiry );
 77+ $ttl = $expiry ? $expiry - time() : 2147483647;
 78+ $blob = serialize( $value );
 79+ if ( strlen( $blob ) > 100 ) {
 80+ $blob = gzdeflate( $blob );
 81+ $contentType = 'application/vnd.php.serialized+deflate';
 82+ } else {
 83+ $contentType = 'application/vnd.php.serialized';
 84+ }
 85+
 86+ $code = $this->attemptPut( $key, $blob, $contentType, $ttl );
 87+
 88+ if ( $code == 404 ) {
 89+ // Maybe the cache does not exist yet, let's try creating it
 90+ if ( !$this->createCache( $key ) ) {
 91+ wfDebug( __METHOD__.": cache creation failed\n" );
 92+ wfProfileOut( __METHOD__ );
 93+ return false;
 94+ }
 95+ $code = $this->attemptPut( $key, $blob, $contentType, $ttl );
 96+ }
 97+
 98+ $result = false;
 99+ if ( !$code ) {
 100+ wfDebug( __METHOD__.": PUT failure for key $key\n" );
 101+ } elseif ( $code >= 300 ) {
 102+ wfDebug( __METHOD__.": PUT failure for key $key: HTTP $code\n" );
 103+ } else {
 104+ $result = true;
 105+ }
 106+
 107+ wfProfileOut( __METHOD__ );
 108+ return $result;
 109+ }
 110+
 111+ public function delete( $key, $time = 0 ) {
 112+ wfProfileIn( __METHOD__ );
 113+ $response = $this->doItemRequest( $key,
 114+ array( CURLOPT_CUSTOMREQUEST => 'DELETE' ) );
 115+ $code = isset( $response['http_code'] ) ? $response['http_code'] : 0;
 116+ if ( !$response || ( $code != 404 && $code >= 300 ) ) {
 117+ wfDebug( __METHOD__.": DELETE failure for key $key\n" );
 118+ $result = false;
 119+ } else {
 120+ $result = true;
 121+ }
 122+ wfProfileOut( __METHOD__ );
 123+ return $result;
 124+ }
 125+
 126+ protected function getCacheUrl( $key ) {
 127+ if ( count( $this->servers ) == 1 ) {
 128+ $server = reset( $this->servers );
 129+ } else {
 130+ // Use consistent hashing
 131+ $hashes = array();
 132+ foreach ( $this->servers as $server ) {
 133+ $hashes[$server] = md5( $server . '/' . $key );
 134+ }
 135+ asort( $hashes );
 136+ reset( $hashes );
 137+ $server = key( $hashes );
 138+ }
 139+ return "http://$server/ehcache/rest/{$this->cacheName}";
 140+ }
 141+
 142+ /**
 143+ * Get a cURL handle for the given cache URL.
 144+ * We cache the handles to allow keepalive.
 145+ */
 146+ protected function getCurl( $cacheUrl ) {
 147+ if ( !isset( $this->curls[$cacheUrl] ) ) {
 148+ $this->curls[$cacheUrl] = curl_init();
 149+ }
 150+ return $this->curls[$cacheUrl];
 151+ }
 152+
 153+ protected function attemptPut( $key, $data, $type, $ttl ) {
 154+ // In initial benchmarking, it was 30 times faster to use CURLOPT_POST
 155+ // than CURLOPT_UPLOAD with CURLOPT_READFUNCTION. This was because
 156+ // CURLOPT_UPLOAD was pushing the request headers first, then waiting
 157+ // for an ACK packet, then sending the data, whereas CURLOPT_POST just
 158+ // sends the headers and the data in a single send().
 159+ $response = $this->doItemRequest( $key,
 160+ array(
 161+ CURLOPT_POST => 1,
 162+ CURLOPT_CUSTOMREQUEST => 'PUT',
 163+ CURLOPT_POSTFIELDS => $data,
 164+ CURLOPT_HTTPHEADER => array(
 165+ 'Content-Type: ' . $type,
 166+ 'ehcacheTimeToLiveSeconds: ' . $ttl
 167+ )
 168+ )
 169+ );
 170+ if ( !$response ) {
 171+ return 0;
 172+ } else {
 173+ return $response['http_code'];
 174+ }
 175+ }
 176+
 177+ protected function createCache( $key ) {
 178+ wfDebug( __METHOD__.": creating cache for $key\n" );
 179+ $response = $this->doCacheRequest( $key,
 180+ array(
 181+ CURLOPT_POST => 1,
 182+ CURLOPT_CUSTOMREQUEST => 'PUT',
 183+ CURLOPT_POSTFIELDS => '',
 184+ ) );
 185+ if ( !$response ) {
 186+ wfDebug( __CLASS__.": failed to create cache for $key\n" );
 187+ return false;
 188+ }
 189+ if ( $response['http_code'] == 201 /* created */
 190+ || $response['http_code'] == 409 /* already there */ )
 191+ {
 192+ return true;
 193+ } else {
 194+ return false;
 195+ }
 196+ }
 197+
 198+ protected function doCacheRequest( $key, $curlOptions = array() ) {
 199+ $cacheUrl = $this->getCacheUrl( $key );
 200+ $curl = $this->getCurl( $cacheUrl );
 201+ return $this->doRequest( $curl, $cacheUrl, $curlOptions );
 202+ }
 203+
 204+ protected function doItemRequest( $key, $curlOptions = array() ) {
 205+ $cacheUrl = $this->getCacheUrl( $key );
 206+ $curl = $this->getCurl( $cacheUrl );
 207+ $url = $cacheUrl . '/' . rawurlencode( $key );
 208+ return $this->doRequest( $curl, $url, $curlOptions );
 209+ }
 210+
 211+ protected function doRequest( $curl, $url, $curlOptions = array() ) {
 212+ if ( array_diff_key( $curlOptions, $this->curlOptions ) ) {
 213+ // var_dump( array_diff_key( $curlOptions, $this->curlOptions ) );
 214+ throw new MWException( __METHOD__.": to prevent options set in one doRequest() " .
 215+ "call from affecting subsequent doRequest() calls, only options listed " .
 216+ "in \$this->curlOptions may be specified in the \$curlOptions parameter." );
 217+ }
 218+ $curlOptions += $this->curlOptions;
 219+ $curlOptions[CURLOPT_URL] = $url;
 220+
 221+ curl_setopt_array( $curl, $curlOptions );
 222+ $result = curl_exec( $curl );
 223+ if ( $result === false ) {
 224+ wfDebug( __CLASS__.": curl error: " . curl_error( $curl ) . "\n" );
 225+ return false;
 226+ }
 227+ $info = curl_getinfo( $curl );
 228+ $info['body'] = $result;
 229+ return $info;
 230+ }
 231+}
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/EhcacheBagOStuff.php
___________________________________________________________________
Added: svn:eol-style
1232 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/WinCacheBagOStuff.php
@@ -0,0 +1,71 @@
 2+<?php
 3+
 4+/**
 5+ * Wrapper for WinCache object caching functions; identical interface
 6+ * to the APC wrapper
 7+ *
 8+ * @ingroup Cache
 9+ */
 10+class WinCacheBagOStuff extends BagOStuff {
 11+
 12+ /**
 13+ * Get a value from the WinCache object cache
 14+ *
 15+ * @param $key String: cache key
 16+ * @return mixed
 17+ */
 18+ public function get( $key ) {
 19+ $val = wincache_ucache_get( $key );
 20+
 21+ if ( is_string( $val ) ) {
 22+ $val = unserialize( $val );
 23+ }
 24+
 25+ return $val;
 26+ }
 27+
 28+ /**
 29+ * Store a value in the WinCache object cache
 30+ *
 31+ * @param $key String: cache key
 32+ * @param $value Mixed: object to store
 33+ * @param $expire Int: expiration time
 34+ * @return bool
 35+ */
 36+ public function set( $key, $value, $expire = 0 ) {
 37+ $result = wincache_ucache_set( $key, serialize( $value ), $expire );
 38+
 39+ /* wincache_ucache_set returns an empty array on success if $value
 40+ was an array, bool otherwise */
 41+ return ( is_array( $result ) && $result === array() ) || $result;
 42+ }
 43+
 44+ /**
 45+ * Remove a value from the WinCache object cache
 46+ *
 47+ * @param $key String: cache key
 48+ * @param $time Int: not used in this implementation
 49+ * @return bool
 50+ */
 51+ public function delete( $key, $time = 0 ) {
 52+ wincache_ucache_delete( $key );
 53+
 54+ return true;
 55+ }
 56+
 57+ public function keys() {
 58+ $info = wincache_ucache_info();
 59+ $list = $info['ucache_entries'];
 60+ $keys = array();
 61+
 62+ if ( is_null( $list ) ) {
 63+ return array();
 64+ }
 65+
 66+ foreach ( $list as $entry ) {
 67+ $keys[] = $entry['key_name'];
 68+ }
 69+
 70+ return $keys;
 71+ }
 72+}
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/WinCacheBagOStuff.php
___________________________________________________________________
Added: svn:eol-style
173 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/APCBagOStuff.php
@@ -0,0 +1,43 @@
 2+<?php
 3+
 4+/**
 5+ * This is a wrapper for APC's shared memory functions
 6+ *
 7+ * @ingroup Cache
 8+ */
 9+class APCBagOStuff extends BagOStuff {
 10+ public function get( $key ) {
 11+ $val = apc_fetch( $key );
 12+
 13+ if ( is_string( $val ) ) {
 14+ $val = unserialize( $val );
 15+ }
 16+
 17+ return $val;
 18+ }
 19+
 20+ public function set( $key, $value, $exptime = 0 ) {
 21+ apc_store( $key, serialize( $value ), $exptime );
 22+
 23+ return true;
 24+ }
 25+
 26+ public function delete( $key, $time = 0 ) {
 27+ apc_delete( $key );
 28+
 29+ return true;
 30+ }
 31+
 32+ public function keys() {
 33+ $info = apc_cache_info( 'user' );
 34+ $list = $info['cache_list'];
 35+ $keys = array();
 36+
 37+ foreach ( $list as $entry ) {
 38+ $keys[] = $entry['info'];
 39+ }
 40+
 41+ return $keys;
 42+ }
 43+}
 44+
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/APCBagOStuff.php
___________________________________________________________________
Added: svn:eol-style
145 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/HashBagOStuff.php
@@ -0,0 +1,58 @@
 2+<?php
 3+
 4+/**
 5+ * This is a test of the interface, mainly. It stores things in an associative
 6+ * array, which is not going to persist between program runs.
 7+ *
 8+ * @ingroup Cache
 9+ */
 10+class HashBagOStuff extends BagOStuff {
 11+ var $bag;
 12+
 13+ function __construct() {
 14+ $this->bag = array();
 15+ }
 16+
 17+ protected function expire( $key ) {
 18+ $et = $this->bag[$key][1];
 19+
 20+ if ( ( $et == 0 ) || ( $et > time() ) ) {
 21+ return false;
 22+ }
 23+
 24+ $this->delete( $key );
 25+
 26+ return true;
 27+ }
 28+
 29+ function get( $key ) {
 30+ if ( !isset( $this->bag[$key] ) ) {
 31+ return false;
 32+ }
 33+
 34+ if ( $this->expire( $key ) ) {
 35+ return false;
 36+ }
 37+
 38+ return $this->bag[$key][0];
 39+ }
 40+
 41+ function set( $key, $value, $exptime = 0 ) {
 42+ $this->bag[$key] = array( $value, $this->convertExpiry( $exptime ) );
 43+ }
 44+
 45+ function delete( $key, $time = 0 ) {
 46+ if ( !isset( $this->bag[$key] ) ) {
 47+ return false;
 48+ }
 49+
 50+ unset( $this->bag[$key] );
 51+
 52+ return true;
 53+ }
 54+
 55+ function keys() {
 56+ return array_keys( $this->bag );
 57+ }
 58+}
 59+
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/HashBagOStuff.php
___________________________________________________________________
Added: svn:eol-style
160 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/MemcachedClient.php
@@ -0,0 +1,1099 @@
 2+<?php
 3+/**
 4+ * +---------------------------------------------------------------------------+
 5+ * | memcached client, PHP |
 6+ * +---------------------------------------------------------------------------+
 7+ * | Copyright (c) 2003 Ryan T. Dean <rtdean@cytherianage.net> |
 8+ * | All rights reserved. |
 9+ * | |
 10+ * | Redistribution and use in source and binary forms, with or without |
 11+ * | modification, are permitted provided that the following conditions |
 12+ * | are met: |
 13+ * | |
 14+ * | 1. Redistributions of source code must retain the above copyright |
 15+ * | notice, this list of conditions and the following disclaimer. |
 16+ * | 2. Redistributions in binary form must reproduce the above copyright |
 17+ * | notice, this list of conditions and the following disclaimer in the |
 18+ * | documentation and/or other materials provided with the distribution. |
 19+ * | |
 20+ * | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
 21+ * | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
 22+ * | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
 23+ * | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
 24+ * | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
 25+ * | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
 26+ * | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
 27+ * | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
 28+ * | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
 29+ * | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
 30+ * +---------------------------------------------------------------------------+
 31+ * | Author: Ryan T. Dean <rtdean@cytherianage.net> |
 32+ * | Heavily influenced by the Perl memcached client by Brad Fitzpatrick. |
 33+ * | Permission granted by Brad Fitzpatrick for relicense of ported Perl |
 34+ * | client logic under 2-clause BSD license. |
 35+ * +---------------------------------------------------------------------------+
 36+ *
 37+ * @file
 38+ * $TCAnet$
 39+ */
 40+
 41+/**
 42+ * This is the PHP client for memcached - a distributed memory cache daemon.
 43+ * More information is available at http://www.danga.com/memcached/
 44+ *
 45+ * Usage example:
 46+ *
 47+ * require_once 'memcached.php';
 48+ *
 49+ * $mc = new MWMemcached(array(
 50+ * 'servers' => array('127.0.0.1:10000',
 51+ * array('192.0.0.1:10010', 2),
 52+ * '127.0.0.1:10020'),
 53+ * 'debug' => false,
 54+ * 'compress_threshold' => 10240,
 55+ * 'persistent' => true));
 56+ *
 57+ * $mc->add('key', array('some', 'array'));
 58+ * $mc->replace('key', 'some random string');
 59+ * $val = $mc->get('key');
 60+ *
 61+ * @author Ryan T. Dean <rtdean@cytherianage.net>
 62+ * @version 0.1.2
 63+ */
 64+
 65+// {{{ requirements
 66+// }}}
 67+
 68+// {{{ class MWMemcached
 69+/**
 70+ * memcached client class implemented using (p)fsockopen()
 71+ *
 72+ * @author Ryan T. Dean <rtdean@cytherianage.net>
 73+ * @ingroup Cache
 74+ */
 75+class MWMemcached {
 76+ // {{{ properties
 77+ // {{{ public
 78+
 79+ // {{{ constants
 80+ // {{{ flags
 81+
 82+ /**
 83+ * Flag: indicates data is serialized
 84+ */
 85+ const SERIALIZED = 1;
 86+
 87+ /**
 88+ * Flag: indicates data is compressed
 89+ */
 90+ const COMPRESSED = 2;
 91+
 92+ // }}}
 93+
 94+ /**
 95+ * Minimum savings to store data compressed
 96+ */
 97+ const COMPRESSION_SAVINGS = 0.20;
 98+
 99+ // }}}
 100+
 101+
 102+ /**
 103+ * Command statistics
 104+ *
 105+ * @var array
 106+ * @access public
 107+ */
 108+ var $stats;
 109+
 110+ // }}}
 111+ // {{{ private
 112+
 113+ /**
 114+ * Cached Sockets that are connected
 115+ *
 116+ * @var array
 117+ * @access private
 118+ */
 119+ var $_cache_sock;
 120+
 121+ /**
 122+ * Current debug status; 0 - none to 9 - profiling
 123+ *
 124+ * @var boolean
 125+ * @access private
 126+ */
 127+ var $_debug;
 128+
 129+ /**
 130+ * Dead hosts, assoc array, 'host'=>'unixtime when ok to check again'
 131+ *
 132+ * @var array
 133+ * @access private
 134+ */
 135+ var $_host_dead;
 136+
 137+ /**
 138+ * Is compression available?
 139+ *
 140+ * @var boolean
 141+ * @access private
 142+ */
 143+ var $_have_zlib;
 144+
 145+ /**
 146+ * Do we want to use compression?
 147+ *
 148+ * @var boolean
 149+ * @access private
 150+ */
 151+ var $_compress_enable;
 152+
 153+ /**
 154+ * At how many bytes should we compress?
 155+ *
 156+ * @var integer
 157+ * @access private
 158+ */
 159+ var $_compress_threshold;
 160+
 161+ /**
 162+ * Are we using persistent links?
 163+ *
 164+ * @var boolean
 165+ * @access private
 166+ */
 167+ var $_persistent;
 168+
 169+ /**
 170+ * If only using one server; contains ip:port to connect to
 171+ *
 172+ * @var string
 173+ * @access private
 174+ */
 175+ var $_single_sock;
 176+
 177+ /**
 178+ * Array containing ip:port or array(ip:port, weight)
 179+ *
 180+ * @var array
 181+ * @access private
 182+ */
 183+ var $_servers;
 184+
 185+ /**
 186+ * Our bit buckets
 187+ *
 188+ * @var array
 189+ * @access private
 190+ */
 191+ var $_buckets;
 192+
 193+ /**
 194+ * Total # of bit buckets we have
 195+ *
 196+ * @var integer
 197+ * @access private
 198+ */
 199+ var $_bucketcount;
 200+
 201+ /**
 202+ * # of total servers we have
 203+ *
 204+ * @var integer
 205+ * @access private
 206+ */
 207+ var $_active;
 208+
 209+ /**
 210+ * Stream timeout in seconds. Applies for example to fread()
 211+ *
 212+ * @var integer
 213+ * @access private
 214+ */
 215+ var $_timeout_seconds;
 216+
 217+ /**
 218+ * Stream timeout in microseconds
 219+ *
 220+ * @var integer
 221+ * @access private
 222+ */
 223+ var $_timeout_microseconds;
 224+
 225+ /**
 226+ * Connect timeout in seconds
 227+ */
 228+ var $_connect_timeout;
 229+
 230+ /**
 231+ * Number of connection attempts for each server
 232+ */
 233+ var $_connect_attempts;
 234+
 235+ // }}}
 236+ // }}}
 237+ // {{{ methods
 238+ // {{{ public functions
 239+ // {{{ memcached()
 240+
 241+ /**
 242+ * Memcache initializer
 243+ *
 244+ * @param $args Array Associative array of settings
 245+ *
 246+ * @return mixed
 247+ */
 248+ public function __construct( $args ) {
 249+ $this->set_servers( isset( $args['servers'] ) ? $args['servers'] : array() );
 250+ $this->_debug = isset( $args['debug'] ) ? $args['debug'] : false;
 251+ $this->stats = array();
 252+ $this->_compress_threshold = isset( $args['compress_threshold'] ) ? $args['compress_threshold'] : 0;
 253+ $this->_persistent = isset( $args['persistent'] ) ? $args['persistent'] : false;
 254+ $this->_compress_enable = true;
 255+ $this->_have_zlib = function_exists( 'gzcompress' );
 256+
 257+ $this->_cache_sock = array();
 258+ $this->_host_dead = array();
 259+
 260+ $this->_timeout_seconds = 0;
 261+ $this->_timeout_microseconds = isset( $args['timeout'] ) ? $args['timeout'] : 100000;
 262+
 263+ $this->_connect_timeout = isset( $args['connect_timeout'] ) ? $args['connect_timeout'] : 0.1;
 264+ $this->_connect_attempts = 2;
 265+ }
 266+
 267+ // }}}
 268+ // {{{ add()
 269+
 270+ /**
 271+ * Adds a key/value to the memcache server if one isn't already set with
 272+ * that key
 273+ *
 274+ * @param $key String: key to set with data
 275+ * @param $val Mixed: value to store
 276+ * @param $exp Integer: (optional) Expiration time. This can be a number of seconds
 277+ * to cache for (up to 30 days inclusive). Any timespans of 30 days + 1 second or
 278+ * longer must be the timestamp of the time at which the mapping should expire. It
 279+ * is safe to use timestamps in all cases, regardless of exipration
 280+ * eg: strtotime("+3 hour")
 281+ *
 282+ * @return Boolean
 283+ */
 284+ public function add( $key, $val, $exp = 0 ) {
 285+ return $this->_set( 'add', $key, $val, $exp );
 286+ }
 287+
 288+ // }}}
 289+ // {{{ decr()
 290+
 291+ /**
 292+ * Decrease a value stored on the memcache server
 293+ *
 294+ * @param $key String: key to decrease
 295+ * @param $amt Integer: (optional) amount to decrease
 296+ *
 297+ * @return Mixed: FALSE on failure, value on success
 298+ */
 299+ public function decr( $key, $amt = 1 ) {
 300+ return $this->_incrdecr( 'decr', $key, $amt );
 301+ }
 302+
 303+ // }}}
 304+ // {{{ delete()
 305+
 306+ /**
 307+ * Deletes a key from the server, optionally after $time
 308+ *
 309+ * @param $key String: key to delete
 310+ * @param $time Integer: (optional) how long to wait before deleting
 311+ *
 312+ * @return Boolean: TRUE on success, FALSE on failure
 313+ */
 314+ public function delete( $key, $time = 0 ) {
 315+ if ( !$this->_active ) {
 316+ return false;
 317+ }
 318+
 319+ $sock = $this->get_sock( $key );
 320+ if ( !is_resource( $sock ) ) {
 321+ return false;
 322+ }
 323+
 324+ $key = is_array( $key ) ? $key[1] : $key;
 325+
 326+ if ( isset( $this->stats['delete'] ) ) {
 327+ $this->stats['delete']++;
 328+ } else {
 329+ $this->stats['delete'] = 1;
 330+ }
 331+ $cmd = "delete $key $time\r\n";
 332+ if( !$this->_safe_fwrite( $sock, $cmd, strlen( $cmd ) ) ) {
 333+ $this->_dead_sock( $sock );
 334+ return false;
 335+ }
 336+ $res = trim( fgets( $sock ) );
 337+
 338+ if ( $this->_debug ) {
 339+ $this->_debugprint( sprintf( "MemCache: delete %s (%s)\n", $key, $res ) );
 340+ }
 341+
 342+ if ( $res == "DELETED" ) {
 343+ return true;
 344+ }
 345+ return false;
 346+ }
 347+
 348+ // }}}
 349+ // {{{ disconnect_all()
 350+
 351+ /**
 352+ * Disconnects all connected sockets
 353+ */
 354+ public function disconnect_all() {
 355+ foreach ( $this->_cache_sock as $sock ) {
 356+ fclose( $sock );
 357+ }
 358+
 359+ $this->_cache_sock = array();
 360+ }
 361+
 362+ // }}}
 363+ // {{{ enable_compress()
 364+
 365+ /**
 366+ * Enable / Disable compression
 367+ *
 368+ * @param $enable Boolean: TRUE to enable, FALSE to disable
 369+ */
 370+ public function enable_compress( $enable ) {
 371+ $this->_compress_enable = $enable;
 372+ }
 373+
 374+ // }}}
 375+ // {{{ forget_dead_hosts()
 376+
 377+ /**
 378+ * Forget about all of the dead hosts
 379+ */
 380+ public function forget_dead_hosts() {
 381+ $this->_host_dead = array();
 382+ }
 383+
 384+ // }}}
 385+ // {{{ get()
 386+
 387+ /**
 388+ * Retrieves the value associated with the key from the memcache server
 389+ *
 390+ * @param $key Mixed: key to retrieve
 391+ *
 392+ * @return Mixed
 393+ */
 394+ public function get( $key ) {
 395+ wfProfileIn( __METHOD__ );
 396+
 397+ if ( $this->_debug ) {
 398+ $this->_debugprint( "get($key)\n" );
 399+ }
 400+
 401+ if ( !$this->_active ) {
 402+ wfProfileOut( __METHOD__ );
 403+ return false;
 404+ }
 405+
 406+ $sock = $this->get_sock( $key );
 407+
 408+ if ( !is_resource( $sock ) ) {
 409+ wfProfileOut( __METHOD__ );
 410+ return false;
 411+ }
 412+
 413+ if ( isset( $this->stats['get'] ) ) {
 414+ $this->stats['get']++;
 415+ } else {
 416+ $this->stats['get'] = 1;
 417+ }
 418+
 419+ $cmd = "get $key\r\n";
 420+ if ( !$this->_safe_fwrite( $sock, $cmd, strlen( $cmd ) ) ) {
 421+ $this->_dead_sock( $sock );
 422+ wfProfileOut( __METHOD__ );
 423+ return false;
 424+ }
 425+
 426+ $val = array();
 427+ $this->_load_items( $sock, $val );
 428+
 429+ if ( $this->_debug ) {
 430+ foreach ( $val as $k => $v ) {
 431+ $this->_debugprint( sprintf( "MemCache: sock %s got %s\n", serialize( $sock ), $k ) );
 432+ }
 433+ }
 434+
 435+ wfProfileOut( __METHOD__ );
 436+ if ( isset( $val[$key] ) ) {
 437+ return $val[$key];
 438+ } else {
 439+ return false;
 440+ }
 441+ }
 442+
 443+ // }}}
 444+ // {{{ get_multi()
 445+
 446+ /**
 447+ * Get multiple keys from the server(s)
 448+ *
 449+ * @param $keys Array: keys to retrieve
 450+ *
 451+ * @return Array
 452+ */
 453+ public function get_multi( $keys ) {
 454+ if ( !$this->_active ) {
 455+ return false;
 456+ }
 457+
 458+ if ( isset( $this->stats['get_multi'] ) ) {
 459+ $this->stats['get_multi']++;
 460+ } else {
 461+ $this->stats['get_multi'] = 1;
 462+ }
 463+ $sock_keys = array();
 464+
 465+ foreach ( $keys as $key ) {
 466+ $sock = $this->get_sock( $key );
 467+ if ( !is_resource( $sock ) ) {
 468+ continue;
 469+ }
 470+ $key = is_array( $key ) ? $key[1] : $key;
 471+ if ( !isset( $sock_keys[$sock] ) ) {
 472+ $sock_keys[$sock] = array();
 473+ $socks[] = $sock;
 474+ }
 475+ $sock_keys[$sock][] = $key;
 476+ }
 477+
 478+ // Send out the requests
 479+ foreach ( $socks as $sock ) {
 480+ $cmd = 'get';
 481+ foreach ( $sock_keys[$sock] as $key ) {
 482+ $cmd .= ' ' . $key;
 483+ }
 484+ $cmd .= "\r\n";
 485+
 486+ if ( $this->_safe_fwrite( $sock, $cmd, strlen( $cmd ) ) ) {
 487+ $gather[] = $sock;
 488+ } else {
 489+ $this->_dead_sock( $sock );
 490+ }
 491+ }
 492+
 493+ // Parse responses
 494+ $val = array();
 495+ foreach ( $gather as $sock ) {
 496+ $this->_load_items( $sock, $val );
 497+ }
 498+
 499+ if ( $this->_debug ) {
 500+ foreach ( $val as $k => $v ) {
 501+ $this->_debugprint( sprintf( "MemCache: got %s\n", $k ) );
 502+ }
 503+ }
 504+
 505+ return $val;
 506+ }
 507+
 508+ // }}}
 509+ // {{{ incr()
 510+
 511+ /**
 512+ * Increments $key (optionally) by $amt
 513+ *
 514+ * @param $key String: key to increment
 515+ * @param $amt Integer: (optional) amount to increment
 516+ *
 517+ * @return Integer: null if the key does not exist yet (this does NOT
 518+ * create new mappings if the key does not exist). If the key does
 519+ * exist, this returns the new value for that key.
 520+ */
 521+ public function incr( $key, $amt = 1 ) {
 522+ return $this->_incrdecr( 'incr', $key, $amt );
 523+ }
 524+
 525+ // }}}
 526+ // {{{ replace()
 527+
 528+ /**
 529+ * Overwrites an existing value for key; only works if key is already set
 530+ *
 531+ * @param $key String: key to set value as
 532+ * @param $value Mixed: value to store
 533+ * @param $exp Integer: (optional) Expiration time. This can be a number of seconds
 534+ * to cache for (up to 30 days inclusive). Any timespans of 30 days + 1 second or
 535+ * longer must be the timestamp of the time at which the mapping should expire. It
 536+ * is safe to use timestamps in all cases, regardless of exipration
 537+ * eg: strtotime("+3 hour")
 538+ *
 539+ * @return Boolean
 540+ */
 541+ public function replace( $key, $value, $exp = 0 ) {
 542+ return $this->_set( 'replace', $key, $value, $exp );
 543+ }
 544+
 545+ // }}}
 546+ // {{{ run_command()
 547+
 548+ /**
 549+ * Passes through $cmd to the memcache server connected by $sock; returns
 550+ * output as an array (null array if no output)
 551+ *
 552+ * NOTE: due to a possible bug in how PHP reads while using fgets(), each
 553+ * line may not be terminated by a \r\n. More specifically, my testing
 554+ * has shown that, on FreeBSD at least, each line is terminated only
 555+ * with a \n. This is with the PHP flag auto_detect_line_endings set
 556+ * to falase (the default).
 557+ *
 558+ * @param $sock Ressource: socket to send command on
 559+ * @param $cmd String: command to run
 560+ *
 561+ * @return Array: output array
 562+ */
 563+ public function run_command( $sock, $cmd ) {
 564+ if ( !is_resource( $sock ) ) {
 565+ return array();
 566+ }
 567+
 568+ if ( !$this->_safe_fwrite( $sock, $cmd, strlen( $cmd ) ) ) {
 569+ return array();
 570+ }
 571+
 572+ while ( true ) {
 573+ $res = fgets( $sock );
 574+ $ret[] = $res;
 575+ if ( preg_match( '/^END/', $res ) ) {
 576+ break;
 577+ }
 578+ if ( strlen( $res ) == 0 ) {
 579+ break;
 580+ }
 581+ }
 582+ return $ret;
 583+ }
 584+
 585+ // }}}
 586+ // {{{ set()
 587+
 588+ /**
 589+ * Unconditionally sets a key to a given value in the memcache. Returns true
 590+ * if set successfully.
 591+ *
 592+ * @param $key String: key to set value as
 593+ * @param $value Mixed: value to set
 594+ * @param $exp Integer: (optional) Expiration time. This can be a number of seconds
 595+ * to cache for (up to 30 days inclusive). Any timespans of 30 days + 1 second or
 596+ * longer must be the timestamp of the time at which the mapping should expire. It
 597+ * is safe to use timestamps in all cases, regardless of exipration
 598+ * eg: strtotime("+3 hour")
 599+ *
 600+ * @return Boolean: TRUE on success
 601+ */
 602+ public function set( $key, $value, $exp = 0 ) {
 603+ return $this->_set( 'set', $key, $value, $exp );
 604+ }
 605+
 606+ // }}}
 607+ // {{{ set_compress_threshold()
 608+
 609+ /**
 610+ * Sets the compression threshold
 611+ *
 612+ * @param $thresh Integer: threshold to compress if larger than
 613+ */
 614+ public function set_compress_threshold( $thresh ) {
 615+ $this->_compress_threshold = $thresh;
 616+ }
 617+
 618+ // }}}
 619+ // {{{ set_debug()
 620+
 621+ /**
 622+ * Sets the debug flag
 623+ *
 624+ * @param $dbg Boolean: TRUE for debugging, FALSE otherwise
 625+ *
 626+ * @see MWMemcached::__construct
 627+ */
 628+ public function set_debug( $dbg ) {
 629+ $this->_debug = $dbg;
 630+ }
 631+
 632+ // }}}
 633+ // {{{ set_servers()
 634+
 635+ /**
 636+ * Sets the server list to distribute key gets and puts between
 637+ *
 638+ * @param $list Array of servers to connect to
 639+ *
 640+ * @see MWMemcached::__construct()
 641+ */
 642+ public function set_servers( $list ) {
 643+ $this->_servers = $list;
 644+ $this->_active = count( $list );
 645+ $this->_buckets = null;
 646+ $this->_bucketcount = 0;
 647+
 648+ $this->_single_sock = null;
 649+ if ( $this->_active == 1 ) {
 650+ $this->_single_sock = $this->_servers[0];
 651+ }
 652+ }
 653+
 654+ /**
 655+ * Sets the timeout for new connections
 656+ *
 657+ * @param $seconds Integer: number of seconds
 658+ * @param $microseconds Integer: number of microseconds
 659+ */
 660+ public function set_timeout( $seconds, $microseconds ) {
 661+ $this->_timeout_seconds = $seconds;
 662+ $this->_timeout_microseconds = $microseconds;
 663+ }
 664+
 665+ // }}}
 666+ // }}}
 667+ // {{{ private methods
 668+ // {{{ _close_sock()
 669+
 670+ /**
 671+ * Close the specified socket
 672+ *
 673+ * @param $sock String: socket to close
 674+ *
 675+ * @access private
 676+ */
 677+ function _close_sock( $sock ) {
 678+ $host = array_search( $sock, $this->_cache_sock );
 679+ fclose( $this->_cache_sock[$host] );
 680+ unset( $this->_cache_sock[$host] );
 681+ }
 682+
 683+ // }}}
 684+ // {{{ _connect_sock()
 685+
 686+ /**
 687+ * Connects $sock to $host, timing out after $timeout
 688+ *
 689+ * @param $sock Integer: socket to connect
 690+ * @param $host String: Host:IP to connect to
 691+ *
 692+ * @return boolean
 693+ * @access private
 694+ */
 695+ function _connect_sock( &$sock, $host ) {
 696+ list( $ip, $port ) = explode( ':', $host );
 697+ $sock = false;
 698+ $timeout = $this->_connect_timeout;
 699+ $errno = $errstr = null;
 700+ for( $i = 0; !$sock && $i < $this->_connect_attempts; $i++ ) {
 701+ wfSuppressWarnings();
 702+ if ( $this->_persistent == 1 ) {
 703+ $sock = pfsockopen( $ip, $port, $errno, $errstr, $timeout );
 704+ } else {
 705+ $sock = fsockopen( $ip, $port, $errno, $errstr, $timeout );
 706+ }
 707+ wfRestoreWarnings();
 708+ }
 709+ if ( !$sock ) {
 710+ if ( $this->_debug ) {
 711+ $this->_debugprint( "Error connecting to $host: $errstr\n" );
 712+ }
 713+ return false;
 714+ }
 715+
 716+ // Initialise timeout
 717+ stream_set_timeout( $sock, $this->_timeout_seconds, $this->_timeout_microseconds );
 718+
 719+ return true;
 720+ }
 721+
 722+ // }}}
 723+ // {{{ _dead_sock()
 724+
 725+ /**
 726+ * Marks a host as dead until 30-40 seconds in the future
 727+ *
 728+ * @param $sock String: socket to mark as dead
 729+ *
 730+ * @access private
 731+ */
 732+ function _dead_sock( $sock ) {
 733+ $host = array_search( $sock, $this->_cache_sock );
 734+ $this->_dead_host( $host );
 735+ }
 736+
 737+ function _dead_host( $host ) {
 738+ $parts = explode( ':', $host );
 739+ $ip = $parts[0];
 740+ $this->_host_dead[$ip] = time() + 30 + intval( rand( 0, 10 ) );
 741+ $this->_host_dead[$host] = $this->_host_dead[$ip];
 742+ unset( $this->_cache_sock[$host] );
 743+ }
 744+
 745+ // }}}
 746+ // {{{ get_sock()
 747+
 748+ /**
 749+ * get_sock
 750+ *
 751+ * @param $key String: key to retrieve value for;
 752+ *
 753+ * @return Mixed: resource on success, false on failure
 754+ * @access private
 755+ */
 756+ function get_sock( $key ) {
 757+ if ( !$this->_active ) {
 758+ return false;
 759+ }
 760+
 761+ if ( $this->_single_sock !== null ) {
 762+ $this->_flush_read_buffer( $this->_single_sock );
 763+ return $this->sock_to_host( $this->_single_sock );
 764+ }
 765+
 766+ $hv = is_array( $key ) ? intval( $key[0] ) : $this->_hashfunc( $key );
 767+
 768+ if ( $this->_buckets === null ) {
 769+ foreach ( $this->_servers as $v ) {
 770+ if ( is_array( $v ) ) {
 771+ for( $i = 0; $i < $v[1]; $i++ ) {
 772+ $bu[] = $v[0];
 773+ }
 774+ } else {
 775+ $bu[] = $v;
 776+ }
 777+ }
 778+ $this->_buckets = $bu;
 779+ $this->_bucketcount = count( $bu );
 780+ }
 781+
 782+ $realkey = is_array( $key ) ? $key[1] : $key;
 783+ for( $tries = 0; $tries < 20; $tries++ ) {
 784+ $host = $this->_buckets[$hv % $this->_bucketcount];
 785+ $sock = $this->sock_to_host( $host );
 786+ if ( is_resource( $sock ) ) {
 787+ $this->_flush_read_buffer( $sock );
 788+ return $sock;
 789+ }
 790+ $hv = $this->_hashfunc( $hv . $realkey );
 791+ }
 792+
 793+ return false;
 794+ }
 795+
 796+ // }}}
 797+ // {{{ _hashfunc()
 798+
 799+ /**
 800+ * Creates a hash integer based on the $key
 801+ *
 802+ * @param $key String: key to hash
 803+ *
 804+ * @return Integer: hash value
 805+ * @access private
 806+ */
 807+ function _hashfunc( $key ) {
 808+ # Hash function must on [0,0x7ffffff]
 809+ # We take the first 31 bits of the MD5 hash, which unlike the hash
 810+ # function used in a previous version of this client, works
 811+ return hexdec( substr( md5( $key ), 0, 8 ) ) & 0x7fffffff;
 812+ }
 813+
 814+ // }}}
 815+ // {{{ _incrdecr()
 816+
 817+ /**
 818+ * Perform increment/decriment on $key
 819+ *
 820+ * @param $cmd String: command to perform
 821+ * @param $key String: key to perform it on
 822+ * @param $amt Integer: amount to adjust
 823+ *
 824+ * @return Integer: new value of $key
 825+ * @access private
 826+ */
 827+ function _incrdecr( $cmd, $key, $amt = 1 ) {
 828+ if ( !$this->_active ) {
 829+ return null;
 830+ }
 831+
 832+ $sock = $this->get_sock( $key );
 833+ if ( !is_resource( $sock ) ) {
 834+ return null;
 835+ }
 836+
 837+ $key = is_array( $key ) ? $key[1] : $key;
 838+ if ( isset( $this->stats[$cmd] ) ) {
 839+ $this->stats[$cmd]++;
 840+ } else {
 841+ $this->stats[$cmd] = 1;
 842+ }
 843+ if ( !$this->_safe_fwrite( $sock, "$cmd $key $amt\r\n" ) ) {
 844+ return $this->_dead_sock( $sock );
 845+ }
 846+
 847+ $line = fgets( $sock );
 848+ $match = array();
 849+ if ( !preg_match( '/^(\d+)/', $line, $match ) ) {
 850+ return null;
 851+ }
 852+ return $match[1];
 853+ }
 854+
 855+ // }}}
 856+ // {{{ _load_items()
 857+
 858+ /**
 859+ * Load items into $ret from $sock
 860+ *
 861+ * @param $sock Ressource: socket to read from
 862+ * @param $ret Array: returned values
 863+ *
 864+ * @access private
 865+ */
 866+ function _load_items( $sock, &$ret ) {
 867+ while ( 1 ) {
 868+ $decl = fgets( $sock );
 869+ if ( $decl == "END\r\n" ) {
 870+ return true;
 871+ } elseif ( preg_match( '/^VALUE (\S+) (\d+) (\d+)\r\n$/', $decl, $match ) ) {
 872+ list( $rkey, $flags, $len ) = array( $match[1], $match[2], $match[3] );
 873+ $bneed = $len + 2;
 874+ $offset = 0;
 875+
 876+ while ( $bneed > 0 ) {
 877+ $data = fread( $sock, $bneed );
 878+ $n = strlen( $data );
 879+ if ( $n == 0 ) {
 880+ break;
 881+ }
 882+ $offset += $n;
 883+ $bneed -= $n;
 884+ if ( isset( $ret[$rkey] ) ) {
 885+ $ret[$rkey] .= $data;
 886+ } else {
 887+ $ret[$rkey] = $data;
 888+ }
 889+ }
 890+
 891+ if ( $offset != $len + 2 ) {
 892+ // Something is borked!
 893+ if ( $this->_debug ) {
 894+ $this->_debugprint( sprintf( "Something is borked! key %s expecting %d got %d length\n", $rkey, $len + 2, $offset ) );
 895+ }
 896+
 897+ unset( $ret[$rkey] );
 898+ $this->_close_sock( $sock );
 899+ return false;
 900+ }
 901+
 902+ if ( $this->_have_zlib && $flags & self::COMPRESSED ) {
 903+ $ret[$rkey] = gzuncompress( $ret[$rkey] );
 904+ }
 905+
 906+ $ret[$rkey] = rtrim( $ret[$rkey] );
 907+
 908+ if ( $flags & self::SERIALIZED ) {
 909+ $ret[$rkey] = unserialize( $ret[$rkey] );
 910+ }
 911+
 912+ } else {
 913+ $this->_debugprint( "Error parsing memcached response\n" );
 914+ return 0;
 915+ }
 916+ }
 917+ }
 918+
 919+ // }}}
 920+ // {{{ _set()
 921+
 922+ /**
 923+ * Performs the requested storage operation to the memcache server
 924+ *
 925+ * @param $cmd String: command to perform
 926+ * @param $key String: key to act on
 927+ * @param $val Mixed: what we need to store
 928+ * @param $exp Integer: (optional) Expiration time. This can be a number of seconds
 929+ * to cache for (up to 30 days inclusive). Any timespans of 30 days + 1 second or
 930+ * longer must be the timestamp of the time at which the mapping should expire. It
 931+ * is safe to use timestamps in all cases, regardless of exipration
 932+ * eg: strtotime("+3 hour")
 933+ *
 934+ * @return Boolean
 935+ * @access private
 936+ */
 937+ function _set( $cmd, $key, $val, $exp ) {
 938+ if ( !$this->_active ) {
 939+ return false;
 940+ }
 941+
 942+ $sock = $this->get_sock( $key );
 943+ if ( !is_resource( $sock ) ) {
 944+ return false;
 945+ }
 946+
 947+ if ( isset( $this->stats[$cmd] ) ) {
 948+ $this->stats[$cmd]++;
 949+ } else {
 950+ $this->stats[$cmd] = 1;
 951+ }
 952+
 953+ $flags = 0;
 954+
 955+ if ( !is_scalar( $val ) ) {
 956+ $val = serialize( $val );
 957+ $flags |= self::SERIALIZED;
 958+ if ( $this->_debug ) {
 959+ $this->_debugprint( sprintf( "client: serializing data as it is not scalar\n" ) );
 960+ }
 961+ }
 962+
 963+ $len = strlen( $val );
 964+
 965+ if ( $this->_have_zlib && $this->_compress_enable &&
 966+ $this->_compress_threshold && $len >= $this->_compress_threshold )
 967+ {
 968+ $c_val = gzcompress( $val, 9 );
 969+ $c_len = strlen( $c_val );
 970+
 971+ if ( $c_len < $len * ( 1 - self::COMPRESSION_SAVINGS ) ) {
 972+ if ( $this->_debug ) {
 973+ $this->_debugprint( sprintf( "client: compressing data; was %d bytes is now %d bytes\n", $len, $c_len ) );
 974+ }
 975+ $val = $c_val;
 976+ $len = $c_len;
 977+ $flags |= self::COMPRESSED;
 978+ }
 979+ }
 980+ if ( !$this->_safe_fwrite( $sock, "$cmd $key $flags $exp $len\r\n$val\r\n" ) ) {
 981+ return $this->_dead_sock( $sock );
 982+ }
 983+
 984+ $line = trim( fgets( $sock ) );
 985+
 986+ if ( $this->_debug ) {
 987+ $this->_debugprint( sprintf( "%s %s (%s)\n", $cmd, $key, $line ) );
 988+ }
 989+ if ( $line == "STORED" ) {
 990+ return true;
 991+ }
 992+ return false;
 993+ }
 994+
 995+ // }}}
 996+ // {{{ sock_to_host()
 997+
 998+ /**
 999+ * Returns the socket for the host
 1000+ *
 1001+ * @param $host String: Host:IP to get socket for
 1002+ *
 1003+ * @return Mixed: IO Stream or false
 1004+ * @access private
 1005+ */
 1006+ function sock_to_host( $host ) {
 1007+ if ( isset( $this->_cache_sock[$host] ) ) {
 1008+ return $this->_cache_sock[$host];
 1009+ }
 1010+
 1011+ $sock = null;
 1012+ $now = time();
 1013+ list( $ip, /* $port */) = explode( ':', $host );
 1014+ if ( isset( $this->_host_dead[$host] ) && $this->_host_dead[$host] > $now ||
 1015+ isset( $this->_host_dead[$ip] ) && $this->_host_dead[$ip] > $now
 1016+ ) {
 1017+ return null;
 1018+ }
 1019+
 1020+ if ( !$this->_connect_sock( $sock, $host ) ) {
 1021+ return $this->_dead_host( $host );
 1022+ }
 1023+
 1024+ // Do not buffer writes
 1025+ stream_set_write_buffer( $sock, 0 );
 1026+
 1027+ $this->_cache_sock[$host] = $sock;
 1028+
 1029+ return $this->_cache_sock[$host];
 1030+ }
 1031+
 1032+ function _debugprint( $str ) {
 1033+ print( $str );
 1034+ }
 1035+
 1036+ /**
 1037+ * Write to a stream, timing out after the correct amount of time
 1038+ *
 1039+ * @return Boolean: false on failure, true on success
 1040+ */
 1041+ /*
 1042+ function _safe_fwrite( $f, $buf, $len = false ) {
 1043+ stream_set_blocking( $f, 0 );
 1044+
 1045+ if ( $len === false ) {
 1046+ wfDebug( "Writing " . strlen( $buf ) . " bytes\n" );
 1047+ $bytesWritten = fwrite( $f, $buf );
 1048+ } else {
 1049+ wfDebug( "Writing $len bytes\n" );
 1050+ $bytesWritten = fwrite( $f, $buf, $len );
 1051+ }
 1052+ $n = stream_select( $r = null, $w = array( $f ), $e = null, 10, 0 );
 1053+ # $this->_timeout_seconds, $this->_timeout_microseconds );
 1054+
 1055+ wfDebug( "stream_select returned $n\n" );
 1056+ stream_set_blocking( $f, 1 );
 1057+ return $n == 1;
 1058+ return $bytesWritten;
 1059+ }*/
 1060+
 1061+ /**
 1062+ * Original behaviour
 1063+ */
 1064+ function _safe_fwrite( $f, $buf, $len = false ) {
 1065+ if ( $len === false ) {
 1066+ $bytesWritten = fwrite( $f, $buf );
 1067+ } else {
 1068+ $bytesWritten = fwrite( $f, $buf, $len );
 1069+ }
 1070+ return $bytesWritten;
 1071+ }
 1072+
 1073+ /**
 1074+ * Flush the read buffer of a stream
 1075+ */
 1076+ function _flush_read_buffer( $f ) {
 1077+ if ( !is_resource( $f ) ) {
 1078+ return;
 1079+ }
 1080+ $n = stream_select( $r = array( $f ), $w = null, $e = null, 0, 0 );
 1081+ while ( $n == 1 && !feof( $f ) ) {
 1082+ fread( $f, 1024 );
 1083+ $n = stream_select( $r = array( $f ), $w = null, $e = null, 0, 0 );
 1084+ }
 1085+ }
 1086+
 1087+ // }}}
 1088+ // }}}
 1089+ // }}}
 1090+}
 1091+
 1092+// vim: sts=3 sw=3 et
 1093+
 1094+// }}}
 1095+
 1096+class MemCachedClientforWiki extends MWMemcached {
 1097+ function _debugprint( $text ) {
 1098+ wfDebug( "memcached: $text" );
 1099+ }
 1100+}
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/MemcachedClient.php
___________________________________________________________________
Added: svn:keywords
11101 + Author Date Id Revision
Added: svn:eol-style
21102 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/MultiWriteBagOStuff.php
@@ -0,0 +1,95 @@
 2+<?php
 3+
 4+/**
 5+ * A cache class that replicates all writes to multiple child caches. Reads
 6+ * are implemented by reading from the caches in the order they are given in
 7+ * the configuration until a cache gives a positive result.
 8+ */
 9+class MultiWriteBagOStuff extends BagOStuff {
 10+ var $caches;
 11+
 12+ /**
 13+ * Constructor. Parameters are:
 14+ *
 15+ * - caches: This should have a numbered array of cache parameter
 16+ * structures, in the style required by $wgObjectCaches. See
 17+ * the documentation of $wgObjectCaches for more detail.
 18+ */
 19+ public function __construct( $params ) {
 20+ if ( !isset( $params['caches'] ) ) {
 21+ throw new MWException( __METHOD__.': the caches parameter is required' );
 22+ }
 23+
 24+ $this->caches = array();
 25+ foreach ( $params['caches'] as $cacheInfo ) {
 26+ $this->caches[] = ObjectCache::newFromParams( $cacheInfo );
 27+ }
 28+ }
 29+
 30+ public function setDebug( $debug ) {
 31+ $this->doWrite( 'setDebug', $debug );
 32+ }
 33+
 34+ public function get( $key ) {
 35+ foreach ( $this->caches as $cache ) {
 36+ $value = $cache->get( $key );
 37+ if ( $value !== false ) {
 38+ return $value;
 39+ }
 40+ }
 41+ return false;
 42+ }
 43+
 44+ public function set( $key, $value, $exptime = 0 ) {
 45+ return $this->doWrite( 'set', $key, $value, $exptime );
 46+ }
 47+
 48+ public function delete( $key, $time = 0 ) {
 49+ return $this->doWrite( 'delete', $key, $time );
 50+ }
 51+
 52+ public function add( $key, $value, $exptime = 0 ) {
 53+ return $this->doWrite( 'add', $key, $value, $exptime );
 54+ }
 55+
 56+ public function replace( $key, $value, $exptime = 0 ) {
 57+ return $this->doWrite( 'replace', $key, $value, $exptime );
 58+ }
 59+
 60+ public function incr( $key, $value = 1 ) {
 61+ return $this->doWrite( 'incr', $key, $value );
 62+ }
 63+
 64+ public function decr( $key, $value = 1 ) {
 65+ return $this->doWrite( 'decr', $key, $value );
 66+ }
 67+
 68+ public function lock( $key, $timeout = 0 ) {
 69+ // Lock only the first cache, to avoid deadlocks
 70+ if ( isset( $this->caches[0] ) ) {
 71+ return $this->caches[0]->lock( $key, $timeout );
 72+ } else {
 73+ return true;
 74+ }
 75+ }
 76+
 77+ public function unlock( $key ) {
 78+ if ( isset( $this->caches[0] ) ) {
 79+ return $this->caches[0]->unlock( $key );
 80+ } else {
 81+ return true;
 82+ }
 83+ }
 84+
 85+ protected function doWrite( $method /*, ... */ ) {
 86+ $ret = true;
 87+ $args = func_get_args();
 88+ array_shift( $args );
 89+
 90+ foreach ( $this->caches as $cache ) {
 91+ $ret = $ret && call_user_func_array( array( $cache, $method ), $args );
 92+ }
 93+ return $ret;
 94+ }
 95+
 96+}
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/MultiWriteBagOStuff.php
___________________________________________________________________
Added: svn:eol-style
197 + native
Index: branches/wmf/1.17wmf1/includes/objectcache/DBABagOStuff.php
@@ -0,0 +1,190 @@
 2+<?php
 3+
 4+/**
 5+ * Cache that uses DBA as a backend.
 6+ * Slow due to the need to constantly open and close the file to avoid holding
 7+ * writer locks. Intended for development use only, as a memcached workalike
 8+ * for systems that don't have it.
 9+ *
 10+ * @ingroup Cache
 11+ */
 12+class DBABagOStuff extends BagOStuff {
 13+ var $mHandler, $mFile, $mReader, $mWriter, $mDisabled;
 14+
 15+ public function __construct( $dir = false ) {
 16+ global $wgDBAhandler;
 17+
 18+ if ( $dir === false ) {
 19+ global $wgTmpDirectory;
 20+ $dir = $wgTmpDirectory;
 21+ }
 22+
 23+ $this->mFile = "$dir/mw-cache-" . wfWikiID();
 24+ $this->mFile .= '.db';
 25+ wfDebug( __CLASS__ . ": using cache file {$this->mFile}\n" );
 26+ $this->mHandler = $wgDBAhandler;
 27+ }
 28+
 29+ /**
 30+ * Encode value and expiry for storage
 31+ */
 32+ function encode( $value, $expiry ) {
 33+ # Convert to absolute time
 34+ $expiry = $this->convertExpiry( $expiry );
 35+
 36+ return sprintf( '%010u', intval( $expiry ) ) . ' ' . serialize( $value );
 37+ }
 38+
 39+ /**
 40+ * @return list containing value first and expiry second
 41+ */
 42+ function decode( $blob ) {
 43+ if ( !is_string( $blob ) ) {
 44+ return array( null, 0 );
 45+ } else {
 46+ return array(
 47+ unserialize( substr( $blob, 11 ) ),
 48+ intval( substr( $blob, 0, 10 ) )
 49+ );
 50+ }
 51+ }
 52+
 53+ function getReader() {
 54+ if ( file_exists( $this->mFile ) ) {
 55+ $handle = dba_open( $this->mFile, 'rl', $this->mHandler );
 56+ } else {
 57+ $handle = $this->getWriter();
 58+ }
 59+
 60+ if ( !$handle ) {
 61+ wfDebug( "Unable to open DBA cache file {$this->mFile}\n" );
 62+ }
 63+
 64+ return $handle;
 65+ }
 66+
 67+ function getWriter() {
 68+ $handle = dba_open( $this->mFile, 'cl', $this->mHandler );
 69+
 70+ if ( !$handle ) {
 71+ wfDebug( "Unable to open DBA cache file {$this->mFile}\n" );
 72+ }
 73+
 74+ return $handle;
 75+ }
 76+
 77+ function get( $key ) {
 78+ wfProfileIn( __METHOD__ );
 79+ wfDebug( __METHOD__ . "($key)\n" );
 80+
 81+ $handle = $this->getReader();
 82+ if ( !$handle ) {
 83+ wfProfileOut( __METHOD__ );
 84+ return null;
 85+ }
 86+
 87+ $val = dba_fetch( $key, $handle );
 88+ list( $val, $expiry ) = $this->decode( $val );
 89+
 90+ # Must close ASAP because locks are held
 91+ dba_close( $handle );
 92+
 93+ if ( !is_null( $val ) && $expiry && $expiry < time() ) {
 94+ # Key is expired, delete it
 95+ $handle = $this->getWriter();
 96+ dba_delete( $key, $handle );
 97+ dba_close( $handle );
 98+ wfDebug( __METHOD__ . ": $key expired\n" );
 99+ $val = null;
 100+ }
 101+
 102+ wfProfileOut( __METHOD__ );
 103+ return $val;
 104+ }
 105+
 106+ function set( $key, $value, $exptime = 0 ) {
 107+ wfProfileIn( __METHOD__ );
 108+ wfDebug( __METHOD__ . "($key)\n" );
 109+
 110+ $blob = $this->encode( $value, $exptime );
 111+
 112+ $handle = $this->getWriter();
 113+ if ( !$handle ) {
 114+ wfProfileOut( __METHOD__ );
 115+ return false;
 116+ }
 117+
 118+ $ret = dba_replace( $key, $blob, $handle );
 119+ dba_close( $handle );
 120+
 121+ wfProfileOut( __METHOD__ );
 122+ return $ret;
 123+ }
 124+
 125+ function delete( $key, $time = 0 ) {
 126+ wfProfileIn( __METHOD__ );
 127+ wfDebug( __METHOD__ . "($key)\n" );
 128+
 129+ $handle = $this->getWriter();
 130+ if ( !$handle ) {
 131+ wfProfileOut( __METHOD__ );
 132+ return false;
 133+ }
 134+
 135+ $ret = dba_delete( $key, $handle );
 136+ dba_close( $handle );
 137+
 138+ wfProfileOut( __METHOD__ );
 139+ return $ret;
 140+ }
 141+
 142+ function add( $key, $value, $exptime = 0 ) {
 143+ wfProfileIn( __METHOD__ );
 144+
 145+ $blob = $this->encode( $value, $exptime );
 146+
 147+ $handle = $this->getWriter();
 148+
 149+ if ( !$handle ) {
 150+ wfProfileOut( __METHOD__ );
 151+ return false;
 152+ }
 153+
 154+ $ret = dba_insert( $key, $blob, $handle );
 155+
 156+ # Insert failed, check to see if it failed due to an expired key
 157+ if ( !$ret ) {
 158+ list( $value, $expiry ) = $this->decode( dba_fetch( $key, $handle ) );
 159+
 160+ if ( $expiry < time() ) {
 161+ # Yes expired, delete and try again
 162+ dba_delete( $key, $handle );
 163+ $ret = dba_insert( $key, $blob, $handle );
 164+ # This time if it failed then it will be handled by the caller like any other race
 165+ }
 166+ }
 167+
 168+ dba_close( $handle );
 169+
 170+ wfProfileOut( __METHOD__ );
 171+ return $ret;
 172+ }
 173+
 174+ function keys() {
 175+ $reader = $this->getReader();
 176+ $k1 = dba_firstkey( $reader );
 177+
 178+ if ( !$k1 ) {
 179+ return array();
 180+ }
 181+
 182+ $result[] = $k1;
 183+
 184+ while ( $key = dba_nextkey( $reader ) ) {
 185+ $result[] = $key;
 186+ }
 187+
 188+ return $result;
 189+ }
 190+}
 191+
Property changes on: branches/wmf/1.17wmf1/includes/objectcache/DBABagOStuff.php
___________________________________________________________________
Added: svn:eol-style
1192 + native
Index: branches/wmf/1.17wmf1/includes/Setup.php
@@ -189,7 +189,6 @@
190190 require_once( "$IP/includes/Hooks.php" );
191191 require_once( "$IP/includes/Namespace.php" );
192192 require_once( "$IP/includes/ProxyTools.php" );
193 -require_once( "$IP/includes/ObjectCache.php" );
194193 require_once( "$IP/includes/ImageFunctions.php" );
195194 wfProfileOut( $fname.'-includes' );
196195 wfProfileIn( $fname.'-misc1' );
@@ -299,9 +298,9 @@
300299 wfProfileOut( $fname.'-misc1' );
301300 wfProfileIn( $fname.'-memcached' );
302301
303 -$wgMemc =& wfGetMainCache();
304 -$messageMemc =& wfGetMessageCacheStorage();
305 -$parserMemc =& wfGetParserCacheStorage();
 302+$wgMemc = wfGetMainCache();
 303+$messageMemc = wfGetMessageCacheStorage();
 304+$parserMemc = wfGetParserCacheStorage();
306305
307306 wfDebug( 'CACHES: ' . get_class( $wgMemc ) . '[main] ' .
308307 get_class( $messageMemc ) . '[message] ' .
Index: branches/wmf/1.17wmf1/includes/MemcachedSessions.php
@@ -92,4 +92,14 @@
9393 return true;
9494 }
9595
 96+function memsess_write_close() {
 97+ session_write_close();
 98+}
 99+
96100 session_set_save_handler( 'memsess_open', 'memsess_close', 'memsess_read', 'memsess_write', 'memsess_destroy', 'memsess_gc' );
 101+
 102+// It's necessary to register a shutdown function to call session_write_close(),
 103+// because by the time the request shutdown function for the session module is
 104+// called, $wgMemc has already been destroyed. Shutdown functions registered
 105+// this way are called before object destruction.
 106+register_shutdown_function( 'memsess_write_close' );
Index: branches/wmf/1.17wmf1/includes/AutoLoader.php
@@ -17,14 +17,12 @@
1818 'AjaxDispatcher' => 'includes/AjaxDispatcher.php',
1919 'AjaxResponse' => 'includes/AjaxResponse.php',
2020 'AlphabeticPager' => 'includes/Pager.php',
21 - 'APCBagOStuff' => 'includes/BagOStuff.php',
2221 'Article' => 'includes/Article.php',
2322 'AtomFeed' => 'includes/Feed.php',
2423 'AuthPlugin' => 'includes/AuthPlugin.php',
2524 'AuthPluginUser' => 'includes/AuthPlugin.php',
2625 'Autopromote' => 'includes/Autopromote.php',
2726 'BacklinkCache' => 'includes/BacklinkCache.php',
28 - 'BagOStuff' => 'includes/BagOStuff.php',
2927 'Block' => 'includes/Block.php',
3028 'CacheDependency' => 'includes/CacheDependency.php',
3129 'CacheTime' => 'includes/parser/ParserOutput.php',
@@ -55,7 +53,6 @@
5654 'Credits' => 'includes/Credits.php',
5755 'CSSJanus' => 'includes/libs/CSSJanus.php',
5856 'CSSMin' => 'includes/libs/CSSMin.php',
59 - 'DBABagOStuff' => 'includes/BagOStuff.php',
6057 'DependencyWrapper' => 'includes/CacheDependency.php',
6158 'DiffHistoryBlob' => 'includes/HistoryBlob.php',
6259 'DjVuImage' => 'includes/DjVuImage.php',
@@ -72,7 +69,6 @@
7370 'DumpNotalkFilter' => 'includes/Export.php',
7471 'DumpOutput' => 'includes/Export.php',
7572 'DumpPipeOutput' => 'includes/Export.php',
76 - 'eAccelBagOStuff' => 'includes/BagOStuff.php',
7773 'EditPage' => 'includes/EditPage.php',
7874 'EmailNotification' => 'includes/UserMailer.php',
7975 'EnhancedChangesList' => 'includes/ChangesList.php',
@@ -86,7 +82,6 @@
8783 'ExternalUser' => 'includes/ExternalUser.php',
8884 'FatalError' => 'includes/Exception.php',
8985 'FakeTitle' => 'includes/FakeTitle.php',
90 - 'FakeMemCachedClient' => 'includes/ObjectCache.php',
9186 'FauxRequest' => 'includes/WebRequest.php',
9287 'FauxResponse' => 'includes/WebResponse.php',
9388 'FeedItem' => 'includes/Feed.php',
@@ -98,7 +93,6 @@
9994 'FormatExif' => 'includes/Exif.php',
10095 'FormOptions' => 'includes/FormOptions.php',
10196 'GlobalDependency' => 'includes/CacheDependency.php',
102 - 'HashBagOStuff' => 'includes/BagOStuff.php',
10397 'HashtableReplacer' => 'includes/StringUtils.php',
10498 'HistoryBlobCurStub' => 'includes/HistoryBlob.php',
10599 'HistoryBlob' => 'includes/HistoryBlob.php',
@@ -160,17 +154,14 @@
161155 'MagicWord' => 'includes/MagicWord.php',
162156 'MailAddress' => 'includes/UserMailer.php',
163157 'MathRenderer' => 'includes/Math.php',
164 - 'MediaWikiBagOStuff' => 'includes/BagOStuff.php',
165158 'MediaWiki_I18N' => 'includes/SkinTemplate.php',
166159 'MediaWiki' => 'includes/Wiki.php',
167 - 'MemCachedClientforWiki' => 'includes/memcached-client.php',
168160 'Message' => 'includes/Message.php',
169161 'MessageBlobStore' => 'includes/MessageBlobStore.php',
170162 'MessageCache' => 'includes/MessageCache.php',
171163 'MimeMagic' => 'includes/MimeMagic.php',
172164 'MWException' => 'includes/Exception.php',
173165 'MWHttpRequest' => 'includes/HttpFunctions.php',
174 - 'MWMemcached' => 'includes/memcached-client.php',
175166 'MWNamespace' => 'includes/Namespace.php',
176167 'OldChangesList' => 'includes/ChangesList.php',
177168 'OutputPage' => 'includes/OutputPage.php',
@@ -225,7 +216,6 @@
226217 'SpecialMytalk' => 'includes/SpecialPage.php',
227218 'SpecialPage' => 'includes/SpecialPage.php',
228219 'SpecialRedirectToSpecial' => 'includes/SpecialPage.php',
229 - 'SqlBagOStuff' => 'includes/BagOStuff.php',
230220 'SquidUpdate' => 'includes/SquidUpdate.php',
231221 'SquidPurgeClient' => 'includes/SquidPurgeClient.php',
232222 'SquidPurgeClientPool' => 'includes/SquidPurgeClient.php',
@@ -259,8 +249,6 @@
260250 'WikiMap' => 'includes/WikiMap.php',
261251 'WikiReference' => 'includes/WikiMap.php',
262252 'WikiXmlError' => 'includes/WikiError.php',
263 - 'WinCacheBagOStuff' => 'includes/BagOStuff.php',
264 - 'XCacheBagOStuff' => 'includes/BagOStuff.php',
265253 'XmlDumpWriter' => 'includes/Export.php',
266254 'Xml' => 'includes/Xml.php',
267255 'XmlJsCode' => 'includes/Xml.php',
@@ -498,6 +486,25 @@
499487 # includes/normal
500488 'UtfNormal' => 'includes/normal/UtfNormal.php',
501489
 490+ # includes/objectcache
 491+ 'APCBagOStuff' => 'includes/objectcache/APCBagOStuff.php',
 492+ 'BagOStuff' => 'includes/objectcache/BagOStuff.php',
 493+ 'DBABagOStuff' => 'includes/objectcache/DBABagOStuff.php',
 494+ 'eAccelBagOStuff' => 'includes/objectcache/eAccelBagOStuff.php',
 495+ 'EhcacheBagOStuff' => 'includes/objectcache/EhcacheBagOStuff.php',
 496+ 'EmptyBagOStuff' => 'includes/objectcache/EmptyBagOStuff.php',
 497+ 'FakeMemCachedClient' => 'includes/objectcache/EmptyBagOStuff.php',
 498+ 'HashBagOStuff' => 'includes/objectcache/HashBagOStuff.php',
 499+ 'MWMemcached' => 'includes/objectcache/MemcachedClient.php',
 500+ 'MediaWikiBagOStuff' => 'includes/objectcache/SqlBagOStuff.php',
 501+ 'MemCachedClientforWiki' => 'includes/objectcache/MemcachedClient.php',
 502+ 'MemcachedPhpBagOStuff' => 'includes/objectcache/MemcachedPhpBagOStuff.php',
 503+ 'MultiWriteBagOStuff' => 'includes/objectcache/MultiWriteBagOStuff.php',
 504+ 'ObjectCache' => 'includes/objectcache/ObjectCache.php',
 505+ 'SqlBagOStuff' => 'includes/objectcache/SqlBagOStuff.php',
 506+ 'WinCacheBagOStuff' => 'includes/objectcache/WinCacheBagOStuff.php',
 507+ 'XCacheBagOStuff' => 'includes/objectcache/XCacheBagOStuff.php',
 508+
502509 # includes/parser
503510 'CoreLinkFunctions' => 'includes/parser/CoreLinkFunctions.php',
504511 'CoreParserFunctions' => 'includes/parser/CoreParserFunctions.php',
Property changes on: branches/wmf/1.17wmf1/includes/AutoLoader.php
___________________________________________________________________
Modified: svn:mergeinfo
505512 Merged /trunk/phase3/includes/AutoLoader.php:r83135-83136,83140,83143,83147,83208,83416,83492
Index: branches/wmf/1.17wmf1/includes/ForkController.php
@@ -115,10 +115,10 @@
116116 }
117117
118118 protected function prepareEnvironment() {
119 - global $wgCaches, $wgMemc;
 119+ global $wgMemc;
120120 // Don't share DB or memcached connections
121121 wfGetLBFactory()->destroyInstance();
122 - $wgCaches = array();
 122+ ObjectCache::clear();
123123 unset( $wgMemc );
124124 }
125125
Index: branches/wmf/1.17wmf1/includes/DefaultSettings.php
@@ -1467,6 +1467,8 @@
14681468 * - CACHE_DBA: Use PHP's DBA extension to store in a DBM-style
14691469 * database. This is slow, and is not recommended for
14701470 * anything other than debugging.
 1471+ * - (other): A string may be used which identifies a cache
 1472+ * configuration in $wgObjectCaches.
14711473 *
14721474 * @see $wgMessageCacheType, $wgParserCacheType
14731475 */
@@ -1489,6 +1491,36 @@
14901492 $wgParserCacheType = CACHE_ANYTHING;
14911493
14921494 /**
 1495+ * Advanced object cache configuration.
 1496+ *
 1497+ * Use this to define the class names and constructor parameters which are used
 1498+ * for the various cache types. Custom cache types may be defined here and
 1499+ * referenced from $wgMainCacheType, $wgMessageCacheType or $wgParserCacheType.
 1500+ *
 1501+ * The format is an associative array where the key is a cache identifier, and
 1502+ * the value is an associative array of parameters. The "class" parameter is the
 1503+ * class name which will be used. Alternatively, a "factory" parameter may be
 1504+ * given, giving a callable function which will generate a suitable cache object.
 1505+ *
 1506+ * The other parameters are dependent on the class used.
 1507+ */
 1508+$wgObjectCaches = array(
 1509+ CACHE_NONE => array( 'class' => 'EmptyBagOStuff' ),
 1510+ CACHE_DB => array( 'class' => 'SqlBagOStuff', 'table' => 'objectcache' ),
 1511+ CACHE_DBA => array( 'class' => 'DBABagOStuff' ),
 1512+
 1513+ CACHE_ANYTHING => array( 'factory' => 'ObjectCache::newAnything' ),
 1514+ CACHE_ACCEL => array( 'factory' => 'ObjectCache::newAccelerator' ),
 1515+ CACHE_MEMCACHED => array( 'factory' => 'ObjectCache::newMemcached' ),
 1516+
 1517+ 'eaccelerator' => array( 'class' => 'eAccelBagOStuff' ),
 1518+ 'apc' => array( 'class' => 'APCBagOStuff' ),
 1519+ 'xcache' => array( 'class' => 'XCacheBagOStuff' ),
 1520+ 'wincache' => array( 'class' => 'WinCacheBagOStuff' ),
 1521+ 'memcached-php' => array( 'class' => 'MemcachedPhpBagOStuff' ),
 1522+);
 1523+
 1524+/**
14931525 * The expiry time for the parser cache, in seconds. The default is 86.4k
14941526 * seconds, otherwise known as a day.
14951527 */
Property changes on: branches/wmf/1.17wmf1/includes/DefaultSettings.php
___________________________________________________________________
Modified: svn:mergeinfo
14961528 Merged /trunk/phase3/includes/DefaultSettings.php:r83135-83136,83140,83143,83147,83208,83416,83492

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r83135Start of ObjectCache reorganisation. Moved the object cache files to includes...tstarling04:38, 3 March 2011
r83136More renames and splits for objectcache reorganisation.tstarling04:48, 3 March 2011
r83140* Rewrote ObjectCache.php to conform to the modern coding style, and to be le...tstarling09:37, 3 March 2011
r83143Tweak debug() to use name of class in debug outputdemon12:52, 3 March 2011
r83147* When CACHE_ANYTHING is requested, return the cached instance, don't constru...tstarling15:24, 3 March 2011
r83208* Added an Ehcache client....tstarling06:01, 4 March 2011
r83416Follow up r83140. Add a clear() method to ObjectCache so that it can be used ...platonides23:07, 6 March 2011
r83492Comment the var_dump() and add a comment....platonides00:20, 8 March 2011

Status & tagging log