Merge pull request #470 from go-redis/fix/remove-scanner

Remove Scanner in favor of ScanCmd.
This commit is contained in:
Vladimir Mihailenco 2017-01-03 13:06:30 +02:00 committed by GitHub
commit b9cc17bae0
3 changed files with 44 additions and 58 deletions

View File

@ -683,12 +683,14 @@ type ScanCmd struct {
page []string page []string
cursor uint64 cursor uint64
process func(cmd Cmder) error
} }
func NewScanCmd(args ...interface{}) *ScanCmd { func NewScanCmd(process func(cmd Cmder) error, args ...interface{}) *ScanCmd {
cmd := newBaseCmd(args)
return &ScanCmd{ return &ScanCmd{
baseCmd: cmd, baseCmd: newBaseCmd(args),
process: process,
} }
} }
@ -709,6 +711,13 @@ func (cmd *ScanCmd) readReply(cn *pool.Conn) error {
return cmd.err return cmd.err
} }
// Iterator creates a new ScanIterator.
func (cmd *ScanCmd) Iterator() *ScanIterator {
return &ScanIterator{
cmd: cmd,
}
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
type ClusterNode struct { type ClusterNode struct {

View File

@ -71,10 +71,10 @@ type Cmdable interface {
SortInterfaces(key string, sort Sort) *SliceCmd SortInterfaces(key string, sort Sort) *SliceCmd
TTL(key string) *DurationCmd TTL(key string) *DurationCmd
Type(key string) *StatusCmd Type(key string) *StatusCmd
Scan(cursor uint64, match string, count int64) Scanner Scan(cursor uint64, match string, count int64) *ScanCmd
SScan(key string, cursor uint64, match string, count int64) Scanner SScan(key string, cursor uint64, match string, count int64) *ScanCmd
HScan(key string, cursor uint64, match string, count int64) Scanner HScan(key string, cursor uint64, match string, count int64) *ScanCmd
ZScan(key string, cursor uint64, match string, count int64) Scanner ZScan(key string, cursor uint64, match string, count int64) *ScanCmd
Append(key, value string) *IntCmd Append(key, value string) *IntCmd
BitCount(key string, bitCount *BitCount) *IntCmd BitCount(key string, bitCount *BitCount) *IntCmd
BitOpAnd(destKey string, keys ...string) *IntCmd BitOpAnd(destKey string, keys ...string) *IntCmd
@ -515,7 +515,7 @@ func (c *cmdable) Type(key string) *StatusCmd {
return cmd return cmd
} }
func (c *cmdable) Scan(cursor uint64, match string, count int64) Scanner { func (c *cmdable) Scan(cursor uint64, match string, count int64) *ScanCmd {
args := []interface{}{"scan", cursor} args := []interface{}{"scan", cursor}
if match != "" { if match != "" {
args = append(args, "match", match) args = append(args, "match", match)
@ -523,15 +523,12 @@ func (c *cmdable) Scan(cursor uint64, match string, count int64) Scanner {
if count > 0 { if count > 0 {
args = append(args, "count", count) args = append(args, "count", count)
} }
cmd := NewScanCmd(args...) cmd := NewScanCmd(c.process, args...)
c.process(cmd) c.process(cmd)
return Scanner{ return cmd
client: c,
ScanCmd: cmd,
}
} }
func (c *cmdable) SScan(key string, cursor uint64, match string, count int64) Scanner { func (c *cmdable) SScan(key string, cursor uint64, match string, count int64) *ScanCmd {
args := []interface{}{"sscan", key, cursor} args := []interface{}{"sscan", key, cursor}
if match != "" { if match != "" {
args = append(args, "match", match) args = append(args, "match", match)
@ -539,15 +536,12 @@ func (c *cmdable) SScan(key string, cursor uint64, match string, count int64) Sc
if count > 0 { if count > 0 {
args = append(args, "count", count) args = append(args, "count", count)
} }
cmd := NewScanCmd(args...) cmd := NewScanCmd(c.process, args...)
c.process(cmd) c.process(cmd)
return Scanner{ return cmd
client: c,
ScanCmd: cmd,
}
} }
func (c *cmdable) HScan(key string, cursor uint64, match string, count int64) Scanner { func (c *cmdable) HScan(key string, cursor uint64, match string, count int64) *ScanCmd {
args := []interface{}{"hscan", key, cursor} args := []interface{}{"hscan", key, cursor}
if match != "" { if match != "" {
args = append(args, "match", match) args = append(args, "match", match)
@ -555,15 +549,12 @@ func (c *cmdable) HScan(key string, cursor uint64, match string, count int64) Sc
if count > 0 { if count > 0 {
args = append(args, "count", count) args = append(args, "count", count)
} }
cmd := NewScanCmd(args...) cmd := NewScanCmd(c.process, args...)
c.process(cmd) c.process(cmd)
return Scanner{ return cmd
client: c,
ScanCmd: cmd,
}
} }
func (c *cmdable) ZScan(key string, cursor uint64, match string, count int64) Scanner { func (c *cmdable) ZScan(key string, cursor uint64, match string, count int64) *ScanCmd {
args := []interface{}{"zscan", key, cursor} args := []interface{}{"zscan", key, cursor}
if match != "" { if match != "" {
args = append(args, "match", match) args = append(args, "match", match)
@ -571,12 +562,9 @@ func (c *cmdable) ZScan(key string, cursor uint64, match string, count int64) Sc
if count > 0 { if count > 0 {
args = append(args, "count", count) args = append(args, "count", count)
} }
cmd := NewScanCmd(args...) cmd := NewScanCmd(c.process, args...)
c.process(cmd) c.process(cmd)
return Scanner{ return cmd
client: c,
ScanCmd: cmd,
}
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View File

@ -2,30 +2,18 @@ package redis
import "sync" import "sync"
type Scanner struct {
client *cmdable
*ScanCmd
}
// Iterator creates a new ScanIterator.
func (s Scanner) Iterator() *ScanIterator {
return &ScanIterator{
Scanner: s,
}
}
// ScanIterator is used to incrementally iterate over a collection of elements. // ScanIterator is used to incrementally iterate over a collection of elements.
// It's safe for concurrent use by multiple goroutines. // It's safe for concurrent use by multiple goroutines.
type ScanIterator struct { type ScanIterator struct {
mu sync.Mutex // protects Scanner and pos mu sync.Mutex // protects Scanner and pos
Scanner cmd *ScanCmd
pos int pos int
} }
// Err returns the last iterator error, if any. // Err returns the last iterator error, if any.
func (it *ScanIterator) Err() error { func (it *ScanIterator) Err() error {
it.mu.Lock() it.mu.Lock()
err := it.ScanCmd.Err() err := it.cmd.Err()
it.mu.Unlock() it.mu.Unlock()
return err return err
} }
@ -36,37 +24,38 @@ func (it *ScanIterator) Next() bool {
defer it.mu.Unlock() defer it.mu.Unlock()
// Instantly return on errors. // Instantly return on errors.
if it.ScanCmd.Err() != nil { if it.cmd.Err() != nil {
return false return false
} }
// Advance cursor, check if we are still within range. // Advance cursor, check if we are still within range.
if it.pos < len(it.ScanCmd.page) { if it.pos < len(it.cmd.page) {
it.pos++ it.pos++
return true return true
} }
for { for {
// Return if there is no more data to fetch. // Return if there is no more data to fetch.
if it.ScanCmd.cursor == 0 { if it.cmd.cursor == 0 {
return false return false
} }
// Fetch next page. // Fetch next page.
if it.ScanCmd._args[0] == "scan" { if it.cmd._args[0] == "scan" {
it.ScanCmd._args[1] = it.ScanCmd.cursor it.cmd._args[1] = it.cmd.cursor
} else { } else {
it.ScanCmd._args[2] = it.ScanCmd.cursor it.cmd._args[2] = it.cmd.cursor
} }
it.client.process(it.ScanCmd)
if it.ScanCmd.Err() != nil { err := it.cmd.process(it.cmd)
if err != nil {
return false return false
} }
it.pos = 1 it.pos = 1
// Redis can occasionally return empty page // Redis can occasionally return empty page.
if len(it.ScanCmd.page) > 0 { if len(it.cmd.page) > 0 {
return true return true
} }
} }
@ -76,8 +65,8 @@ func (it *ScanIterator) Next() bool {
func (it *ScanIterator) Val() string { func (it *ScanIterator) Val() string {
var v string var v string
it.mu.Lock() it.mu.Lock()
if it.ScanCmd.Err() == nil && it.pos > 0 && it.pos <= len(it.ScanCmd.page) { if it.cmd.Err() == nil && it.pos > 0 && it.pos <= len(it.cmd.page) {
v = it.ScanCmd.page[it.pos-1] v = it.cmd.page[it.pos-1]
} }
it.mu.Unlock() it.mu.Unlock()
return v return v