MediaWiki  master
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.
69 use Psr\Log\LoggerInterface;
70 use Psr\Log\NullLogger;
71 
72 // {{{ class MemcachedClient
80  // {{{ properties
81  // {{{ public
82 
83  // {{{ constants
84  // {{{ flags
85 
89  const SERIALIZED = 1;
90 
94  const COMPRESSED = 2;
95 
99  const INTVAL = 4;
100 
101  // }}}
102 
106  const COMPRESSION_SAVINGS = 0.20;
107 
108  // }}}
109 
116  public $stats;
117 
118  // }}}
119  // {{{ private
120 
127  public $_cache_sock;
128 
135  public $_debug;
136 
143  public $_host_dead;
144 
151  public $_have_zlib;
152 
160 
168 
175  public $_persistent;
176 
184 
191  public $_servers;
192 
199  public $_buckets;
200 
208 
215  public $_active;
216 
224 
232 
237 
242 
246  private $_logger;
247 
248  // }}}
249  // }}}
250  // {{{ methods
251  // {{{ public functions
252  // {{{ memcached()
253 
259  public function __construct( $args ) {
260  $this->set_servers( $args['servers'] ?? array() );
261  $this->_debug = $args['debug'] ?? false;
262  $this->stats = array();
263  $this->_compress_threshold = $args['compress_threshold'] ?? 0;
264  $this->_persistent = $args['persistent'] ?? false;
265  $this->_compress_enable = true;
266  $this->_have_zlib = function_exists( 'gzcompress' );
267 
268  $this->_cache_sock = array();
269  $this->_host_dead = array();
270 
271  $this->_timeout_seconds = 0;
272  $this->_timeout_microseconds = $args['timeout'] ?? 500000;
273 
274  $this->_connect_timeout = $args['connect_timeout'] ?? 0.1;
275  $this->_connect_attempts = 2;
276 
277  $this->_logger = $args['logger'] ?? new NullLogger();
278  }
279 
280  // }}}
281 
286  public function serialize( $value ) {
287  return serialize( $value );
288  }
289 
294  public function unserialize( $value ) {
295  return unserialize( $value );
296  }
297 
298  // {{{ add()
299 
314  public function add( $key, $val, $exp = 0 ) {
315  return $this->_set( 'add', $key, $val, $exp );
316  }
317 
318  // }}}
319  // {{{ decr()
320 
329  public function decr( $key, $amt = 1 ) {
330  return $this->_incrdecr( 'decr', $key, $amt );
331  }
332 
333  // }}}
334  // {{{ delete()
335 
344  public function delete( $key, $time = 0 ) {
345  if ( !$this->_active ) {
346  return false;
347  }
348 
349  $sock = $this->get_sock( $key );
350  if ( !is_resource( $sock ) ) {
351  return false;
352  }
353 
354  $key = is_array( $key ) ? $key[1] : $key;
355 
356  if ( isset( $this->stats['delete'] ) ) {
357  $this->stats['delete']++;
358  } else {
359  $this->stats['delete'] = 1;
360  }
361  $cmd = "delete $key $time\r\n";
362  if ( !$this->_fwrite( $sock, $cmd ) ) {
363  return false;
364  }
365  $res = $this->_fgets( $sock );
366 
367  if ( $this->_debug ) {
368  $this->_debugprint( sprintf( "MemCache: delete %s (%s)", $key, $res ) );
369  }
370 
371  if ( $res == "DELETED" || $res == "NOT_FOUND" ) {
372  return true;
373  }
374 
375  return false;
376  }
377 
386  public function touch( $key, $time = 0 ) {
387  if ( !$this->_active ) {
388  return false;
389  }
390 
391  $sock = $this->get_sock( $key );
392  if ( !is_resource( $sock ) ) {
393  return false;
394  }
395 
396  $key = is_array( $key ) ? $key[1] : $key;
397 
398  if ( isset( $this->stats['touch'] ) ) {
399  $this->stats['touch']++;
400  } else {
401  $this->stats['touch'] = 1;
402  }
403  $cmd = "touch $key $time\r\n";
404  if ( !$this->_fwrite( $sock, $cmd ) ) {
405  return false;
406  }
407  $res = $this->_fgets( $sock );
408 
409  if ( $this->_debug ) {
410  $this->_debugprint( sprintf( "MemCache: touch %s (%s)", $key, $res ) );
411  }
412 
413  if ( $res == "TOUCHED" ) {
414  return true;
415  }
416 
417  return false;
418  }
419 
420  // }}}
421  // {{{ disconnect_all()
422 
426  public function disconnect_all() {
427  foreach ( $this->_cache_sock as $sock ) {
428  fclose( $sock );
429  }
430 
431  $this->_cache_sock = array();
432  }
433 
434  // }}}
435  // {{{ enable_compress()
436 
442  public function enable_compress( $enable ) {
443  $this->_compress_enable = $enable;
444  }
445 
446  // }}}
447  // {{{ forget_dead_hosts()
448 
452  public function forget_dead_hosts() {
453  $this->_host_dead = array();
454  }
455 
456  // }}}
457  // {{{ get()
458 
467  public function get( $key, &$casToken = null ) {
468  $getToken = ( func_num_args() >= 2 );
469 
470  if ( $this->_debug ) {
471  $this->_debugprint( "get($key)" );
472  }
473 
474  if ( !is_array( $key ) && strval( $key ) === '' ) {
475  $this->_debugprint( "Skipping key which equals to an empty string" );
476  return false;
477  }
478 
479  if ( !$this->_active ) {
480  return false;
481  }
482 
483  $sock = $this->get_sock( $key );
484 
485  if ( !is_resource( $sock ) ) {
486  return false;
487  }
488 
489  $key = is_array( $key ) ? $key[1] : $key;
490  if ( isset( $this->stats['get'] ) ) {
491  $this->stats['get']++;
492  } else {
493  $this->stats['get'] = 1;
494  }
495 
496  $cmd = $getToken ? "gets" : "get";
497  $cmd .= " $key\r\n";
498  if ( !$this->_fwrite( $sock, $cmd ) ) {
499  return false;
500  }
501 
502  $val = array();
503  $this->_load_items( $sock, $val, $casToken );
504 
505  if ( $this->_debug ) {
506  foreach ( $val as $k => $v ) {
507  $this->_debugprint(
508  sprintf( "MemCache: sock %s got %s", $this->serialize( $sock ), $k ) );
509  }
510  }
511 
512  $value = false;
513  if ( isset( $val[$key] ) ) {
514  $value = $val[$key];
515  }
516  return $value;
517  }
518 
519  // }}}
520  // {{{ get_multi()
521 
529  public function get_multi( $keys ) {
530  if ( !$this->_active ) {
531  return array();
532  }
533 
534  if ( isset( $this->stats['get_multi'] ) ) {
535  $this->stats['get_multi']++;
536  } else {
537  $this->stats['get_multi'] = 1;
538  }
539  $sock_keys = array();
540  $socks = array();
541  foreach ( $keys as $key ) {
542  $sock = $this->get_sock( $key );
543  if ( !is_resource( $sock ) ) {
544  continue;
545  }
546  $key = is_array( $key ) ? $key[1] : $key;
547  if ( !isset( $sock_keys[$sock] ) ) {
548  $sock_keys[intval( $sock )] = array();
549  $socks[] = $sock;
550  }
551  $sock_keys[intval( $sock )][] = $key;
552  }
553 
554  $gather = array();
555  // Send out the requests
556  foreach ( $socks as $sock ) {
557  $cmd = 'get';
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 );
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 ( !is_resource( $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  list( $ip, $port ) = preg_split( '/:(?=\d)/', $host );
787  $sock = false;
788  $timeout = $this->_connect_timeout;
789  $errno = $errstr = null;
790  for ( $i = 0; !$sock && $i < $this->_connect_attempts; $i++ ) {
791  Wikimedia\suppressWarnings();
792  if ( $this->_persistent == 1 ) {
793  $sock = pfsockopen( $ip, $port, $errno, $errstr, $timeout );
794  } else {
795  $sock = fsockopen( $ip, $port, $errno, $errstr, $timeout );
796  }
797  Wikimedia\restoreWarnings();
798  }
799  if ( !$sock ) {
800  $this->_error_log( "Error connecting to $host: $errstr" );
801  $this->_dead_host( $host );
802  return false;
803  }
804 
805  // Initialise timeout
806  stream_set_timeout( $sock, $this->_timeout_seconds, $this->_timeout_microseconds );
807 
808  // If the connection was persistent, flush the read buffer in case there
809  // was a previous incomplete request on this connection
810  if ( $this->_persistent ) {
811  $this->_flush_read_buffer( $sock );
812  }
813  return true;
814  }
815 
816  // }}}
817  // {{{ _dead_sock()
818 
826  function _dead_sock( $sock ) {
827  $host = array_search( $sock, $this->_cache_sock );
828  $this->_dead_host( $host );
829  }
830 
834  function _dead_host( $host ) {
835  $ip = explode( ':', $host )[0];
836  $this->_host_dead[$ip] = time() + 30 + intval( rand( 0, 10 ) );
837  $this->_host_dead[$host] = $this->_host_dead[$ip];
838  unset( $this->_cache_sock[$host] );
839  }
840 
841  // }}}
842  // {{{ get_sock()
843 
852  function get_sock( $key ) {
853  if ( !$this->_active ) {
854  return false;
855  }
856 
857  if ( $this->_single_sock !== null ) {
858  return $this->sock_to_host( $this->_single_sock );
859  }
860 
861  $hv = is_array( $key ) ? intval( $key[0] ) : $this->_hashfunc( $key );
862  if ( $this->_buckets === null ) {
863  $bu = array();
864  foreach ( $this->_servers as $v ) {
865  if ( is_array( $v ) ) {
866  for ( $i = 0; $i < $v[1]; $i++ ) {
867  $bu[] = $v[0];
868  }
869  } else {
870  $bu[] = $v;
871  }
872  }
873  $this->_buckets = $bu;
874  $this->_bucketcount = count( $bu );
875  }
876 
877  $realkey = is_array( $key ) ? $key[1] : $key;
878  for ( $tries = 0; $tries < 20; $tries++ ) {
879  $host = $this->_buckets[$hv % $this->_bucketcount];
880  $sock = $this->sock_to_host( $host );
881  if ( is_resource( $sock ) ) {
882  return $sock;
883  }
884  $hv = $this->_hashfunc( $hv . $realkey );
885  }
886 
887  return false;
888  }
889 
890  // }}}
891  // {{{ _hashfunc()
892 
901  function _hashfunc( $key ) {
902  # Hash function must be in [0,0x7ffffff]
903  # We take the first 31 bits of the MD5 hash, which unlike the hash
904  # function used in a previous version of this client, works
905  return hexdec( substr( md5( $key ), 0, 8 ) ) & 0x7fffffff;
906  }
907 
908  // }}}
909  // {{{ _incrdecr()
910 
921  function _incrdecr( $cmd, $key, $amt = 1 ) {
922  if ( !$this->_active ) {
923  return null;
924  }
925 
926  $sock = $this->get_sock( $key );
927  if ( !is_resource( $sock ) ) {
928  return null;
929  }
930 
931  $key = is_array( $key ) ? $key[1] : $key;
932  if ( isset( $this->stats[$cmd] ) ) {
933  $this->stats[$cmd]++;
934  } else {
935  $this->stats[$cmd] = 1;
936  }
937  if ( !$this->_fwrite( $sock, "$cmd $key $amt\r\n" ) ) {
938  return null;
939  }
940 
941  $line = $this->_fgets( $sock );
942  $match = array();
943  if ( !preg_match( '/^(\d+)/', $line, $match ) ) {
944  return null;
945  }
946  return $match[1];
947  }
948 
949  // }}}
950  // {{{ _load_items()
951 
962  function _load_items( $sock, &$ret, &$casToken = null ) {
963  $results = array();
964 
965  while ( 1 ) {
966  $decl = $this->_fgets( $sock );
967 
968  if ( $decl === false ) {
969  /*
970  * If nothing can be read, something is wrong because we know exactly when
971  * to stop reading (right after "END") and we return right after that.
972  */
973  return false;
974  } elseif ( preg_match( '/^VALUE (\S+) (\d+) (\d+)(?: (\d+))?$/', $decl, $match ) ) {
975  /*
976  * Read all data returned. This can be either one or multiple values.
977  * Save all that data (in an array) to be processed later: we'll first
978  * want to continue reading until "END" before doing anything else,
979  * to make sure that we don't leave our client in a state where it's
980  * output is not yet fully read.
981  */
982  $results[] = array(
983  $match[1], // rkey
984  $match[2], // flags
985  $match[3], // len
986  $match[4] ?? null, // casToken (appears with "gets" but not "get")
987  $this->_fread( $sock, $match[3] + 2 ), // data
988  );
989  } elseif ( $decl == "END" ) {
990  if ( count( $results ) == 0 ) {
991  return false;
992  }
993 
998  foreach ( $results as $vars ) {
999  list( $rkey, $flags, /* length */, $casToken, $data ) = $vars;
1000 
1001  if ( $data === false || substr( $data, -2 ) !== "\r\n" ) {
1002  $this->_handle_error( $sock,
1003  'line ending missing from data block from $1' );
1004  return false;
1005  }
1006  $data = substr( $data, 0, -2 );
1007  $ret[$rkey] = $data;
1008 
1009  if ( $this->_have_zlib && $flags & self::COMPRESSED ) {
1010  $ret[$rkey] = gzuncompress( $ret[$rkey] );
1011  }
1012 
1013  /*
1014  * This unserialize is the exact reason that we only want to
1015  * process data after having read until "END" (instead of doing
1016  * this right away): "unserialize" can trigger outside code:
1017  * in the event that $ret[$rkey] is a serialized object,
1018  * unserializing it will trigger __wakeup() if present. If that
1019  * function attempted to read from memcached (while we did not
1020  * yet read "END"), these 2 calls would collide.
1021  */
1022  if ( $flags & self::SERIALIZED ) {
1023  $ret[$rkey] = $this->unserialize( $ret[$rkey] );
1024  } elseif ( $flags & self::INTVAL ) {
1025  $ret[$rkey] = intval( $ret[$rkey] );
1026  }
1027  }
1028 
1029  return true;
1030  } else {
1031  $this->_handle_error( $sock, 'Error parsing response from $1' );
1032  return false;
1033  }
1034  }
1035  }
1036 
1037  // }}}
1038  // {{{ _set()
1039 
1056  function _set( $cmd, $key, $val, $exp, $casToken = null ) {
1057  if ( !$this->_active ) {
1058  return false;
1059  }
1060 
1061  $sock = $this->get_sock( $key );
1062  if ( !is_resource( $sock ) ) {
1063  return false;
1064  }
1065 
1066  if ( isset( $this->stats[$cmd] ) ) {
1067  $this->stats[$cmd]++;
1068  } else {
1069  $this->stats[$cmd] = 1;
1070  }
1071 
1072  $flags = 0;
1073 
1074  if ( is_int( $val ) ) {
1075  $flags |= self::INTVAL;
1076  } elseif ( !is_scalar( $val ) ) {
1077  $val = $this->serialize( $val );
1078  $flags |= self::SERIALIZED;
1079  if ( $this->_debug ) {
1080  $this->_debugprint( sprintf( "client: serializing data as it is not scalar" ) );
1081  }
1082  }
1083 
1084  $len = strlen( $val );
1085 
1086  if ( $this->_have_zlib && $this->_compress_enable
1087  && $this->_compress_threshold && $len >= $this->_compress_threshold
1088  ) {
1089  $c_val = gzcompress( $val, 9 );
1090  $c_len = strlen( $c_val );
1091 
1092  if ( $c_len < $len * ( 1 - self::COMPRESSION_SAVINGS ) ) {
1093  if ( $this->_debug ) {
1094  $this->_debugprint( sprintf( "client: compressing data; was %d bytes is now %d bytes", $len, $c_len ) );
1095  }
1096  $val = $c_val;
1097  $len = $c_len;
1098  $flags |= self::COMPRESSED;
1099  }
1100  }
1101 
1102  $command = "$cmd $key $flags $exp $len";
1103  if ( $casToken ) {
1104  $command .= " $casToken";
1105  }
1106 
1107  if ( !$this->_fwrite( $sock, "$command\r\n$val\r\n" ) ) {
1108  return false;
1109  }
1110 
1111  $line = $this->_fgets( $sock );
1112 
1113  if ( $this->_debug ) {
1114  $this->_debugprint( sprintf( "%s %s (%s)", $cmd, $key, $line ) );
1115  }
1116  if ( $line === "STORED" ) {
1117  return true;
1118  } elseif ( $line === "NOT_STORED" && $cmd === "set" ) {
1119  // "Not stored" is always used as the mcrouter response with AllAsyncRoute
1120  return true;
1121  }
1122 
1123  return false;
1124  }
1125 
1126  // }}}
1127  // {{{ sock_to_host()
1128 
1137  function sock_to_host( $host ) {
1138  if ( isset( $this->_cache_sock[$host] ) ) {
1139  return $this->_cache_sock[$host];
1140  }
1141 
1142  $sock = null;
1143  $now = time();
1144  list( $ip, /* $port */) = explode( ':', $host );
1145  if ( isset( $this->_host_dead[$host] ) && $this->_host_dead[$host] > $now ||
1146  isset( $this->_host_dead[$ip] ) && $this->_host_dead[$ip] > $now
1147  ) {
1148  return null;
1149  }
1150 
1151  if ( !$this->_connect_sock( $sock, $host ) ) {
1152  return null;
1153  }
1154 
1155  // Do not buffer writes
1156  stream_set_write_buffer( $sock, 0 );
1157 
1158  $this->_cache_sock[$host] = $sock;
1159 
1160  return $this->_cache_sock[$host];
1161  }
1162 
1166  function _debugprint( $text ) {
1167  $this->_logger->debug( $text );
1168  }
1169 
1173  function _error_log( $text ) {
1174  $this->_logger->error( "Memcached error: $text" );
1175  }
1176 
1184  function _fwrite( $sock, $buf ) {
1185  $bytesWritten = 0;
1186  $bufSize = strlen( $buf );
1187  while ( $bytesWritten < $bufSize ) {
1188  $result = fwrite( $sock, $buf );
1189  $data = stream_get_meta_data( $sock );
1190  if ( $data['timed_out'] ) {
1191  $this->_handle_error( $sock, 'timeout writing to $1' );
1192  return false;
1193  }
1194  // Contrary to the documentation, fwrite() returns zero on error in PHP 5.3.
1195  if ( $result === false || $result === 0 ) {
1196  $this->_handle_error( $sock, 'error writing to $1' );
1197  return false;
1198  }
1199  $bytesWritten += $result;
1200  }
1201 
1202  return true;
1203  }
1204 
1211  function _handle_error( $sock, $msg ) {
1212  $peer = stream_socket_get_name( $sock, true );
1213  if ( strval( $peer ) === '' ) {
1214  $peer = array_search( $sock, $this->_cache_sock );
1215  if ( $peer === false ) {
1216  $peer = '[unknown host]';
1217  }
1218  }
1219  $msg = str_replace( '$1', $peer, $msg );
1220  $this->_error_log( "$msg" );
1221  $this->_dead_sock( $sock );
1222  }
1223 
1232  function _fread( $sock, $len ) {
1233  $buf = '';
1234  while ( $len > 0 ) {
1235  $result = fread( $sock, $len );
1236  $data = stream_get_meta_data( $sock );
1237  if ( $data['timed_out'] ) {
1238  $this->_handle_error( $sock, 'timeout reading from $1' );
1239  return false;
1240  }
1241  if ( $result === false ) {
1242  $this->_handle_error( $sock, 'error reading buffer from $1' );
1243  return false;
1244  }
1245  if ( $result === '' ) {
1246  // This will happen if the remote end of the socket is shut down
1247  $this->_handle_error( $sock, 'unexpected end of file reading from $1' );
1248  return false;
1249  }
1250  $len -= strlen( $result );
1251  $buf .= $result;
1252  }
1253  return $buf;
1254  }
1255 
1263  function _fgets( $sock ) {
1264  $result = fgets( $sock );
1265  // fgets() may return a partial line if there is a select timeout after
1266  // a successful recv(), so we have to check for a timeout even if we
1267  // got a string response.
1268  $data = stream_get_meta_data( $sock );
1269  if ( $data['timed_out'] ) {
1270  $this->_handle_error( $sock, 'timeout reading line from $1' );
1271  return false;
1272  }
1273  if ( $result === false ) {
1274  $this->_handle_error( $sock, 'error reading line from $1' );
1275  return false;
1276  }
1277  if ( substr( $result, -2 ) === "\r\n" ) {
1278  $result = substr( $result, 0, -2 );
1279  } elseif ( substr( $result, -1 ) === "\n" ) {
1280  $result = substr( $result, 0, -1 );
1281  } else {
1282  $this->_handle_error( $sock, 'line ending missing in response from $1' );
1283  return false;
1284  }
1285  return $result;
1286  }
1287 
1292  function _flush_read_buffer( $f ) {
1293  if ( !is_resource( $f ) ) {
1294  return;
1295  }
1296  $r = array( $f );
1297  $w = null;
1298  $e = null;
1299  $n = stream_select( $r, $w, $e, 0, 0 );
1300  while ( $n == 1 && !feof( $f ) ) {
1301  fread( $f, 1024 );
1302  $r = array( $f );
1303  $w = null;
1304  $e = null;
1305  $n = stream_select( $r, $w, $e, 0, 0 );
1306  }
1307  }
1308 
1309  // }}}
1310  // }}}
1311  // }}}
1312 }
1313 
1314 // }}}
MemcachedClient\get_multi
get_multi( $keys)
Get multiple keys from the server(s)
Definition: MemcachedClient.php:529
MemcachedClient\get_sock
get_sock( $key)
get_sock
Definition: MemcachedClient.php:852
MemcachedClient\$_compress_threshold
int $_compress_threshold
At how many bytes should we compress?
Definition: MemcachedClient.php:167
MemcachedClient\_close_sock
_close_sock( $sock)
Close the specified socket.
Definition: MemcachedClient.php:767
MemcachedClient\set_servers
set_servers( $list)
Set the server list to distribute key gets and puts between.
Definition: MemcachedClient.php:732
MemcachedClient\_debugprint
_debugprint( $text)
Definition: MemcachedClient.php:1166
MemcachedClient\$_bucketcount
int $_bucketcount
Total # of bit buckets we have.
Definition: MemcachedClient.php:207
MemcachedClient\$_active
int $_active
Definition: MemcachedClient.php:215
MemcachedClient\$_servers
array $_servers
Array containing ip:port or array(ip:port, weight)
Definition: MemcachedClient.php:191
MemcachedClient\set_debug
set_debug( $dbg)
Set the debug flag.
Definition: MemcachedClient.php:719
MemcachedClient\$_timeout_microseconds
int $_timeout_microseconds
Stream timeout in microseconds.
Definition: MemcachedClient.php:231
MemcachedClient\touch
touch( $key, $time=0)
Changes the TTL on a key from the server to $time.
Definition: MemcachedClient.php:386
MemcachedClient\$_connect_attempts
$_connect_attempts
Number of connection attempts for each server.
Definition: MemcachedClient.php:241
MemcachedClient\$_compress_enable
bool $_compress_enable
Do we want to use compression?
Definition: MemcachedClient.php:159
MemcachedClient\$_timeout_seconds
int $_timeout_seconds
Stream timeout in seconds.
Definition: MemcachedClient.php:223
$res
$res
Definition: testCompression.php:57
MemcachedClient\unserialize
unserialize( $value)
Definition: MemcachedClient.php:294
MemcachedClient\_dead_host
_dead_host( $host)
Definition: MemcachedClient.php:834
MemcachedClient\COMPRESSED
const COMPRESSED
Flag: indicates data is compressed.
Definition: MemcachedClient.php:94
MemcachedClient\$_connect_timeout
$_connect_timeout
Connect timeout in seconds.
Definition: MemcachedClient.php:236
MemcachedClient
memcached client class implemented using (p)fsockopen()
Definition: MemcachedClient.php:79
MemcachedClient\_error_log
_error_log( $text)
Definition: MemcachedClient.php:1173
MemcachedClient\incr
incr( $key, $amt=1)
Increments $key (optionally) by $amt.
Definition: MemcachedClient.php:596
MemcachedClient\disconnect_all
disconnect_all()
Disconnects all connected sockets.
Definition: MemcachedClient.php:426
MemcachedClient\$_host_dead
array $_host_dead
Dead hosts, assoc array, 'host'=>'unixtime when ok to check again'.
Definition: MemcachedClient.php:143
MemcachedClient\_handle_error
_handle_error( $sock, $msg)
Handle an I/O error.
Definition: MemcachedClient.php:1211
MemcachedClient\COMPRESSION_SAVINGS
const COMPRESSION_SAVINGS
Minimum savings to store data compressed.
Definition: MemcachedClient.php:106
MemcachedClient\_fgets
_fgets( $sock)
Read a line from a stream.
Definition: MemcachedClient.php:1263
MemcachedClient\serialize
serialize( $value)
Definition: MemcachedClient.php:286
MemcachedClient\_flush_read_buffer
_flush_read_buffer( $f)
Flush the read buffer of a stream.
Definition: MemcachedClient.php:1292
MemcachedClient\replace
replace( $key, $value, $exp=0)
Overwrites an existing value for key; only works if key is already set.
Definition: MemcachedClient.php:616
MemcachedClient\_fread
_fread( $sock, $len)
Read the specified number of bytes from a stream.
Definition: MemcachedClient.php:1232
$args
if( $line===false) $args
Definition: mcc.php:124
MemcachedClient\_set
_set( $cmd, $key, $val, $exp, $casToken=null)
Performs the requested storage operation to the memcache server.
Definition: MemcachedClient.php:1056
MemcachedClient\forget_dead_hosts
forget_dead_hosts()
Forget about all of the dead hosts.
Definition: MemcachedClient.php:452
MemcachedClient\$_debug
bool $_debug
Current debug status; 0 - none to 9 - profiling.
Definition: MemcachedClient.php:135
MemcachedClient\sock_to_host
sock_to_host( $host)
Returns the socket for the host.
Definition: MemcachedClient.php:1137
MemcachedClient\$stats
array $stats
Command statistics.
Definition: MemcachedClient.php:116
MemcachedClient\decr
decr( $key, $amt=1)
Decrease a value stored on the memcache server.
Definition: MemcachedClient.php:329
MemcachedClient\set_compress_threshold
set_compress_threshold( $thresh)
Set the compression threshold.
Definition: MemcachedClient.php:706
$line
$line
Definition: mcc.php:119
MemcachedClient\add
add( $key, $val, $exp=0)
Adds a key/value to the memcache server if one isn't already set with that key.
Definition: MemcachedClient.php:314
MemcachedClient\INTVAL
const INTVAL
Flag: indicates data is an integer.
Definition: MemcachedClient.php:99
MemcachedClient\$_persistent
bool $_persistent
Are we using persistent links?
Definition: MemcachedClient.php:175
MemcachedClient\_fwrite
_fwrite( $sock, $buf)
Write to a stream.
Definition: MemcachedClient.php:1184
MemcachedClient\$_buckets
array $_buckets
Our bit buckets.
Definition: MemcachedClient.php:199
MemcachedClient\$_cache_sock
array $_cache_sock
Cached Sockets that are connected.
Definition: MemcachedClient.php:127
$command
$command
Definition: mcc.php:125
MemcachedClient\_hashfunc
_hashfunc( $key)
Creates a hash integer based on the $key.
Definition: MemcachedClient.php:901
MemcachedClient\__construct
__construct( $args)
Memcache initializer.
Definition: MemcachedClient.php:259
MemcachedClient\$_have_zlib
bool $_have_zlib
Is compression available?
Definition: MemcachedClient.php:151
MemcachedClient\cas
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,...
Definition: MemcachedClient.php:694
MemcachedClient\_connect_sock
_connect_sock(&$sock, $host)
Connects $sock to $host, timing out after $timeout.
Definition: MemcachedClient.php:785
$keys
$keys
Definition: testCompression.php:72
MemcachedClient\enable_compress
enable_compress( $enable)
Enable / Disable compression.
Definition: MemcachedClient.php:442
MemcachedClient\_dead_sock
_dead_sock( $sock)
Marks a host as dead until 30-40 seconds in the future.
Definition: MemcachedClient.php:826
MemcachedClient\$_logger
LoggerInterface $_logger
Definition: MemcachedClient.php:246
MemcachedClient\run_command
run_command( $sock, $cmd)
Passes through $cmd to the memcache server connected by $sock; returns output as an array (null array...
Definition: MemcachedClient.php:632
MemcachedClient\_incrdecr
_incrdecr( $cmd, $key, $amt=1)
Perform increment/decriment on $key.
Definition: MemcachedClient.php:921
MemcachedClient\SERIALIZED
const SERIALIZED
Flag: indicates data is serialized.
Definition: MemcachedClient.php:89
MemcachedClient\$_single_sock
string $_single_sock
If only using one server; contains ip:port to connect to.
Definition: MemcachedClient.php:183
MemcachedClient\set_timeout
set_timeout( $seconds, $microseconds)
Sets the timeout for new connections.
Definition: MemcachedClient.php:750
MemcachedClient\_load_items
_load_items( $sock, &$ret, &$casToken=null)
Load items into $ret from $sock.
Definition: MemcachedClient.php:962