From da83f910f2e5d3bf919bd2166cd3e0e4f67a6772 Mon Sep 17 00:00:00 2001 From: Aleksey Myasnikov Date: Thu, 26 Oct 2023 13:03:08 +0300 Subject: [PATCH] * Allowed `sql.LevelSerializable` isolation level in read-write mode in `database/sql` transactions --- CHANGELOG.md | 1 + internal/xsql/isolation/isolation.go | 14 +++++++---- internal/xsql/isolation/isolation_test.go | 29 +++++++++++++++++------ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfc546658..75cecf15f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,4 @@ +* Allowed `sql.LevelSerializable` isolation level in read-write mode in `database/sql` transactions * Refactored traces and metrics * Added `{retry,table}.WithLabel` options for mark retriers calls * Added `ydb.WithTraceRetry` option diff --git a/internal/xsql/isolation/isolation.go b/internal/xsql/isolation/isolation.go index e6df88441..2b1f026cf 100644 --- a/internal/xsql/isolation/isolation.go +++ b/internal/xsql/isolation/isolation.go @@ -15,11 +15,15 @@ import ( // It returns error on unsupported options. func ToYDB(opts driver.TxOptions) (txcControl table.TxOption, err error) { level := sql.IsolationLevel(opts.Isolation) - if !opts.ReadOnly && level == sql.LevelDefault { - return table.WithSerializableReadWrite(), nil - } - if opts.ReadOnly && level == sql.LevelSnapshot { - return table.WithSnapshotReadOnly(), nil + switch level { + case sql.LevelDefault, sql.LevelSerializable: + if !opts.ReadOnly { + return table.WithSerializableReadWrite(), nil + } + case sql.LevelSnapshot: + if opts.ReadOnly { + return table.WithSnapshotReadOnly(), nil + } } return nil, xerrors.WithStackTrace(fmt.Errorf( "unsupported transaction options: %+v", opts, diff --git a/internal/xsql/isolation/isolation_test.go b/internal/xsql/isolation/isolation_test.go index cf32efcde..9f4b0ed89 100644 --- a/internal/xsql/isolation/isolation_test.go +++ b/internal/xsql/isolation/isolation_test.go @@ -3,23 +3,24 @@ package isolation import ( "database/sql" "database/sql/driver" - "fmt" "testing" "github.com/stretchr/testify/require" - "google.golang.org/protobuf/proto" + "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest" "github.com/ydb-platform/ydb-go-sdk/v3/table" ) func TestToYDB(t *testing.T) { for _, tt := range []struct { + name string txOptions driver.TxOptions txControl table.TxOption err bool }{ // read-write { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelDefault), ReadOnly: false, @@ -28,6 +29,7 @@ func TestToYDB(t *testing.T) { err: false, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelReadUncommitted), ReadOnly: false, @@ -35,6 +37,7 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelReadCommitted), ReadOnly: false, @@ -42,6 +45,7 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelWriteCommitted), ReadOnly: false, @@ -49,6 +53,7 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelRepeatableRead), ReadOnly: false, @@ -56,6 +61,7 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelSnapshot), ReadOnly: false, @@ -63,13 +69,16 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelSerializable), ReadOnly: false, }, - err: true, + txControl: table.WithSerializableReadWrite(), + err: false, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelLinearizable), ReadOnly: false, @@ -79,6 +88,7 @@ func TestToYDB(t *testing.T) { // read-only { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelDefault), ReadOnly: true, @@ -86,6 +96,7 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelReadUncommitted), ReadOnly: true, @@ -93,6 +104,7 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelReadCommitted), ReadOnly: true, @@ -100,6 +112,7 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelWriteCommitted), ReadOnly: true, @@ -107,6 +120,7 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelRepeatableRead), ReadOnly: true, @@ -114,6 +128,7 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelSnapshot), ReadOnly: true, @@ -122,6 +137,7 @@ func TestToYDB(t *testing.T) { err: false, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelSerializable), ReadOnly: true, @@ -129,6 +145,7 @@ func TestToYDB(t *testing.T) { err: true, }, { + name: xtest.CurrentFileLine(), txOptions: driver.TxOptions{ Isolation: driver.IsolationLevel(sql.LevelLinearizable), ReadOnly: true, @@ -136,13 +153,11 @@ func TestToYDB(t *testing.T) { err: true, }, } { - t.Run(fmt.Sprintf("%+v", tt.txOptions), func(t *testing.T) { + t.Run(tt.name, func(t *testing.T) { toYDB, err := ToYDB(tt.txOptions) if !tt.err { require.NoError(t, err) - if !proto.Equal(table.TxSettings(tt.txControl).Settings(), table.TxSettings(toYDB).Settings()) { - t.Errorf("%+v != %+v", toYDB, tt.txControl) - } + require.Equal(t, table.TxSettings(tt.txControl).Settings(), table.TxSettings(toYDB).Settings()) } else { require.Error(t, err) }