3
* Redisent, a Redis interface for the modest
4
* @author Justin Poliey <jdp34@njit.edu>
5
* @copyright 2009 Justin Poliey <jdp34@njit.edu>
6
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
10
require_once dirname(__FILE__) . '/Redisent.php';
13
* A generalized Redisent interface for a cluster of Redis servers
15
class RedisentCluster {
18
* Collection of Redisent objects attached to Redis servers
25
* Aliases of Redisent objects attached to Redis servers, used to route commands to specific servers
26
* @see RedisentCluster::to
33
* Hash ring of Redis server nodes
40
* Individual nodes of pointers to Redis servers on the hash ring
47
* Number of replicas of each node to make around the hash ring
51
private $replicas = 128;
54
* The commands that are not subject to hashing
58
private $dont_hash = array(
59
'RANDOMKEY', 'DBSIZE',
60
'SELECT', 'MOVE', 'FLUSHDB', 'FLUSHALL',
61
'SAVE', 'BGSAVE', 'LASTSAVE', 'SHUTDOWN',
62
'INFO', 'MONITOR', 'SLAVEOF'
66
* Creates a Redisent interface to a cluster of Redis servers
67
* @param array $servers The Redis servers in the cluster. Each server should be in the format array('host' => hostname, 'port' => port)
69
function __construct($servers) {
70
$this->ring = array();
71
$this->aliases = array();
72
foreach ($servers as $alias => $server) {
73
$this->redisents[] = new Redisent($server['host'], $server['port']);
74
if (is_string($alias)) {
75
$this->aliases[$alias] = $this->redisents[count($this->redisents)-1];
77
for ($replica = 1; $replica <= $this->replicas; $replica++) {
78
$this->ring[crc32($server['host'].':'.$server['port'].'-'.$replica)] = $this->redisents[count($this->redisents)-1];
81
ksort($this->ring, SORT_NUMERIC);
82
$this->nodes = array_keys($this->ring);
86
* Routes a command to a specific Redis server aliased by {$alias}.
87
* @param string $alias The alias of the Redis server
88
* @return Redisent The Redisent object attached to the Redis server
91
if (isset($this->aliases[$alias])) {
92
return $this->aliases[$alias];
95
throw new Exception("That Redisent alias does not exist");
99
/* Execute a Redis command on the cluster */
100
function __call($name, $args) {
102
/* Pick a server node to send the command to */
103
$name = strtoupper($name);
104
if (!in_array($name, $this->dont_hash)) {
105
$node = $this->nextNode(crc32($args[0]));
106
$redisent = $this->ring[$node];
109
$redisent = $this->redisents[0];
112
/* Execute the command on the server */
113
return call_user_func_array(array($redisent, $name), $args);
117
* Routes to the proper server node
118
* @param integer $needle The hash value of the Redis command
119
* @return Redisent The Redisent object associated with the hash
121
private function nextNode($needle) {
122
$haystack = $this->nodes;
123
while (count($haystack) > 2) {
124
$try = floor(count($haystack) / 2);
125
if ($haystack[$try] == $needle) {
128
if ($needle < $haystack[$try]) {
129
$haystack = array_slice($haystack, 0, $try + 1);
131
if ($needle > $haystack[$try]) {
132
$haystack = array_slice($haystack, $try + 1);
135
return $haystack[count($haystack)-1];
b'\\ No newline at end of file'