From 263da450bd142f77a02a96fe4e7ab9df063d6e1d Mon Sep 17 00:00:00 2001 From: Aleksey Myasnikov Date: Thu, 24 Apr 2025 19:55:40 +0300 Subject: [PATCH] Added Isolation concept --- internal/query/transaction.go | 4 +- internal/tx/isolation.go | 74 ++++++++++++++++++++++++++ internal/tx/settings.go | 97 ++++++++++++++++++++++++++++++++--- query/transaction.go | 22 +++++++- table/table.go | 2 +- 5 files changed, 188 insertions(+), 11 deletions(-) create mode 100644 internal/tx/isolation.go diff --git a/internal/query/transaction.go b/internal/query/transaction.go index 3f7f65389..7c577c4ed 100644 --- a/internal/query/transaction.go +++ b/internal/query/transaction.go @@ -45,7 +45,7 @@ func begin( response, err := client.BeginTransaction(ctx, &Ydb_Query.BeginTransactionRequest{ SessionId: sessionID, - TxSettings: txSettings.ToYdbQuerySettings(), + TxSettings: txSettings.ToQuerySettings(), }, ) if err != nil { @@ -185,7 +185,7 @@ func (tx *Transaction) txControl() *baseTx.Control { } return baseTx.NewControl( - baseTx.BeginTx(tx.txSettings...), + tx.txSettings, ) } diff --git a/internal/tx/isolation.go b/internal/tx/isolation.go new file mode 100644 index 000000000..f7cb00fa9 --- /dev/null +++ b/internal/tx/isolation.go @@ -0,0 +1,74 @@ +package tx + +import ( + "fmt" + + "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query" + "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Table" +) + +type Isolation int + +func (iso Isolation) ToTableSettings() *Ydb_Table.TransactionSettings { + return iso.tableTxSelector().BeginTx +} + +func (iso Isolation) ToQuerySettings() *Ydb_Query.TransactionSettings { + return iso.queryTxSelector().BeginTx +} + +func (iso Isolation) applyQueryTxSelector(txControl *Ydb_Query.TransactionControl) { + txControl.TxSelector = iso.queryTxSelector() +} + +func (iso Isolation) applyTableTxSelector(txControl *Ydb_Table.TransactionControl) { + txControl.TxSelector = iso.tableTxSelector() +} + +func (iso Isolation) applyTxControlOption(txControl *Control) { + txControl.selector = iso +} + +func (iso Isolation) tableTxSelector() *Ydb_Table.TransactionControl_BeginTx { + switch iso { + case SerializableRW: + return tableSerializableReadWriteTxSelector + case SnapshotRO: + return tableSnapshotReadOnlyTxSelector + case OnlineRO: + return tableOnlineReadOnlyForbidInconsistentReadsTxSelector + case OnlineROWithInconsistentReads: + return tableOnlineReadOnlyAllowInconsistentReadsTxSelector + case StaleRO: + return tableStaleReadOnlyTxSelector + default: + panic(fmt.Sprintf("unknown isolation: %d", iso)) + } +} + +func (iso Isolation) queryTxSelector() *Ydb_Query.TransactionControl_BeginTx { + switch iso { + case SerializableRW: + return querySerializableReadWriteTxSelector + case SnapshotRO: + return querySnapshotReadOnlyTxSelector + case OnlineRO: + return queryOnlineReadOnlyForbidInconsistentReadsTxSelector + case OnlineROWithInconsistentReads: + return queryOnlineReadOnlyAllowInconsistentReadsTxSelector + case StaleRO: + return queryStaleReadOnlyTxSelector + default: + panic(fmt.Sprintf("unknown isolation: %d", iso)) + } +} + +const ( + SerializableRW = Isolation(iota) + SnapshotRO + OnlineRO + OnlineROWithInconsistentReads + StaleRO +) + +var _ Settings = Isolation(0) diff --git a/internal/tx/settings.go b/internal/tx/settings.go index d8864e180..2aac6bfa4 100644 --- a/internal/tx/settings.go +++ b/internal/tx/settings.go @@ -9,33 +9,83 @@ var ( querySerializableReadWrite = &Ydb_Query.TransactionSettings_SerializableReadWrite{ SerializableReadWrite: &Ydb_Query.SerializableModeSettings{}, } + querySerializableReadWriteTxSelector = &Ydb_Query.TransactionControl_BeginTx{ + BeginTx: &Ydb_Query.TransactionSettings{ + TxMode: querySerializableReadWrite, + }, + } queryStaleReadOnly = &Ydb_Query.TransactionSettings_StaleReadOnly{ StaleReadOnly: &Ydb_Query.StaleModeSettings{}, } + queryStaleReadOnlyTxSelector = &Ydb_Query.TransactionControl_BeginTx{ + BeginTx: &Ydb_Query.TransactionSettings{ + TxMode: queryStaleReadOnly, + }, + } querySnapshotReadOnly = &Ydb_Query.TransactionSettings_SnapshotReadOnly{ SnapshotReadOnly: &Ydb_Query.SnapshotModeSettings{}, } + querySnapshotReadOnlyTxSelector = &Ydb_Query.TransactionControl_BeginTx{ + BeginTx: &Ydb_Query.TransactionSettings{ + TxMode: querySnapshotReadOnly, + }, + } queryOnlineReadOnlyAllowInconsistentReads = &Ydb_Query.TransactionSettings_OnlineReadOnly{ OnlineReadOnly: &Ydb_Query.OnlineModeSettings{AllowInconsistentReads: true}, } + queryOnlineReadOnlyAllowInconsistentReadsTxSelector = &Ydb_Query.TransactionControl_BeginTx{ + BeginTx: &Ydb_Query.TransactionSettings{ + TxMode: queryOnlineReadOnlyAllowInconsistentReads, + }, + } queryOnlineReadOnlyForbidInconsistentReads = &Ydb_Query.TransactionSettings_OnlineReadOnly{ OnlineReadOnly: &Ydb_Query.OnlineModeSettings{AllowInconsistentReads: false}, } + queryOnlineReadOnlyForbidInconsistentReadsTxSelector = &Ydb_Query.TransactionControl_BeginTx{ + BeginTx: &Ydb_Query.TransactionSettings{ + TxMode: queryOnlineReadOnlyForbidInconsistentReads, + }, + } tableSerializableReadWrite = &Ydb_Table.TransactionSettings_SerializableReadWrite{ SerializableReadWrite: &Ydb_Table.SerializableModeSettings{}, } + tableSerializableReadWriteTxSelector = &Ydb_Table.TransactionControl_BeginTx{ + BeginTx: &Ydb_Table.TransactionSettings{ + TxMode: tableSerializableReadWrite, + }, + } tableStaleReadOnly = &Ydb_Table.TransactionSettings_StaleReadOnly{ StaleReadOnly: &Ydb_Table.StaleModeSettings{}, } + tableStaleReadOnlyTxSelector = &Ydb_Table.TransactionControl_BeginTx{ + BeginTx: &Ydb_Table.TransactionSettings{ + TxMode: tableStaleReadOnly, + }, + } tableSnapshotReadOnly = &Ydb_Table.TransactionSettings_SnapshotReadOnly{ SnapshotReadOnly: &Ydb_Table.SnapshotModeSettings{}, } + tableSnapshotReadOnlyTxSelector = &Ydb_Table.TransactionControl_BeginTx{ + BeginTx: &Ydb_Table.TransactionSettings{ + TxMode: tableSnapshotReadOnly, + }, + } tableOnlineReadOnlyAllowInconsistentReads = &Ydb_Table.TransactionSettings_OnlineReadOnly{ OnlineReadOnly: &Ydb_Table.OnlineModeSettings{AllowInconsistentReads: true}, } + tableOnlineReadOnlyAllowInconsistentReadsTxSelector = &Ydb_Table.TransactionControl_BeginTx{ + BeginTx: &Ydb_Table.TransactionSettings{ + TxMode: tableOnlineReadOnlyAllowInconsistentReads, + }, + } tableOnlineReadOnlyForbidInconsistentReads = &Ydb_Table.TransactionSettings_OnlineReadOnly{ OnlineReadOnly: &Ydb_Table.OnlineModeSettings{AllowInconsistentReads: false}, } + tableOnlineReadOnlyForbidInconsistentReadsTxSelector = &Ydb_Table.TransactionControl_BeginTx{ + BeginTx: &Ydb_Table.TransactionSettings{ + TxMode: tableOnlineReadOnlyForbidInconsistentReads, + }, + } ) // Transaction settings options @@ -44,10 +94,45 @@ type ( ApplyQueryTxSettingsOption(txSettings *Ydb_Query.TransactionSettings) ApplyTableTxSettingsOption(txSettings *Ydb_Table.TransactionSettings) } - Settings []SettingsOption + Settings interface { + ControlOption + Selector + + ToTableSettings() *Ydb_Table.TransactionSettings + ToQuerySettings() *Ydb_Query.TransactionSettings + } + Options []SettingsOption ) -func (opts Settings) applyTableTxSelector(txControl *Ydb_Table.TransactionControl) { +func (opts Options) applyTxControlOption(txControl *Control) { + txControl.selector = BeginTx(opts...) +} + +func (opts Options) ToTableSettings() *Ydb_Table.TransactionSettings { + txSettings := &Ydb_Table.TransactionSettings{} + for _, opt := range opts { + if opt != nil { + opt.ApplyTableTxSettingsOption(txSettings) + } + } + + return txSettings +} + +func (opts Options) ToQuerySettings() *Ydb_Query.TransactionSettings { + txSettings := &Ydb_Query.TransactionSettings{} + for _, opt := range opts { + if opt != nil { + opt.ApplyQueryTxSettingsOption(txSettings) + } + } + + return txSettings +} + +var _ Settings = Options(nil) + +func (opts Options) applyTableTxSelector(txControl *Ydb_Table.TransactionControl) { beginTx := &Ydb_Table.TransactionControl_BeginTx{ BeginTx: &Ydb_Table.TransactionSettings{}, } @@ -59,7 +144,7 @@ func (opts Settings) applyTableTxSelector(txControl *Ydb_Table.TransactionContro txControl.TxSelector = beginTx } -func (opts Settings) applyQueryTxSelector(txControl *Ydb_Query.TransactionControl) { +func (opts Options) applyQueryTxSelector(txControl *Ydb_Query.TransactionControl) { beginTx := &Ydb_Query.TransactionControl_BeginTx{ BeginTx: &Ydb_Query.TransactionSettings{}, } @@ -71,7 +156,7 @@ func (opts Settings) applyQueryTxSelector(txControl *Ydb_Query.TransactionContro txControl.TxSelector = beginTx } -func (opts Settings) ToYdbQuerySettings() *Ydb_Query.TransactionSettings { +func (opts Options) ToYdbQuerySettings() *Ydb_Query.TransactionSettings { txSettings := &Ydb_Query.TransactionSettings{} for _, opt := range opts { if opt != nil { @@ -82,7 +167,7 @@ func (opts Settings) ToYdbQuerySettings() *Ydb_Query.TransactionSettings { return txSettings } -func (opts Settings) ToYdbTableSettings() *Ydb_Table.TransactionSettings { +func (opts Options) ToYdbTableSettings() *Ydb_Table.TransactionSettings { txSettings := &Ydb_Table.TransactionSettings{} for _, opt := range opts { if opt != nil { @@ -94,7 +179,7 @@ func (opts Settings) ToYdbTableSettings() *Ydb_Table.TransactionSettings { } // NewSettings returns transaction settings -func NewSettings(opts ...SettingsOption) Settings { +func NewSettings(opts ...SettingsOption) Options { return opts } diff --git a/query/transaction.go b/query/transaction.go index 81444fde5..a23f5b405 100644 --- a/query/transaction.go +++ b/query/transaction.go @@ -18,9 +18,27 @@ type ( CommitTx(ctx context.Context) (err error) Rollback(ctx context.Context) (err error) } - TransactionControl = tx.Control + + // TransactionControl is a special YDB object for define how to start (TransactionSettings) and end (CommitTx flag) + // of transaction per each query + // Deprecated: doesn't exists any use cases, when CommitTx=false + TransactionControl = tx.Control + TransactionSettings = tx.Settings TransactionOption = tx.SettingsOption + + // Isolation is well-known definition about isolation concurrent transactions + // The closest concept of isolation in ydb is transaction settings. + // Almost TransactionSettings matches to standard isolation levels (excluding OnlineReadOnly) + Isolation = tx.Settings +) + +const ( + SerializableRW = tx.SerializableRW + SnapshotRO = tx.SnapshotRO + OnlineRO = tx.OnlineRO + OnlineROWithInconsistentReads = tx.OnlineROWithInconsistentReads + StaleRO = tx.StaleRO ) // BeginTx returns selector transaction control option @@ -96,7 +114,7 @@ func SnapshotReadOnlyTxControl() *TransactionControl { // TxSettings returns transaction settings func TxSettings(opts ...tx.SettingsOption) TransactionSettings { - return opts + return tx.NewSettings(opts...) } func WithDefaultTxMode() TransactionOption { diff --git a/table/table.go b/table/table.go index 454722ccf..995010007 100644 --- a/table/table.go +++ b/table/table.go @@ -177,7 +177,7 @@ type Session interface { } type ( - TransactionSettings = tx.Settings + TransactionSettings = tx.Options // Transaction control options TxOption = tx.SettingsOption )