2016-04-13 11:52:47 +03:00
|
|
|
package redis
|
|
|
|
|
2019-06-04 13:30:47 +03:00
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
)
|
2016-04-13 11:52:47 +03:00
|
|
|
|
|
|
|
// ScanIterator is used to incrementally iterate over a collection of elements.
|
|
|
|
// It's safe for concurrent use by multiple goroutines.
|
|
|
|
type ScanIterator struct {
|
2017-01-03 13:44:06 +03:00
|
|
|
mu sync.Mutex // protects Scanner and pos
|
|
|
|
cmd *ScanCmd
|
2016-04-13 11:52:47 +03:00
|
|
|
pos int
|
|
|
|
}
|
|
|
|
|
|
|
|
// Err returns the last iterator error, if any.
|
|
|
|
func (it *ScanIterator) Err() error {
|
|
|
|
it.mu.Lock()
|
2017-01-03 13:44:06 +03:00
|
|
|
err := it.cmd.Err()
|
2016-04-13 11:52:47 +03:00
|
|
|
it.mu.Unlock()
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next advances the cursor and returns true if more values can be read.
|
|
|
|
func (it *ScanIterator) Next() bool {
|
|
|
|
it.mu.Lock()
|
|
|
|
defer it.mu.Unlock()
|
|
|
|
|
|
|
|
// Instantly return on errors.
|
2017-01-03 13:44:06 +03:00
|
|
|
if it.cmd.Err() != nil {
|
2016-04-13 11:52:47 +03:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Advance cursor, check if we are still within range.
|
2017-01-03 13:44:06 +03:00
|
|
|
if it.pos < len(it.cmd.page) {
|
2016-04-13 11:52:47 +03:00
|
|
|
it.pos++
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2016-09-08 16:07:49 +03:00
|
|
|
for {
|
2016-09-08 16:40:45 +03:00
|
|
|
// Return if there is no more data to fetch.
|
2017-01-03 13:44:06 +03:00
|
|
|
if it.cmd.cursor == 0 {
|
2016-09-08 16:07:49 +03:00
|
|
|
return false
|
|
|
|
}
|
2016-04-13 11:52:47 +03:00
|
|
|
|
2016-09-08 16:07:49 +03:00
|
|
|
// Fetch next page.
|
2019-08-24 11:55:13 +03:00
|
|
|
if it.cmd.args[0] == "scan" {
|
|
|
|
it.cmd.args[1] = it.cmd.cursor
|
2016-09-08 16:07:49 +03:00
|
|
|
} else {
|
2019-08-24 11:55:13 +03:00
|
|
|
it.cmd.args[2] = it.cmd.cursor
|
2016-09-08 16:07:49 +03:00
|
|
|
}
|
2017-01-03 13:44:06 +03:00
|
|
|
|
|
|
|
err := it.cmd.process(it.cmd)
|
|
|
|
if err != nil {
|
2016-09-08 16:07:49 +03:00
|
|
|
return false
|
|
|
|
}
|
2016-04-13 11:52:47 +03:00
|
|
|
|
2016-09-08 16:07:49 +03:00
|
|
|
it.pos = 1
|
2016-09-08 16:40:45 +03:00
|
|
|
|
2017-01-03 13:44:06 +03:00
|
|
|
// Redis can occasionally return empty page.
|
|
|
|
if len(it.cmd.page) > 0 {
|
2016-09-08 16:07:49 +03:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
2016-04-13 11:52:47 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Val returns the key/field at the current cursor position.
|
|
|
|
func (it *ScanIterator) Val() string {
|
|
|
|
var v string
|
|
|
|
it.mu.Lock()
|
2017-01-03 13:44:06 +03:00
|
|
|
if it.cmd.Err() == nil && it.pos > 0 && it.pos <= len(it.cmd.page) {
|
|
|
|
v = it.cmd.page[it.pos-1]
|
2016-04-13 11:52:47 +03:00
|
|
|
}
|
|
|
|
it.mu.Unlock()
|
|
|
|
return v
|
|
|
|
}
|