mirror of https://github.com/tikv/client-go.git
251 lines
5.7 KiB
Go
251 lines
5.7 KiB
Go
// Copyright 2021 TiKV Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// NOTE: The code in this file is based on code from the
|
|
// TiDB project, licensed under the Apache License v 2.0
|
|
//
|
|
// https://github.com/pingcap/tidb/tree/cc5e161ac06827589c4966674597c137cc9e809c/store/tikv/unionstore/memdb_iterator.go
|
|
//
|
|
|
|
// Copyright 2020 PingCAP, Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package unionstore
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
"github.com/tikv/client-go/v2/kv"
|
|
)
|
|
|
|
// MemdbIterator is an Iterator with KeyFlags related functions.
|
|
type MemdbIterator struct {
|
|
db *MemDB
|
|
curr memdbNodeAddr
|
|
start []byte
|
|
end []byte
|
|
reverse bool
|
|
includeFlags bool
|
|
}
|
|
|
|
// Iter creates an Iterator positioned on the first entry that k <= entry's key.
|
|
// If such entry is not found, it returns an invalid Iterator with no error.
|
|
// It yields only keys that < upperBound. If upperBound is nil, it means the upperBound is unbounded.
|
|
// The Iterator must be Closed after use.
|
|
func (db *MemDB) Iter(k []byte, upperBound []byte) (Iterator, error) {
|
|
i := &MemdbIterator{
|
|
db: db,
|
|
start: k,
|
|
end: upperBound,
|
|
}
|
|
i.init()
|
|
return i, nil
|
|
}
|
|
|
|
// IterReverse creates a reversed Iterator positioned on the first entry which key is less than k.
|
|
// The returned iterator will iterate from greater key to smaller key.
|
|
// If k is nil, the returned iterator will be positioned at the last key.
|
|
// TODO: Add lower bound limit
|
|
func (db *MemDB) IterReverse(k []byte) (Iterator, error) {
|
|
i := &MemdbIterator{
|
|
db: db,
|
|
end: k,
|
|
reverse: true,
|
|
}
|
|
i.init()
|
|
return i, nil
|
|
}
|
|
|
|
// IterWithFlags returns a MemdbIterator.
|
|
func (db *MemDB) IterWithFlags(k []byte, upperBound []byte) *MemdbIterator {
|
|
i := &MemdbIterator{
|
|
db: db,
|
|
start: k,
|
|
end: upperBound,
|
|
includeFlags: true,
|
|
}
|
|
i.init()
|
|
return i
|
|
}
|
|
|
|
// IterReverseWithFlags returns a reversed MemdbIterator.
|
|
func (db *MemDB) IterReverseWithFlags(k []byte) *MemdbIterator {
|
|
i := &MemdbIterator{
|
|
db: db,
|
|
end: k,
|
|
reverse: true,
|
|
includeFlags: true,
|
|
}
|
|
i.init()
|
|
return i
|
|
}
|
|
|
|
func (i *MemdbIterator) init() {
|
|
if i.reverse {
|
|
if len(i.end) == 0 {
|
|
i.seekToLast()
|
|
} else {
|
|
i.seek(i.end)
|
|
}
|
|
} else {
|
|
if len(i.start) == 0 {
|
|
i.seekToFirst()
|
|
} else {
|
|
i.seek(i.start)
|
|
}
|
|
}
|
|
|
|
if i.isFlagsOnly() && !i.includeFlags {
|
|
err := i.Next()
|
|
_ = err // memdbIterator will never fail
|
|
}
|
|
}
|
|
|
|
// Valid returns true if the current iterator is valid.
|
|
func (i *MemdbIterator) Valid() bool {
|
|
if !i.reverse {
|
|
return !i.curr.isNull() && (i.end == nil || bytes.Compare(i.Key(), i.end) < 0)
|
|
}
|
|
return !i.curr.isNull()
|
|
}
|
|
|
|
// Flags returns flags belong to current iterator.
|
|
func (i *MemdbIterator) Flags() kv.KeyFlags {
|
|
return i.curr.getKeyFlags()
|
|
}
|
|
|
|
// UpdateFlags updates and apply with flagsOp.
|
|
func (i *MemdbIterator) UpdateFlags(ops ...kv.FlagsOp) {
|
|
origin := i.curr.getKeyFlags()
|
|
n := kv.ApplyFlagsOps(origin, ops...)
|
|
i.curr.setKeyFlags(n)
|
|
}
|
|
|
|
// HasValue returns false if it is flags only.
|
|
func (i *MemdbIterator) HasValue() bool {
|
|
return !i.isFlagsOnly()
|
|
}
|
|
|
|
// Key returns current key.
|
|
func (i *MemdbIterator) Key() []byte {
|
|
return i.curr.getKey()
|
|
}
|
|
|
|
// Handle returns MemKeyHandle with the current position.
|
|
func (i *MemdbIterator) Handle() MemKeyHandle {
|
|
return MemKeyHandle{
|
|
idx: uint16(i.curr.addr.idx),
|
|
off: i.curr.addr.off,
|
|
}
|
|
}
|
|
|
|
// Value returns the value.
|
|
func (i *MemdbIterator) Value() []byte {
|
|
return i.db.vlog.getValue(i.curr.vptr)
|
|
}
|
|
|
|
// Next goes the next position.
|
|
func (i *MemdbIterator) Next() error {
|
|
for {
|
|
if i.reverse {
|
|
i.curr = i.db.predecessor(i.curr)
|
|
} else {
|
|
i.curr = i.db.successor(i.curr)
|
|
}
|
|
|
|
// We need to skip persistent flags only nodes.
|
|
if i.includeFlags || !i.isFlagsOnly() {
|
|
break
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Close closes the current iterator.
|
|
func (i *MemdbIterator) Close() {}
|
|
|
|
func (i *MemdbIterator) seekToFirst() {
|
|
y := memdbNodeAddr{nil, nullAddr}
|
|
x := i.db.getNode(i.db.root)
|
|
|
|
for !x.isNull() {
|
|
y = x
|
|
x = y.getLeft(i.db)
|
|
}
|
|
|
|
i.curr = y
|
|
}
|
|
|
|
func (i *MemdbIterator) seekToLast() {
|
|
y := memdbNodeAddr{nil, nullAddr}
|
|
x := i.db.getNode(i.db.root)
|
|
|
|
for !x.isNull() {
|
|
y = x
|
|
x = y.getRight(i.db)
|
|
}
|
|
|
|
i.curr = y
|
|
}
|
|
|
|
func (i *MemdbIterator) seek(key []byte) {
|
|
y := memdbNodeAddr{nil, nullAddr}
|
|
x := i.db.getNode(i.db.root)
|
|
|
|
var cmp int
|
|
for !x.isNull() {
|
|
y = x
|
|
cmp = bytes.Compare(key, y.getKey())
|
|
|
|
if cmp < 0 {
|
|
x = y.getLeft(i.db)
|
|
} else if cmp > 0 {
|
|
x = y.getRight(i.db)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
|
|
if !i.reverse {
|
|
if cmp > 0 {
|
|
// Move to next
|
|
i.curr = i.db.successor(y)
|
|
return
|
|
}
|
|
i.curr = y
|
|
return
|
|
}
|
|
|
|
if cmp <= 0 && !y.isNull() {
|
|
i.curr = i.db.predecessor(y)
|
|
return
|
|
}
|
|
i.curr = y
|
|
}
|
|
|
|
func (i *MemdbIterator) isFlagsOnly() bool {
|
|
return !i.curr.isNull() && i.curr.vptr.isNull()
|
|
}
|