memcache.inc 5.51 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
<?php
// $ID$

/*
 * A memcache API for Drupal.
 */

/**
 *  Place an item into memcache
 * 
 * @param $key The string with with you will retrieve this item later.
 * @param $value The item to be stored.
 * @param $exp Parameter expire is expiration time in seconds. If it's 0, the item never expires
 *   (but memcached server doesn't guarantee this item to be stored all the time, it could be
 *   deleted from the cache to make place for other items).
 * @param $bin The name of the Drupal subsystem that is making this call. Examples could be
 *   'cache', 'alias', 'taxonomy term' etc. It is possible to map different $bin values to
 *   different memcache servers.
 *
 * @return bool
 */
function dmemcache_set($key, $value, $exp = 0, $bin = 'default') {
  if ($mc = dmemcache_object($bin)) {
    $full_key = dmemcache_key($key, $bin);
    if (!$mc->set($full_key, $value, FALSE, $exp)) {
      watchdog('memcache', 'Failed to set key: ' . $full_key);
    }
    else {
      return TRUE;
    }
  }
  return FALSE;
}

/**
 * Retrieve a value from the cache.
 *
 * @param $key The key with which the item was stored.
 * @param $bin The bin in which the item was stored.
 *
 * @return The item which was originally saved or FALSE
 */
function dmemcache_get($key, $bin = 'default') {
  if ($mc = dmemcache_object($bin)) {
    $full_key = dmemcache_key($key, $bin);
    return $mc->get($full_key);
  }
}

/**
 * Deletes an item from the cache.
 *
 * @param $key The key with which the item was stored.
 * @param $bin The bin in which the item was stored.
 *
 * @return Returns TRUE on success or FALSE on failure.
 */
function dmemcache_delete($key, $bin = 'default') {
  if ($mc = dmemcache_object($bin)) {
    $full_key = dmemcache_key($key, $bin);
    return $mc->delete($full_key);
  }
  return FALSE;
}

/**
 * Immediately invalidates all existing items. dmemcache_flush doesn't actually free any
 * resources, it only marks all the items as expired, so occupied memory will be overwritten by
 * new items.
 *
 * @param $bin The bin to flush. Note that this will flush all bins mapped to the same server
 *   as $bin. There is no way at this time to empty just one bin.
 *
 * @return Returns TRUE on success or FALSE on failure.
 */
function dmemcache_flush($bin = 'default') {
  if ($mc = dmemcache_object($bin)) {
    return $mc->flush();
  }
}

function dmemcache_stats($bin = 'default') {
  if ($mc = dmemcache_object($bin)) {
    return $mc->getStats();
  }
}
87 88 89 90 91 92 93 94 95 96
/**
$conf['memcache'][] = array(
  '#servers' => array('localhost:11211', 'localhost:11212'),
  '#bins'    => array('default'),
);
$conf['memcache'][] = array(
  '#servers' => array('localhost:11212'),
  '#bins'    => array('alias', 'src'),
);
*/
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114

/**
 * Returns an Memcache object based on the bin requested. Note that there is nothing preventing
 * developers from calling this function directly to get the Memcache object. Do this if you need
 * functionality not provided by this API or if you need to use existing code. Otherwise, use
 * the dmemcache API functions provided here.
 *
 * @param $bin The bin which is to be used. Note that this maps to a physical server that
 *   may or may not be shared with other bins.
 * @param $flush Rebuild the bin/server mapping from the global $conf array.
 *
 * @return an Memcache object or FALSE.
 */
function dmemcache_object($bin = 'default', $flush = FALSE) {
  global $conf;
  static $caches;

  if ($flush) {
115 116 117
    foreach ($caches as $cluster) {
      $cluster->close();
    }
118 119 120 121 122 123 124
    unset($caches);
  }

  if (!isset($caches)) {
    // initialize the static cache
    $caches = array();

125 126 127 128 129 130 131 132 133 134
    if (isset($conf['memcache'])) {
      // Each cluster is a list of host:port and bin groups
      foreach ($conf['memcache'] as $cluster_config) {
        $cluster = new Memcache;
        $first_server = TRUE;
        foreach ($cluster_config['#servers'] as $server) {
          list($host, $port) = explode(':', $server);
          if ($first_server) {
            $cluster->connect($host, $port);
            $first_server = FALSE;
135
          }
136 137 138 139 140 141 142 143 144 145 146 147 148
          else {
            $cluster->addServer($host, $port);
          }
        }

        // Now that the $cluster has all of its servers connected and added
        // we cycle through the bins and map this cluster to each of them.
        // This allows the retrieval of the right cluster for each bin later.
        // Note: It is the administrator's responsibility to make sure the $conf
        // array is structured correctly, ie no clusters without bins and a mapping
        // for the default bin.
        foreach ($cluster_config['#bins'] as $bin_name) {
          $caches[$bin_name] = &$cluster;
149 150 151
        }
      }
    }
152
    // If $conf['memcache'] was not set, we try to initialize the default server
153
    else {
154 155 156 157
      $cluster = new Memcache;
      $cluster->connect('localhost', '11211');
      if ($cluster->getServerStatus('localhost', 11211)) {
        $caches['default'] = &$cluster;
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
      }
    }
  }

  // If there is a server set up for the requested $bin, return it.
  if (isset($caches[$bin])) {
   return $caches[$bin];
  }
  // Otherwise, return the first server listed.
  else {
    $tmp = $caches;
    return array_shift($tmp);
  }
  return FALSE;
}

/**
 * Build a key that is urlencoded (better whitespace handling) and namespaced with the bin.
 *
 * @param $key The base key that identifies an object.
 * @param $bin The bin in which the object resides or will reside.
 *
 * @return A string that will ultimately be used as the actual key.
 */
function dmemcache_key($key, $bin = 'default') {
  return urlencode($bin) . '::' . urlencode($key);
}