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
cursor uint64
process func(cmd Cmder) error
}
func NewScanCmd(args ...interface{}) *ScanCmd {
cmd := newBaseCmd(args)
func NewScanCmd(process func(cmd Cmder) error, args ...interface{}) *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
}
// Iterator creates a new ScanIterator.
func (cmd *ScanCmd) Iterator() *ScanIterator {
return &ScanIterator{
cmd: cmd,
}
}
//------------------------------------------------------------------------------
type ClusterNode struct {

View File

@ -71,10 +71,10 @@ type Cmdable interface {
SortInterfaces(key string, sort Sort) *SliceCmd
TTL(key string) *DurationCmd
Type(key string) *StatusCmd
Scan(cursor uint64, match string, count int64) Scanner
SScan(key string, cursor uint64, match string, count int64) Scanner
HScan(key string, cursor uint64, match string, count int64) Scanner
ZScan(key string, cursor uint64, match string, count int64) Scanner
Scan(cursor uint64, match string, count int64) *ScanCmd
SScan(key string, cursor uint64, match string, count int64) *ScanCmd
HScan(key string, cursor uint64, match string, count int64) *ScanCmd
ZScan(key string, cursor uint64, match string, count int64) *ScanCmd
Append(key, value string) *IntCmd
BitCount(key string, bitCount *BitCount) *IntCmd
BitOpAnd(destKey string, keys ...string) *IntCmd
@ -515,7 +515,7 @@ func (c *cmdable) Type(key string) *StatusCmd {
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}
if match != "" {
args = append(args, "match", match)
@ -523,15 +523,12 @@ func (c *cmdable) Scan(cursor uint64, match string, count int64) Scanner {
if count > 0 {
args = append(args, "count", count)
}
cmd := NewScanCmd(args...)
cmd := NewScanCmd(c.process, args...)
c.process(cmd)
return Scanner{
client: c,
ScanCmd: cmd,
}
return 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}
if 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 {
args = append(args, "count", count)
}
cmd := NewScanCmd(args...)
cmd := NewScanCmd(c.process, args...)
c.process(cmd)
return Scanner{
client: c,
ScanCmd: cmd,
}
return 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}
if 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 {
args = append(args, "count", count)
}
cmd := NewScanCmd(args...)
cmd := NewScanCmd(c.process, args...)
c.process(cmd)
return Scanner{
client: c,
ScanCmd: cmd,
}
return 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}
if 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 {
args = append(args, "count", count)
}
cmd := NewScanCmd(args...)
cmd := NewScanCmd(c.process, args...)
c.process(cmd)
return Scanner{
client: c,
ScanCmd: cmd,
}
return cmd
}
//------------------------------------------------------------------------------

View File

@ -2,30 +2,18 @@ package redis
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.
// It's safe for concurrent use by multiple goroutines.
type ScanIterator struct {
mu sync.Mutex // protects Scanner and pos
Scanner
cmd *ScanCmd
pos int
}
// Err returns the last iterator error, if any.
func (it *ScanIterator) Err() error {
it.mu.Lock()
err := it.ScanCmd.Err()
err := it.cmd.Err()
it.mu.Unlock()
return err
}
@ -36,37 +24,38 @@ func (it *ScanIterator) Next() bool {
defer it.mu.Unlock()
// Instantly return on errors.
if it.ScanCmd.Err() != nil {
if it.cmd.Err() != nil {
return false
}
// 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++
return true
}
for {
// Return if there is no more data to fetch.
if it.ScanCmd.cursor == 0 {
if it.cmd.cursor == 0 {
return false
}
// Fetch next page.
if it.ScanCmd._args[0] == "scan" {
it.ScanCmd._args[1] = it.ScanCmd.cursor
if it.cmd._args[0] == "scan" {
it.cmd._args[1] = it.cmd.cursor
} 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
}
it.pos = 1
// Redis can occasionally return empty page
if len(it.ScanCmd.page) > 0 {
// Redis can occasionally return empty page.
if len(it.cmd.page) > 0 {
return true
}
}
@ -76,8 +65,8 @@ func (it *ScanIterator) Next() bool {
func (it *ScanIterator) Val() string {
var v string
it.mu.Lock()
if it.ScanCmd.Err() == nil && it.pos > 0 && it.pos <= len(it.ScanCmd.page) {
v = it.ScanCmd.page[it.pos-1]
if it.cmd.Err() == nil && it.pos > 0 && it.pos <= len(it.cmd.page) {
v = it.cmd.page[it.pos-1]
}
it.mu.Unlock()
return v