Skip to content

Commit

Permalink
Add keyonly support for seek (#7419)
Browse files Browse the repository at this point in the history
  • Loading branch information
shafreeck authored and ngaut committed Aug 30, 2018
1 parent 5823fb5 commit b4fdaf3
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 12 deletions.
2 changes: 2 additions & 0 deletions kv/kv.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ const (
// BypassLatch option tells 2PC commit to bypass latches, it would be true when the
// transaction is not conflict-retryable, for example: 'select for update', 'load data'.
BypassLatch
// KeyOnly retrieve only keys, it can be used in scan now.
KeyOnly
)

// Priority value for transaction priority.
Expand Down
16 changes: 16 additions & 0 deletions store/tikv/lock_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,22 @@ func (s *testLockSuite) TestScanLockResolveWithSeek(c *C) {
}
}

func (s *testLockSuite) TestScanLockResolveWithSeekKeyOnly(c *C) {
s.putAlphabets(c)
s.prepareAlphabetLocks(c)

txn, err := s.store.Begin()
c.Assert(err, IsNil)
txn.SetOption(kv.KeyOnly, true)
iter, err := txn.Seek([]byte("a"))
c.Assert(err, IsNil)
for ch := byte('a'); ch <= byte('z'); ch++ {
c.Assert(iter.Valid(), IsTrue)
c.Assert([]byte(iter.Key()), BytesEquals, []byte{ch})
c.Assert(iter.Next(), IsNil)
}
}

func (s *testLockSuite) TestScanLockResolveWithBatchGet(c *C) {
s.putAlphabets(c)
s.prepareAlphabetLocks(c)
Expand Down
30 changes: 18 additions & 12 deletions store/tikv/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,22 @@ func (s *Scanner) Next() error {
continue
}
}
if err := s.resolveCurrentLock(bo); err != nil {
s.Close()
return errors.Trace(err)
}
if len(s.Value()) == 0 {
// nil stands for NotExist, go to next KV pair.
continue

current := s.cache[s.idx]
// Try to resolve the lock
if current.GetError() != nil {
// 'current' would be modified if the lock being resolved
if err := s.resolveCurrentLock(bo, current); err != nil {
s.Close()
return errors.Trace(err)
}

// The check here does not violate the KeyOnly semantic, because current's value
// is filled by resolveCurrentLock which fetches the value by snapshot.get, so an empty
// value stands for NotExist
if len(current.Value) == 0 {
continue
}
}
return nil
}
Expand All @@ -115,11 +124,7 @@ func (s *Scanner) startTS() uint64 {
return s.snapshot.version.Ver
}

func (s *Scanner) resolveCurrentLock(bo *Backoffer) error {
current := s.cache[s.idx]
if current.GetError() == nil {
return nil
}
func (s *Scanner) resolveCurrentLock(bo *Backoffer, current *pb.KvPair) error {
val, err := s.snapshot.get(bo, kv.Key(current.Key))
if err != nil {
return errors.Trace(err)
Expand All @@ -144,6 +149,7 @@ func (s *Scanner) getData(bo *Backoffer) error {
StartKey: s.nextStartKey,
Limit: uint32(s.batchSize),
Version: s.startTS(),
KeyOnly: s.snapshot.keyOnly,
},
Context: pb.Context{
Priority: s.snapshot.priority,
Expand Down
37 changes: 37 additions & 0 deletions store/tikv/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"time"

. "github.com/pingcap/check"
"github.com/pingcap/tidb/kv"
"golang.org/x/net/context"
)

Expand Down Expand Up @@ -91,5 +92,41 @@ func (s *testScanSuite) TestSeek(c *C) {
}
scan.Next()
c.Assert(scan.Valid(), IsFalse)

txn3 := s.beginTxn(c)
txn3.SetOption(kv.KeyOnly, true)
scan, err = txn3.Seek(encodeKey(s.prefix, ""))
c.Assert(err, IsNil)

for i := 0; i < rowNum; i++ {
k := scan.Key()
c.Assert([]byte(k), BytesEquals, encodeKey(s.prefix, s08d("key", i)))
// Because newScan return first item without calling scan.Next() just like go-hbase,
// for-loop count will decrease 1.
if i < rowNum-1 {
scan.Next()
}
}
scan.Next()
c.Assert(scan.Valid(), IsFalse)

// Restore KeyOnly to false
txn3.SetOption(kv.KeyOnly, false)
scan, err = txn3.Seek(encodeKey(s.prefix, ""))
c.Assert(err, IsNil)

for i := 0; i < rowNum; i++ {
k := scan.Key()
c.Assert([]byte(k), BytesEquals, encodeKey(s.prefix, s08d("key", i)))
v := scan.Value()
c.Assert(v, BytesEquals, valueBytes(i))
// Because newScan return first item without calling scan.Next() just like go-hbase,
// for-loop count will decrease 1.
if i < rowNum-1 {
scan.Next()
}
}
scan.Next()
c.Assert(scan.Valid(), IsFalse)
}
}
1 change: 1 addition & 0 deletions store/tikv/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type tikvSnapshot struct {
priority pb.CommandPri
notFillCache bool
syncLog bool
keyOnly bool
vars *kv.Variables
}

Expand Down
2 changes: 2 additions & 0 deletions store/tikv/txn.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ func (txn *tikvTxn) SetOption(opt kv.Option, val interface{}) {
txn.snapshot.notFillCache = val.(bool)
case kv.SyncLog:
txn.snapshot.syncLog = val.(bool)
case kv.KeyOnly:
txn.snapshot.keyOnly = val.(bool)
}
}

Expand Down

0 comments on commit b4fdaf3

Please sign in to comment.