Skip to content

Commit e93da37

Browse files
author
Harmen
authored
SWAPDB
2 parents 9615c64 + 0c69bd8 commit e93da37

File tree

8 files changed

+161
-6
lines changed

8 files changed

+161
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/integration/redis_src/
2+
*.swp

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ This should be the change needed to upgrade:
7474
1.0:
7575

7676
m.Expire() == 4
77-
77+
7878
2.0:
7979

8080
m.TTL() == 4 * time.Second
@@ -92,7 +92,7 @@ Implemented commands:
9292
- PING
9393
- SELECT
9494
- QUIT
95-
- Key
95+
- Key
9696
- DEL
9797
- EXISTS
9898
- EXPIRE
@@ -328,13 +328,13 @@ Commands which will probably not be implemented:
328328
- ~~SLAVEOF~~
329329
- ~~SLOWLOG~~
330330
- ~~SYNC~~
331-
331+
332332

333333
## &c.
334334

335335
Tests are run against Redis 5.0.3. The [./integration](./integration/) subdir
336336
compares miniredis against a real redis instance.
337337

338338

339-
[![Build Status](https://travis-ci.org/alicebob/miniredis.svg?branch=master)](https://travis-ci.org/alicebob/miniredis)
339+
[![Build Status](https://travis-ci.org/alicebob/miniredis.svg?branch=master)](https://travis-ci.org/alicebob/miniredis)
340340
[![GoDoc](https://godoc.org/github.com/alicebob/miniredis?status.svg)](https://godoc.org/github.com/alicebob/miniredis)

cmd_connection.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ func commandsConnection(m *Miniredis) {
1313
m.srv.Register("ECHO", m.cmdEcho)
1414
m.srv.Register("PING", m.cmdPing)
1515
m.srv.Register("SELECT", m.cmdSelect)
16+
m.srv.Register("SWAPDB", m.cmdSwapdb)
1617
m.srv.Register("QUIT", m.cmdQuit)
1718
}
1819

@@ -124,6 +125,42 @@ func (m *Miniredis) cmdSelect(c *server.Peer, cmd string, args []string) {
124125
c.WriteOK()
125126
}
126127

128+
// SWAPDB
129+
func (m *Miniredis) cmdSwapdb(c *server.Peer, cmd string, args []string) {
130+
if len(args) != 2 {
131+
setDirty(c)
132+
c.WriteError(errWrongNumber(cmd))
133+
return
134+
}
135+
if !m.handleAuth(c) {
136+
return
137+
}
138+
139+
withTx(m, c, func(c *server.Peer, ctx *connCtx) {
140+
id1, err := strconv.Atoi(args[0])
141+
if err != nil {
142+
c.WriteError("ERR invalid first DB index")
143+
setDirty(c)
144+
return
145+
}
146+
id2, err := strconv.Atoi(args[1])
147+
if err != nil {
148+
c.WriteError("ERR invalid second DB index")
149+
setDirty(c)
150+
return
151+
}
152+
if id1 < 0 || id2 < 0 {
153+
c.WriteError("ERR DB index is out of range")
154+
setDirty(c)
155+
return
156+
}
157+
158+
m.swapDB(id1, id2)
159+
160+
c.WriteOK()
161+
})
162+
}
163+
127164
// QUIT
128165
func (m *Miniredis) cmdQuit(c *server.Peer, cmd string, args []string) {
129166
// QUIT isn't transactionfied and accepts any arguments.

cmd_connection_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,66 @@ func TestSelect(t *testing.T) {
9595
equals(t, "bar", v)
9696
}
9797

98+
func TestSwapdb(t *testing.T) {
99+
s, err := Run()
100+
ok(t, err)
101+
defer s.Close()
102+
c, err := redis.Dial("tcp", s.Addr())
103+
ok(t, err)
104+
105+
_, err = redis.String(c.Do("SET", "foo", "bar"))
106+
ok(t, err)
107+
108+
_, err = redis.String(c.Do("SELECT", "5"))
109+
ok(t, err)
110+
111+
_, err = redis.String(c.Do("SET", "foo", "baz"))
112+
ok(t, err)
113+
114+
res, err := redis.String(c.Do("SWAPDB", "0", "5"))
115+
ok(t, err)
116+
equals(t, "OK", res)
117+
118+
got, err := s.Get("foo")
119+
ok(t, err)
120+
equals(t, "baz", got)
121+
s.Select(5)
122+
got, err = s.Get("foo")
123+
ok(t, err)
124+
equals(t, "bar", got)
125+
126+
// Another connection should have its own idea of the db:
127+
c2, err := redis.Dial("tcp", s.Addr())
128+
ok(t, err)
129+
v, err := redis.String(c2.Do("GET", "foo"))
130+
ok(t, err)
131+
equals(t, "baz", v)
132+
133+
// errors
134+
{
135+
_, err := redis.String(c.Do("SWAPDB"))
136+
mustFail(t, err, errWrongNumber("SWAPDB"))
137+
138+
_, err = redis.String(c.Do("SWAPDB", 1, 2, 3))
139+
mustFail(t, err, errWrongNumber("SWAPDB"))
140+
141+
_, err = redis.String(c.Do("SWAPDB", "foo", 2))
142+
mustFail(t, err, "ERR invalid first DB index")
143+
144+
_, err = redis.String(c.Do("SWAPDB", 1, "bar"))
145+
mustFail(t, err, "ERR invalid second DB index")
146+
147+
_, err = redis.String(c.Do("SWAPDB", "foo", "bar"))
148+
mustFail(t, err, "ERR invalid first DB index")
149+
150+
_, err = redis.String(c.Do("SWAPDB", -1, 2))
151+
mustFail(t, err, "ERR DB index is out of range")
152+
153+
_, err = redis.String(c.Do("SWAPDB", 1, -2))
154+
mustFail(t, err, "ERR DB index is out of range")
155+
}
156+
}
157+
98158
func TestQuit(t *testing.T) {
99159
s, err := Run()
100160
ok(t, err)

cmd_scripting.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
"strings"
1010

1111
luajson "github.com/alicebob/gopher-json"
12-
"github.com/yuin/gopher-lua"
12+
lua "github.com/yuin/gopher-lua"
1313
"github.com/yuin/gopher-lua/parse"
1414

1515
"github.com/alicebob/miniredis/server"

integration/generic_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,39 @@ func TestProto(t *testing.T) {
213213
succ("ECHO", strings.Repeat("X", 1<<24)),
214214
)
215215
}
216+
217+
func TestSwapdb(t *testing.T) {
218+
testCommands(t,
219+
succ("SET", "key1", "val1"),
220+
succ("SWAPDB", "0", "1"),
221+
succ("SELECT", "1"),
222+
succ("GET", "key1"),
223+
224+
succ("SWAPDB", "1", "1"),
225+
succ("GET", "key1"),
226+
227+
fail("SWAPDB"),
228+
fail("SWAPDB", 1),
229+
fail("SWAPDB", 1, 2, 3),
230+
fail("SWAPDB", "foo", 2),
231+
fail("SWAPDB", 1, "bar"),
232+
fail("SWAPDB", "foo", "bar"),
233+
fail("SWAPDB", -1, 2),
234+
fail("SWAPDB", 1, -2),
235+
// fail("SWAPDB", 1, 1000), // miniredis has no upperlimit
236+
)
237+
238+
// SWAPDB with transactions
239+
testClients2(t, func(r1, r2 chan<- command) {
240+
r1 <- succ("SET", "foo", "foooooo")
241+
242+
r1 <- succ("MULTI")
243+
r1 <- succ("SWAPDB", 0, 2)
244+
r1 <- succ("GET", "foo")
245+
r2 <- succ("GET", "foo")
246+
247+
r1 <- succ("EXEC")
248+
r1 <- succ("GET", "foo")
249+
r2 <- succ("GET", "foo")
250+
})
251+
}

lua.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package miniredis
22

33
import (
44
redigo "github.com/gomodule/redigo/redis"
5-
"github.com/yuin/gopher-lua"
5+
lua "github.com/yuin/gopher-lua"
66

77
"github.com/alicebob/miniredis/server"
88
)

miniredis.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,27 @@ func (m *Miniredis) db(i int) *RedisDB {
197197
return &db
198198
}
199199

200+
// SwapDB swaps DBs by IDs.
201+
func (m *Miniredis) SwapDB(i, j int) bool {
202+
m.Lock()
203+
defer m.Unlock()
204+
return m.swapDB(i, j)
205+
}
206+
207+
// swap DB. No locks!
208+
func (m *Miniredis) swapDB(i, j int) bool {
209+
db1 := m.db(i)
210+
db2 := m.db(j)
211+
212+
db1.id = j
213+
db2.id = i
214+
215+
m.dbs[i] = db2
216+
m.dbs[j] = db1
217+
218+
return true
219+
}
220+
200221
// Addr returns '127.0.0.1:12345'. Can be given to a Dial(). See also Host()
201222
// and Port(), which return the same things.
202223
func (m *Miniredis) Addr() string {

0 commit comments

Comments
 (0)