-
Notifications
You must be signed in to change notification settings - Fork 0
/
shardis.go
155 lines (131 loc) · 3.45 KB
/
shardis.go
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
package shardis
import (
"errors"
"regexp"
)
var (
// RegexFormat is a regex string used to extract substring enclosed by "{" and "}"
RegexFormat = "{.*}"
)
// Shardis represents a sharis client
type Shardis struct {
Nodes []string
Connections map[string]*Connection
Ring *HashRing
}
// New Create a Shardis instance
func New(config *Config) (*Shardis, error) {
numServers := len(config.Servers)
nodes := make([]string, numServers)
connections := make(map[string]*Connection)
for i, server := range config.Servers {
nodes[i] = server["name"].(string)
conn := NewConnection(server["host"].(string), "", int(server["block_timeout"].(float64)))
connections[server["name"].(string)] = conn
}
ring, err := NewHashRing(nodes, config.HashMethod, config.Replicas)
if err != nil {
return nil, err
}
return &Shardis{
Nodes: nodes,
Connections: connections,
Ring: ring,
}, nil
}
// GetServer gets connection of the server that given key is mapped to
func (shard *Shardis) GetServer(key string) *Connection {
serverName := shard.GetServerName(key)
return shard.Connections[serverName]
}
// GetServerName gets name of the server that given key is hashed to
func (shard *Shardis) GetServerName(key string) string {
re := regexp.MustCompile(RegexFormat)
tag := re.FindString(key)
if len(tag) == 0 {
// for key without tag enclosed by {}, ex, "foobar"
// directly hash the key
tag = key
} else {
// ignore "{", "}"
tag = tag[1 : len(tag)-1]
}
name := shard.Ring.GetNode(tag)
return name
}
/* Redis methods for Shardis */
// Set is for Redis SET command
func (shard *Shardis) Set(key string, value interface{}) error {
conn := shard.GetServer(key)
if conn == nil {
return errors.New("no server mapped to given key")
}
err := conn.Set(key, value)
return err
}
// Get is for Redis GET
func (shard *Shardis) Get(key string) (interface{}, error) {
conn := shard.GetServer(key)
if conn == nil {
return nil, errors.New("no server mapped to given key")
}
value, err := conn.Get(key)
if err != nil {
return nil, err
}
return value, nil
}
// Lpush is for Redis LPUSH
func (shard *Shardis) Lpush(key string, value interface{}) error {
conn := shard.GetServer(key)
if conn == nil {
return errors.New("no server mapped to given key")
}
err := conn.Lpush(key, value)
return err
}
// Rpush is for Redis RPUSH
func (shard *Shardis) Rpush(key string, value interface{}) error {
conn := shard.GetServer(key)
if conn == nil {
return errors.New("no server mapped to given key")
}
err := conn.Rpush(key, value)
return err
}
// Lpop is for Redis LPOP
func (shard *Shardis) Lpop(key string) (interface{}, error) {
conn := shard.GetServer(key)
if conn == nil {
return nil, errors.New("no server mapped to given key")
}
value, err := conn.Lpop(key)
if err != nil || value == nil {
return nil, err
}
return value, nil
}
// Rpop is for Redis LPOP
func (shard *Shardis) Rpop(key string) (interface{}, error) {
conn := shard.GetServer(key)
if conn == nil {
return nil, errors.New("no server mapped to given key")
}
value, err := conn.Rpop(key)
if err != nil || value == nil {
return nil, err
}
return value, nil
}
// Blpop is for Redis BLPOP
func (shard *Shardis) Blpop(key string) (interface{}, error) {
conn := shard.GetServer(key)
if conn == nil {
return nil, errors.New("no server mapped to given key")
}
value, err := conn.Blpop(key)
if err != nil || value == nil {
return nil, err
}
return value, nil
}