[ Index ]
 

Code source de LifeType 1.2.4

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables

title

Body

[fermer]

/class/cache/Memcached_Client/ -> memcached-client.php (source)

   1  <?php
   2  //

   3  // +---------------------------------------------------------------------------+

   4  // | memcached client, PHP                                                     |

   5  // +---------------------------------------------------------------------------+

   6  // | Copyright (c) 2003 Ryan T. Dean <rtdean@cytherianage.net>                 |

   7  // | All rights reserved.                                                      |

   8  // |                                                                           |

   9  // | Redistribution and use in source and binary forms, with or without        |

  10  // | modification, are permitted provided that the following conditions        |

  11  // | are met:                                                                  |

  12  // |                                                                           |

  13  // | 1. Redistributions of source code must retain the above copyright         |

  14  // |    notice, this list of conditions and the following disclaimer.          |

  15  // | 2. Redistributions in binary form must reproduce the above copyright      |

  16  // |    notice, this list of conditions and the following disclaimer in the    |

  17  // |    documentation and/or other materials provided with the distribution.   |

  18  // |                                                                           |

  19  // | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR      |

  20  // | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |

  21  // | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.   |

  22  // | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,          |

  23  // | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT  |

  24  // | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |

  25  // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY     |

  26  // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       |

  27  // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF  |

  28  // | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.         |

  29  // +---------------------------------------------------------------------------+

  30  // | Author: Ryan T. Dean <rtdean@cytherianage.net>                            |

  31  // | Heavily influenced by the Perl memcached client by Brad Fitzpatrick.      |

  32  // |   Permission granted by Brad Fitzpatrick for relicense of ported Perl     |

  33  // |   client logic under 2-clause BSD license.                                |

  34  // +---------------------------------------------------------------------------+

  35  //

  36  // $TCAnet$

  37  //

  38  
  39  /**

  40   * This is the PHP client for memcached - a distributed memory cache daemon.

  41   * More information is available at http://www.danga.com/memcached/

  42   *

  43   * Usage example:

  44   *

  45   * require_once 'memcached.php';

  46   *

  47   * $mc = new memcached(array(

  48   *              'servers' => array('127.0.0.1:10000',

  49   *                                 array('192.0.0.1:10010', 2),

  50   *                                 '127.0.0.1:10020'),

  51   *              'debug'   => false,

  52   *              'compress_threshold' => 10240,

  53   *              'persistant' => true));

  54   *

  55   * $mc->add('key', array('some', 'array'));

  56   * $mc->replace('key', 'some random string');

  57   * $val = $mc->get('key');

  58   *

  59   * @author  Ryan T. Dean <rtdean@cytherianage.net>

  60   * @package memcached-client

  61   * @version 0.1.2

  62   */
  63  
  64  // {{{ requirements

  65  // }}}

  66  
  67  // {{{ constants

  68  // {{{ flags

  69  
  70  /**

  71   * Flag: indicates data is serialized

  72   */
  73  define("MEMCACHE_SERIALIZED", 1<<0);
  74  
  75  /**

  76   * Flag: indicates data is compressed

  77   */
  78  define("MEMCACHE_COMPRESSED", 1<<1);
  79  
  80  // }}}

  81  
  82  /**

  83   * Minimum savings to store data compressed

  84   */
  85  define("COMPRESSION_SAVINGS", 0.20);
  86  
  87  // }}}

  88  
  89  // {{{ class memcached

  90  /**

  91   * memcached client class implemented using (p)fsockopen()

  92   *

  93   * @author  Ryan T. Dean <rtdean@cytherianage.net>

  94   * @package memcached-client

  95   */
  96  class memcached
  97  {
  98     // {{{ properties

  99     // {{{ public

 100  
 101     /**

 102      * Command statistics

 103      *

 104      * @var     array

 105      * @access  public

 106      */
 107     var $stats;
 108  
 109     // }}}

 110     // {{{ private

 111  
 112     /**

 113      * Cached Sockets that are connected

 114      *

 115      * @var     array

 116      * @access  private

 117      */
 118     var $_cache_sock;
 119  
 120     /**

 121      * Current debug status; 0 - none to 9 - profiling

 122      *

 123      * @var     boolean

 124      * @access  private

 125      */
 126     var $_debug;
 127  
 128     /**

 129      * Dead hosts, assoc array, 'host'=>'unixtime when ok to check again'

 130      *

 131      * @var     array

 132      * @access  private

 133      */
 134     var $_host_dead;
 135  
 136     /**

 137      * Is compression available?

 138      *

 139      * @var     boolean

 140      * @access  private

 141      */
 142     var $_have_zlib;
 143  
 144     /**

 145      * Do we want to use compression?

 146      *

 147      * @var     boolean

 148      * @access  private

 149      */
 150     var $_compress_enable;
 151  
 152     /**

 153      * At how many bytes should we compress?

 154      *

 155      * @var     interger

 156      * @access  private

 157      */
 158     var $_compress_threshold;
 159  
 160     /**

 161      * Are we using persistant links?

 162      *

 163      * @var     boolean

 164      * @access  private

 165      */
 166     var $_persistant;
 167  
 168     /**

 169      * If only using one server; contains ip:port to connect to

 170      *

 171      * @var     string

 172      * @access  private

 173      */
 174     var $_single_sock;
 175  
 176     /**

 177      * Array containing ip:port or array(ip:port, weight)

 178      *

 179      * @var     array

 180      * @access  private

 181      */
 182     var $_servers;
 183  
 184     /**

 185      * Our bit buckets

 186      *

 187      * @var     array

 188      * @access  private

 189      */
 190     var $_buckets;
 191  
 192     /**

 193      * Total # of bit buckets we have

 194      *

 195      * @var     interger

 196      * @access  private

 197      */
 198     var $_bucketcount;
 199  
 200     /**

 201      * # of total servers we have

 202      *

 203      * @var     interger

 204      * @access  private

 205      */
 206     var $_active;
 207  
 208     /**

 209      * Stream timeout in seconds. Applies for example to fread()

 210      *

 211      * @var     integer

 212      * @access  private

 213      */
 214     var $_timeout_seconds;
 215  
 216     /**

 217      * Stream timeout in microseconds

 218      *

 219      * @var     integer

 220      * @access  private

 221      */
 222     var $_timeout_microseconds;
 223  
 224     // }}}

 225     // }}}

 226     // {{{ methods

 227     // {{{ public functions

 228     // {{{ memcached()

 229  
 230     /**

 231      * Memcache initializer

 232      *

 233      * @param   array    $args    Associative array of settings

 234      *

 235      * @return  mixed

 236      * @access  public

 237      */
 238     function memcached ($args)
 239     {
 240        $this->set_servers(@$args['servers']);
 241        $this->_debug = @$args['debug'];
 242        $this->stats = array();
 243        $this->_compress_threshold = @$args['compress_threshold'];
 244        $this->_persistant = array_key_exists('persistant', $args) ? (@$args['persistant']) : false;
 245        $this->_compress_enable = true;
 246        $this->_have_zlib = function_exists("gzcompress");
 247  
 248        $this->_cache_sock = array();
 249        $this->_host_dead = array();
 250  
 251        $this->_timeout_seconds = 1;
 252        $this->_timeout_microseconds = 0;
 253     }
 254  
 255     // }}}

 256     // {{{ add()

 257  
 258     /**

 259      * Adds a key/value to the memcache server if one isn't already set with

 260      * that key

 261      *

 262      * @param   string   $key     Key to set with data

 263      * @param   mixed    $val     Value to store

 264      * @param   interger $exp     (optional) Time to expire data at

 265      *

 266      * @return  boolean

 267      * @access  public

 268      */
 269     function add ($key, $val, $exp = 0)
 270     {
 271        return $this->_set('add', $key, $val, $exp);
 272     }
 273  
 274     // }}}

 275     // {{{ decr()

 276  
 277     /**

 278      * Decriment a value stored on the memcache server

 279      *

 280      * @param   string   $key     Key to decriment

 281      * @param   interger $amt     (optional) Amount to decriment

 282      *

 283      * @return  mixed    FALSE on failure, value on success

 284      * @access  public

 285      */
 286     function decr ($key, $amt=1)
 287     {
 288        return $this->_incrdecr('decr', $key, $amt);
 289     }
 290  
 291     // }}}

 292     // {{{ delete()

 293  
 294     /**

 295      * Deletes a key from the server, optionally after $time

 296      *

 297      * @param   string   $key     Key to delete

 298      * @param   interger $time    (optional) How long to wait before deleting

 299      *

 300      * @return  boolean  TRUE on success, FALSE on failure

 301      * @access  public

 302      */
 303     function delete ($key, $time = 0)
 304     {
 305        if (!$this->_active)
 306           return false;
 307  
 308        $sock = $this->get_sock($key);
 309        if (!is_resource($sock))
 310           return false;
 311  
 312        $key = is_array($key) ? $key[1] : $key;
 313  
 314        @$this->stats['delete']++;
 315        $cmd = "delete $key $time\r\n";
 316        if(!$this->_safe_fwrite($sock, $cmd, strlen($cmd)))
 317        {
 318           $this->_dead_sock($sock);
 319           return false;
 320        }
 321        $res = trim(fgets($sock));
 322  
 323        if ($this->_debug)
 324           $this->_debugprint(sprintf("MemCache: delete %s (%s)\n", $key, $res));
 325  
 326        if ($res == "DELETED")
 327           return true;
 328        return false;
 329     }
 330     
 331     // }}}

 332     // {{{ flush_all()

 333  
 334     /**

 335      * Flush all keys from the server

 336      *

 337      * @return  boolean  Always TRUE

 338      * @access  public

 339      */
 340     function flush_all ()
 341     {
 342        if (!$this->_active)
 343           return false;
 344  
 345        foreach ($this->_servers as $server)
 346        {
 347           if (is_array($server))
 348           {
 349              for ($i=0; $i<$server[1]; $i++)
 350                 $hosts[] = $server[0];
 351           } else
 352           {
 353              $hosts[] = $server;
 354           }
 355        }
 356        
 357        foreach ($hosts as $host)
 358        {  
 359           $sock = $this->sock_to_host($host);
 360           if (is_resource($sock)) {
 361              $this->_flush_read_buffer($sock);
 362        
 363              @$this->stats['flush_all']++;
 364              $cmd = "flush_all\r\n";
 365              if(!$this->_safe_fwrite($sock, $cmd, strlen($cmd)))
 366              {
 367                 $this->_dead_sock($sock);
 368                 continue;
 369              }
 370              $res = trim(fgets($sock));
 371  
 372              if ($this->_debug)
 373                 $this->_debugprint(sprintf("MemCache: flush_all %s (%s)\n", $host, $res));
 374           }
 375        }
 376        return true;
 377     }
 378  
 379     // }}}

 380     // {{{ disconnect_all()

 381  
 382     /**

 383      * Disconnects all connected sockets

 384      *

 385      * @access  public

 386      */
 387     function disconnect_all ()
 388     {
 389        foreach ($this->_cache_sock as $sock)
 390           fclose($sock);
 391  
 392        $this->_cache_sock = array();
 393     }
 394  
 395     // }}}

 396     // {{{ enable_compress()

 397  
 398     /**

 399      * Enable / Disable compression

 400      *

 401      * @param   boolean  $enable  TRUE to enable, FALSE to disable

 402      *

 403      * @access  public

 404      */
 405     function enable_compress ($enable)
 406     {
 407        $this->_compress_enable = $enable;
 408     }
 409  
 410     // }}}

 411     // {{{ forget_dead_hosts()

 412  
 413     /**

 414      * Forget about all of the dead hosts

 415      *

 416      * @access  public

 417      */
 418     function forget_dead_hosts ()
 419     {
 420        $this->_host_dead = array();
 421     }
 422  
 423     // }}}

 424     // {{{ get()

 425  
 426     /**

 427      * Retrieves the value associated with the key from the memcache server

 428      *

 429      * @param  string   $key     Key to retrieve

 430      *

 431      * @return  mixed

 432      * @access  public

 433      */
 434     function get ($key)
 435     {
 436        if (!$this->_active) {
 437           return false;
 438        }
 439  
 440        $sock = $this->get_sock($key);
 441  
 442        if (!is_resource($sock)) {
 443           return false;
 444        }
 445  
 446        @$this->stats['get']++;
 447  
 448        $cmd = "get $key\r\n";
 449        if (!$this->_safe_fwrite($sock, $cmd, strlen($cmd)))
 450        {
 451           $this->_dead_sock($sock);
 452           return false;
 453        }
 454  
 455        $val = array();
 456        $this->_load_items($sock, $val);
 457  
 458        if ($this->_debug)
 459           foreach ($val as $k => $v)
 460              $this->_debugprint(@sprintf("MemCache: sock %s got %s => %s\r\n", serialize($sock), $k, $v));
 461  
 462        return @$val[$key];
 463     }
 464  
 465     // }}}

 466     // {{{ get_multi()

 467  
 468     /**

 469      * Get multiple keys from the server(s)

 470      *

 471      * @param   array    $keys    Keys to retrieve

 472      *

 473      * @return  array

 474      * @access  public

 475      */
 476     function get_multi ($keys)
 477     {
 478        if (!$this->_active)
 479           return false;
 480  
 481        $this->stats['get_multi']++;
 482  
 483        foreach ($keys as $key)
 484        {
 485           $sock = $this->get_sock($key);
 486           if (!is_resource($sock)) continue;
 487           $key = is_array($key) ? $key[1] : $key;
 488           if (!isset($sock_keys[$sock]))
 489           {
 490              $sock_keys[$sock] = array();
 491              $socks[] = $sock;
 492           }
 493           $sock_keys[$sock][] = $key;
 494        }
 495  
 496        // Send out the requests

 497        foreach ($socks as $sock)
 498        {
 499           $cmd = "get";
 500           foreach ($sock_keys[$sock] as $key)
 501           {
 502              $cmd .= " ". $key;
 503           }
 504           $cmd .= "\r\n";
 505  
 506           if ($this->_safe_fwrite($sock, $cmd, strlen($cmd)))
 507           {
 508              $gather[] = $sock;
 509           } else
 510           {
 511              $this->_dead_sock($sock);
 512           }
 513        }
 514  
 515        // Parse responses

 516        $val = array();
 517        foreach ($gather as $sock)
 518        {
 519           $this->_load_items($sock, $val);
 520        }
 521  
 522        if ($this->_debug)
 523           foreach ($val as $k => $v)
 524              $this->_debugprint(sprintf("MemCache: got %s => %s\r\n", $k, $v));
 525  
 526        return $val;
 527     }
 528  
 529     // }}}

 530     // {{{ incr()

 531  
 532     /**

 533      * Increments $key (optionally) by $amt

 534      *

 535      * @param   string   $key     Key to increment

 536      * @param   interger $amt     (optional) amount to increment

 537      *

 538      * @return  interger New key value?

 539      * @access  public

 540      */
 541     function incr ($key, $amt=1)
 542     {
 543        return $this->_incrdecr('incr', $key, $amt);
 544     }
 545  
 546     // }}}

 547     // {{{ replace()

 548  
 549     /**

 550      * Overwrites an existing value for key; only works if key is already set

 551      *

 552      * @param   string   $key     Key to set value as

 553      * @param   mixed    $value   Value to store

 554      * @param   interger $exp     (optional) Experiation time

 555      *

 556      * @return  boolean

 557      * @access  public

 558      */
 559     function replace ($key, $value, $exp=0)
 560     {
 561        return $this->_set('replace', $key, $value, $exp);
 562     }
 563  
 564     // }}}

 565     // {{{ run_command()

 566  
 567     /**

 568      * Passes through $cmd to the memcache server connected by $sock; returns

 569      * output as an array (null array if no output)

 570      *

 571      * NOTE: due to a possible bug in how PHP reads while using fgets(), each

 572      *       line may not be terminated by a \r\n.  More specifically, my testing

 573      *       has shown that, on FreeBSD at least, each line is terminated only

 574      *       with a \n.  This is with the PHP flag auto_detect_line_endings set

 575      *       to falase (the default).

 576      *

 577      * @param   resource $sock    Socket to send command on

 578      * @param   string   $cmd     Command to run

 579      *

 580      * @return  array    Output array

 581      * @access  public

 582      */
 583     function run_command ($sock, $cmd)
 584     {
 585        if (!is_resource($sock))
 586           return array();
 587  
 588        if (!$this->_safe_fwrite($sock, $cmd, strlen($cmd)))
 589           return array();
 590  
 591        while (true)
 592        {
 593           $res = fgets($sock);
 594           $ret[] = $res;
 595           if (preg_match('/^END/', $res))
 596              break;
 597           if (strlen($res) == 0)
 598              break;
 599        }
 600        return $ret;
 601     }
 602  
 603     // }}}

 604     // {{{ set()

 605  
 606     /**

 607      * Unconditionally sets a key to a given value in the memcache.  Returns true

 608      * if set successfully.

 609      *

 610      * @param   string   $key     Key to set value as

 611      * @param   mixed    $value   Value to set

 612      * @param   interger $exp     (optional) Experiation time

 613      *

 614      * @return  boolean  TRUE on success

 615      * @access  public

 616      */
 617     function set ($key, $value, $exp=0)
 618     {
 619        return $this->_set('set', $key, $value, $exp);
 620     }
 621  
 622     // }}}

 623     // {{{ set_compress_threshold()

 624  
 625     /**

 626      * Sets the compression threshold

 627      *

 628      * @param   interger $thresh  Threshold to compress if larger than

 629      *

 630      * @access  public

 631      */
 632     function set_compress_threshold ($thresh)
 633     {
 634        $this->_compress_threshold = $thresh;
 635     }
 636  
 637     // }}}

 638     // {{{ set_debug()

 639  
 640     /**

 641      * Sets the debug flag

 642      *

 643      * @param   boolean  $dbg     TRUE for debugging, FALSE otherwise

 644      *

 645      * @access  public

 646      *

 647      * @see     memcahced::memcached

 648      */
 649     function set_debug ($dbg)
 650     {
 651        $this->_debug = $dbg;
 652     }
 653  
 654     // }}}

 655     // {{{ set_servers()

 656  
 657     /**

 658      * Sets the server list to distribute key gets and puts between

 659      *

 660      * @param   array    $list    Array of servers to connect to

 661      *

 662      * @access  public

 663      *

 664      * @see     memcached::memcached()

 665      */
 666     function set_servers ($list)
 667     {
 668        $this->_servers = $list;
 669        $this->_active = count($list);
 670        $this->_buckets = null;
 671        $this->_bucketcount = 0;
 672  
 673        $this->_single_sock = null;
 674        if ($this->_active == 1)
 675           $this->_single_sock = $this->_servers[0];
 676     }
 677  
 678     /**

 679      * Sets the timeout for new connections

 680      *

 681      * @param   integer  $seconds Number of seconds

 682      * @param   integer  $microseconds  Number of microseconds

 683      *

 684      * @access  public

 685      */
 686     function set_timeout ($seconds, $microseconds)
 687     {
 688        $this->_timeout_seconds = $seconds;
 689        $this->_timeout_microseconds = $microseconds;
 690     }
 691  
 692     // }}}

 693     // }}}

 694     // {{{ private methods

 695     // {{{ _close_sock()

 696  
 697     /**

 698      * Close the specified socket

 699      *

 700      * @param   string   $sock    Socket to close

 701      *

 702      * @access  private

 703      */
 704     function _close_sock ($sock)
 705     {
 706        $host = array_search($sock, $this->_cache_sock);
 707        fclose($this->_cache_sock[$host]);
 708        unset($this->_cache_sock[$host]);
 709     }
 710  
 711     // }}}

 712     // {{{ _connect_sock()

 713  
 714     /**

 715      * Connects $sock to $host, timing out after $timeout

 716      *

 717      * @param   interger $sock    Socket to connect

 718      * @param   string   $host    Host:IP to connect to

 719      * @param   float    $timeout (optional) Timeout value, defaults to 0.25s

 720      *

 721      * @return  boolean

 722      * @access  private

 723      */
 724     function _connect_sock (&$sock, $host, $timeout = 0.25)
 725     {
 726        list ($ip, $port) = explode(":", $host);
 727        if ($this->_persistant == 1)
 728        {
 729           $sock = @pfsockopen($ip, $port, $errno, $errstr, $timeout);
 730        } else
 731        {
 732           $sock = @fsockopen($ip, $port, $errno, $errstr, $timeout);
 733        }
 734  
 735        if (!$sock) {
 736           if ($this->_debug)
 737              $this->_debugprint( "Error connecting to $host: $errstr\n" );
 738           return false;
 739        }
 740  
 741        // Initialise timeout

 742        stream_set_timeout($sock, $this->_timeout_seconds, $this->_timeout_microseconds);
 743  
 744        return true;
 745     }
 746  
 747     // }}}

 748     // {{{ _dead_sock()

 749  
 750     /**

 751      * Marks a host as dead until 30-40 seconds in the future

 752      *

 753      * @param   string   $sock    Socket to mark as dead

 754      *

 755      * @access  private

 756      */
 757     function _dead_sock ($sock)
 758     {
 759        $host = array_search($sock, $this->_cache_sock);
 760        @list ($ip, $port) = explode(":", $host);
 761        $this->_host_dead[$ip] = time() + 30 + intval(rand(0, 10));
 762        $this->_host_dead[$host] = $this->_host_dead[$ip];
 763        unset($this->_cache_sock[$host]);
 764     }
 765  
 766     // }}}

 767     // {{{ get_sock()

 768  
 769     /**

 770      * get_sock

 771      *

 772      * @param   string   $key     Key to retrieve value for;

 773      *

 774      * @return  mixed    resource on success, false on failure

 775      * @access  private

 776      */
 777     function get_sock ($key)
 778     {
 779        if (!$this->_active)
 780           return false;
 781  
 782        if ($this->_single_sock !== null) {
 783           $this->_flush_read_buffer($this->_single_sock);
 784           return $this->sock_to_host($this->_single_sock);
 785        }
 786  
 787        $hv = is_array($key) ? intval($key[0]) : $this->_hashfunc($key);
 788  
 789        if ($this->_buckets === null)
 790        {
 791           foreach ($this->_servers as $v)
 792           {
 793              if (is_array($v))
 794              {
 795                 for ($i=0; $i<$v[1]; $i++)
 796                    $bu[] = $v[0];
 797              } else
 798              {
 799                 $bu[] = $v;
 800              }
 801           }
 802           $this->_buckets = $bu;
 803           $this->_bucketcount = count($bu);
 804        }
 805  
 806        $realkey = is_array($key) ? $key[1] : $key;
 807        for ($tries = 0; $tries<20; $tries++)
 808        {
 809           $host = $this->_buckets[$hv % $this->_bucketcount];
 810           $sock = $this->sock_to_host($host);
 811           if (is_resource($sock)) {
 812              $this->_flush_read_buffer($sock);
 813              return $sock;
 814           }
 815           $hv += $this->_hashfunc($tries . $realkey);
 816        }
 817  
 818        return false;
 819     }
 820  
 821     // }}}

 822     // {{{ _hashfunc()

 823  
 824     /**

 825      * Creates a hash interger based on the $key

 826      *

 827      * @param   string   $key     Key to hash

 828      *

 829      * @return  interger Hash value

 830      * @access  private

 831      */
 832     function _hashfunc ($key)
 833     {
 834        # Hash function must on [0,0x7ffffff]

 835        # We take the first 31 bits of the MD5 hash, which unlike the hash

 836        # function used in a previous version of this client, works

 837        return hexdec(substr(md5($key),0,8)) & 0x7fffffff;
 838     }
 839  
 840     // }}}

 841     // {{{ _incrdecr()

 842  
 843     /**

 844      * Perform increment/decriment on $key

 845      *

 846      * @param   string   $cmd     Command to perform

 847      * @param   string   $key     Key to perform it on

 848      * @param   interger $amt     Amount to adjust

 849      *

 850      * @return  interger    New value of $key

 851      * @access  private

 852      */
 853     function _incrdecr ($cmd, $key, $amt=1)
 854     {
 855        if (!$this->_active)
 856           return null;
 857  
 858        $sock = $this->get_sock($key);
 859        if (!is_resource($sock))
 860           return null;
 861  
 862        $key = is_array($key) ? $key[1] : $key;
 863        @$this->stats[$cmd]++;
 864        if (!$this->_safe_fwrite($sock, "$cmd $key $amt\r\n"))
 865           return $this->_dead_sock($sock);
 866  
 867        stream_set_timeout($sock, 1, 0);
 868        $line = fgets($sock);
 869        if (!preg_match('/^(\d+)/', $line, $match))
 870           return null;
 871        return $match[1];
 872     }
 873  
 874     // }}}

 875     // {{{ _load_items()

 876  
 877     /**

 878      * Load items into $ret from $sock

 879      *

 880      * @param   resource $sock    Socket to read from

 881      * @param   array    $ret     Returned values

 882      *

 883      * @access  private

 884      */
 885     function _load_items ($sock, &$ret)
 886     {
 887        while (1)
 888        {
 889           $decl = fgets($sock);
 890           if ($decl == "END\r\n")
 891           {
 892              return true;
 893           } elseif (preg_match('/^VALUE (\S+) (\d+) (\d+)\r\n$/', $decl, $match))
 894           {
 895              list($rkey, $flags, $len) = array($match[1], $match[2], $match[3]);
 896              $bneed = $len+2;
 897              $offset = 0;
 898  
 899              while ($bneed > 0)
 900              {
 901                 $data = fread($sock, $bneed);
 902                 $n = strlen($data);
 903                 if ($n == 0)
 904                    break;
 905                 $offset += $n;
 906                 $bneed -= $n;
 907                 @$ret[$rkey] .= $data;
 908              }
 909  
 910              if ($offset != $len+2)
 911              {
 912                 // Something is borked!

 913                 if ($this->_debug)
 914                    $this->_debugprint(sprintf("Something is borked!  key %s expecting %d got %d length\n", $rkey, $len+2, $offset));
 915  
 916                 unset($ret[$rkey]);
 917                 $this->_close_sock($sock);
 918                 return false;
 919              }
 920  
 921              if ($this->_have_zlib && $flags & MEMCACHE_COMPRESSED)
 922                 $ret[$rkey] = gzuncompress($ret[$rkey]);
 923  
 924              $ret[$rkey] = rtrim($ret[$rkey]);
 925  
 926              if ($flags & MEMCACHE_SERIALIZED)
 927                 $ret[$rkey] = unserialize($ret[$rkey]);
 928  
 929           } else
 930           {
 931              $this->_debugprint("Error parsing memcached response\n");
 932              return 0;
 933           }
 934        }
 935     }
 936  
 937     // }}}

 938     // {{{ _set()

 939  
 940     /**

 941      * Performs the requested storage operation to the memcache server

 942      *

 943      * @param   string   $cmd     Command to perform

 944      * @param   string   $key     Key to act on

 945      * @param   mixed    $val     What we need to store

 946      * @param   interger $exp     When it should expire

 947      *

 948      * @return  boolean

 949      * @access  private

 950      */
 951     function _set ($cmd, $key, $val, $exp)
 952     {
 953        if (!$this->_active)
 954           return false;
 955  
 956        $sock = $this->get_sock($key);
 957        if (!is_resource($sock))
 958           return false;
 959  
 960        @$this->stats[$cmd]++;
 961  
 962        $flags = 0;
 963  
 964        if (!is_scalar($val))
 965        {
 966           $val = serialize($val);
 967           $flags |= MEMCACHE_SERIALIZED;
 968           if ($this->_debug)
 969              $this->_debugprint(sprintf("client: serializing data as it is not scalar\n"));
 970        }
 971  
 972        $len = strlen($val);
 973  
 974        if ($this->_have_zlib && $this->_compress_enable &&
 975            $this->_compress_threshold && $len >= $this->_compress_threshold)
 976        {
 977           $c_val = gzcompress($val, 9);
 978           $c_len = strlen($c_val);
 979  
 980           if ($c_len < $len*(1 - COMPRESSION_SAVINGS))
 981           {
 982              if ($this->_debug)
 983                 $this->_debugprint(sprintf("client: compressing data; was %d bytes is now %d bytes\n", $len, $c_len));
 984              $val = $c_val;
 985              $len = $c_len;
 986              $flags |= MEMCACHE_COMPRESSED;
 987           }
 988        }
 989        if (!$this->_safe_fwrite($sock, "$cmd $key $flags $exp $len\r\n$val\r\n"))
 990           return $this->_dead_sock($sock);
 991  
 992        $line = trim(fgets($sock));
 993  
 994        if ($this->_debug)
 995        {
 996           if ($flags & MEMCACHE_COMPRESSED)
 997              $val = 'compressed data';
 998           $this->_debugprint(sprintf("MemCache: %s %s => %s (%s)\n", $cmd, $key, $val, $line));
 999        }
1000        if ($line == "STORED")
1001           return true;
1002        return false;
1003     }
1004  
1005     // }}}

1006     // {{{ sock_to_host()

1007  
1008     /**

1009      * Returns the socket for the host

1010      *

1011      * @param   string   $host    Host:IP to get socket for

1012      *

1013      * @return  mixed    IO Stream or false

1014      * @access  private

1015      */
1016     function sock_to_host ($host)
1017     {
1018        if (isset($this->_cache_sock[$host]))
1019           return $this->_cache_sock[$host];
1020  
1021        $now = time();
1022        list ($ip, $port) = explode (":", $host);
1023        if (isset($this->_host_dead[$host]) && $this->_host_dead[$host] > $now ||
1024            isset($this->_host_dead[$ip]) && $this->_host_dead[$ip] > $now)
1025           return null;
1026  
1027        if (!$this->_connect_sock($sock, $host))
1028           return $this->_dead_sock($host);
1029  
1030        // Do not buffer writes

1031        stream_set_write_buffer($sock, 0);
1032  
1033        $this->_cache_sock[$host] = $sock;
1034  
1035        return $this->_cache_sock[$host];
1036     }
1037  
1038     function _debugprint($str){
1039        print($str);
1040     }
1041  
1042     /**

1043      * Write to a stream, timing out after the correct amount of time

1044      *

1045      * @return bool false on failure, true on success

1046      */
1047     function _safe_fwrite($f, $buf, $len = false) {
1048        if ($len === false) {
1049           $bytesWritten = @fwrite($f, $buf);
1050        } else {
1051           $bytesWritten = @fwrite($f, $buf, $len);
1052        }
1053        return $bytesWritten;
1054     }
1055  
1056     /**

1057      * Flush the read buffer of a stream

1058      */
1059     function _flush_read_buffer($f) {
1060        if (!is_resource($f)) {
1061           return;
1062        }
1063        $n = stream_select($r=array($f), $w = NULL, $e = NULL, 0, 0);
1064        while ($n == 1 && !feof($f)) {
1065           fread($f, 1024);
1066           $n = stream_select($r=array($f), $w = NULL, $e = NULL, 0, 0);
1067        }
1068     }
1069  
1070     // }}}

1071     // }}}

1072     // }}}

1073  }
1074  
1075  // vim: sts=3 sw=3 et

1076  
1077  // }}}

1078  ?>


Généré le : Mon Nov 26 21:04:15 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics