2014-08-14 11:24:41 +04:00
|
|
|
package ledis
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2014-10-20 18:36:16 +04:00
|
|
|
"github.com/siddontang/ledisdb/store"
|
2014-08-25 18:25:10 +04:00
|
|
|
"regexp"
|
2014-08-14 11:24:41 +04:00
|
|
|
)
|
|
|
|
|
|
|
|
var errDataType = errors.New("error data type")
|
|
|
|
var errMetaKey = errors.New("error meta key")
|
|
|
|
|
2015-03-02 06:10:54 +03:00
|
|
|
//fif inclusive is true, scan range [cursor, inf) else (cursor, inf)
|
|
|
|
func (db *DB) Scan(dataType DataType, cursor []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
|
|
storeDataType, err := getDataStoreType(dataType)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return db.scanGeneric(storeDataType, cursor, count, inclusive, match, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
//if inclusive is true, revscan range (-inf, cursor] else (inf, cursor)
|
|
|
|
func (db *DB) RevScan(dataType DataType, cursor []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
|
|
storeDataType, err := getDataStoreType(dataType)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return db.scanGeneric(storeDataType, cursor, count, inclusive, match, true)
|
2014-10-20 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2015-03-02 06:10:54 +03:00
|
|
|
func getDataStoreType(dataType DataType) (byte, error) {
|
|
|
|
var storeDataType byte
|
|
|
|
switch dataType {
|
|
|
|
case KV:
|
|
|
|
storeDataType = KVType
|
|
|
|
case LIST:
|
|
|
|
storeDataType = LMetaType
|
|
|
|
case HASH:
|
|
|
|
storeDataType = HSizeType
|
|
|
|
case SET:
|
|
|
|
storeDataType = SSizeType
|
|
|
|
case ZSET:
|
|
|
|
storeDataType = ZSizeType
|
|
|
|
default:
|
|
|
|
return 0, errDataType
|
|
|
|
}
|
|
|
|
return storeDataType, nil
|
2014-10-20 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2015-03-02 06:10:54 +03:00
|
|
|
func (db *DB) scanGeneric(storeDataType byte, key []byte, count int,
|
2014-10-20 18:36:16 +04:00
|
|
|
inclusive bool, match string, reverse bool) ([][]byte, error) {
|
2014-08-14 11:24:41 +04:00
|
|
|
var minKey, maxKey []byte
|
|
|
|
var err error
|
2014-08-25 18:25:10 +04:00
|
|
|
var r *regexp.Regexp
|
|
|
|
|
|
|
|
if len(match) > 0 {
|
|
|
|
if r, err = regexp.Compile(match); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-20 18:36:16 +04:00
|
|
|
tp := store.RangeOpen
|
|
|
|
|
|
|
|
if !reverse {
|
2015-03-02 06:10:54 +03:00
|
|
|
if minKey, err = db.encodeScanMinKey(storeDataType, key); err != nil {
|
2014-08-14 11:24:41 +04:00
|
|
|
return nil, err
|
|
|
|
}
|
2015-03-02 06:10:54 +03:00
|
|
|
if maxKey, err = db.encodeScanMaxKey(storeDataType, nil); err != nil {
|
2014-08-14 11:24:41 +04:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2014-10-20 18:36:16 +04:00
|
|
|
if inclusive {
|
|
|
|
tp = store.RangeROpen
|
|
|
|
}
|
2014-08-14 11:24:41 +04:00
|
|
|
} else {
|
2015-03-02 06:10:54 +03:00
|
|
|
if minKey, err = db.encodeScanMinKey(storeDataType, nil); err != nil {
|
2014-10-20 18:36:16 +04:00
|
|
|
return nil, err
|
|
|
|
}
|
2015-03-02 06:10:54 +03:00
|
|
|
if maxKey, err = db.encodeScanMaxKey(storeDataType, key); err != nil {
|
2014-08-14 11:24:41 +04:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2014-10-20 18:36:16 +04:00
|
|
|
if inclusive {
|
|
|
|
tp = store.RangeLOpen
|
|
|
|
}
|
2014-08-14 11:24:41 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if count <= 0 {
|
|
|
|
count = defaultScanCount
|
|
|
|
}
|
|
|
|
|
2014-10-20 18:36:16 +04:00
|
|
|
var it *store.RangeLimitIterator
|
|
|
|
if !reverse {
|
|
|
|
it = db.bucket.RangeIterator(minKey, maxKey, tp)
|
|
|
|
} else {
|
|
|
|
it = db.bucket.RevRangeIterator(minKey, maxKey, tp)
|
2014-08-14 11:24:41 +04:00
|
|
|
}
|
|
|
|
|
2014-10-20 18:36:16 +04:00
|
|
|
v := make([][]byte, 0, count)
|
|
|
|
|
|
|
|
for i := 0; it.Valid() && i < count; it.Next() {
|
2015-03-02 06:10:54 +03:00
|
|
|
if k, err := db.decodeScanKey(storeDataType, it.Key()); err != nil {
|
2014-08-14 11:24:41 +04:00
|
|
|
continue
|
2014-08-25 18:25:10 +04:00
|
|
|
} else if r != nil && !r.Match(k) {
|
|
|
|
continue
|
2014-08-14 11:24:41 +04:00
|
|
|
} else {
|
|
|
|
v = append(v, k)
|
2014-08-25 18:25:10 +04:00
|
|
|
i++
|
2014-08-14 11:24:41 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
it.Close()
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
|
2015-03-02 06:10:54 +03:00
|
|
|
func (db *DB) encodeScanMinKey(storeDataType byte, key []byte) ([]byte, error) {
|
2014-10-20 18:36:16 +04:00
|
|
|
if len(key) == 0 {
|
2015-03-02 06:10:54 +03:00
|
|
|
return db.encodeScanKey(storeDataType, nil)
|
2014-10-20 18:36:16 +04:00
|
|
|
} else {
|
|
|
|
if err := checkKeySize(key); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-03-02 06:10:54 +03:00
|
|
|
return db.encodeScanKey(storeDataType, key)
|
2014-10-20 18:36:16 +04:00
|
|
|
}
|
2014-08-14 11:24:41 +04:00
|
|
|
}
|
|
|
|
|
2015-03-02 06:10:54 +03:00
|
|
|
func (db *DB) encodeScanMaxKey(storeDataType byte, key []byte) ([]byte, error) {
|
2014-10-20 18:36:16 +04:00
|
|
|
if len(key) > 0 {
|
|
|
|
if err := checkKeySize(key); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2015-03-02 06:10:54 +03:00
|
|
|
return db.encodeScanKey(storeDataType, key)
|
2014-10-20 18:36:16 +04:00
|
|
|
}
|
|
|
|
|
2015-03-02 06:10:54 +03:00
|
|
|
k, err := db.encodeScanKey(storeDataType, nil)
|
2014-08-14 15:05:17 +04:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-03-02 06:10:54 +03:00
|
|
|
k[len(k)-1] = storeDataType + 1
|
2014-08-14 11:24:41 +04:00
|
|
|
return k, nil
|
|
|
|
}
|
|
|
|
|
2015-03-02 06:10:54 +03:00
|
|
|
func (db *DB) encodeScanKey(storeDataType byte, key []byte) ([]byte, error) {
|
|
|
|
switch storeDataType {
|
2014-08-14 11:24:41 +04:00
|
|
|
case KVType:
|
|
|
|
return db.encodeKVKey(key), nil
|
|
|
|
case LMetaType:
|
|
|
|
return db.lEncodeMetaKey(key), nil
|
|
|
|
case HSizeType:
|
|
|
|
return db.hEncodeSizeKey(key), nil
|
|
|
|
case ZSizeType:
|
|
|
|
return db.zEncodeSizeKey(key), nil
|
|
|
|
case BitMetaType:
|
|
|
|
return db.bEncodeMetaKey(key), nil
|
2014-08-16 12:55:36 +04:00
|
|
|
case SSizeType:
|
|
|
|
return db.sEncodeSizeKey(key), nil
|
2014-08-14 11:24:41 +04:00
|
|
|
default:
|
2014-08-14 15:05:17 +04:00
|
|
|
return nil, errDataType
|
2014-08-14 11:24:41 +04:00
|
|
|
}
|
|
|
|
}
|
2015-03-02 06:10:54 +03:00
|
|
|
func (db *DB) decodeScanKey(storeDataType byte, ek []byte) ([]byte, error) {
|
|
|
|
if len(ek) < 2 || ek[0] != db.index || ek[1] != storeDataType {
|
2014-08-14 11:24:41 +04:00
|
|
|
return nil, errMetaKey
|
|
|
|
}
|
|
|
|
return ek[2:], nil
|
|
|
|
}
|