mirror of https://github.com/tikv/client-go.git
156 lines
4.8 KiB
Go
156 lines
4.8 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,
|
|
// 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/union_store.go
|
|
//
|
|
|
|
// Copyright 2021 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,
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package unionstore
|
|
|
|
import (
|
|
"context"
|
|
|
|
tikverr "github.com/tikv/client-go/v2/error"
|
|
"github.com/tikv/client-go/v2/kv"
|
|
)
|
|
|
|
// Iterator is the interface for a iterator on KV store.
|
|
type Iterator interface {
|
|
Valid() bool
|
|
Key() []byte
|
|
Value() []byte
|
|
Next() error
|
|
Close()
|
|
}
|
|
|
|
// Getter is the interface for the Get method.
|
|
type Getter interface {
|
|
// Get gets the value for key k from kv store.
|
|
// If corresponding kv pair does not exist, it returns nil and ErrNotExist.
|
|
Get(k []byte) ([]byte, error)
|
|
}
|
|
|
|
// uSnapshot defines the interface for the snapshot fetched from KV store.
|
|
type uSnapshot interface {
|
|
// Get gets the value for key k from kv store.
|
|
// If corresponding kv pair does not exist, it returns nil and ErrNotExist.
|
|
Get(ctx context.Context, k []byte) ([]byte, error)
|
|
// 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.
|
|
Iter(k []byte, upperBound []byte) (Iterator, error)
|
|
|
|
// 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
|
|
IterReverse(k []byte) (Iterator, error)
|
|
}
|
|
|
|
// KVUnionStore is an in-memory Store which contains a buffer for write and a
|
|
// snapshot for read.
|
|
type KVUnionStore struct {
|
|
memBuffer *MemDB
|
|
snapshot uSnapshot
|
|
}
|
|
|
|
// NewUnionStore builds a new unionStore.
|
|
func NewUnionStore(snapshot uSnapshot) *KVUnionStore {
|
|
return &KVUnionStore{
|
|
snapshot: snapshot,
|
|
memBuffer: newMemDB(),
|
|
}
|
|
}
|
|
|
|
// GetMemBuffer return the MemBuffer binding to this unionStore.
|
|
func (us *KVUnionStore) GetMemBuffer() *MemDB {
|
|
return us.memBuffer
|
|
}
|
|
|
|
// Get implements the Retriever interface.
|
|
func (us *KVUnionStore) Get(ctx context.Context, k []byte) ([]byte, error) {
|
|
v, err := us.memBuffer.Get(k)
|
|
if tikverr.IsErrNotFound(err) {
|
|
v, err = us.snapshot.Get(ctx, k)
|
|
}
|
|
if err != nil {
|
|
return v, err
|
|
}
|
|
if len(v) == 0 {
|
|
return nil, tikverr.ErrNotExist
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
// Iter implements the Retriever interface.
|
|
func (us *KVUnionStore) Iter(k, upperBound []byte) (Iterator, error) {
|
|
bufferIt, err := us.memBuffer.Iter(k, upperBound)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
retrieverIt, err := us.snapshot.Iter(k, upperBound)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewUnionIter(bufferIt, retrieverIt, false)
|
|
}
|
|
|
|
// IterReverse implements the Retriever interface.
|
|
func (us *KVUnionStore) IterReverse(k []byte) (Iterator, error) {
|
|
bufferIt, err := us.memBuffer.IterReverse(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
retrieverIt, err := us.snapshot.IterReverse(k)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return NewUnionIter(bufferIt, retrieverIt, true)
|
|
}
|
|
|
|
// HasPresumeKeyNotExists gets the key exist error info for the lazy check.
|
|
func (us *KVUnionStore) HasPresumeKeyNotExists(k []byte) bool {
|
|
flags, err := us.memBuffer.GetFlags(k)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
return flags.HasPresumeKeyNotExists()
|
|
}
|
|
|
|
// UnmarkPresumeKeyNotExists deletes the key exist error info for the lazy check.
|
|
func (us *KVUnionStore) UnmarkPresumeKeyNotExists(k []byte) {
|
|
us.memBuffer.UpdateFlags(k, kv.DelPresumeKeyNotExists)
|
|
}
|
|
|
|
// SetEntrySizeLimit sets the size limit for each entry and total buffer.
|
|
func (us *KVUnionStore) SetEntrySizeLimit(entryLimit, bufferLimit uint64) {
|
|
us.memBuffer.entrySizeLimit = entryLimit
|
|
us.memBuffer.bufferSizeLimit = bufferLimit
|
|
}
|