transactions: start sessions and transactions at the same place
this make it possible for handler to use `withSession` when transactions is not nedded and `inTransactionCtx` if its needed without knowing who owns the session/transaction
This commit is contained in:
@@ -22,21 +22,30 @@ func newSession() *DBSession {
|
|||||||
return &DBSession{Session: x.NewSession()}
|
return &DBSession{Session: x.NewSession()}
|
||||||
}
|
}
|
||||||
|
|
||||||
func startSession(ctx context.Context) *DBSession {
|
func startSession(ctx context.Context, engine *xorm.Engine, beginTran bool) (*DBSession, error) {
|
||||||
value := ctx.Value(ContextSessionName)
|
value := ctx.Value(ContextSessionName)
|
||||||
var sess *DBSession
|
var sess *DBSession
|
||||||
sess, ok := value.(*DBSession)
|
sess, ok := value.(*DBSession)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
newSess := newSession()
|
newSess := &DBSession{Session: engine.NewSession()}
|
||||||
return newSess
|
if beginTran {
|
||||||
|
err := newSess.Begin()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newSess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return sess
|
return sess, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func withDbSession(ctx context.Context, callback dbTransactionFunc) error {
|
func withDbSession(ctx context.Context, callback dbTransactionFunc) error {
|
||||||
sess := startSession(ctx)
|
sess, err := startSession(ctx, x, false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return callback(sess)
|
return callback(sess)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,16 +14,16 @@ func (ss *SqlStore) InTransaction(ctx context.Context, fn func(ctx context.Conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ss *SqlStore) inTransactionWithRetry(ctx context.Context, fn func(ctx context.Context) error, retry int) error {
|
func (ss *SqlStore) inTransactionWithRetry(ctx context.Context, fn func(ctx context.Context) error, retry int) error {
|
||||||
sess := startSession(ctx)
|
sess, err := startSession(ctx, ss.engine, true)
|
||||||
defer sess.Close()
|
if err != nil {
|
||||||
|
|
||||||
if err := sess.Begin(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer sess.Close()
|
||||||
|
|
||||||
withValue := context.WithValue(ctx, ContextSessionName, sess)
|
withValue := context.WithValue(ctx, ContextSessionName, sess)
|
||||||
|
|
||||||
err := fn(withValue)
|
err = fn(withValue)
|
||||||
|
|
||||||
// special handling of database locked errors for sqlite, then we can retry 3 times
|
// special handling of database locked errors for sqlite, then we can retry 3 times
|
||||||
if sqlError, ok := err.(sqlite3.Error); ok && retry < 5 {
|
if sqlError, ok := err.(sqlite3.Error); ok && retry < 5 {
|
||||||
@@ -60,16 +60,13 @@ func inTransactionWithRetry(callback dbTransactionFunc, retry int) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func inTransactionWithRetryCtx(ctx context.Context, callback dbTransactionFunc, retry int) error {
|
func inTransactionWithRetryCtx(ctx context.Context, callback dbTransactionFunc, retry int) error {
|
||||||
var err error
|
sess, err := startSession(ctx, x, true)
|
||||||
|
if err != nil {
|
||||||
sess := startSession(ctx)
|
|
||||||
|
|
||||||
defer sess.Close()
|
|
||||||
|
|
||||||
if err = sess.Begin(); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer sess.Close()
|
||||||
|
|
||||||
err = callback(sess)
|
err = callback(sess)
|
||||||
|
|
||||||
// special handling of database locked errors for sqlite, then we can retry 3 times
|
// special handling of database locked errors for sqlite, then we can retry 3 times
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/log"
|
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
|
||||||
. "github.com/smartystreets/goconvey/convey"
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
@@ -18,11 +17,9 @@ type testQuery struct {
|
|||||||
var ProvokedError = errors.New("testing error.")
|
var ProvokedError = errors.New("testing error.")
|
||||||
|
|
||||||
func TestTransaction(t *testing.T) {
|
func TestTransaction(t *testing.T) {
|
||||||
InitTestDB(t)
|
ss := InitTestDB(t)
|
||||||
|
|
||||||
Convey("InTransaction asdf asdf", t, func() {
|
Convey("InTransaction asdf asdf", t, func() {
|
||||||
ss := SqlStore{log: log.New("test-logger")}
|
|
||||||
|
|
||||||
cmd := &models.AddApiKeyCommand{Key: "secret-key", Name: "key", OrgId: 1}
|
cmd := &models.AddApiKeyCommand{Key: "secret-key", Name: "key", OrgId: 1}
|
||||||
|
|
||||||
err := AddApiKey(cmd)
|
err := AddApiKey(cmd)
|
||||||
@@ -50,7 +47,6 @@ func TestTransaction(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ProvokedError
|
return ProvokedError
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
So(err, ShouldEqual, ProvokedError)
|
So(err, ShouldEqual, ProvokedError)
|
||||||
|
|||||||
Reference in New Issue
Block a user