r83136 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r83135‎ | r83136 | r83137 >
Date:04:48, 3 March 2011
Author:tstarling
Status:ok (Comments)
Tags:
Comment:
More renames and splits for objectcache reorganisation.
Modified paths:
  • /trunk/phase3/includes/AutoLoader.php (modified) (history)
  • /trunk/phase3/includes/memcached-client.php (deleted) (history)
  • /trunk/phase3/includes/objectcache/MemcachedClient.php (added) (history)
  • /trunk/phase3/includes/objectcache/ObjectCache.php (modified) (history)

Diff [purge]

Index: trunk/phase3/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: trunk/phase3/includes/objectcache/ObjectCache.php
@@ -6,31 +6,6 @@
77 * @ingroup Cache
88 */
99
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 -
3510 global $wgCaches;
3611 $wgCaches = array();
3712
Index: trunk/phase3/includes/objectcache/MemcachedClient.php
@@ -0,0 +1,1096 @@
 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+}
Property changes on: trunk/phase3/includes/objectcache/MemcachedClient.php
___________________________________________________________________
Added: svn:eol-style
11098 + native
Added: svn:keywords
21099 + Author Date Id Revision
Index: trunk/phase3/includes/AutoLoader.php
@@ -158,7 +158,6 @@
159159 'MathRenderer' => 'includes/Math.php',
160160 'MediaWiki_I18N' => 'includes/SkinTemplate.php',
161161 'MediaWiki' => 'includes/Wiki.php',
162 - 'MemCachedClientforWiki' => 'includes/memcached-client.php',
163162 'Message' => 'includes/Message.php',
164163 'MessageBlobStore' => 'includes/MessageBlobStore.php',
165164 'MessageCache' => 'includes/MessageCache.php',
@@ -166,7 +165,6 @@
167166 'MWException' => 'includes/Exception.php',
168167 'MWFunction' => 'includes/MWFunction.php',
169168 'MWHttpRequest' => 'includes/HttpFunctions.php',
170 - 'MWMemcached' => 'includes/memcached-client.php',
171169 'MWNamespace' => 'includes/Namespace.php',
172170 'OldChangesList' => 'includes/ChangesList.php',
173171 'OutputPage' => 'includes/OutputPage.php',
@@ -506,13 +504,15 @@
507505 'APCBagOStuff' => 'includes/objectcache/APCBagOStuff.php',
508506 'BagOStuff' => 'includes/objectcache/BagOStuff.php',
509507 'DBABagOStuff' => 'includes/objectcache/DBABagOStuff.php',
 508+ 'eAccelBagOStuff' => 'includes/objectcache/eAccelBagOStuff.php',
510509 'FakeMemCachedClient' => 'includes/objectcache/ObjectCache.php',
511510 'HashBagOStuff' => 'includes/objectcache/HashBagOStuff.php',
 511+ 'MWMemcached' => 'includes/objectcache/MemcachedClient.php',
512512 'MediaWikiBagOStuff' => 'includes/objectcache/SqlBagOStuff.php',
 513+ 'MemCachedClientforWiki' => 'includes/objectcache/MemcachedClient.php',
513514 'SqlBagOStuff' => 'includes/objectcache/SqlBagOStuff.php',
514515 'WinCacheBagOStuff' => 'includes/objectcache/WinCacheBagOStuff.php',
515516 'XCacheBagOStuff' => 'includes/objectcache/XCacheBagOStuff.php',
516 - 'eAccelBagOStuff' => 'includes/objectcache/eAccelBagOStuff.php',
517517
518518 # includes/parser
519519 'CoreLinkFunctions' => 'includes/parser/CoreLinkFunctions.php',

Sign-offs

UserFlagDate
Hasharinspected10:16, 3 March 2011

Follow-up revisions

RevisionCommit summaryAuthorDate
r83140* Rewrote ObjectCache.php to conform to the modern coding style, and to be le...tstarling09:37, 3 March 2011
r84727Merged in the ObjectCache refactor and the Ehcache client. MFT r83135, r83136...tstarling03:28, 25 March 2011

Comments

#Comment by IAlex (talk | contribs)   07:33, 3 March 2011

FakeMemCachedClient class disappeared.

#Comment by Tim Starling (talk | contribs)   07:40, 3 March 2011

It's coming back in the next commit.

#Comment by Tim Starling (talk | contribs)   09:39, 3 March 2011

Should be fixed in r83140.

#Comment by IAlex (talk | contribs)   10:01, 3 March 2011

It is. (Nice rewrite btw.)

Status & tagging log