/
multinoderedis.py
164 lines (138 loc) · 5.4 KB
/
multinoderedis.py
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
from multinodepipeline import MultiNodePipeline
from multinodemanager import MultiNodeManager
from multinodeexceptions import MultiNodeRedisException
class MultiNodeRedis(object):
def __init__(self, master_servers, slave_servers=None):
"""
Initialize MultiNodeRedis object. The master hosts should contain
the key "node_name". This key identifies the node, and will be
used to maintain a node mapping for sharding data.
Args:
master_servers - e.g. [node1|127.0.0.1:6379,
node2|127.0.0.1:6370]
slave_servers - same as master_hosts
"""
self.manager = MultiNodeManager(master_servers, slave_servers=slave_servers)
def __setitem__(self, name, value):
self.set(name, value)
def __getitem__(self, name):
"""
Return the value at key ``name``, raises a KeyError if the key
doesn't exist.
"""
value = self.get(name)
if value:
return value
raise KeyError(name)
@classmethod
def _list_or_args(cls, keys, args):
# returns a single list combining keys and args
try:
iter(keys)
# a string or bytes instance can be iterated, but indicates
# keys wasn't passed as a list
if isinstance(keys, (basestring, bytes)):
keys = [keys]
except TypeError:
keys = [keys]
if args:
keys.extend(args)
return keys
def _get_node(self, key, use_slave=False):
return self.manager._get_node(key, use_slave=use_slave)
def _get_all_nodes(self):
return self.manager._get_all_nodes()
def delete(self, key):
node = self._get_node(key)
return node.delete(key)
def expire(self, key, time):
node = self._get_node(key)
return node.expire(key, time)
def flushall(self):
for node in self._get_all_nodes():
node.flushall()
def get(self, key):
node = self._get_node(key)
return node.get(key)
def hget(self, key, field):
node = self._get_node(key)
return node.hget(key, field)
def hgetall(self, key):
node = self._get_node(key)
return node.hgetall(key)
def hincrby(self, key, field, amount=1):
node = self._get_node(key)
return node.hincrby(key, field, amount=amount)
def hmset(self, key, mapping):
node = self._get_node(key)
return node.hmset(key, mapping)
def hset(self, key, field, value):
node = self._get_node(key)
return node.hset(key, field, value)
def incr(self, key, amount=1):
node = self._get_node(key)
return node.incr(key, amount=amount)
def llen(self, key):
node = self._get_node(key)
return node.llen(key)
def mget(self, keys, *args):
args = self._list_or_args(keys, args)
node_map = {}
for key in args:
node = self._get_node(key)
if node not in node_map:
node_map[node] = []
node_map[node].append(key)
mapping = {}
for node, node_keys in node_map.iteritems():
node_values = node.mget(node_keys)
for i, node_key in enumerate(node_keys):
mapping[node_key] = node_values[i]
values = []
for key in args:
values.append(mapping.get(key, None))
return values
def mset(self, *args, **kwargs):
if args:
if len(args) != 1 or not isinstance(args[0], dict):
raise MultiNodeRedisException('MSET requires **kwargs or a ' +
'single dict arg')
kwargs.update(args[0])
node_map = {}
for key, value in kwargs.iteritems():
node = self._get_node(key)
if node not in node_map:
node_map[node] = {}
node_map[node][key] = value
success = 0
for node, node_kwargs in node_map.iteritems():
success = success or node.mset(node_kwargs)
return success
def persist(self, key):
node = self._get_node(key)
return node.persist(key)
def pipeline(self, transaction=True, shard_hint=None):
# TODO(ks) - 5/22/14 - I'm not actually sure if pipeline should return
# the same pipeline object or a new one each time.
return MultiNodePipeline(self.manager,
transaction=transaction,
shard_hint=shard_hint)
def set(self, key, value, ex=None, px=None, nx=False, xx=False):
node = self._get_node(key)
return node.set(key, value)
# TODO(ks) - 5/22/14 - Figure out why ex doesn't work
# return node.set(key, value, ex=ex, px=px, nx=nx, xx=xx)
def ttl(self, key):
node = self._get_node(key)
return node.ttl(key)
def zadd(self, key, *args, **kwargs):
node = self._get_node(key)
return node.zadd(key, *args, **kwargs)
def zincrby(self, key, value, amount=1):
node = self._get_node(key)
return node.zincrby(key, value, amount=amount)
def zrange(self, key, start, end, desc=False, withscores=False,
score_cast_func=float):
node = self._get_node(key)
return node.zrange(key, start, end, desc=desc, withscores=withscores,
score_cast_func=score_cast_func)