MediaWiki REL1_35
MemcachedClient.php
Go to the documentation of this file.
1<?php
2// phpcs:ignoreFile -- It's an external lib and it isn't. Let's not bother.
69use Psr\Log\LoggerInterface;
70use Psr\Log\NullLogger;
71use Wikimedia\IPUtils;
72
73// {{{ class MemcachedClient
81 // {{{ properties
82 // {{{ public
83
84 // {{{ constants
85 // {{{ flags
86
90 const SERIALIZED = 1;
91
95 const COMPRESSED = 2;
96
100 const INTVAL = 4;
101
102 // }}}
103
108
109 // }}}
110
117 public $stats;
118
119 // }}}
120 // {{{ private
121
129
136 public $_debug;
137
145
153
161
169
177
185
192 public $_servers;
193
200 public $_buckets;
201
209
216 public $_active;
217
225
233
238
243
247 private $_logger;
248
249 // }}}
250 // }}}
251 // {{{ methods
252 // {{{ public functions
253 // {{{ memcached()
254
260 public function __construct( $args ) {
261 $this->set_servers( $args['servers'] ?? array() );
262 $this->_debug = $args['debug'] ?? false;
263 $this->stats = array();
264 $this->_compress_threshold = $args['compress_threshold'] ?? 0;
265 $this->_persistent = $args['persistent'] ?? false;
266 $this->_compress_enable = true;
267 $this->_have_zlib = function_exists( 'gzcompress' );
268
269 $this->_cache_sock = array();
270 $this->_host_dead = array();
271
272 $this->_timeout_seconds = 0;
273 $this->_timeout_microseconds = $args['timeout'] ?? 500000;
274
275 $this->_connect_timeout = $args['connect_timeout'] ?? 0.1;
276 $this->_connect_attempts = 2;
277
278 $this->_logger = $args['logger'] ?? new NullLogger();
279 }
280
281 // }}}
282
287 public function serialize( $value ) {
288 return serialize( $value );
289 }
290
295 public function unserialize( $value ) {
296 return unserialize( $value );
297 }
298
299 // {{{ add()
300
315 public function add( $key, $val, $exp = 0 ) {
316 return $this->_set( 'add', $key, $val, $exp );
317 }
318
319 // }}}
320 // {{{ decr()
321
330 public function decr( $key, $amt = 1 ) {
331 return $this->_incrdecr( 'decr', $key, $amt );
332 }
333
334 // }}}
335 // {{{ delete()
336
345 public function delete( $key, $time = 0 ) {
346 if ( !$this->_active ) {
347 return false;
348 }
349
350 $sock = $this->get_sock( $key );
351 if ( !$sock ) {
352 return false;
353 }
354
355 $key = is_array( $key ) ? $key[1] : $key;
356
357 if ( isset( $this->stats['delete'] ) ) {
358 $this->stats['delete']++;
359 } else {
360 $this->stats['delete'] = 1;
361 }
362 $cmd = "delete $key $time\r\n";
363 if ( !$this->_fwrite( $sock, $cmd ) ) {
364 return false;
365 }
366 $res = $this->_fgets( $sock );
367
368 if ( $this->_debug ) {
369 $this->_debugprint( sprintf( "MemCache: delete %s (%s)", $key, $res ) );
370 }
371
372 if ( $res == "DELETED" || $res == "NOT_FOUND" ) {
373 return true;
374 }
375
376 return false;
377 }
378
387 public function touch( $key, $time = 0 ) {
388 if ( !$this->_active ) {
389 return false;
390 }
391
392 $sock = $this->get_sock( $key );
393 if ( !$sock ) {
394 return false;
395 }
396
397 $key = is_array( $key ) ? $key[1] : $key;
398
399 if ( isset( $this->stats['touch'] ) ) {
400 $this->stats['touch']++;
401 } else {
402 $this->stats['touch'] = 1;
403 }
404 $cmd = "touch $key $time\r\n";
405 if ( !$this->_fwrite( $sock, $cmd ) ) {
406 return false;
407 }
408 $res = $this->_fgets( $sock );
409
410 if ( $this->_debug ) {
411 $this->_debugprint( sprintf( "MemCache: touch %s (%s)", $key, $res ) );
412 }
413
414 if ( $res == "TOUCHED" ) {
415 return true;
416 }
417
418 return false;
419 }
420
421 // }}}
422 // {{{ disconnect_all()
423
427 public function disconnect_all() {
428 foreach ( $this->_cache_sock as $sock ) {
429 fclose( $sock );
430 }
431
432 $this->_cache_sock = array();
433 }
434
435 // }}}
436 // {{{ enable_compress()
437
443 public function enable_compress( $enable ) {
444 $this->_compress_enable = $enable;
445 }
446
447 // }}}
448 // {{{ forget_dead_hosts()
449
453 public function forget_dead_hosts() {
454 $this->_host_dead = array();
455 }
456
457 // }}}
458 // {{{ get()
459
468 public function get( $key, &$casToken = null ) {
469 if ( $this->_debug ) {
470 $this->_debugprint( "get($key)" );
471 }
472
473 if ( !is_array( $key ) && strval( $key ) === '' ) {
474 $this->_debugprint( "Skipping key which equals to an empty string" );
475 return false;
476 }
477
478 if ( !$this->_active ) {
479 return false;
480 }
481
482 $sock = $this->get_sock( $key );
483
484 if ( !$sock ) {
485 return false;
486 }
487
488 $key = is_array( $key ) ? $key[1] : $key;
489 if ( isset( $this->stats['get'] ) ) {
490 $this->stats['get']++;
491 } else {
492 $this->stats['get'] = 1;
493 }
494
495 $cmd = "gets $key\r\n";
496 if ( !$this->_fwrite( $sock, $cmd ) ) {
497 return false;
498 }
499
500 $val = array();
501 $this->_load_items( $sock, $val, $casToken );
502
503 if ( $this->_debug ) {
504 foreach ( $val as $k => $v ) {
505 $this->_debugprint(
506 sprintf( "MemCache: sock %s got %s", $this->serialize( $sock ), $k ) );
507 }
508 }
509
510 $value = false;
511 if ( isset( $val[$key] ) ) {
512 $value = $val[$key];
513 }
514 return $value;
515 }
516
517 // }}}
518 // {{{ get_multi()
519
527 public function get_multi( $keys ) {
528 if ( !$this->_active ) {
529 return array();
530 }
531
532 if ( isset( $this->stats['get_multi'] ) ) {
533 $this->stats['get_multi']++;
534 } else {
535 $this->stats['get_multi'] = 1;
536 }
537 $sock_keys = array();
538 $socks = array();
539 foreach ( $keys as $key ) {
540 $sock = $this->get_sock( $key );
541 if ( !$sock ) {
542 continue;
543 }
544 $key = is_array( $key ) ? $key[1] : $key;
545 $sockValue = intval( $sock );
546
547 if ( !isset( $sock_keys[$sockValue] ) ) {
548 $sock_keys[$sockValue] = array();
549 $socks[] = $sock;
550 }
551 $sock_keys[$sockValue][] = $key;
552 }
553
554 $gather = array();
555 // Send out the requests
556 foreach ( $socks as $sock ) {
557 $cmd = 'gets';
558 foreach ( $sock_keys[intval( $sock )] as $key ) {
559 $cmd .= ' ' . $key;
560 }
561 $cmd .= "\r\n";
562
563 if ( $this->_fwrite( $sock, $cmd ) ) {
564 $gather[] = $sock;
565 }
566 }
567
568 // Parse responses
569 $val = array();
570 foreach ( $gather as $sock ) {
571 $this->_load_items( $sock, $val, $casToken );
572 }
573
574 if ( $this->_debug ) {
575 foreach ( $val as $k => $v ) {
576 $this->_debugprint( sprintf( "MemCache: got %s", $k ) );
577 }
578 }
579
580 return $val;
581 }
582
583 // }}}
584 // {{{ incr()
585
596 public function incr( $key, $amt = 1 ) {
597 return $this->_incrdecr( 'incr', $key, $amt );
598 }
599
600 // }}}
601 // {{{ replace()
602
616 public function replace( $key, $value, $exp = 0 ) {
617 return $this->_set( 'replace', $key, $value, $exp );
618 }
619
620 // }}}
621 // {{{ run_command()
622
632 public function run_command( $sock, $cmd ) {
633 if ( !$sock ) {
634 return array();
635 }
636
637 if ( !$this->_fwrite( $sock, $cmd ) ) {
638 return array();
639 }
640
641 $ret = array();
642 while ( true ) {
643 $res = $this->_fgets( $sock );
644 $ret[] = $res;
645 if ( preg_match( '/^END/', $res ) ) {
646 break;
647 }
648 if ( strlen( $res ) == 0 ) {
649 break;
650 }
651 }
652 return $ret;
653 }
654
655 // }}}
656 // {{{ set()
657
672 public function set( $key, $value, $exp = 0 ) {
673 return $this->_set( 'set', $key, $value, $exp );
674 }
675
676 // }}}
677 // {{{ cas()
678
694 public function cas( $casToken, $key, $value, $exp = 0 ) {
695 return $this->_set( 'cas', $key, $value, $exp, $casToken );
696 }
697
698 // }}}
699 // {{{ set_compress_threshold()
700
706 public function set_compress_threshold( $thresh ) {
707 $this->_compress_threshold = $thresh;
708 }
709
710 // }}}
711 // {{{ set_debug()
712
719 public function set_debug( $dbg ) {
720 $this->_debug = $dbg;
721 }
722
723 // }}}
724 // {{{ set_servers()
725
732 public function set_servers( $list ) {
733 $this->_servers = $list;
734 $this->_active = count( $list );
735 $this->_buckets = null;
736 $this->_bucketcount = 0;
737
738 $this->_single_sock = null;
739 if ( $this->_active == 1 ) {
740 $this->_single_sock = $this->_servers[0];
741 }
742 }
743
750 public function set_timeout( $seconds, $microseconds ) {
751 $this->_timeout_seconds = $seconds;
752 $this->_timeout_microseconds = $microseconds;
753 }
754
755 // }}}
756 // }}}
757 // {{{ private methods
758 // {{{ _close_sock()
759
767 function _close_sock( $sock ) {
768 $host = array_search( $sock, $this->_cache_sock );
769 fclose( $this->_cache_sock[$host] );
770 unset( $this->_cache_sock[$host] );
771 }
772
773 // }}}
774 // {{{ _connect_sock()
775
785 function _connect_sock( &$sock, $host ) {
786 $port = null;
787 $hostAndPort = IPUtils::splitHostAndPort( $host );
788 if ( $hostAndPort ) {
789 $ip = $hostAndPort[0];
790 if ( $hostAndPort[1] ) {
791 $port = $hostAndPort[1];
792 }
793 } else {
794 $ip = $host;
795 }
796 $sock = false;
797 $timeout = $this->_connect_timeout;
798 $errno = $errstr = null;
799 for ( $i = 0; !$sock && $i < $this->_connect_attempts; $i++ ) {
800 Wikimedia\suppressWarnings();
801 if ( $this->_persistent == 1 ) {
802 $sock = pfsockopen( $ip, $port, $errno, $errstr, $timeout );
803 } else {
804 $sock = fsockopen( $ip, $port, $errno, $errstr, $timeout );
805 }
806 Wikimedia\restoreWarnings();
807 }
808 if ( !$sock ) {
809 $this->_error_log( "Error connecting to $host: $errstr" );
810 $this->_dead_host( $host );
811 return false;
812 }
813
814 // Initialise timeout
815 stream_set_timeout( $sock, $this->_timeout_seconds, $this->_timeout_microseconds );
816
817 // If the connection was persistent, flush the read buffer in case there
818 // was a previous incomplete request on this connection
819 if ( $this->_persistent ) {
820 $this->_flush_read_buffer( $sock );
821 }
822 return true;
823 }
824
825 // }}}
826 // {{{ _dead_sock()
827
835 function _dead_sock( $sock ) {
836 $host = array_search( $sock, $this->_cache_sock );
837 $this->_dead_host( $host );
838 }
839
843 function _dead_host( $host ) {
844 $hostAndPort = IPUtils::splitHostAndPort( $host );
845 if ( $hostAndPort ) {
846 $ip = $hostAndPort[0];
847 } else {
848 $ip = $host;
849 }
850 $this->_host_dead[$ip] = time() + 30 + intval( rand( 0, 10 ) );
851 $this->_host_dead[$host] = $this->_host_dead[$ip];
852 unset( $this->_cache_sock[$host] );
853 }
854
855 // }}}
856 // {{{ get_sock()
857
866 function get_sock( $key ) {
867 if ( !$this->_active ) {
868 return false;
869 }
870
871 if ( $this->_single_sock !== null ) {
872 return $this->sock_to_host( $this->_single_sock );
873 }
874
875 $hv = is_array( $key ) ? intval( $key[0] ) : $this->_hashfunc( $key );
876 if ( $this->_buckets === null ) {
877 $bu = array();
878 foreach ( $this->_servers as $v ) {
879 if ( is_array( $v ) ) {
880 for ( $i = 0; $i < $v[1]; $i++ ) {
881 $bu[] = $v[0];
882 }
883 } else {
884 $bu[] = $v;
885 }
886 }
887 $this->_buckets = $bu;
888 $this->_bucketcount = count( $bu );
889 }
890
891 $realkey = is_array( $key ) ? $key[1] : $key;
892 for ( $tries = 0; $tries < 20; $tries++ ) {
893 $host = $this->_buckets[$hv % $this->_bucketcount];
894 $sock = $this->sock_to_host( $host );
895 if ( $sock ) {
896 return $sock;
897 }
898 $hv = $this->_hashfunc( $hv . $realkey );
899 }
900
901 return false;
902 }
903
904 // }}}
905 // {{{ _hashfunc()
906
915 function _hashfunc( $key ) {
916 # Hash function must be in [0,0x7ffffff]
917 # We take the first 31 bits of the MD5 hash, which unlike the hash
918 # function used in a previous version of this client, works
919 return hexdec( substr( md5( $key ), 0, 8 ) ) & 0x7fffffff;
920 }
921
922 // }}}
923 // {{{ _incrdecr()
924
935 function _incrdecr( $cmd, $key, $amt = 1 ) {
936 if ( !$this->_active ) {
937 return null;
938 }
939
940 $sock = $this->get_sock( $key );
941 if ( !$sock ) {
942 return null;
943 }
944
945 $key = is_array( $key ) ? $key[1] : $key;
946 if ( isset( $this->stats[$cmd] ) ) {
947 $this->stats[$cmd]++;
948 } else {
949 $this->stats[$cmd] = 1;
950 }
951 if ( !$this->_fwrite( $sock, "$cmd $key $amt\r\n" ) ) {
952 return null;
953 }
954
955 $line = $this->_fgets( $sock );
956 $match = array();
957 if ( !preg_match( '/^(\d+)/', $line, $match ) ) {
958 return null;
959 }
960 return $match[1];
961 }
962
963 // }}}
964 // {{{ _load_items()
965
976 function _load_items( $sock, &$ret, &$casToken = null ) {
977 $results = array();
978
979 while ( 1 ) {
980 $decl = $this->_fgets( $sock );
981
982 if ( $decl === false ) {
983 /*
984 * If nothing can be read, something is wrong because we know exactly when
985 * to stop reading (right after "END") and we return right after that.
986 */
987 return false;
988 } elseif ( preg_match( '/^VALUE (\S+) (\d+) (\d+) (\d+)$/', $decl, $match ) ) {
989 /*
990 * Read all data returned. This can be either one or multiple values.
991 * Save all that data (in an array) to be processed later: we'll first
992 * want to continue reading until "END" before doing anything else,
993 * to make sure that we don't leave our client in a state where it's
994 * output is not yet fully read.
995 */
996 $results[] = array(
997 $match[1], // rkey
998 $match[2], // flags
999 $match[3], // len
1000 $match[4], // casToken
1001 $this->_fread( $sock, $match[3] + 2 ), // data
1002 );
1003 } elseif ( $decl == "END" ) {
1004 if ( count( $results ) == 0 ) {
1005 return false;
1006 }
1007
1012 foreach ( $results as $vars ) {
1013 list( $rkey, $flags, $len, $casToken, $data ) = $vars;
1014
1015 if ( $data === false || substr( $data, -2 ) !== "\r\n" ) {
1016 $this->_handle_error( $sock,
1017 'line ending missing from data block from $1' );
1018 return false;
1019 }
1020 $data = substr( $data, 0, -2 );
1021 $ret[$rkey] = $data;
1022
1023 if ( $this->_have_zlib && $flags & self::COMPRESSED ) {
1024 $ret[$rkey] = gzuncompress( $ret[$rkey] );
1025 }
1026
1027 /*
1028 * This unserialize is the exact reason that we only want to
1029 * process data after having read until "END" (instead of doing
1030 * this right away): "unserialize" can trigger outside code:
1031 * in the event that $ret[$rkey] is a serialized object,
1032 * unserializing it will trigger __wakeup() if present. If that
1033 * function attempted to read from memcached (while we did not
1034 * yet read "END"), these 2 calls would collide.
1035 */
1036 if ( $flags & self::SERIALIZED ) {
1037 $ret[$rkey] = $this->unserialize( $ret[$rkey] );
1038 } elseif ( $flags & self::INTVAL ) {
1039 $ret[$rkey] = intval( $ret[$rkey] );
1040 }
1041 }
1042
1043 return true;
1044 } else {
1045 $this->_handle_error( $sock, 'Error parsing response from $1' );
1046 return false;
1047 }
1048 }
1049 }
1050
1051 // }}}
1052 // {{{ _set()
1053
1070 function _set( $cmd, $key, $val, $exp, $casToken = null ) {
1071 if ( !$this->_active ) {
1072 return false;
1073 }
1074
1075 $sock = $this->get_sock( $key );
1076 if ( !$sock ) {
1077 return false;
1078 }
1079
1080 if ( isset( $this->stats[$cmd] ) ) {
1081 $this->stats[$cmd]++;
1082 } else {
1083 $this->stats[$cmd] = 1;
1084 }
1085
1086 $flags = 0;
1087
1088 if ( is_int( $val ) ) {
1089 $flags |= self::INTVAL;
1090 } elseif ( !is_scalar( $val ) ) {
1091 $val = $this->serialize( $val );
1092 $flags |= self::SERIALIZED;
1093 if ( $this->_debug ) {
1094 $this->_debugprint( sprintf( "client: serializing data as it is not scalar" ) );
1095 }
1096 }
1097
1098 $len = strlen( $val );
1099
1100 if ( $this->_have_zlib && $this->_compress_enable
1101 && $this->_compress_threshold && $len >= $this->_compress_threshold
1102 ) {
1103 $c_val = gzcompress( $val, 9 );
1104 $c_len = strlen( $c_val );
1105
1106 if ( $c_len < $len * ( 1 - self::COMPRESSION_SAVINGS ) ) {
1107 if ( $this->_debug ) {
1108 $this->_debugprint( sprintf( "client: compressing data; was %d bytes is now %d bytes", $len, $c_len ) );
1109 }
1110 $val = $c_val;
1111 $len = $c_len;
1112 $flags |= self::COMPRESSED;
1113 }
1114 }
1115
1116 $command = "$cmd $key $flags $exp $len";
1117 if ( $casToken ) {
1118 $command .= " $casToken";
1119 }
1120
1121 if ( !$this->_fwrite( $sock, "$command\r\n$val\r\n" ) ) {
1122 return false;
1123 }
1124
1125 $line = $this->_fgets( $sock );
1126
1127 if ( $this->_debug ) {
1128 $this->_debugprint( sprintf( "%s %s (%s)", $cmd, $key, $line ) );
1129 }
1130 if ( $line === "STORED" ) {
1131 return true;
1132 } elseif ( $line === "NOT_STORED" && $cmd === "set" ) {
1133 // "Not stored" is always used as the mcrouter response with AllAsyncRoute
1134 return true;
1135 }
1136
1137 return false;
1138 }
1139
1140 // }}}
1141 // {{{ sock_to_host()
1142
1151 function sock_to_host( $host ) {
1152 if ( isset( $this->_cache_sock[$host] ) ) {
1153 return $this->_cache_sock[$host];
1154 }
1155
1156 $sock = null;
1157 $now = time();
1158 $hostAndPort = IPUtils::splitHostAndPort( $host );
1159 if ( $hostAndPort ) {
1160 $ip = $hostAndPort[0];
1161 } else {
1162 $ip = $host;
1163 }
1164 if ( isset( $this->_host_dead[$host] ) && $this->_host_dead[$host] > $now ||
1165 isset( $this->_host_dead[$ip] ) && $this->_host_dead[$ip] > $now
1166 ) {
1167 return null;
1168 }
1169
1170 if ( !$this->_connect_sock( $sock, $host ) ) {
1171 return null;
1172 }
1173
1174 // Do not buffer writes
1175 stream_set_write_buffer( $sock, 0 );
1176
1177 $this->_cache_sock[$host] = $sock;
1178
1179 return $this->_cache_sock[$host];
1180 }
1181
1185 function _debugprint( $text ) {
1186 $this->_logger->debug( $text );
1187 }
1188
1192 function _error_log( $text ) {
1193 $this->_logger->error( "Memcached error: $text" );
1194 }
1195
1203 function _fwrite( $sock, $buf ) {
1204 $bytesWritten = 0;
1205 $bufSize = strlen( $buf );
1206 while ( $bytesWritten < $bufSize ) {
1207 $result = fwrite( $sock, $buf );
1208 $data = stream_get_meta_data( $sock );
1209 if ( $data['timed_out'] ) {
1210 $this->_handle_error( $sock, 'timeout writing to $1' );
1211 return false;
1212 }
1213 // Contrary to the documentation, fwrite() returns zero on error in PHP 5.3.
1214 if ( $result === false || $result === 0 ) {
1215 $this->_handle_error( $sock, 'error writing to $1' );
1216 return false;
1217 }
1218 $bytesWritten += $result;
1219 }
1220
1221 return true;
1222 }
1223
1230 function _handle_error( $sock, $msg ) {
1231 $peer = stream_socket_get_name( $sock, true );
1232 if ( strval( $peer ) === '' ) {
1233 $peer = array_search( $sock, $this->_cache_sock );
1234 if ( $peer === false ) {
1235 $peer = '[unknown host]';
1236 }
1237 }
1238 $msg = str_replace( '$1', $peer, $msg );
1239 $this->_error_log( "$msg" );
1240 $this->_dead_sock( $sock );
1241 }
1242
1251 function _fread( $sock, $len ) {
1252 $buf = '';
1253 while ( $len > 0 ) {
1254 $result = fread( $sock, $len );
1255 $data = stream_get_meta_data( $sock );
1256 if ( $data['timed_out'] ) {
1257 $this->_handle_error( $sock, 'timeout reading from $1' );
1258 return false;
1259 }
1260 if ( $result === false ) {
1261 $this->_handle_error( $sock, 'error reading buffer from $1' );
1262 return false;
1263 }
1264 if ( $result === '' ) {
1265 // This will happen if the remote end of the socket is shut down
1266 $this->_handle_error( $sock, 'unexpected end of file reading from $1' );
1267 return false;
1268 }
1269 $len -= strlen( $result );
1270 $buf .= $result;
1271 }
1272 return $buf;
1273 }
1274
1282 function _fgets( $sock ) {
1283 $result = fgets( $sock );
1284 // fgets() may return a partial line if there is a select timeout after
1285 // a successful recv(), so we have to check for a timeout even if we
1286 // got a string response.
1287 $data = stream_get_meta_data( $sock );
1288 if ( $data['timed_out'] ) {
1289 $this->_handle_error( $sock, 'timeout reading line from $1' );
1290 return false;
1291 }
1292 if ( $result === false ) {
1293 $this->_handle_error( $sock, 'error reading line from $1' );
1294 return false;
1295 }
1296 if ( substr( $result, -2 ) === "\r\n" ) {
1297 $result = substr( $result, 0, -2 );
1298 } elseif ( substr( $result, -1 ) === "\n" ) {
1299 $result = substr( $result, 0, -1 );
1300 } else {
1301 $this->_handle_error( $sock, 'line ending missing in response from $1' );
1302 return false;
1303 }
1304 return $result;
1305 }
1306
1311 function _flush_read_buffer( $f ) {
1312 if ( !$f ) {
1313 return;
1314 }
1315 $r = array( $f );
1316 $w = null;
1317 $e = null;
1318 $n = stream_select( $r, $w, $e, 0, 0 );
1319 while ( $n == 1 && !feof( $f ) ) {
1320 fread( $f, 1024 );
1321 $r = array( $f );
1322 $w = null;
1323 $e = null;
1324 $n = stream_select( $r, $w, $e, 0, 0 );
1325 }
1326 }
1327
1328 // }}}
1329 // }}}
1330 // }}}
1331}
1332
1333// }}}
serialize()
memcached client class implemented using (p)fsockopen()
set_debug( $dbg)
Set the debug flag.
array $_cache_sock
Cached Sockets that are connected.
const SERIALIZED
Flag: indicates data is serialized.
const COMPRESSION_SAVINGS
Minimum savings to store data compressed.
_hashfunc( $key)
Creates a hash integer based on the $key.
set_compress_threshold( $thresh)
Set the compression threshold.
_fread( $sock, $len)
Read the specified number of bytes from a stream.
array $_servers
Array containing ip:port or array(ip:port, weight)
bool $_compress_enable
Do we want to use compression?
decr( $key, $amt=1)
Decrease a value stored on the memcache server.
const INTVAL
Flag: indicates data is an integer.
int $_compress_threshold
At how many bytes should we compress?
int $_timeout_seconds
Stream timeout in seconds.
disconnect_all()
Disconnects all connected sockets.
cas( $casToken, $key, $value, $exp=0)
Sets a key to a given value in the memcache if the current value still corresponds to a known,...
array $_buckets
Our bit buckets.
set_timeout( $seconds, $microseconds)
Sets the timeout for new connections.
_fgets( $sock)
Read a line from a stream.
incr( $key, $amt=1)
Increments $key (optionally) by $amt.
forget_dead_hosts()
Forget about all of the dead hosts.
_incrdecr( $cmd, $key, $amt=1)
Perform increment/decriment on $key.
$_connect_attempts
Number of connection attempts for each server.
add( $key, $val, $exp=0)
Adds a key/value to the memcache server if one isn't already set with that key.
_handle_error( $sock, $msg)
Handle an I/O error.
sock_to_host( $host)
Returns the socket for the host.
$_connect_timeout
Connect timeout in seconds.
touch( $key, $time=0)
Changes the TTL on a key from the server to $time.
bool $_have_zlib
Is compression available?
int $_bucketcount
Total # of bit buckets we have.
_fwrite( $sock, $buf)
Write to a stream.
bool $_debug
Current debug status; 0 - none to 9 - profiling.
replace( $key, $value, $exp=0)
Overwrites an existing value for key; only works if key is already set.
set_servers( $list)
Set the server list to distribute key gets and puts between.
_load_items( $sock, &$ret, &$casToken=null)
Load items into $ret from $sock.
string $_single_sock
If only using one server; contains ip:port to connect to.
get_multi( $keys)
Get multiple keys from the server(s)
_close_sock( $sock)
Close the specified socket.
run_command( $sock, $cmd)
Passes through $cmd to the memcache server connected by $sock; returns output as an array (null array...
_set( $cmd, $key, $val, $exp, $casToken=null)
Performs the requested storage operation to the memcache server.
LoggerInterface $_logger
int $_timeout_microseconds
Stream timeout in microseconds.
__construct( $args)
Memcache initializer.
_flush_read_buffer( $f)
Flush the read buffer of a stream.
enable_compress( $enable)
Enable / Disable compression.
array $_host_dead
Dead hosts, assoc array, 'host'=>'unixtime when ok to check again'.
const COMPRESSED
Flag: indicates data is compressed.
get_sock( $key)
get_sock
_dead_sock( $sock)
Marks a host as dead until 30-40 seconds in the future.
_connect_sock(&$sock, $host)
Connects $sock to $host, timing out after $timeout.
array $stats
Command statistics.
bool $_persistent
Are we using persistent links?
$line
Definition mcc.php:119
$command
Definition mcc.php:125
if( $line===false) $args
Definition mcc.php:124