mirror of
https://github.com/talent-plan/tinykv.git
synced 2024-12-27 13:20:24 +08:00
5e089a2cd1
Signed-off-by: Connor <zbk602423539@gmail.com> Co-authored-by: Nick Cameron <nrc@ncameron.org> Co-authored-by: linning <linningde25@gmail.com> Co-authored-by: YangKeao <keao.yang@yahoo.com> Co-authored-by: andylokandy <andylokandy@hotmail.com> Co-authored-by: Iosmanthus Teng <myosmanthustree@gmail.com>
485 lines
20 KiB
Go
485 lines
20 KiB
Go
package transaction
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"testing"
|
|
|
|
"github.com/pingcap-incubator/tinykv/kv/util/engine_util"
|
|
"github.com/pingcap-incubator/tinykv/proto/pkg/kvrpcpb"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// TestEmptyRollback4C tests a rollback with no keys.
|
|
func TestEmptyRollback4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.rollbackRequest([][]byte{}...)
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.BatchRollbackResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(0, 0, 0)
|
|
}
|
|
|
|
// TestRollback4C tests a successful rollback.
|
|
func TestRollback4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.rollbackRequest([]byte{3})
|
|
|
|
builder.init([]kv{
|
|
// See TestSinglePrewrite.
|
|
{cf: engine_util.CfDefault, key: []byte{3}, value: []byte{42}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{1, 1, 0, 0, 0, 0, 0, 0, 0, builder.ts(), 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.BatchRollbackResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(0, 0, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
})
|
|
}
|
|
|
|
// TestRollbackDuplicateKeys4C tests a rollback which rolls back multiple keys, including one duplicated key.
|
|
func TestRollbackDuplicateKeys4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.rollbackRequest([]byte{3}, []byte{15}, []byte{3})
|
|
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, value: []byte{42}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{1, 1, 0, 0, 0, 0, 0, 0, 0, builder.ts(), 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
{cf: engine_util.CfDefault, key: []byte{15}, value: []byte{0}},
|
|
{cf: engine_util.CfLock, key: []byte{15}, value: []byte{1, 1, 0, 0, 0, 0, 0, 0, 0, builder.ts(), 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.BatchRollbackResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(0, 0, 2)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
{cf: engine_util.CfWrite, key: []byte{15}, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
})
|
|
}
|
|
|
|
// TestRollbackMissingPrewrite4C tests trying to roll back a missing prewrite.
|
|
func TestRollbackMissingPrewrite4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.rollbackRequest([]byte{3})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.BatchRollbackResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(0, 0, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
})
|
|
}
|
|
|
|
// TestRollbackCommitted4C tests trying to roll back a transaction which is already committed.
|
|
func TestRollbackCommitted4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.rollbackRequest([]byte{3})
|
|
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 110, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.BatchRollbackResponse)
|
|
|
|
assert.NotNil(t, resp.Error.Abort)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(1, 0, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 110},
|
|
})
|
|
}
|
|
|
|
// TestRollbackDuplicate4C tests trying to roll back a transaction which has already been rolled back.
|
|
func TestRollbackDuplicate4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.rollbackRequest([]byte{3})
|
|
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 100, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.BatchRollbackResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(0, 0, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 100},
|
|
})
|
|
}
|
|
|
|
// TestRollbackOtherTxn4C tests trying to roll back the wrong transaction.
|
|
func TestRollbackOtherTxn4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.rollbackRequest([]byte{3})
|
|
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 80, value: []byte{42}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{1, 1, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.BatchRollbackResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(1, 1, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 80},
|
|
{cf: engine_util.CfLock, key: []byte{3}},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 100, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
})
|
|
}
|
|
|
|
// TestCheckTxnStatusTtlExpired4C checks that if there is a lock and its ttl has expired, then it is rolled back.
|
|
func TestCheckTxnStatusTtlExpired4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.checkTxnStatusRequest([]byte{3})
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: cmd.LockTs, value: []byte{42}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{3, 1, 0, 0, 5, 0, 0, 0, 0, builder.ts(), 0, 0, 0, 0, 0, 0, 0, 8}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CheckTxnStatusResponse)
|
|
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Equal(t, kvrpcpb.Action_TTLExpireRollback, resp.Action)
|
|
builder.assertLens(0, 0, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: cmd.LockTs, value: []byte{3, 0, 0, 5, 0, 0, 0, 0, builder.ts()}},
|
|
})
|
|
}
|
|
|
|
// TestCheckTxnStatusTtlNotExpired4C checks that if there is a lock and its ttl has not expired, then nothing changes.
|
|
func TestCheckTxnStatusTtlNotExpired4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.checkTxnStatusRequest([]byte{3})
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: cmd.LockTs, value: []byte{42}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{3, 1, 0, 0, 5, 0, 0, 0, 0, builder.ts(), 0, 0, 0, 1, 0, 0, 0, 8}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CheckTxnStatusResponse)
|
|
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Equal(t, kvrpcpb.Action_NoAction, resp.Action)
|
|
builder.assertLens(1, 1, 0)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: cmd.LockTs},
|
|
{cf: engine_util.CfLock, key: []byte{3}},
|
|
})
|
|
}
|
|
|
|
// TestCheckTxnStatusRolledBack4C tests checking a key which has already been rolled back..
|
|
func TestCheckTxnStatusRolledBack4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.checkTxnStatusRequest([]byte{3})
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: cmd.LockTs, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: cmd.LockTs, value: []byte{3, 0, 0, 5, 0, 0, 0, 0, builder.ts()}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{3, 1, 0, 0, 8, 0, 0, 0, 0, builder.ts(), 0, 0, 0, 0, 0, 0, 0, 8}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CheckTxnStatusResponse)
|
|
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Equal(t, kvrpcpb.Action_NoAction, resp.Action)
|
|
assert.Equal(t, uint64(0), resp.CommitVersion)
|
|
builder.assertLens(1, 1, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: cmd.LockTs},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: cmd.LockTs},
|
|
{cf: engine_util.CfLock, key: []byte{3}},
|
|
})
|
|
}
|
|
|
|
// TestCheckTxnStatusCommitted4C tests checking a key which has already been committed.
|
|
func TestCheckTxnStatusCommitted4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.checkTxnStatusRequest([]byte{3})
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: cmd.LockTs, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: cmd.LockTs, value: []byte{1, 0, 0, 5, 0, 0, 0, 0, builder.ts()}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CheckTxnStatusResponse)
|
|
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Equal(t, kvrpcpb.Action_NoAction, resp.Action)
|
|
assert.Equal(t, binary.BigEndian.Uint64([]byte{0, 0, 5, 0, 0, 0, 0, builder.ts()}), resp.CommitVersion)
|
|
builder.assertLens(1, 0, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: cmd.LockTs},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: cmd.LockTs},
|
|
})
|
|
}
|
|
|
|
// TestCheckTxnStatusNoLockNoWrite4C checks if there is no data for the key, then we get the right response.
|
|
func TestCheckTxnStatusNoLockNoWrite4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.checkTxnStatusRequest([]byte{3})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CheckTxnStatusResponse)
|
|
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Equal(t, kvrpcpb.Action_LockNotExistRollback, resp.Action)
|
|
builder.assertLens(0, 0, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: cmd.LockTs, value: []byte{3, 0, 0, 5, 0, 0, 0, 0, builder.ts()}},
|
|
})
|
|
}
|
|
|
|
// TestEmptyResolve4C tests a completely empty resolve request.
|
|
func TestEmptyResolve4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := resolveRequest(0, 0)
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.ResolveLockResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(0, 0, 0)
|
|
}
|
|
|
|
// TestResolveCommit4C should commit all keys in the specified transaction.
|
|
func TestResolveCommit4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := resolveRequest(100, 120)
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 100, value: []byte{42}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
{cf: engine_util.CfDefault, key: []byte{7}, ts: 100, value: []byte{43}},
|
|
{cf: engine_util.CfLock, key: []byte{7}, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
{cf: engine_util.CfDefault, key: []byte{200}, ts: 110, value: []byte{44}},
|
|
{cf: engine_util.CfLock, key: []byte{200}, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.ResolveLockResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(3, 1, 2)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 100},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 120, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 100}},
|
|
{cf: engine_util.CfDefault, key: []byte{7}, ts: 100},
|
|
{cf: engine_util.CfWrite, key: []byte{7}, ts: 120, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 100}},
|
|
{cf: engine_util.CfDefault, key: []byte{200}, ts: 110},
|
|
{cf: engine_util.CfLock, key: []byte{200}},
|
|
})
|
|
}
|
|
|
|
// TestResolveRollback4C should rollback all keys in the specified transaction.
|
|
func TestResolveRollback4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := resolveRequest(100, 0)
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 100, value: []byte{42}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
{cf: engine_util.CfDefault, key: []byte{7}, ts: 100, value: []byte{43}},
|
|
{cf: engine_util.CfLock, key: []byte{7}, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
{cf: engine_util.CfDefault, key: []byte{200}, ts: 110, value: []byte{44}},
|
|
{cf: engine_util.CfLock, key: []byte{200}, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.ResolveLockResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(1, 1, 2)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 100, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, 100}},
|
|
{cf: engine_util.CfWrite, key: []byte{7}, ts: 100, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, 100}},
|
|
{cf: engine_util.CfDefault, key: []byte{200}, ts: 110},
|
|
{cf: engine_util.CfLock, key: []byte{200}},
|
|
})
|
|
}
|
|
|
|
// TestResolveCommitWritten4C tests a resolve where the matched keys are already committed or rolled back.
|
|
func TestResolveCommitWritten4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := resolveRequest(100, 120)
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 100, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{201}, ts: 120, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 100}},
|
|
{cf: engine_util.CfDefault, key: []byte{7}, ts: 100, value: []byte{43}},
|
|
{cf: engine_util.CfWrite, key: []byte{201}, ts: 100, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, 100}},
|
|
{cf: engine_util.CfDefault, key: []byte{200}, ts: 110, value: []byte{44}},
|
|
{cf: engine_util.CfLock, key: []byte{200}, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.ResolveLockResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(3, 1, 2)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 100},
|
|
{cf: engine_util.CfWrite, key: []byte{201}, ts: 120},
|
|
{cf: engine_util.CfDefault, key: []byte{7}, ts: 100},
|
|
{cf: engine_util.CfWrite, key: []byte{201}, ts: 100},
|
|
{cf: engine_util.CfDefault, key: []byte{200}, ts: 110},
|
|
{cf: engine_util.CfLock, key: []byte{200}},
|
|
})
|
|
}
|
|
|
|
// TestResolveRollbackWritten4C tests a rollback resolve where data has already been committed or rolled back.
|
|
func TestResolveRollbackWritten4C(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := resolveRequest(100, 0)
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 100, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{201}, ts: 120, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 100}},
|
|
{cf: engine_util.CfDefault, key: []byte{7}, ts: 100, value: []byte{43}},
|
|
{cf: engine_util.CfWrite, key: []byte{201}, ts: 100, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, 100}},
|
|
{cf: engine_util.CfDefault, key: []byte{200}, ts: 110, value: []byte{44}},
|
|
{cf: engine_util.CfLock, key: []byte{200}, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.ResolveLockResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(3, 1, 2)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 100},
|
|
{cf: engine_util.CfWrite, key: []byte{201}, ts: 120},
|
|
{cf: engine_util.CfDefault, key: []byte{7}, ts: 100},
|
|
{cf: engine_util.CfWrite, key: []byte{201}, ts: 100},
|
|
{cf: engine_util.CfDefault, key: []byte{200}, ts: 110},
|
|
{cf: engine_util.CfLock, key: []byte{200}},
|
|
})
|
|
}
|
|
|
|
// TestScanEmpty4C tests a scan after the end of the DB.
|
|
func TestScanEmpty4C(t *testing.T) {
|
|
builder := builderForScan(t)
|
|
|
|
cmd := builder.scanRequest([]byte{200}, 10000)
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.ScanResponse)
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Empty(t, resp.Pairs)
|
|
}
|
|
|
|
// TestScanLimitZero4C tests we get nothing if limit is 0.
|
|
func TestScanLimitZero4C(t *testing.T) {
|
|
builder := builderForScan(t)
|
|
|
|
cmd := builder.scanRequest([]byte{3}, 0)
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.ScanResponse)
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Empty(t, resp.Pairs)
|
|
}
|
|
|
|
// TestScanAll4C start at the beginning of the DB and read all pairs, respecting the timestamp.
|
|
func TestScanAll4C(t *testing.T) {
|
|
builder := builderForScan(t)
|
|
|
|
cmd := builder.scanRequest([]byte{0}, 10000)
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.ScanResponse)
|
|
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Equal(t, 11, len(resp.Pairs))
|
|
assert.Equal(t, []byte{1}, resp.Pairs[0].Key)
|
|
assert.Equal(t, []byte{50}, resp.Pairs[0].Value)
|
|
assert.Equal(t, []byte{199}, resp.Pairs[10].Key)
|
|
assert.Equal(t, []byte{54}, resp.Pairs[10].Value)
|
|
}
|
|
|
|
// TestScanLimit4C tests that scan takes the limit into account.
|
|
func TestScanLimit4C(t *testing.T) {
|
|
builder := builderForScan(t)
|
|
|
|
cmd := builder.scanRequest([]byte{2}, 6)
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.ScanResponse)
|
|
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Equal(t, 6, len(resp.Pairs))
|
|
assert.Equal(t, []byte{3}, resp.Pairs[0].Key)
|
|
assert.Equal(t, []byte{51}, resp.Pairs[0].Value)
|
|
assert.Equal(t, []byte{4}, resp.Pairs[5].Key)
|
|
assert.Equal(t, []byte{52}, resp.Pairs[5].Value)
|
|
}
|
|
|
|
// TestScanDeleted4C scan over a value which is deleted then replaced.
|
|
func TestScanDeleted4C(t *testing.T) {
|
|
builder := builderForScan(t)
|
|
|
|
req1 := builder.scanRequest([]byte{100}, 10000)
|
|
req1.Version = 100
|
|
req2 := builder.scanRequest([]byte{100}, 10000)
|
|
req2.Version = 105
|
|
req3 := builder.scanRequest([]byte{100}, 10000)
|
|
req3.Version = 120
|
|
|
|
resps := builder.runRequests(req1, req2, req3)
|
|
|
|
resp1 := resps[0].(*kvrpcpb.ScanResponse)
|
|
assert.Nil(t, resp1.RegionError)
|
|
assert.Equal(t, 3, len(resp1.Pairs))
|
|
assert.Equal(t, []byte{150}, resp1.Pairs[1].Key)
|
|
assert.Equal(t, []byte{42}, resp1.Pairs[1].Value)
|
|
|
|
resp2 := resps[1].(*kvrpcpb.ScanResponse)
|
|
assert.Nil(t, resp2.RegionError)
|
|
assert.Equal(t, 2, len(resp2.Pairs))
|
|
assert.Equal(t, []byte{120}, resp2.Pairs[0].Key)
|
|
assert.Equal(t, []byte{199}, resp2.Pairs[1].Key)
|
|
|
|
resp3 := resps[2].(*kvrpcpb.ScanResponse)
|
|
assert.Nil(t, resp3.RegionError)
|
|
assert.Equal(t, 3, len(resp3.Pairs))
|
|
assert.Equal(t, []byte{150}, resp3.Pairs[1].Key)
|
|
assert.Equal(t, []byte{64}, resp3.Pairs[1].Value)
|
|
}
|
|
|
|
func builderForScan(t *testing.T) *testBuilder {
|
|
values := []kv{
|
|
// Committed before 100.
|
|
{engine_util.CfDefault, []byte{1}, 80, []byte{50}},
|
|
{engine_util.CfWrite, []byte{1}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{engine_util.CfDefault, []byte{1, 23}, 80, []byte{55}},
|
|
{engine_util.CfWrite, []byte{1, 23}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{engine_util.CfDefault, []byte{3}, 80, []byte{51}},
|
|
{engine_util.CfWrite, []byte{3}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{engine_util.CfDefault, []byte{3, 45}, 80, []byte{56}},
|
|
{engine_util.CfWrite, []byte{3, 45}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{engine_util.CfDefault, []byte{3, 46}, 80, []byte{57}},
|
|
{engine_util.CfWrite, []byte{3, 46}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{engine_util.CfDefault, []byte{3, 47}, 80, []byte{58}},
|
|
{engine_util.CfWrite, []byte{3, 47}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{engine_util.CfDefault, []byte{3, 48}, 80, []byte{59}},
|
|
{engine_util.CfWrite, []byte{3, 48}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{engine_util.CfDefault, []byte{4}, 80, []byte{52}},
|
|
{engine_util.CfWrite, []byte{4}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{engine_util.CfDefault, []byte{120}, 80, []byte{53}},
|
|
{engine_util.CfWrite, []byte{120}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{engine_util.CfDefault, []byte{199}, 80, []byte{54}},
|
|
{engine_util.CfWrite, []byte{199}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
|
|
// Committed after 100.
|
|
{engine_util.CfDefault, []byte{4, 45}, 110, []byte{58}},
|
|
{engine_util.CfWrite, []byte{4, 45}, 116, []byte{1, 0, 0, 0, 0, 0, 0, 0, 110}},
|
|
{engine_util.CfDefault, []byte{4, 46}, 110, []byte{57}},
|
|
{engine_util.CfWrite, []byte{4, 46}, 116, []byte{1, 0, 0, 0, 0, 0, 0, 0, 110}},
|
|
{engine_util.CfDefault, []byte{4, 47}, 110, []byte{58}},
|
|
{engine_util.CfWrite, []byte{4, 47}, 116, []byte{1, 0, 0, 0, 0, 0, 0, 0, 110}},
|
|
{engine_util.CfDefault, []byte{4, 48}, 110, []byte{59}},
|
|
{engine_util.CfWrite, []byte{4, 48}, 116, []byte{1, 0, 0, 0, 0, 0, 0, 0, 110}},
|
|
|
|
// Committed after 100, but started before.
|
|
{engine_util.CfDefault, []byte{5, 45}, 97, []byte{60}},
|
|
{engine_util.CfWrite, []byte{5, 45}, 101, []byte{1, 0, 0, 0, 0, 0, 0, 0, 97}},
|
|
{engine_util.CfDefault, []byte{5, 46}, 97, []byte{61}},
|
|
{engine_util.CfWrite, []byte{5, 46}, 101, []byte{1, 0, 0, 0, 0, 0, 0, 0, 97}},
|
|
{engine_util.CfDefault, []byte{5, 47}, 97, []byte{62}},
|
|
{engine_util.CfWrite, []byte{5, 47}, 101, []byte{1, 0, 0, 0, 0, 0, 0, 0, 97}},
|
|
{engine_util.CfDefault, []byte{5, 48}, 97, []byte{63}},
|
|
{engine_util.CfWrite, []byte{5, 48}, 101, []byte{1, 0, 0, 0, 0, 0, 0, 0, 97}},
|
|
|
|
// A deleted value and replaced value.
|
|
{engine_util.CfDefault, []byte{150}, 80, []byte{42}},
|
|
{engine_util.CfWrite, []byte{150}, 99, []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{engine_util.CfWrite, []byte{150}, 101, []byte{2, 0, 0, 0, 0, 0, 0, 0, 97}},
|
|
{engine_util.CfDefault, []byte{150}, 110, []byte{64}},
|
|
{engine_util.CfWrite, []byte{150}, 116, []byte{1, 0, 0, 0, 0, 0, 0, 0, 110}},
|
|
}
|
|
builder := newBuilder(t)
|
|
builder.init(values)
|
|
return &builder
|
|
}
|