mirror of
https://github.com/talent-plan/tinykv.git
synced 2025-01-15 06:41:35 +08:00
15838152aa
* fix invalid order of expected and actual in tests Co-authored-by: Connor <zbk602423539@gmail.com>
597 lines
22 KiB
Go
597 lines
22 KiB
Go
package transaction
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/pingcap-incubator/tinykv/kv/transaction/mvcc"
|
|
"github.com/pingcap-incubator/tinykv/kv/util/engine_util"
|
|
"github.com/pingcap-incubator/tinykv/proto/pkg/kvrpcpb"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// TestGetValue4B getting a value works in the simple case.
|
|
func TestGetValue4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{99}, ts: 50, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{99}, ts: 54, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 50}},
|
|
})
|
|
|
|
var req kvrpcpb.GetRequest
|
|
req.Key = []byte{99}
|
|
req.Version = mvcc.TsMax
|
|
resp := builder.runOneRequest(&req).(*kvrpcpb.GetResponse)
|
|
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Nil(t, resp.Error)
|
|
assert.Equal(t, []byte{42}, resp.Value)
|
|
}
|
|
|
|
// TestGetValueTs4B getting a value works with different timestamps.
|
|
func TestGetValueTs4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{99}, ts: 50, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{99}, ts: 54, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 50}},
|
|
})
|
|
|
|
var req0 kvrpcpb.GetRequest
|
|
req0.Key = []byte{99}
|
|
req0.Version = 100
|
|
var req1 kvrpcpb.GetRequest
|
|
req1.Key = []byte{99}
|
|
req1.Version = 100
|
|
var req2 kvrpcpb.GetRequest
|
|
req2.Key = []byte{99}
|
|
req2.Version = 100
|
|
|
|
resps := builder.runRequests(&req0, &req1, &req2)
|
|
resp0 := resps[0].(*kvrpcpb.GetResponse)
|
|
resp1 := resps[1].(*kvrpcpb.GetResponse)
|
|
resp2 := resps[2].(*kvrpcpb.GetResponse)
|
|
assert.Nil(t, resp0.RegionError)
|
|
assert.Nil(t, resp0.Error)
|
|
assert.Equal(t, []byte{42}, resp0.Value)
|
|
assert.Nil(t, resp1.RegionError)
|
|
assert.Nil(t, resp1.Error)
|
|
assert.Equal(t, []byte{42}, resp1.Value)
|
|
assert.Nil(t, resp2.RegionError)
|
|
assert.Nil(t, resp2.Error)
|
|
assert.Equal(t, []byte{42}, resp2.Value)
|
|
}
|
|
|
|
// TestGetEmpty4B tests that get on an empty DB.
|
|
func TestGetEmpty4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
|
|
var req kvrpcpb.GetRequest
|
|
req.Key = []byte{100}
|
|
req.Version = mvcc.TsMax
|
|
resp := builder.runOneRequest(&req).(*kvrpcpb.GetResponse)
|
|
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Nil(t, resp.Error)
|
|
assert.True(t, resp.NotFound)
|
|
}
|
|
|
|
// TestGetNone4B tests that getting a missing key works.
|
|
func TestGetNone4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{99}, ts: 50, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{99}, ts: 54, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 50}},
|
|
{cf: engine_util.CfDefault, key: []byte{101}, ts: 50, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{101}, ts: 54, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 50}},
|
|
})
|
|
|
|
var req kvrpcpb.GetRequest
|
|
req.Key = []byte{100}
|
|
req.Version = mvcc.TsMax
|
|
|
|
resp := builder.runOneRequest(&req).(*kvrpcpb.GetResponse)
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Nil(t, resp.Error)
|
|
assert.True(t, resp.NotFound)
|
|
}
|
|
|
|
// TestGetVersions4B tests we get the correct value when there are multiple versions.
|
|
func TestGetVersions4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{99}, ts: 50, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{99}, ts: 54, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 50}},
|
|
{cf: engine_util.CfDefault, key: []byte{99}, ts: 60, value: []byte{43}},
|
|
{cf: engine_util.CfWrite, key: []byte{99}, ts: 66, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 60}},
|
|
{cf: engine_util.CfDefault, key: []byte{99}, ts: 120, value: []byte{44}},
|
|
{cf: engine_util.CfWrite, key: []byte{99}, ts: 122, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 120}},
|
|
})
|
|
|
|
var req0 kvrpcpb.GetRequest
|
|
req0.Key = []byte{99}
|
|
req0.Version = 40
|
|
var req1 kvrpcpb.GetRequest
|
|
req1.Key = []byte{99}
|
|
req1.Version = 56
|
|
var req2 kvrpcpb.GetRequest
|
|
req2.Key = []byte{99}
|
|
req2.Version = 60
|
|
var req3 kvrpcpb.GetRequest
|
|
req3.Key = []byte{99}
|
|
req3.Version = 65
|
|
var req4 kvrpcpb.GetRequest
|
|
req4.Key = []byte{99}
|
|
req4.Version = 66
|
|
var req5 kvrpcpb.GetRequest
|
|
req5.Key = []byte{99}
|
|
req5.Version = 100
|
|
|
|
resps := builder.runRequests(&req0, &req1, &req2, &req3, &req4, &req5)
|
|
resp0 := resps[0].(*kvrpcpb.GetResponse)
|
|
resp1 := resps[1].(*kvrpcpb.GetResponse)
|
|
resp2 := resps[2].(*kvrpcpb.GetResponse)
|
|
resp3 := resps[3].(*kvrpcpb.GetResponse)
|
|
resp4 := resps[4].(*kvrpcpb.GetResponse)
|
|
resp5 := resps[5].(*kvrpcpb.GetResponse)
|
|
|
|
assert.Nil(t, resp0.RegionError)
|
|
assert.Nil(t, resp0.Error)
|
|
assert.True(t, resp0.NotFound)
|
|
assert.Nil(t, resp1.RegionError)
|
|
assert.Nil(t, resp1.Error)
|
|
assert.Equal(t, []byte{42}, resp1.Value)
|
|
assert.Nil(t, resp2.RegionError)
|
|
assert.Nil(t, resp2.Error)
|
|
assert.Equal(t, []byte{42}, resp2.Value)
|
|
assert.Nil(t, resp3.RegionError)
|
|
assert.Nil(t, resp3.Error)
|
|
assert.Equal(t, []byte{42}, resp3.Value)
|
|
assert.Nil(t, resp4.RegionError)
|
|
assert.Nil(t, resp4.Error)
|
|
assert.Equal(t, []byte{43}, resp4.Value)
|
|
assert.Nil(t, resp5.RegionError)
|
|
assert.Nil(t, resp5.Error)
|
|
assert.Equal(t, []byte{43}, resp5.Value)
|
|
}
|
|
|
|
// TestGetDeleted4B tests we get the correct value when there are multiple versions, including a deletion.
|
|
func TestGetDeleted4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{99}, ts: 50, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{99}, ts: 54, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 50}},
|
|
{cf: engine_util.CfDefault, key: []byte{99}, ts: 60, value: nil},
|
|
{cf: engine_util.CfWrite, key: []byte{99}, ts: 66, value: []byte{2, 0, 0, 0, 0, 0, 0, 0, 60}},
|
|
{cf: engine_util.CfDefault, key: []byte{99}, ts: 120, value: []byte{44}},
|
|
{cf: engine_util.CfWrite, key: []byte{99}, ts: 122, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 120}},
|
|
})
|
|
|
|
var req0 kvrpcpb.GetRequest
|
|
req0.Key = []byte{99}
|
|
req0.Version = 54
|
|
var req1 kvrpcpb.GetRequest
|
|
req1.Key = []byte{99}
|
|
req1.Version = 60
|
|
var req2 kvrpcpb.GetRequest
|
|
req2.Key = []byte{99}
|
|
req2.Version = 65
|
|
var req3 kvrpcpb.GetRequest
|
|
req3.Key = []byte{99}
|
|
req3.Version = 66
|
|
var req4 kvrpcpb.GetRequest
|
|
req4.Key = []byte{99}
|
|
req4.Version = 67
|
|
var req5 kvrpcpb.GetRequest
|
|
req5.Key = []byte{99}
|
|
req5.Version = 122
|
|
|
|
resps := builder.runRequests(&req0, &req1, &req2, &req3, &req4, &req5)
|
|
resp0 := resps[0].(*kvrpcpb.GetResponse)
|
|
resp1 := resps[1].(*kvrpcpb.GetResponse)
|
|
resp2 := resps[2].(*kvrpcpb.GetResponse)
|
|
resp3 := resps[3].(*kvrpcpb.GetResponse)
|
|
resp4 := resps[4].(*kvrpcpb.GetResponse)
|
|
resp5 := resps[5].(*kvrpcpb.GetResponse)
|
|
|
|
assert.Nil(t, resp0.RegionError)
|
|
assert.Nil(t, resp0.Error)
|
|
assert.Equal(t, []byte{42}, resp0.Value)
|
|
assert.Nil(t, resp1.RegionError)
|
|
assert.Nil(t, resp1.Error)
|
|
assert.Equal(t, []byte{42}, resp1.Value)
|
|
assert.Nil(t, resp2.RegionError)
|
|
assert.Nil(t, resp2.Error)
|
|
assert.Equal(t, []byte{42}, resp2.Value)
|
|
assert.Nil(t, resp3.RegionError)
|
|
assert.Nil(t, resp3.Error)
|
|
assert.True(t, resp3.NotFound)
|
|
assert.Nil(t, resp4.RegionError)
|
|
assert.Nil(t, resp4.Error)
|
|
assert.True(t, resp4.NotFound)
|
|
assert.Nil(t, resp5.RegionError)
|
|
assert.Nil(t, resp5.Error)
|
|
assert.Equal(t, []byte{44}, resp5.Value)
|
|
}
|
|
|
|
// TestGetLocked4B tests getting a value when it is locked by another transaction.
|
|
func TestGetLocked4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{99}, ts: 50, value: []byte{42}},
|
|
{cf: engine_util.CfWrite, key: []byte{99}, ts: 54, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 50}},
|
|
{cf: engine_util.CfLock, key: []byte{99}, value: []byte{99, 1, 0, 0, 0, 0, 0, 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
|
|
var req0 kvrpcpb.GetRequest
|
|
req0.Key = []byte{99}
|
|
req0.Version = 55
|
|
var req1 kvrpcpb.GetRequest
|
|
req1.Key = []byte{99}
|
|
req1.Version = 300
|
|
|
|
resps := builder.runRequests(&req0, &req1)
|
|
resp0 := resps[0].(*kvrpcpb.GetResponse)
|
|
resp1 := resps[1].(*kvrpcpb.GetResponse)
|
|
|
|
assert.Nil(t, resp0.RegionError)
|
|
assert.Nil(t, resp0.Error)
|
|
assert.Equal(t, []byte{42}, resp0.Value)
|
|
|
|
assert.Nil(t, resp1.RegionError)
|
|
lockInfo := resp1.Error.Locked
|
|
assert.Equal(t, []byte{99}, lockInfo.Key)
|
|
assert.Equal(t, []byte{99}, lockInfo.PrimaryLock)
|
|
assert.Equal(t, uint64(200), lockInfo.LockVersion)
|
|
}
|
|
|
|
// TestEmptyPrewrite4B tests that a Prewrite with no mutations succeeds and changes nothing.
|
|
func TestEmptyPrewrite4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.prewriteRequest()
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.PrewriteResponse)
|
|
|
|
assert.Empty(t, resp.Errors)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLen(engine_util.CfDefault, 0)
|
|
}
|
|
|
|
// TestSinglePrewrite4B tests a prewrite with one write, it should succeed, we test all the expected values.
|
|
func TestSinglePrewrite4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.prewriteRequest(mutation(3, []byte{42}, kvrpcpb.Op_Put))
|
|
cmd.LockTtl = 1000
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.PrewriteResponse)
|
|
|
|
assert.Empty(t, resp.Errors)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(1, 1, 0)
|
|
builder.assert([]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, 3, 232}},
|
|
})
|
|
}
|
|
|
|
// TestPrewriteLocked4B tests that two prewrites to the same key causes a lock error.
|
|
func TestPrewriteLocked4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.prewriteRequest(mutation(3, []byte{42}, kvrpcpb.Op_Put))
|
|
cmd2 := builder.prewriteRequest(mutation(3, []byte{53}, kvrpcpb.Op_Put))
|
|
resps := builder.runRequests(cmd, cmd2)
|
|
|
|
assert.Empty(t, resps[0].(*kvrpcpb.PrewriteResponse).Errors)
|
|
assert.Nil(t, resps[0].(*kvrpcpb.PrewriteResponse).RegionError)
|
|
assert.Equal(t, 1, len(resps[1].(*kvrpcpb.PrewriteResponse).Errors))
|
|
assert.Nil(t, resps[1].(*kvrpcpb.PrewriteResponse).RegionError)
|
|
builder.assertLens(1, 1, 0)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 100, value: []byte{42}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{1, 1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
}
|
|
|
|
// TestPrewriteWritten4B tests an attempted prewrite with a write conflict.
|
|
func TestPrewriteWritten4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.prewriteRequest(mutation(3, []byte{42}, kvrpcpb.Op_Put))
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 80, value: []byte{5}},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 101, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.PrewriteResponse)
|
|
|
|
assert.Equal(t, 1, len(resp.Errors))
|
|
assert.NotNil(t, resp.Errors[0].Conflict)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(1, 0, 1)
|
|
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 80, value: []byte{5}},
|
|
})
|
|
}
|
|
|
|
// TestPrewriteWrittenNoConflict4B tests an attempted prewrite with a write already present, but no conflict.
|
|
func TestPrewriteWrittenNoConflict4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.prewriteRequest(mutation(3, []byte{42}, kvrpcpb.Op_Put))
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 80, value: []byte{5}},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 90, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.PrewriteResponse)
|
|
|
|
assert.Empty(t, resp.Errors)
|
|
assert.Nil(t, resp.RegionError)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(2, 1, 1)
|
|
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, value: []byte{5}, ts: 80},
|
|
{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}},
|
|
})
|
|
}
|
|
|
|
// TestMultiplePrewrites4B tests that multiple prewrites to different keys succeeds.
|
|
func TestMultiplePrewrites4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.prewriteRequest(mutation(3, []byte{42}, kvrpcpb.Op_Put))
|
|
cmd2 := builder.prewriteRequest(mutation(4, []byte{53}, kvrpcpb.Op_Put))
|
|
resps := builder.runRequests(cmd, cmd2)
|
|
|
|
assert.Empty(t, resps[0].(*kvrpcpb.PrewriteResponse).Errors)
|
|
assert.Nil(t, resps[0].(*kvrpcpb.PrewriteResponse).RegionError)
|
|
assert.Empty(t, resps[1].(*kvrpcpb.PrewriteResponse).Errors)
|
|
assert.Nil(t, resps[1].(*kvrpcpb.PrewriteResponse).RegionError)
|
|
builder.assertLens(2, 2, 0)
|
|
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 100, value: []byte{42}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{1, 1, 0, 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
{cf: engine_util.CfDefault, key: []byte{4}, ts: 101, value: []byte{53}},
|
|
{cf: engine_util.CfLock, key: []byte{4}, value: []byte{1, 1, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
}
|
|
|
|
// TestPrewriteOverwrite4B tests that two writes in the same prewrite succeed and we see the second write.
|
|
func TestPrewriteOverwrite4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.prewriteRequest(mutation(3, []byte{42}, kvrpcpb.Op_Put), mutation(3, []byte{45}, kvrpcpb.Op_Put))
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.PrewriteResponse)
|
|
|
|
assert.Empty(t, resp.Errors)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(1, 1, 0)
|
|
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, value: []byte{45}},
|
|
{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}},
|
|
})
|
|
}
|
|
|
|
// TestPrewriteMultiple4B tests that a prewrite with multiple mutations succeeds.
|
|
func TestPrewriteMultiple4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.prewriteRequest(
|
|
mutation(3, []byte{42}, kvrpcpb.Op_Put),
|
|
mutation(4, []byte{43}, kvrpcpb.Op_Put),
|
|
mutation(5, []byte{44}, kvrpcpb.Op_Put),
|
|
mutation(4, nil, kvrpcpb.Op_Del),
|
|
mutation(4, []byte{1, 3, 5}, kvrpcpb.Op_Put),
|
|
mutation(255, []byte{45}, kvrpcpb.Op_Put),
|
|
)
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.PrewriteResponse)
|
|
|
|
assert.Empty(t, resp.Errors)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(4, 4, 0)
|
|
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{4}, value: []byte{1, 3, 5}},
|
|
})
|
|
}
|
|
|
|
// TestEmptyCommit4B tests a commit request with no keys to commit.
|
|
func TestEmptyCommit4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.commitRequest([][]byte{}...)
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CommitResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(0, 0, 0)
|
|
}
|
|
|
|
// TestSimpleCommit4B tests committing a single key.
|
|
func TestSingleCommit4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.commitRequest([]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, 0, 0, 0, 0, 0, 0, 0, builder.ts(), 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CommitResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(1, 0, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 110, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
{cf: engine_util.CfDefault, key: []byte{3}},
|
|
})
|
|
}
|
|
|
|
// TestCommitOverwrite4B tests committing where there is already a write.
|
|
func TestCommitOverwrite4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.commitRequest([]byte{3})
|
|
builder.init([]kv{
|
|
// A previous, committed write.
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 80, value: []byte{15}},
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 84, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
|
|
// The current, pre-written write.
|
|
{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.CommitResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(2, 0, 2)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 110, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
{cf: engine_util.CfDefault, key: []byte{3}},
|
|
})
|
|
}
|
|
|
|
// TestCommitMultipleKeys4B tests committing multiple keys in the same commit. Also puts some other data in the DB and test
|
|
// that it is unchanged.
|
|
func TestCommitMultipleKeys4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.commitRequest([]byte{3}, []byte{12, 4, 0}, []byte{15})
|
|
builder.init([]kv{
|
|
// Current, pre-written.
|
|
{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{12, 4, 0}, value: []byte{1, 1, 0, 0, 1, 5}},
|
|
{cf: engine_util.CfLock, key: []byte{12, 4, 0}, 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}},
|
|
|
|
// Some committed data.
|
|
{cf: engine_util.CfDefault, key: []byte{4}, ts: 80, value: []byte{15}},
|
|
{cf: engine_util.CfWrite, key: []byte{4}, ts: 84, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{cf: engine_util.CfDefault, key: []byte{3, 0}, ts: 80, value: []byte{150}},
|
|
{cf: engine_util.CfWrite, key: []byte{3, 0}, ts: 84, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
|
|
// Another pre-written transaction.
|
|
{cf: engine_util.CfDefault, key: []byte{2}, ts: 99, value: []byte{0, 0, 0, 8}},
|
|
{cf: engine_util.CfLock, key: []byte{2}, value: []byte{1, 2, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
{cf: engine_util.CfDefault, key: []byte{43, 6}, ts: 99, value: []byte{1, 1, 0, 0, 1, 5}},
|
|
{cf: engine_util.CfLock, key: []byte{43, 6}, value: []byte{1, 2, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CommitResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(7, 2, 5)
|
|
builder.assert([]kv{
|
|
// The newly committed data.
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 110, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
{cf: engine_util.CfWrite, key: []byte{12, 4, 0}, ts: 110, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
{cf: engine_util.CfWrite, key: []byte{15}, ts: 110, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
|
|
// Committed data is untouched.
|
|
{cf: engine_util.CfDefault, key: []byte{4}, ts: 80},
|
|
{cf: engine_util.CfWrite, key: []byte{4}, ts: 84},
|
|
{cf: engine_util.CfDefault, key: []byte{3, 0}, ts: 80},
|
|
{cf: engine_util.CfWrite, key: []byte{3, 0}, ts: 84},
|
|
|
|
// Pre-written data is untouched.
|
|
{cf: engine_util.CfDefault, key: []byte{2}, ts: 99},
|
|
{cf: engine_util.CfLock, key: []byte{2}},
|
|
{cf: engine_util.CfDefault, key: []byte{43, 6}, ts: 99},
|
|
{cf: engine_util.CfLock, key: []byte{43, 6}},
|
|
})
|
|
}
|
|
|
|
// TestRecommitKey4B tests committing the same key multiple times in one commit.
|
|
func TestRecommitKey4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.commitRequest([]byte{3}, []byte{3})
|
|
builder.init([]kv{
|
|
// The current, pre-written write.
|
|
{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.CommitResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(1, 0, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 110, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
{cf: engine_util.CfDefault, key: []byte{3}},
|
|
})
|
|
}
|
|
|
|
// TestCommitConflictRollback4B tests committing a rolled back transaction.
|
|
func TestCommitConflictRollback4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.commitRequest([]byte{3})
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 110, value: []byte{3, 0, 0, 0, 0, 0, 0, 0, builder.ts()}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CommitResponse)
|
|
|
|
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: 110},
|
|
})
|
|
}
|
|
|
|
// TestCommitConflictRace4B tests committing where a key is pre-written by a different transaction.
|
|
func TestCommitConflictRace4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.commitRequest([]byte{3})
|
|
builder.init([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 90, value: []byte{110}},
|
|
{cf: engine_util.CfLock, key: []byte{3}, value: []byte{1, 3, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 0, 0, 0, 0, 0}},
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CommitResponse)
|
|
|
|
assert.NotNil(t, resp.Error.Retryable)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(1, 1, 0)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfLock, key: []byte{3}},
|
|
{cf: engine_util.CfDefault, key: []byte{3}, ts: 90},
|
|
})
|
|
}
|
|
|
|
// TestCommitConflictRepeat4B tests recommitting a transaction (i.e., the same commit request is received twice).
|
|
func TestCommitConflictRepeat4B(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.commitRequest([]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.CommitResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(1, 0, 1)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfWrite, key: []byte{3}, ts: 110},
|
|
{cf: engine_util.CfDefault, key: []byte{3}},
|
|
})
|
|
}
|
|
|
|
// TestCommitMissingPrewrite4a tests committing a transaction which was not prewritten (i.e., a request was lost, but
|
|
// the commit request was not).
|
|
func TestCommitMissingPrewrite4a(t *testing.T) {
|
|
builder := newBuilder(t)
|
|
cmd := builder.commitRequest([]byte{3})
|
|
builder.init([]kv{
|
|
// Some committed data.
|
|
{cf: engine_util.CfDefault, key: []byte{4}, ts: 80, value: []byte{15}},
|
|
{cf: engine_util.CfWrite, key: []byte{4}, ts: 84, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
{cf: engine_util.CfDefault, key: []byte{3, 0}, ts: 80, value: []byte{150}},
|
|
{cf: engine_util.CfWrite, key: []byte{3, 0}, ts: 84, value: []byte{1, 0, 0, 0, 0, 0, 0, 0, 80}},
|
|
// Note no prewrite.
|
|
})
|
|
resp := builder.runOneRequest(cmd).(*kvrpcpb.CommitResponse)
|
|
|
|
assert.Nil(t, resp.Error)
|
|
assert.Nil(t, resp.RegionError)
|
|
builder.assertLens(2, 0, 2)
|
|
builder.assert([]kv{
|
|
{cf: engine_util.CfDefault, key: []byte{4}, ts: 80},
|
|
{cf: engine_util.CfWrite, key: []byte{4}, ts: 84},
|
|
{cf: engine_util.CfDefault, key: []byte{3, 0}, ts: 80},
|
|
{cf: engine_util.CfWrite, key: []byte{3, 0}, ts: 84},
|
|
})
|
|
}
|