From 10c56cede39fec28a4daab451ee35a982edc12d5 Mon Sep 17 00:00:00 2001 From: Vladimir Mihailenco Date: Tue, 3 Jan 2017 12:44:06 +0200 Subject: [PATCH] Remove Scanner in favor of ScanCmd. --- command.go | 15 ++++++++++++--- commands.go | 44 ++++++++++++++++---------------------------- iterator.go | 43 ++++++++++++++++--------------------------- 3 files changed, 44 insertions(+), 58 deletions(-) diff --git a/command.go b/command.go index 98098131..f8417079 100644 --- a/command.go +++ b/command.go @@ -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 { diff --git a/commands.go b/commands.go index 5bbcc104..2e50cda1 100644 --- a/commands.go +++ b/commands.go @@ -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 } //------------------------------------------------------------------------------ diff --git a/iterator.go b/iterator.go index 4f753608..5d4bedfe 100644 --- a/iterator.go +++ b/iterator.go @@ -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 + mu sync.Mutex // protects Scanner and pos + 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